An Error in the LimeSuite Libraries

There appears to be an error in the LimeSuite Libraries. The call to “LMS_StopStream” should stop the transmission - it doesn’t. Even after the call to “LMS_DestroyStream” - the LimeSDR mini continues to transmit. It is not until the call to “LMS_Close” completely shuts things down that the transmission stop. I have include a version of basicTX.cpp that waits after the calls to LMS_StopStream and LMS_DestroyStream. The video

shows the problem - the LimeSDR mini continues to transmit after the calls to shut the stream down. It happens on MacOS, Ubuntu 18.04, Windows 10 and the Raspberry PI.

/**
@file basicTX.cpp
@author Lime Microsystems (www.limemicro.com)
@brief minimal TX example
*/
#include
#include
#include <math.h>
#include “lime/LimeSuite.h”

using namespace std;

//Device structure, should be initialize to NULL
lms_device_t* device = NULL;

int error()
{
if (device != NULL)
LMS_Close(device);
exit(-1);
}

int main(int argc, char** argv)
{
const double frequency = 500e6; //center frequency to 500 MHz
const double sample_rate = 5e6; //sample rate to 5 MHz
const double tone_freq = 1e6; //tone frequency
//Find devices
int n;
lms_info_str_t list[8]; //should be large enough to hold all detected devices
if ((n = LMS_GetDeviceList(list)) < 0) //NULL can be passed to only get number of devices
error();

cout << "Devices found: " << n << endl; //print number of devices
if (n < 1)
    return -1;

//open the first device
if (LMS_Open(&device, list[0], NULL))
    error();

//Initialize device with default configuration
//Do not use if you want to keep existing configuration
//Use LMS_LoadConfig(device, "/path/to/file.ini") to load config from INI
if (LMS_Init(device)!=0)
    error();

//Enable TX channel,Channels are numbered starting at 0
if (LMS_EnableChannel(device, LMS_CH_TX, 0, true)!=0)
    error();

//Set sample rate
if (LMS_SetSampleRate(device, sample_rate, 0)!=0)
    error();
cout << "Sample rate: " << sample_rate/1e6 << " MHz" << endl;

//Set center frequency
if (LMS_SetLOFrequency(device,LMS_CH_TX, 0, frequency)!=0)
    error();
cout << "Center frequency: " << frequency/1e6 << " MHz" << endl;

//select TX1_1 antenna
if (LMS_SetAntenna(device, LMS_CH_TX, 0, LMS_PATH_TX1)!=0)
    error();

//set TX gain
if (LMS_SetNormalizedGain(device, LMS_CH_TX, 0, 0.7) != 0)
    error();

//Streaming Setup

lms_stream_t tx_stream;                 //stream structure
tx_stream.channel = 0;                  //channel number
tx_stream.fifoSize = 256*1024;          //fifo size in samples
tx_stream.throughputVsLatency = 0.5;    //0 min latency, 1 max throughput
tx_stream.dataFmt = lms_stream_t::LMS_FMT_F32; //floating point samples
tx_stream.isTx = true;                  //TX channel
LMS_SetupStream(device, &tx_stream);

//Initialize data buffers
const int tx_size = 1024*8;
float tx_buffer[2*tx_size];     //buffer to hold complex values (2*samples))
for (int i = 0; i <tx_size; i++) {      //generate TX tone
    const double pi = acos(-1);
    double w = 2*pi*i*tone_freq/sample_rate;
    tx_buffer[2*i] = cos(w);
    tx_buffer[2*i+1] = sin(w);
}
cout << "Tx tone frequency: " << tone_freq/1e6 << " MHz" << endl;

LMS_StartStream(&tx_stream);         //Start streaming
//Streaming
auto t1 = chrono::high_resolution_clock::now();
auto t2 = t1;
while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(10)) //run for 10 seconds
{
    //Transmit samples
    int ret = LMS_SendStream(&tx_stream, tx_buffer, tx_size, nullptr, 1000);
    if (ret != tx_size)
        cout << "error: samples sent: " << ret << "/" << tx_size << endl;
    //Print data rate (once per second)
    if (chrono::high_resolution_clock::now() - t2 > chrono::seconds(1))
    {
        t2 = chrono::high_resolution_clock::now();
        lms_stream_status_t status;
        LMS_GetStreamStatus(&tx_stream, &status);  //Get stream status

// cout << “TX data rate: " << status.linkRate / 1e6 << " MB/s\n”; //link data rate
cout << “active " << status.active << " TX data rate: " << status.linkRate / 1e6 << " MB/s\n”; //link data rate

    }
}
//Stop streaming
LMS_StopStream(&tx_stream);
LMS_DestroyStream(device, &tx_stream);

 cout << " Wait After LMS_StopStream and LMS_DestroyStream" << endl;

t1 = chrono::high_resolution_clock::now();
while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(10)) //run for 10 seconds
{
    if (chrono::high_resolution_clock::now() - t2 > chrono::seconds(1))
    {
        t2 = chrono::high_resolution_clock::now();
        lms_stream_status_t status;
        LMS_GetStreamStatus(&tx_stream, &status);  //Get stream status
        cout << "active " << status.active << " TX data rate: " << status.linkRate / 1e6 << " MB/s\n"; //link data rate
    }
}



//Disable TX channel
if (LMS_EnableChannel(device, LMS_CH_TX, 0, false)!=0)
    error();

//Close device
if (LMS_Close(device)==0)
    cout << "Closed" << endl;
return 0;

}

I’ve just come here to ask about exactly the same thing, but not nearly so eloquently so thank you! I’ve been using the Soapy libraries but I’m seeing exactly the same problem, it just never stops transmitting.

Did you ever have any luck finding a way around it?

I have encountered the error too. I even had cases where the LimeSDR Mini started transmitting without even writing any samples. To work around that, I do:

const void *txbufs[1];
complex float *buf;
buf = calloc(BUFSIZE, sizeof(*buf));
if (!buf) return memerr();
txbufs[0] = buf;

/* ... */

// activate TX stream:
if (SoapySDRDevice_activateStream(device, tx, 0, 0, 0))
    return deverr("Could not activate TX stream");

// silence TX:
buf[0] = 0;
flags = 0;
if (SoapySDRDevice_writeStream(
    device, tx, txbufs, 1, &flags, 0, 1000000
) != 1) deverr("Could not silence RF");

/* ... */

// silence TX:
buf[0] = 0;
flags = 0;
if (SoapySDRDevice_writeStream(
    device, tx, txbufs, 1, &flags, 0, 1000000
) != 1) deverr("Could not silence RF");

// close TX stream:
if (SoapySDRDevice_deactivateStream(device, tx, 0, 0))
    deverr("Could not deactivate TX stream");

(Note the “silence TX” sections)

It’s a dirty workaround, and I think this should be fixed in the library instead.

Thanks, I’ll give that a go! Best thing I’ve found so far is tearing everything down and reinitialising it, which takes ages. I’ve raised it as a bug on the limesdr GitHub page, maybe it’ll get fixed someday but it’s going to be a fairly major change so I’m not holding my breathe.

I also found that initialization takes quite a long time. This is why I usually initialize once, and then send one zero sample to silence the transmitter. It will not fully stop emitting RF, but it is pretty quiet.

I think somewhere it has been discussed to extend the Soapy libraries in such way that you can disable TX to not go through initialization again if you want to interrupt TX and later continue. But not sure when/if that’s done.

In SdrGlut , I stop the lime transmission with -

     device->deactivateStream(txStream);
    
    device->closeStream(txStream);

    device->setFrequency(SOAPY_SDR_TX, rx->channel, frequency);
    
    device->setGain(SOAPY_SDR_TX, rx->channel, 0.0);

Although, I think that setting the gain to 0.0, (not the minimum) is all that is required.