Created
October 17, 2017 17:30
-
-
Save wowa-2017/49f15b2e47ad0fb6987a0c37a5d622aa to your computer and use it in GitHub Desktop.
LimeSDR dualRX_01
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
@file singleRX.cpp | |
@author Lime Microsystems (www.limemicro.com) | |
@brief RX example | |
*/ | |
#include "lime/LimeSuite.h" | |
#include <iostream> | |
#include <chrono> | |
#ifdef USE_GNU_PLOT | |
#include "gnuPlotPipe.h" | |
#endif | |
#include "Writer.h" | |
using namespace std; | |
//Device structure, should be initialize to NULL | |
lms_device_t* device = NULL; | |
const double Fc = 1e9; // Гц | |
//const double Fc = 800e6; // Гц | |
const double Fs = 5e6; | |
//const double Fs = 8e6; | |
const double FsOvrFact = 2; | |
//const double FsOvrFact = 2; | |
const double Flpw = 120e6; | |
const int Gain = 10; // дБ | |
const double TgtTime = 0.1; // секунд | |
const long TgtSampCnt = TgtTime*Fs; | |
int error() | |
{ | |
//print last error message | |
cout << "ERROR:" << LMS_GetLastErrorMessage(); | |
if (device != NULL) | |
LMS_Close(device); | |
exit(-1); | |
} | |
int main(int argc, char** argv) | |
{ | |
//Find devices | |
//First we find number of devices, then allocate large enough list, and then populate the list | |
int n; | |
if ((n = LMS_GetDeviceList(NULL)) < 0)//Pass NULL to only obtain number of devices | |
error(); | |
cout << "Devices found: " << n << endl; | |
if (n < 1) | |
return -1; | |
lms_info_str_t* list = new lms_info_str_t[n]; //allocate device list | |
if (LMS_GetDeviceList(list) < 0) //Populate device list | |
error(); | |
for (int i = 0; i < n; i++) //print device list | |
cout << i << ": " << list[i] << endl; | |
cout << endl; | |
//Open the first device | |
if (LMS_Open(&device, list[0], NULL)) | |
error(); | |
delete [] list; //free device list | |
//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) { | |
cout << "Init attempt failed (" << LMS_GetLastError() << "): " << LMS_GetLastErrorMessage() << endl; | |
cout << "Trying to reset..." << endl; | |
if (LMS_Reset(device) != 0) | |
error(); | |
cout << "Init attempt 2:" << endl; | |
if (LMS_Init(device) != 0) | |
error(); | |
} // if | |
//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_RX, 1, true) != 0) | |
error(); | |
//Set center frequency to 800 MHz | |
if (LMS_SetLOFrequency(device, LMS_CH_RX, 0, Fc) != 0) | |
error(); | |
if (LMS_SetLOFrequency(device, LMS_CH_RX, 1, Fc) != 0) | |
error(); | |
//print currently set center frequency | |
float_type freq; | |
if (LMS_GetLOFrequency(device, LMS_CH_RX, 0, &freq) != 0) | |
error(); | |
cout << "\nCenter frequency: " << freq / 1e6 << " MHz\n"; | |
//select antenna port | |
lms_name_t antenna_list[10]; //large enough list for antenna names. | |
//Alternatively, NULL can be passed to LMS_GetAntennaList() to obtain number of antennae | |
if ((n = LMS_GetAntennaList(device, LMS_CH_RX, 0, antenna_list)) < 0) | |
error(); | |
cout << "Available antennae:\n"; //print available antennae names | |
for (int i = 0; i < n; i++) | |
cout << i << ": " << antenna_list[i] << endl; | |
if ((n = LMS_GetAntenna(device, LMS_CH_RX, 0)) < 0) //get currently selected antenna index | |
error(); | |
//print antenna index and name | |
cout << "Automatically selected antenna: " << n << ": " << antenna_list[n] << endl; | |
if (LMS_SetAntenna(device, LMS_CH_RX, 0, LMS_PATH_LNAW) != 0) // manually select antenna | |
error(); | |
if (LMS_SetAntenna(device, LMS_CH_RX, 1, LMS_PATH_LNAW) != 0) // manually select antenna | |
error(); | |
if ((n = LMS_GetAntenna(device, LMS_CH_RX, 0)) < 0) //get currently selected antenna index | |
error(); | |
//print antenna index and name | |
cout << "Manually selected antenna: " << n << ": " << antenna_list[n] << endl; | |
//Set sample rate to 8 MHz, preferred oversampling in RF 8x | |
//This set sampling rate for all channels | |
if (LMS_SetSampleRate(device, Fs, FsOvrFact/*8e6, 8*/) != 0) | |
error(); | |
//print resulting sampling rates (interface to host , and ADC) | |
float_type rate, rf_rate; | |
if (LMS_GetSampleRate(device, LMS_CH_RX, 0, &rate, &rf_rate) != 0) //NULL can be passed | |
error(); | |
cout << "\nHost interface sample rate: " << rate / 1e6 << " MHz\nRF ADC sample rate: " << rf_rate / 1e6 << "MHz\n\n"; | |
//Example of getting allowed parameter value range | |
//There are also functions to get other parameter ranges (check LimeSuite.h) | |
//Get allowed LPF bandwidth range | |
lms_range_t range; | |
if (LMS_GetLOFrequencyRange(device, LMS_CH_RX, &range)!=0) | |
error(); | |
cout << "RX center freq range: " << range.min / 1e6 << " - " << range.max / 1e6 << " MHz\n"; | |
if (LMS_GetSampleRateRange(device, LMS_CH_RX, &range)!=0) | |
error(); | |
cout << "RX sample rate range: " << range.min / 1e6 << " - " << range.max / 1e6 << " MHz\n"; | |
if (LMS_GetLPFBWRange(device,LMS_CH_RX,&range)!=0) | |
error(); | |
cout << "RX LPF bandwitdh range: " << range.min / 1e6 << " - " << range.max / 1e6 << " MHz\n\n"; | |
//Configure LPF, bandwidth 8 MHz | |
if (LMS_SetLPFBW(device, LMS_CH_RX, 0, Flpw) != 0) | |
error(); | |
if (LMS_SetLPFBW(device, LMS_CH_RX, 1, Flpw) != 0) | |
error(); | |
//Set RX gain | |
if (LMS_SetGaindB(device, LMS_CH_RX, 0, Gain) != 0) | |
error(); | |
if (LMS_SetGaindB(device, LMS_CH_RX, 1, Gain) != 0) | |
error(); | |
/*if (LMS_SetNormalizedGain(device, LMS_CH_RX, 0, 0) != 0) | |
error(); | |
if (LMS_SetNormalizedGain(device, LMS_CH_RX, 1, 0) != 0) | |
error();*/ | |
//Print RX gain | |
float_type gain; //normalized gain | |
if (LMS_GetNormalizedGain(device, LMS_CH_RX, 0, &gain) != 0) | |
error(); | |
cout << "Normalized RX Gain: " << gain << endl; | |
unsigned int gaindB; //gain in dB | |
if (LMS_GetGaindB(device, LMS_CH_RX, 0, &gaindB) != 0) | |
error(); | |
cout << "RX Gain: " << gaindB << " dB" << endl; | |
//Perform automatic calibration | |
if (LMS_Calibrate(device, LMS_CH_RX, 0, Flpw, 0) != 0) | |
error(); | |
if (LMS_Calibrate(device, LMS_CH_RX, 1, Flpw, 0) != 0) | |
error();/**/ | |
// Switch off DC corrector | |
if (LMS_WriteParam(device, LMS7_DC_BYP_RXTSP, 1) != 0) | |
error(); | |
//Enable test signal generation | |
//To receive data from RF, remove this line or change signal to LMS_TESTSIG_NONE | |
/*if (LMS_SetTestSignal(device, LMS_CH_RX, 0, LMS_TESTSIG_NONE, 0, 0) != 0) | |
error(); | |
if (LMS_SetTestSignal(device, LMS_CH_RX, 1, LMS_TESTSIG_NONE, 0, 0) != 0) | |
error();/**/ | |
/*if (LMS_SetTestSignal(device, LMS_CH_RX, 0, LMS_TESTSIG_NCODIV8, 0, 0) != 0) | |
error(); | |
if (LMS_SetTestSignal(device, LMS_CH_RX, 1, LMS_TESTSIG_NCODIV8, 0, 0) != 0) | |
error();*/ | |
if (!wrOpen("f:\\Sig\\lime_trace.dat")) { | |
cout << "Can't open output file!" << endl; | |
exit(-1); | |
} // if | |
if (!wrWriteSetCrTrHdrProps(pdu_DefLime, round(Fc), round(Fs), TgtSampCnt)) { | |
cout << "Can't write output file header!" << endl; | |
exit(-1); | |
} // if | |
//Streaming Setup | |
lms_stream_t::_dataFmt Fmt = lms_stream_t::LMS_FMT_I16; | |
double ThrVsLat = 1; | |
//Initialize stream | |
lms_stream_t streamId[2]; | |
streamId[0].channel = 0; //channel number | |
streamId[0].fifoSize = 1024 * 1024; //fifo size in samples | |
streamId[0].throughputVsLatency = 1; //optimize for max throughput | |
streamId[0].isTx = false; //RX channel | |
streamId[0].dataFmt = Fmt; | |
if (LMS_SetupStream(device, &streamId[0]) != 0) | |
error(); | |
streamId[1].channel = 1; //channel number | |
streamId[1].fifoSize = 1024 * 1024; //fifo size in samples | |
streamId[1].throughputVsLatency = 1; //optimize for max throughput | |
streamId[1].isTx = false; //RX channel | |
streamId[1].dataFmt = Fmt; | |
//if (LMS_SetupStream(device, &streamId[1]) != 0) | |
// error(); | |
//Data buffers | |
const int bufersize = 50000; //complex samples per buffer | |
int16_t buffer[2][bufersize * 2]; //must hold I+Q values of each sample | |
//Start streaming | |
LMS_StartStream(&streamId[0]); | |
//LMS_StartStream(&streamId[1]); | |
auto t1 = chrono::high_resolution_clock::now(); | |
auto t2 = t1; | |
long SampsWritten = 0; | |
lms_stream_meta_t rx_md[2]; //Use metadata for additional control over sample receive function behavior | |
rx_md[0].flushPartialPacket = false; //currently has no effect in RX | |
rx_md[0].waitForTimestamp = false; //currently has no effect in RX | |
rx_md[1].flushPartialPacket = false; //currently has no effect in RX | |
rx_md[1].waitForTimestamp = false; //currently has no effect in RX | |
lms_stream_status_t st[2]; | |
//while (chrono::high_resolution_clock::now() - t1 < chrono::seconds(3)) //run for 10 seconds | |
while (SampsWritten < TgtSampCnt) { | |
int samplesRead[2]; | |
//Receive samples | |
samplesRead[0] = LMS_RecvStream(&streamId[0], buffer[0], bufersize, &rx_md[0], 1000); | |
//I and Q samples are interleaved in buffer: IQIQIQ... | |
//samplesRead[1] = LMS_RecvStream(&streamId[1], buffer[1], bufersize, &rx_md[1], 1000); | |
LMS_GetStreamStatus(&streamId[0], &st[0]); | |
//LMS_GetStreamStatus(&streamId[1], &st[1]); | |
printf("%d/%d samples received at %I64u/%I64u\n", samplesRead[0], samplesRead[1], rx_md[0].timestamp, rx_md[0].timestamp); | |
printf("ovrrun: %d/%d, drops: %d/%d, samps recvd: %d/%d\n", | |
st[0].overrun, st[1].overrun, st[0].droppedPackets, st[1].droppedPackets, samplesRead[0], samplesRead[1]); | |
int Samps2Write = min(TgtSampCnt-SampsWritten, samplesRead[0]); | |
if (!wrWrite(buffer[0], 2 * Samps2Write * sizeof(__int16))) { | |
cout << "Can't write samples to output file!" << endl; | |
exit(-1); | |
} // if | |
SampsWritten += Samps2Write; | |
//Print stats (once per second) | |
if (chrono::high_resolution_clock::now() - t2 > chrono::milliseconds(500)) | |
{ | |
t2 = chrono::high_resolution_clock::now(); | |
//Get stream status | |
//LMS_GetStreamStatus(&streamId[0], &st[0]); | |
//LMS_GetStreamStatus(&streamId[1], &status[1]); | |
cout << "RX_1 data rate: " << st[0].linkRate / 1e6 << " MB/s\n"; //link data rate | |
//cout << "RX_2 data rate: " << status[1].linkRate / 1e6 << " MB/s\n"; //link data rate | |
cout << "RX_1 sample rate: " << st[0].sampleRate / 1e6 << " MSamples/s\n"; //link data rate | |
//cout << "RX_2 sample rate: " << status[1].sampleRate / 1e6 << " MSamples/s\n"; //link data rate | |
cout << "RX_1 fifo: " << 100 * st[0].fifoFilledCount / st[0].fifoSize << "%" << endl; //percentage of FIFO filled | |
//cout << "RX_2 fifo: " << 100 * status[1].fifoFilledCount / status[1].fifoSize << "%" << endl; //percentage of FIFO filled | |
} | |
} // while | |
wrClose(); | |
//Stop streaming | |
LMS_StopStream(&streamId[0]); //stream is stopped but can be started again with LMS_StartStream() | |
//LMS_StopStream(&streamId[1]); //stream is stopped but can be started again with LMS_StartStream() | |
LMS_DestroyStream(device, &streamId[0]); //stream is deallocated and can no longer be used | |
//LMS_DestroyStream(device, &streamId[1]); //stream is deallocated and can no longer be used | |
//Close device | |
LMS_Close(device); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment