Transmit and Receive Continuously at the Same Time

Hello,
I have been working on a LimeSuite API C++ program where I want to receive the same thing that I am transmitting from LimeSDR. However, it seems that Lime transmits the samples in the tx buffer then starts receiving once the transmission have been finished. Am I missing something? Is there a way to do this simultaneously? Below you can see the main method of my code.

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();

if (LMS_Init(device) != 0)
    error();

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

//Set center frequency to 800 MHz
if (LMS_SetLOFrequency(device, LMS_CH_RX, 0, 63795683.36) != 0)
    error();

//Set sample rate to 8 MHz, ask to use 2x oversampling in RF
//This set sampling rate for all channels
if (LMS_SetSampleRate(device, 4e6, 0) != 0)
    error();

if( LMS_SetNormalizedGain(device, LMS_CH_RX, 0, 0.4) != 0)
	error();

//TX
//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 buffer_size = 500000*2;
float tx_buffer[2*buffer_size];
int j = 0;
for (int i = 0; i <buffer_size; i++)
{
	//const double pi = acos(-1);
	//double w = 2*pi*i*f_ratio;
	tx_buffer[2 * i +1] = 0;
	if ( j < 50 ) {
		tx_buffer[2 * i] = 1;//sin(w)
	}
	else {
		tx_buffer[2 * i] = 0;
	}
	if ( j == 99 ){
		j = 0;
	}
	else {
		j++;
	}
	/*if (i > 1000 && i <= 11000)
		tx_buffer[2 * i] =0.06;*/
}

//Initialize stream

lms_stream_t streamId; //stream structure
streamId.channel = 0; //channel number
streamId.fifoSize = 1024 * 1024; //fifo size in samples
streamId.throughputVsLatency = 1.0; //optimize for max throughput
streamId.isTx = false; //RX channel
streamId.dataFmt = lms_stream_t::LMS_FMT_I12; //12-bit integers
if (LMS_SetupStream(device, &streamId) != 0)
    error();

//Initialize data buffers
const int sampleCnt = 50000; //complex samples per buffer
int16_t buffer[sampleCnt * 2]; //buffer to hold complex values (2*samples))

//Streaming
GNUPlotPipe gp;
gp.write("set size square\n set xrange[0:20000]\n set yrange[-2050:2050]\n");
LMS_StartStream(&tx_stream);         //Start streaming
LMS_StartStream(&streamId);
cout << "SENDING" << endl;
for (int i = 0; i < 10; i++ ){
	int ret = LMS_SendStream(&tx_stream, tx_buffer, send_cnt, nullptr, 1000);
	cout << "SENT" << endl;
	int samplesRead = LMS_RecvStream(&streamId, buffer, sampleCnt, NULL, 1000);
	//I and Q samples are interleaved in buffer: IQIQIQ...
	printf("Received %d samples\n", samplesRead);


	//Plot samples
	gp.write("plot '-' with points\n");
	for (int j = 0; j < samplesRead; ++j)
		gp.writef("%i %i\n", j, buffer[2 * j ]);
	gp.write("e\n");
	gp.flush();
}
//Stop streaming
LMS_StopStream(&streamId); //stream is stopped but can be started again with LMS_StartStream()
LMS_DestroyStream(device, &streamId); //stream is deallocated and can no longer be used*/
LMS_StopStream(&tx_stream);
LMS_DestroyStream(device, &tx_stream);


//Close device
LMS_Close(device);

return 0;

I do not know, but I suspect that the document in this post might help.

And I suspect that the dualRXTX.cpp example code may help as well LimeSuite/src/examples at master · myriadrf/LimeSuite · GitHub

EDIT: I just re-read your question and now I think that you may be asking a fundamental programming question, which is not inherently related to SDR, “How do you use multithreading to have different things happening at the same time ?”
In C++ 11 you can use std::thread, or pthread’s is another option with any C/C++. Both have a high setup and tear down overheads, so you would typically setup threads and reuse them as much as possible. The performance of each should be the exact same since it is the OS that ultimately handles the creation of new threads.

I checked out the dualRxTx.cpp example and it is basically where I got the inspiration for my code. However, you might be right that I need threading. But before trying so, are we sure that limeSDR hardware is capable of doing this so the threading will work?

I’m going to guess yes ?


And if it is not you can always use locks (mutual exclusion or mutex).

Of the programs that can control the Lime Devices, CubicSDR uses three threads per receive channel - no transmit. SdrGlut has one background thread per receive channel and does the transmit in a background audio loop while the foreground thread waits. Gqrx also has at least one background receive channel - no transmit.

1 Like

Yes definitely.

In your code above you send, then you receive, 10 times in a row. If you had 2 threads you could continuously send as well as receive at the same time.

1 Like