Hello,
I have a LimePCIe-SDR and I am trying to find ways to reduce switching time between Tx CH-A and TX CH-B. With the code below I get a switching time of around 3 msec.
- Has any one measured the switching time at their end?
- What is the minimum time that can be achieved?
- What are other methods that can used to reduce switching time?
- I am switching channels by turning TBB module of respective channel ON/OFF. Is there any other better method?
/*******************************************************************************
- INCLUDE FILES
******************************************************************************/
#include
#include
#include
#include
#include <unistd.h>
#include
#include <signal.h>
#include
#include
#include
#include “lime/LimeSuite.h”
#include “lime/Logger.h”
#include “lime/dataTypes.h”
#define USE_GNU_PLOT
#ifdef USE_GNU_PLOT
#include “gnuPlotPipe.h”
#endif
/*******************************************************************************
- NAMESPACE
******************************************************************************/
using namespace std;
using namespace lime;
/*******************************************************************************
- LOCAL DATA
******************************************************************************/
int samplesToCapture = 16384;
int onTime = 1;
volatile sig_atomic_t stop;
//Device structure, should be initialize to NULL
lms_device_t* device = NULL;
/*******************************************************************************
- LOCAL FUNCTION DECLARATION
******************************************************************************/
static void TxThread(void);
static void RxThread(void);
static inline void SwitchTx(void);
static void inthand(int signum);
static int error();
/*******************************************************************************
-
@brief This function is the main application
-
@param argc argument count from command line
-
@param argv array of pointers to arguments passed
-
@return Fail: -1 or Success: 0
****************************************************************************/
int main(int argc, char argv)
{
//Find devices
int n;
signal(SIGINT, inthand);if(argc > 1)
{
for(int i=1; i < argc;)
{
if((std::string)argv[i] == “–sample”)
{
if(atoi(argv[2]) > 1)
samplesToCapture = atoi(argv[2]);
}if((std::string)argv[i] == "--ontime") onTime = atoi(argv[4]); i = i + 2; }
}
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();
if(LMS_LoadConfig(device,"/Desktop/mimo-test.ini") != 0)
error();//Get number of channels
if ((n = LMS_GetNumChannels(device, LMS_CH_RX)) < 0)
error();
cout << "Number of RX channels: " << n << endl;
if ((n = LMS_GetNumChannels(device, LMS_CH_TX)) < 0)
error();
cout << "Number of TX channels: " << n << endl;LMS_WriteParam(device,LMS7_MAC,2);
LMS_WriteParam(device,LMS7_LOSS_MAIN_TXPAD_R3,0);
LMS_WriteParam(device,LMS7_CG_IAMP_TBB_R3,63);
LMS_WriteParam(device,LMS7_EN_G_TBB,0);
LMS_WriteParam(device,LMS7_MAC,1);
LMS_WriteParam(device,LMS7_LOSS_MAIN_TXPAD_R3,0);
LMS_WriteParam(device,LMS7_EN_G_TBB,0);std::thread t1(TxThread);
std::thread t2(RxThread);t1.join();
t2.join();if (LMS_EnableChannel(device, LMS_CH_RX, 0, false) != 0)
error();
if (LMS_EnableChannel(device, LMS_CH_RX, 1, false) != 0)
error();
//Enable TX channels
if (LMS_EnableChannel(device, LMS_CH_TX, 0, false) != 0)
error();
if (LMS_EnableChannel(device, LMS_CH_TX, 1, false) != 0)
error();
//Close device
LMS_Close(device);return 0;
}
/*******************************************************************************
-
@brief This function is tx thread. This function switches the Tx port after
-
every 1 msec
-
@param void
-
@param void
-
@return void
******************************************************************************/
void TxThread(void)
{
static uint16_t i = 0;
auto start = chrono::high_resolution_clock::now();
auto switchTime = start;
while(!stop)
{
switchTime = chrono::high_resolution_clock::now();
SwitchTx();
while ((chrono::high_resolution_clock::now() - switchTime) < chrono::milliseconds(onTime))
{
}
}auto finish = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_castchrono::microseconds(finish - start);
cout<<“TxT:”<< elapsed.count() <<endl;
cout<<endl;
}
/*******************************************************************************
-
@brief This function is rx thread. This function gathers data from all Rx ports
-
and dumps it onto a file for offline analysis
-
@param void
-
@param void
-
@return void
***************************************************************************/
void RxThread(void)
{
//Initialize stream
lms_stream_t streamId[2];
lime::complex16_t buffers;
const int channelsCount = 2;
int avgCount = 512;
int noOfSamples = samplesToCapture;
unsigned short samplesToGetPerCall = 16384;
const int fifoSize = samplesToGetPerCall512;streamId[0].channel = 0; //channel number
streamId[0].fifoSize = fifoSize;//1024 * 1024; //fifo size in samples
streamId[0].throughputVsLatency = 1.0; //optimize for max throughput
streamId[0].isTx = false; //RX channel
streamId[0].dataFmt = lms_stream_t::LMS_FMT_I16;
if (LMS_SetupStream(device, &streamId[0]) != 0)
error();streamId[1].channel = 1; //channel number
streamId[1].fifoSize = fifoSize;//1024 * 1024; //fifo size in samples
streamId[1].throughputVsLatency = 1.0; //optimize for max throughput
streamId[1].isTx = false; //RX channel
streamId[1].dataFmt = lms_stream_t::LMS_FMT_I16;
if (LMS_SetupStream(device, &streamId[1]) != 0)
error();buffers = new lime::complex16_t*[channelsCount];
for (int i = 0; i < channelsCount; ++i)
buffers[i] = new complex16_t[samplesToGetPerCall];vector<complex16_t> captureBuffer[channelsCount];
uint32_t samplesToCapture[channelsCount];
uint32_t samplesCaptured[channelsCount];for(int ch=0; ch<channelsCount; ++ch)
{
samplesToCapture[ch] = noOfSamples;
captureBuffer[ch].resize(samplesToCapture[ch]);
samplesCaptured[ch] = 0;
}LMS_StartStream(&streamId[0]);
LMS_StartStream(&streamId[1]);lms_stream_meta_t meta;
meta.waitForTimestamp = 0;//syncTx;
meta.flushPartialPacket = false;
int fftCounter = 0;auto start = std::chrono::high_resolution_clock::now();
auto t1 = std::chrono::high_resolution_clock::now();while(!stop)
{
do{
uint32_t samplesPopped[channelsCount];
uint64_t ts[channelsCount];
for(int i=0; i<channelsCount; ++i)
{
samplesPopped[i] = LMS_RecvStream(&streamId[i], &buffers[i][0], samplesToGetPerCall, &meta, 1000);
ts[i] = meta.timestamp + fifoSize/4;
}for(int ch=0; ch<channelsCount; ++ch) { uint32_t samplesToCopy = min(samplesPopped[ch], samplesToCapture[ch]); if(samplesToCopy <= 0) continue; memcpy((captureBuffer[ch].data() + samplesCaptured[ch]), buffers[ch], samplesToCopy*sizeof(complex16_t)); samplesToCapture[ch] -= samplesToCopy; samplesCaptured[ch] += samplesToCopy; } }while(samplesToCapture[0] != 0 && samplesToCapture[1] != 0); if(samplesToCapture[0] == 0 && samplesToCapture[1] == 0) { ofstream fout; fout.open("samples.txt",std::ofstream::trunc | std::ofstream::out); #if 1 fout << "AI\tAQ"; if(channelsCount > 1) fout << "\tBI\tBQ"; fout << endl; #endif int samplesCnt = captureBuffer[0].size(); for(int i=0; i<samplesCnt; ++i) { for(int ch=0; ch<channelsCount; ++ch) { fout << captureBuffer[ch][i].i << "\t" << captureBuffer[ch][i].q << "\t"; } fout << endl; } fout.close(); auto finish = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast<chrono::microseconds>(finish - start); cout<<"RxT:"<< elapsed.count() <<endl; cout << endl <<"samplesCaptured Ch 1:" << samplesCaptured[0]<< endl; cout << endl <<"samplesCaptured Ch 2:" << samplesCaptured[1]<< endl; stop = 1; } // }while(1);//while(++fftCounter < avgCount);//while(++fftCounter < avgCount); //Reset values for next run ; required only if continuous acquisiton is required #if 0 samplesToCapture[0] = noOfSamples; samplesToCapture[1] = noOfSamples; samplesCaptured[0] = 0; samplesCaptured[1] = 0; fftCounter = 0; #endif
#if 0
string filename = “samples.absdbfs”;
fout.open(filename.c_str());
fout << "AI\tAQ";
if(channelsCount > 1)
fout << "\tBI\tBQ";
fout << endl;
for(int i=0; i<samplesCnt; ++i)
{
for(int ch=0; ch<channelsCount; ++ch)
{
fout
<< (captureBuffer[ch][i].i == 0 ? -67 : 20*log10(abs(captureBuffer[ch][i].i)/2048))<< "\t"
<< (captureBuffer[ch][i].q == 0 ? -67 : 20*log10(abs(captureBuffer[ch][i].q)/2048))<< "\t";
}
fout << endl;
}
fout.close();
#endif
}
for(int i=0; i<channelsCount; ++i)
{
LMS_StopStream(&streamId[i]);
LMS_DestroyStream(device, &streamId[i]);
}
for (int i = 0; i < channelsCount; ++i)
delete [] buffers[i];
delete [] buffers;
}
/*******************************************************************************
-
@brief This function controls the switching of Tx ports.
-
@param void
-
@param void
-
@return void
******************************************************************************/
inline void SwitchTx(void)
{
static uint16_t toggle = 0xFF;if(toggle)
{
//Disable TBB Module A
LMS_WriteParam(device,LMS7_EN_G_TBB,0);//Change MAC to select channel B LMS_WriteParam(device,LMS7_MAC,2); //Enable TBB Module B LMS_WriteParam(device,LMS7_EN_G_TBB,1);
}
else
{//Disable TBB Module B LMS_WriteParam(device,LMS7_EN_G_TBB,0); //Change MAC to select channel A LMS_WriteParam(device,LMS7_MAC,1); //Enable TBB Module A LMS_WriteParam(device,LMS7_EN_G_TBB,1);
}
toggle ^= 0xFF;
}
/*******************************************************************************
- @brief This function is a utility funtion to toggle stop variable upon receiving
- ctrl^c signal from user. This terminates the application.
- @param void
- @param void
-
@return void
******************************************************************************/
static void inthand(int signum) {
stop = 1;
}
/*******************************************************************************
- @brief This function is a utility funtion for error handling
- @param void
- @param void
-
@return void
******************************************************************************/
static int error()
{
if (device != NULL)
LMS_Close(device);
exit(-1);
}
Thanks.