mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
LimeSDR Windows build: upgraded to LimeSuite 17.06.0
This commit is contained in:
parent
22900b868a
commit
f546af58e9
@ -35,6 +35,7 @@ INCLUDEPATH += $$LIBLIMESUITESRC/external/cpp-feather-ini-parser
|
|||||||
SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\
|
SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\
|
||||||
$$LIBLIMESUITESRC/src/API/lms7_api.cpp\
|
$$LIBLIMESUITESRC/src/API/lms7_api.cpp\
|
||||||
$$LIBLIMESUITESRC/src/API/lms7_device.cpp\
|
$$LIBLIMESUITESRC/src/API/lms7_device.cpp\
|
||||||
|
$$LIBLIMESUITESRC/src/API/qLimeSDR.cpp\
|
||||||
src/BuiltinConnections.cpp\
|
src/BuiltinConnections.cpp\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.cpp\
|
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.cpp\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.cpp\
|
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.cpp\
|
||||||
@ -44,8 +45,8 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\
|
|||||||
srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp\
|
srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp\
|
||||||
srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp\
|
srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp\
|
||||||
srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp\
|
srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp\
|
||||||
srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\
|
|
||||||
srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp\
|
srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp\
|
||||||
|
srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybus.cpp\
|
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybus.cpp\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusEntry.cpp\
|
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusEntry.cpp\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusing.cpp\
|
$$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusing.cpp\
|
||||||
@ -77,6 +78,7 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\
|
|||||||
|
|
||||||
HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\
|
HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\
|
||||||
$$LIBLIMESUITESRC/src/API/lms7_device.h\
|
$$LIBLIMESUITESRC/src/API/lms7_device.h\
|
||||||
|
$$LIBLIMESUITESRC/src/API/qLimeSDR.h\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.h\
|
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.h\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.h\
|
$$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.h\
|
||||||
$$LIBLIMESUITESRC/src/ConnectionRegistry/IConnection.h\
|
$$LIBLIMESUITESRC/src/ConnectionRegistry/IConnection.h\
|
||||||
|
@ -28,8 +28,6 @@ using namespace std;
|
|||||||
|
|
||||||
using namespace lime;
|
using namespace lime;
|
||||||
|
|
||||||
const uint8_t ConnectionSTREAM::streamBulkOutAddr = 0x01;
|
|
||||||
const uint8_t ConnectionSTREAM::streamBulkInAddr = 0x81;
|
|
||||||
const uint8_t ConnectionSTREAM::ctrlBulkOutAddr = 0x0F;
|
const uint8_t ConnectionSTREAM::ctrlBulkOutAddr = 0x0F;
|
||||||
const uint8_t ConnectionSTREAM::ctrlBulkInAddr = 0x8F;
|
const uint8_t ConnectionSTREAM::ctrlBulkInAddr = 0x8F;
|
||||||
|
|
||||||
@ -70,6 +68,9 @@ ConnectionSTREAM::ConnectionSTREAM(void *arg, const std::string &vidpid, const s
|
|||||||
OutCtrlEndPt3 = nullptr;
|
OutCtrlEndPt3 = nullptr;
|
||||||
InCtrlBulkEndPt = nullptr;
|
InCtrlBulkEndPt = nullptr;
|
||||||
OutCtrlBulkEndPt = nullptr;
|
OutCtrlBulkEndPt = nullptr;
|
||||||
|
for (int i = 0; i < MAX_EP_CNT; i++)
|
||||||
|
InEndPt[i] = OutEndPt[i] = nullptr;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
dev_handle = nullptr;
|
dev_handle = nullptr;
|
||||||
ctx = (libusb_context *)arg;
|
ctx = (libusb_context *)arg;
|
||||||
@ -178,15 +179,6 @@ double ConnectionSTREAM::DetectRefClk(void)
|
|||||||
*/
|
*/
|
||||||
ConnectionSTREAM::~ConnectionSTREAM()
|
ConnectionSTREAM::~ConnectionSTREAM()
|
||||||
{
|
{
|
||||||
for(auto i : mTxStreams)
|
|
||||||
ControlStream((size_t)i, false);
|
|
||||||
for(auto i : mRxStreams)
|
|
||||||
ControlStream((size_t)i, false);
|
|
||||||
for(auto i : mTxStreams)
|
|
||||||
CloseStream((size_t)i);
|
|
||||||
for(auto i : mRxStreams)
|
|
||||||
CloseStream((size_t)i);
|
|
||||||
UpdateThreads();
|
|
||||||
Close();
|
Close();
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
delete USBDevicePrimary;
|
delete USBDevicePrimary;
|
||||||
@ -230,22 +222,23 @@ int ConnectionSTREAM::Open(const std::string &vidpid, const std::string &serial,
|
|||||||
OutCtrlEndPt3->Index = CTR_W_INDEX;
|
OutCtrlEndPt3->Index = CTR_W_INDEX;
|
||||||
OutCtrlEndPt3->TimeOut = 3000;
|
OutCtrlEndPt3->TimeOut = 3000;
|
||||||
|
|
||||||
for (int i=0; i<USBDevicePrimary->EndPointCount(); i++)
|
for (int i = 0; i < USBDevicePrimary->EndPointCount(); i++)
|
||||||
if(USBDevicePrimary->EndPoints[i]->Address == streamBulkOutAddr)
|
{
|
||||||
|
auto adr = USBDevicePrimary->EndPoints[i]->Address;
|
||||||
|
if (adr < ctrlBulkOutAddr)
|
||||||
{
|
{
|
||||||
OutEndPt = USBDevicePrimary->EndPoints[i];
|
OutEndPt[adr] = USBDevicePrimary->EndPoints[i];
|
||||||
long len = OutEndPt->MaxPktSize * 64;
|
long len = OutEndPt[adr]->MaxPktSize * 64;
|
||||||
OutEndPt->SetXferSize(len);
|
OutEndPt[adr]->SetXferSize(len);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
for (int i=0; i<USBDevicePrimary->EndPointCount(); i++)
|
else if (adr < ctrlBulkInAddr)
|
||||||
if(USBDevicePrimary->EndPoints[i]->Address == streamBulkInAddr)
|
|
||||||
{
|
{
|
||||||
InEndPt = USBDevicePrimary->EndPoints[i];
|
adr &= 0xF;
|
||||||
long len = InEndPt->MaxPktSize * 64;
|
InEndPt[adr] = USBDevicePrimary->EndPoints[i];
|
||||||
InEndPt->SetXferSize(len);
|
long len = InEndPt[adr]->MaxPktSize * 64;
|
||||||
break;
|
InEndPt[adr]->SetXferSize(len);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InCtrlBulkEndPt = nullptr;
|
InCtrlBulkEndPt = nullptr;
|
||||||
for (int i=0; i<USBDevicePrimary->EndPointCount(); i++)
|
for (int i=0; i<USBDevicePrimary->EndPointCount(); i++)
|
||||||
@ -356,21 +349,21 @@ int ConnectionSTREAM::Open(const std::string &vidpid, const std::string &serial,
|
|||||||
void ConnectionSTREAM::Close()
|
void ConnectionSTREAM::Close()
|
||||||
{
|
{
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
USBDevicePrimary->Close();
|
USBDevicePrimary->Close();
|
||||||
InEndPt = nullptr;
|
for (int i = 0; i < MAX_EP_CNT; i++)
|
||||||
OutEndPt = nullptr;
|
InEndPt[i] = OutEndPt[i] = nullptr;
|
||||||
InCtrlBulkEndPt = nullptr;
|
InCtrlBulkEndPt = nullptr;
|
||||||
OutCtrlBulkEndPt = nullptr;
|
OutCtrlBulkEndPt = nullptr;
|
||||||
if (InCtrlEndPt3)
|
if (InCtrlEndPt3)
|
||||||
{
|
{
|
||||||
delete InCtrlEndPt3;
|
delete InCtrlEndPt3;
|
||||||
InCtrlEndPt3 = nullptr;
|
InCtrlEndPt3 = nullptr;
|
||||||
}
|
}
|
||||||
if (OutCtrlEndPt3)
|
if (OutCtrlEndPt3)
|
||||||
{
|
{
|
||||||
delete OutCtrlEndPt3;
|
delete OutCtrlEndPt3;
|
||||||
OutCtrlEndPt3 = nullptr;
|
OutCtrlEndPt3 = nullptr;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(dev_handle != 0)
|
if(dev_handle != 0)
|
||||||
{
|
{
|
||||||
@ -532,9 +525,10 @@ void callback_libusbtransfer(libusb_transfer *trans)
|
|||||||
@brief Starts asynchronous data reading from board
|
@brief Starts asynchronous data reading from board
|
||||||
@param *buffer buffer where to store received data
|
@param *buffer buffer where to store received data
|
||||||
@param length number of bytes to read
|
@param length number of bytes to read
|
||||||
|
@param streamBulkInAddr endpoint index?
|
||||||
@return handle of transfer context
|
@return handle of transfer context
|
||||||
*/
|
*/
|
||||||
int ConnectionSTREAM::BeginDataReading(char *buffer, uint32_t length)
|
int ConnectionSTREAM::BeginDataReading(char *buffer, uint32_t length, const uint8_t streamBulkInAddr)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
bool contextFound = false;
|
bool contextFound = false;
|
||||||
@ -554,8 +548,11 @@ int ConnectionSTREAM::BeginDataReading(char *buffer, uint32_t length)
|
|||||||
}
|
}
|
||||||
contexts[i].used = true;
|
contexts[i].used = true;
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
if(InEndPt)
|
if (InEndPt[streamBulkInAddr & 0xF])
|
||||||
contexts[i].context = InEndPt->BeginDataXfer((unsigned char*)buffer, length, contexts[i].inOvLap);
|
{
|
||||||
|
contexts[i].EndPt = InEndPt[streamBulkInAddr & 0xF];
|
||||||
|
contexts[i].context = contexts[i].EndPt->BeginDataXfer((unsigned char*)buffer, length, contexts[i].inOvLap);
|
||||||
|
}
|
||||||
return i;
|
return i;
|
||||||
#else
|
#else
|
||||||
unsigned int Timeout = 500;
|
unsigned int Timeout = 500;
|
||||||
@ -587,8 +584,7 @@ int ConnectionSTREAM::WaitForReading(int contextHandle, unsigned int timeout_ms)
|
|||||||
{
|
{
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
if(InEndPt)
|
status = contexts[contextHandle].EndPt->WaitForXfer(contexts[contextHandle].inOvLap, timeout_ms);
|
||||||
status = InEndPt->WaitForXfer(contexts[contextHandle].inOvLap, timeout_ms);
|
|
||||||
return status;
|
return status;
|
||||||
#else
|
#else
|
||||||
auto t1 = chrono::high_resolution_clock::now();
|
auto t1 = chrono::high_resolution_clock::now();
|
||||||
@ -622,8 +618,7 @@ int ConnectionSTREAM::FinishDataReading(char *buffer, uint32_t length, int conte
|
|||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
long len = length;
|
long len = length;
|
||||||
if(InEndPt)
|
status = contexts[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contexts[contextHandle].inOvLap, contexts[contextHandle].context);
|
||||||
status = InEndPt->FinishDataXfer((unsigned char*)buffer, len, contexts[contextHandle].inOvLap, contexts[contextHandle].context);
|
|
||||||
contexts[contextHandle].used = false;
|
contexts[contextHandle].used = false;
|
||||||
contexts[contextHandle].reset();
|
contexts[contextHandle].reset();
|
||||||
return len;
|
return len;
|
||||||
@ -641,14 +636,16 @@ int ConnectionSTREAM::FinishDataReading(char *buffer, uint32_t length, int conte
|
|||||||
/**
|
/**
|
||||||
@brief Aborts reading operations
|
@brief Aborts reading operations
|
||||||
*/
|
*/
|
||||||
void ConnectionSTREAM::AbortReading()
|
void ConnectionSTREAM::AbortReading(int ep)
|
||||||
{
|
{
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
InEndPt->Abort();
|
for (int i = 0; i < MAX_EP_CNT; i++)
|
||||||
|
if (InEndPt[i] && InEndPt[i]->Address == ep)
|
||||||
|
InEndPt[i]->Abort();
|
||||||
#else
|
#else
|
||||||
for(int i=0; i<USB_MAX_CONTEXTS; ++i)
|
for(int i=0; i<USB_MAX_CONTEXTS; ++i)
|
||||||
{
|
{
|
||||||
if(contexts[i].used)
|
if(contexts[i].used && contexts[i].transfer->endpoint == ep)
|
||||||
libusb_cancel_transfer( contexts[i].transfer );
|
libusb_cancel_transfer( contexts[i].transfer );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -658,9 +655,10 @@ void ConnectionSTREAM::AbortReading()
|
|||||||
@brief Starts asynchronous data Sending to board
|
@brief Starts asynchronous data Sending to board
|
||||||
@param *buffer buffer to send
|
@param *buffer buffer to send
|
||||||
@param length number of bytes to send
|
@param length number of bytes to send
|
||||||
|
@param streamBulkOutAddr endpoint index?
|
||||||
@return handle of transfer context
|
@return handle of transfer context
|
||||||
*/
|
*/
|
||||||
int ConnectionSTREAM::BeginDataSending(const char *buffer, uint32_t length)
|
int ConnectionSTREAM::BeginDataSending(const char *buffer, uint32_t length, const uint8_t streamBulkOutAddr)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
//find not used context
|
//find not used context
|
||||||
@ -677,8 +675,11 @@ int ConnectionSTREAM::BeginDataSending(const char *buffer, uint32_t length)
|
|||||||
return -1;
|
return -1;
|
||||||
contextsToSend[i].used = true;
|
contextsToSend[i].used = true;
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
if(OutEndPt)
|
if (OutEndPt[streamBulkOutAddr])
|
||||||
contextsToSend[i].context = OutEndPt->BeginDataXfer((unsigned char*)buffer, length, contextsToSend[i].inOvLap);
|
{
|
||||||
|
contextsToSend[i].EndPt = OutEndPt[streamBulkOutAddr];
|
||||||
|
contextsToSend[i].context = contextsToSend[i].EndPt->BeginDataXfer((unsigned char*)buffer, length, contextsToSend[i].inOvLap);
|
||||||
|
}
|
||||||
return i;
|
return i;
|
||||||
#else
|
#else
|
||||||
unsigned int Timeout = 500;
|
unsigned int Timeout = 500;
|
||||||
@ -708,12 +709,11 @@ int ConnectionSTREAM::WaitForSending(int contextHandle, unsigned int timeout_ms)
|
|||||||
{
|
{
|
||||||
if( contextsToSend[contextHandle].used == true )
|
if( contextsToSend[contextHandle].used == true )
|
||||||
{
|
{
|
||||||
#ifndef __unix__
|
# ifndef __unix__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
if(OutEndPt)
|
status = contextsToSend[contextHandle].EndPt->WaitForXfer(contextsToSend[contextHandle].inOvLap, timeout_ms);
|
||||||
status = OutEndPt->WaitForXfer(contextsToSend[contextHandle].inOvLap, timeout_ms);
|
|
||||||
return status;
|
return status;
|
||||||
#else
|
# else
|
||||||
auto t1 = chrono::high_resolution_clock::now();
|
auto t1 = chrono::high_resolution_clock::now();
|
||||||
auto t2 = chrono::high_resolution_clock::now();
|
auto t2 = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
@ -725,7 +725,7 @@ int ConnectionSTREAM::WaitForSending(int contextHandle, unsigned int timeout_ms)
|
|||||||
t2 = chrono::high_resolution_clock::now();
|
t2 = chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
return contextsToSend[contextHandle].done == true;
|
return contextsToSend[contextHandle].done == true;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
@ -744,8 +744,7 @@ int ConnectionSTREAM::FinishDataSending(const char *buffer, uint32_t length, int
|
|||||||
{
|
{
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
long len = length;
|
long len = length;
|
||||||
if(OutEndPt)
|
contextsToSend[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contextsToSend[contextHandle].inOvLap, contextsToSend[contextHandle].context);
|
||||||
OutEndPt->FinishDataXfer((unsigned char*)buffer, len, contextsToSend[contextHandle].inOvLap, contextsToSend[contextHandle].context);
|
|
||||||
contextsToSend[contextHandle].used = false;
|
contextsToSend[contextHandle].used = false;
|
||||||
contextsToSend[contextHandle].reset();
|
contextsToSend[contextHandle].reset();
|
||||||
return len;
|
return len;
|
||||||
@ -763,19 +762,39 @@ int ConnectionSTREAM::FinishDataSending(const char *buffer, uint32_t length, int
|
|||||||
/**
|
/**
|
||||||
@brief Aborts sending operations
|
@brief Aborts sending operations
|
||||||
*/
|
*/
|
||||||
void ConnectionSTREAM::AbortSending()
|
void ConnectionSTREAM::AbortSending(int ep)
|
||||||
{
|
{
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
OutEndPt->Abort();
|
for (int i = 0; i < MAX_EP_CNT; i++)
|
||||||
|
if (OutEndPt[i] && OutEndPt[i]->Address == ep)
|
||||||
|
OutEndPt[i]->Abort();
|
||||||
#else
|
#else
|
||||||
for (int i = 0; i<USB_MAX_CONTEXTS; ++i)
|
for (int i = 0; i<USB_MAX_CONTEXTS; ++i)
|
||||||
{
|
{
|
||||||
if(contextsToSend[i].used)
|
if(contextsToSend[i].used && contextsToSend[i].transfer->endpoint == ep)
|
||||||
libusb_cancel_transfer(contextsToSend[i].transfer);
|
libusb_cancel_transfer(contextsToSend[i].transfer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ConnectionSTREAM::SendData(const char* buffer, int length, int epIndex, int timeout)
|
||||||
|
{
|
||||||
|
const unsigned char ep = 0x01;
|
||||||
|
int context = BeginDataSending((char*)buffer, length, ep);
|
||||||
|
if (WaitForSending(context, timeout)==false)
|
||||||
|
AbortSending(ep);
|
||||||
|
return FinishDataSending((char*)buffer, length , context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectionSTREAM::ReceiveData(char* buffer, int length, int epIndex, int timeout)
|
||||||
|
{
|
||||||
|
const unsigned char ep = 0x81;
|
||||||
|
int context = BeginDataReading(buffer, length, ep);
|
||||||
|
if (WaitForReading(context, timeout) == false)
|
||||||
|
AbortReading(ep);
|
||||||
|
return FinishDataReading(buffer, length, context);
|
||||||
|
}
|
||||||
|
|
||||||
int ConnectionSTREAM::ProgramWrite(const char *buffer, const size_t length, const int programmingMode, const int device, ProgrammingCallback callback)
|
int ConnectionSTREAM::ProgramWrite(const char *buffer, const size_t length, const int programmingMode, const int device, ProgrammingCallback callback)
|
||||||
{
|
{
|
||||||
if (device == LMS64CProtocol::FX3 && programmingMode == 1)
|
if (device == LMS64CProtocol::FX3 && programmingMode == 1)
|
||||||
|
@ -48,6 +48,7 @@ public:
|
|||||||
memset(inOvLap, 0, sizeof(OVERLAPPED));
|
memset(inOvLap, 0, sizeof(OVERLAPPED));
|
||||||
inOvLap->hEvent = CreateEvent(NULL, false, false, NULL);
|
inOvLap->hEvent = CreateEvent(NULL, false, false, NULL);
|
||||||
context = NULL;
|
context = NULL;
|
||||||
|
EndPt = nullptr;
|
||||||
#else
|
#else
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = libusb_alloc_transfer(0);
|
||||||
bytesXfered = 0;
|
bytesXfered = 0;
|
||||||
@ -80,6 +81,7 @@ public:
|
|||||||
static int idCounter;
|
static int idCounter;
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
PUCHAR context;
|
PUCHAR context;
|
||||||
|
CCyUSBEndPoint* EndPt;
|
||||||
OVERLAPPED* inOvLap;
|
OVERLAPPED* inOvLap;
|
||||||
#else
|
#else
|
||||||
libusb_transfer* transfer;
|
libusb_transfer* transfer;
|
||||||
@ -106,27 +108,27 @@ public:
|
|||||||
virtual int Write(const unsigned char* buffer, int length, int timeout_ms = 100) override;
|
virtual int Write(const unsigned char* buffer, int length, int timeout_ms = 100) override;
|
||||||
virtual int Read(unsigned char* buffer, int length, int timeout_ms = 100) override;
|
virtual int Read(unsigned char* buffer, int length, int timeout_ms = 100) override;
|
||||||
|
|
||||||
virtual int UploadWFM(const void* const* samples, uint8_t chCount, size_t sample_count, StreamConfig::StreamDataFormat format) override;
|
|
||||||
|
|
||||||
//hooks to update FPGA plls when baseband interface data rate is changed
|
//hooks to update FPGA plls when baseband interface data rate is changed
|
||||||
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate) override;
|
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate) override;
|
||||||
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate, const double txPhase, const double rxPhase) override;
|
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate, const double txPhase, const double rxPhase) override;
|
||||||
virtual int ProgramWrite(const char *buffer, const size_t length, const int programmingMode, const int device, ProgrammingCallback callback) override;
|
virtual int ProgramWrite(const char *buffer, const size_t length, const int programmingMode, const int device, ProgrammingCallback callback) override;
|
||||||
int ProgramUpdate(const bool download, ProgrammingCallback callback);
|
int ProgramUpdate(const bool download, ProgrammingCallback callback);
|
||||||
int ReadRawStreamData(char* buffer, unsigned length, int timeout_ms = 100)override;
|
int ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms = 100)override;
|
||||||
protected:
|
protected:
|
||||||
virtual void ReceivePacketsLoop(const ThreadData args) override;
|
virtual void ReceivePacketsLoop(Streamer* args) override;
|
||||||
virtual void TransmitPacketsLoop(const ThreadData args) override;
|
virtual void TransmitPacketsLoop(Streamer* args) override;
|
||||||
|
int SendData(const char* buffer, int length, int epIndex = 0, int timeout = 100)override;
|
||||||
|
int ReceiveData(char* buffer, int length, int epIndex = 0, int timeout = 100)override;
|
||||||
|
|
||||||
virtual int BeginDataReading(char* buffer, uint32_t length);
|
virtual int BeginDataReading(char* buffer, uint32_t length, const uint8_t streamBulkInAddr = 0x81);
|
||||||
virtual int WaitForReading(int contextHandle, unsigned int timeout_ms);
|
virtual int WaitForReading(int contextHandle, unsigned int timeout_ms);
|
||||||
virtual int FinishDataReading(char* buffer, uint32_t length, int contextHandle);
|
virtual int FinishDataReading(char* buffer, uint32_t length, int contextHandle);
|
||||||
virtual void AbortReading();
|
virtual void AbortReading(int ep);
|
||||||
|
|
||||||
virtual int BeginDataSending(const char* buffer, uint32_t length);
|
virtual int BeginDataSending(const char* buffer, uint32_t length, const uint8_t streamBulkOutAddr = 0x01);
|
||||||
virtual int WaitForSending(int contextHandle, uint32_t timeout_ms);
|
virtual int WaitForSending(int contextHandle, uint32_t timeout_ms);
|
||||||
virtual int FinishDataSending(const char* buffer, uint32_t length, int contextHandle);
|
virtual int FinishDataSending(const char* buffer, uint32_t length, int contextHandle);
|
||||||
virtual void AbortSending();
|
virtual void AbortSending(int ep);
|
||||||
|
|
||||||
int ResetStreamBuffers() override;
|
int ResetStreamBuffers() override;
|
||||||
eConnectionType GetType(void) {return USB_PORT;}
|
eConnectionType GetType(void) {return USB_PORT;}
|
||||||
@ -139,14 +141,15 @@ protected:
|
|||||||
bool isConnected;
|
bool isConnected;
|
||||||
|
|
||||||
#ifndef __unix__
|
#ifndef __unix__
|
||||||
|
static const int MAX_EP_CNT = 16;
|
||||||
CCyFX3Device* USBDevicePrimary;
|
CCyFX3Device* USBDevicePrimary;
|
||||||
//control endpoints
|
//control endpoints
|
||||||
CCyControlEndPoint* InCtrlEndPt3;
|
CCyControlEndPoint* InCtrlEndPt3;
|
||||||
CCyControlEndPoint* OutCtrlEndPt3;
|
CCyControlEndPoint* OutCtrlEndPt3;
|
||||||
|
|
||||||
//end points for samples reading and writing
|
//end points for samples reading and writing
|
||||||
CCyUSBEndPoint* InEndPt;
|
CCyUSBEndPoint* InEndPt[MAX_EP_CNT];
|
||||||
CCyUSBEndPoint* OutEndPt;
|
CCyUSBEndPoint* OutEndPt[MAX_EP_CNT];
|
||||||
|
|
||||||
CCyUSBEndPoint* InCtrlBulkEndPt;
|
CCyUSBEndPoint* InCtrlBulkEndPt;
|
||||||
CCyUSBEndPoint* OutCtrlBulkEndPt;
|
CCyUSBEndPoint* OutCtrlBulkEndPt;
|
||||||
@ -157,8 +160,6 @@ protected:
|
|||||||
int fx3_usbboot_download(unsigned char *buf, int len);
|
int fx3_usbboot_download(unsigned char *buf, int len);
|
||||||
int ram_write(unsigned char *buf, unsigned int ramAddress, int len);
|
int ram_write(unsigned char *buf, unsigned int ramAddress, int len);
|
||||||
#endif
|
#endif
|
||||||
static const uint8_t streamBulkOutAddr;
|
|
||||||
static const uint8_t streamBulkInAddr;
|
|
||||||
static const uint8_t ctrlBulkOutAddr;
|
static const uint8_t ctrlBulkOutAddr;
|
||||||
static const uint8_t ctrlBulkInAddr;
|
static const uint8_t ctrlBulkInAddr;
|
||||||
static const std::set<uint8_t> commandsToBulkCtrlHw1;
|
static const std::set<uint8_t> commandsToBulkCtrlHw1;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
@file ConnectionSTREAMing.cpp
|
@file ConnectionSTREAMing.cpp
|
||||||
@author Lime Microsystems
|
@author Lime Microsystems
|
||||||
@brief Implementation of STREAM board connection (streaming API)
|
@brief Implementation of STREAM board connection (streaming API)
|
||||||
@ -20,93 +20,40 @@
|
|||||||
using namespace lime;
|
using namespace lime;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int ConnectionSTREAM::UploadWFM(const void* const* samples, uint8_t chCount, size_t sample_count, StreamConfig::StreamDataFormat format)
|
|
||||||
{
|
|
||||||
WriteRegister(0x000C, 0x3); //channels 0,1
|
|
||||||
WriteRegister(0x000E, 0x2); //12bit samples
|
|
||||||
WriteRegister(0x000D, 0x0004); //WFM_LOAD
|
|
||||||
|
|
||||||
lime::FPGA_DataPacket pkt;
|
|
||||||
size_t samplesUsed = 0;
|
|
||||||
|
|
||||||
const complex16_t* const* src = (const complex16_t* const*)samples;
|
|
||||||
int cnt = sample_count;
|
|
||||||
|
|
||||||
const lime::complex16_t** batch = new const lime::complex16_t*[chCount];
|
|
||||||
while(cnt > 0)
|
|
||||||
{
|
|
||||||
pkt.counter = 0;
|
|
||||||
pkt.reserved[0] = 0;
|
|
||||||
int samplesToSend = cnt > 1360/chCount ? 1360/chCount : cnt;
|
|
||||||
cnt -= samplesToSend;
|
|
||||||
|
|
||||||
for(uint8_t i=0; i<chCount; ++i)
|
|
||||||
batch[i] = &src[i][samplesUsed];
|
|
||||||
samplesUsed += samplesToSend;
|
|
||||||
|
|
||||||
size_t bufPos = 0;
|
|
||||||
lime::fpga::Samples2FPGAPacketPayload(batch, samplesToSend, chCount, format, pkt.data, &bufPos);
|
|
||||||
int payloadSize = (bufPos / 4) * 4;
|
|
||||||
if(bufPos % 4 != 0)
|
|
||||||
lime::error("Packet samples count not multiple of 4");
|
|
||||||
pkt.reserved[2] = (payloadSize >> 8) & 0xFF; //WFM loading
|
|
||||||
pkt.reserved[1] = payloadSize & 0xFF; //WFM loading
|
|
||||||
pkt.reserved[0] = 0x1 << 5; //WFM loading
|
|
||||||
|
|
||||||
long bToSend = 16+payloadSize;
|
|
||||||
int context = BeginDataSending((char*)&pkt, bToSend );
|
|
||||||
if(WaitForSending(context, 250) == false)
|
|
||||||
{
|
|
||||||
FinishDataSending((char*)&pkt, bToSend , context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FinishDataSending((char*)&pkt, bToSend , context);
|
|
||||||
}
|
|
||||||
delete[] batch;
|
|
||||||
/*Give FX3 some time to load samples to FPGA*/
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
|
||||||
if(cnt == 0)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return ReportError(-1, "Failed to upload waveform");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Configures FPGA PLLs to LimeLight interface frequency
|
/** @brief Configures FPGA PLLs to LimeLight interface frequency
|
||||||
*/
|
*/
|
||||||
int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz, const double txPhase, const double rxPhase)
|
int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz, const double txPhase, const double rxPhase)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
lime::fpga::FPGA_PLL_clock clocks[2];
|
||||||
lime::debug("ConnectionSTREAM::ConfigureFPGA_PLL(tx=%gMHz, rx=%gMHz)", txRate_Hz/1e6, rxRate_Hz/1e6);
|
|
||||||
#endif
|
if (channel == 2)
|
||||||
|
{
|
||||||
|
clocks[0].index = 0;
|
||||||
|
clocks[0].outFrequency = rxRate_Hz;
|
||||||
|
clocks[1].index = 1;
|
||||||
|
clocks[1].outFrequency = txRate_Hz;
|
||||||
|
return lime::fpga::SetPllFrequency(this, 4, 30.72e6, clocks, 2);
|
||||||
|
}
|
||||||
|
|
||||||
const float txInterfaceClk = 2 * txRate_Hz;
|
const float txInterfaceClk = 2 * txRate_Hz;
|
||||||
const float rxInterfaceClk = 2 * rxRate_Hz;
|
const float rxInterfaceClk = 2 * rxRate_Hz;
|
||||||
mExpectedSampleRate = rxRate_Hz;
|
mExpectedSampleRate = rxRate_Hz;
|
||||||
|
const int pll_ind = (channel == 1) ? 2 : 0;
|
||||||
|
|
||||||
lime::fpga::FPGA_PLL_clock clocks[2];
|
|
||||||
clocks[0].bypass = false;
|
|
||||||
clocks[0].index = 0;
|
clocks[0].index = 0;
|
||||||
clocks[0].outFrequency = rxInterfaceClk;
|
clocks[0].outFrequency = rxInterfaceClk;
|
||||||
clocks[0].phaseShift_deg = 0;
|
|
||||||
clocks[0].findPhase = false;
|
|
||||||
clocks[1].bypass = false;
|
|
||||||
clocks[1].index = 1;
|
clocks[1].index = 1;
|
||||||
clocks[1].outFrequency = rxInterfaceClk;
|
clocks[1].outFrequency = rxInterfaceClk;
|
||||||
clocks[1].phaseShift_deg = rxPhase;
|
clocks[1].phaseShift_deg = rxPhase;
|
||||||
clocks[1].findPhase = false;
|
if (lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2)!=0)
|
||||||
if (lime::fpga::SetPllFrequency(this, 1, rxInterfaceClk, clocks, 2)!=0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
clocks[0].bypass = false;
|
|
||||||
clocks[0].index = 0;
|
clocks[0].index = 0;
|
||||||
clocks[0].outFrequency = txInterfaceClk;
|
clocks[0].outFrequency = txInterfaceClk;
|
||||||
clocks[0].phaseShift_deg = 0;
|
|
||||||
clocks[0].findPhase = false;
|
|
||||||
clocks[1].bypass = false;
|
|
||||||
clocks[1].index = 1;
|
clocks[1].index = 1;
|
||||||
clocks[1].outFrequency = txInterfaceClk;
|
clocks[1].outFrequency = txInterfaceClk;
|
||||||
clocks[1].phaseShift_deg = txPhase;
|
clocks[1].phaseShift_deg = txPhase;
|
||||||
clocks[1].findPhase = false;
|
if (lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2)!=0)
|
||||||
if (lime::fpga::SetPllFrequency(this, 0, txInterfaceClk, clocks, 2)!=0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -116,11 +63,9 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double
|
|||||||
*/
|
*/
|
||||||
int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz)
|
int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
lime::debug("ConnectionSTREAM::ConfigureFPGA_PLL(tx=%gMHz, rx=%gMHz)", txRate_Hz/1e6, rxRate_Hz/1e6);
|
|
||||||
#endif
|
|
||||||
const float txInterfaceClk = 2 * txRate_Hz;
|
const float txInterfaceClk = 2 * txRate_Hz;
|
||||||
const float rxInterfaceClk = 2 * rxRate_Hz;
|
const float rxInterfaceClk = 2 * rxRate_Hz;
|
||||||
|
const int pll_ind = (channel == 1) ? 2 : 0;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
uint32_t reg20;
|
uint32_t reg20;
|
||||||
const double rxPhC1[] = { 91.08, 89.46 };
|
const double rxPhC1[] = { 91.08, 89.46 };
|
||||||
@ -128,18 +73,17 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double
|
|||||||
const double txPhC1[] = { 89.75, 89.61 };
|
const double txPhC1[] = { 89.75, 89.61 };
|
||||||
const double txPhC2[] = { -3.0e-7, 2.71e-7 };
|
const double txPhC2[] = { -3.0e-7, 2.71e-7 };
|
||||||
|
|
||||||
const std::vector<uint32_t> spiAddr = {0x0021, 0x0022, 0x0023, 0x0024,
|
const std::vector<uint32_t> spiAddr = { 0x021, 0x022, 0x023, 0x024, 0x027, 0x02A,
|
||||||
0x0027, 0x002A, 0x0400, 0x040C,
|
0x400, 0x40C, 0x40B, 0x400, 0x40B, 0x400};
|
||||||
0x040B, 0x0400, 0x040B, 0x0400};
|
|
||||||
const int bakRegCnt = spiAddr.size() - 4;
|
const int bakRegCnt = spiAddr.size() - 4;
|
||||||
auto info = GetDeviceInfo();
|
auto info = GetDeviceInfo();
|
||||||
const int addrLMS7002M = info.addrsLMS7002M.at(0);
|
|
||||||
bool phaseSearch = false;
|
bool phaseSearch = false;
|
||||||
if (this->chipVersion == 0x3841 && stoi(info.gatewareRevision) >= 7 && stoi(info.gatewareVersion) >= 2) //0x3840 LMS7002Mr2, 0x3841 LMS7002Mr3
|
if (!(mStreamers.size() > channel && (mStreamers[channel]->rxRunning || mStreamers[channel]->txRunning)))
|
||||||
if(rxInterfaceClk >= 5e6 || txInterfaceClk >= 5e6)
|
if (this->chipVersion == 0x3841 && stoi(info.gatewareRevision) >= 7 && stoi(info.gatewareVersion) >= 2) //0x3840 LMS7002Mr2, 0x3841 LMS7002Mr3
|
||||||
phaseSearch = true;
|
if(rxInterfaceClk >= 5e6 || txInterfaceClk >= 5e6)
|
||||||
mExpectedSampleRate = rxRate_Hz;
|
phaseSearch = true;
|
||||||
|
|
||||||
|
mExpectedSampleRate = rxRate_Hz;
|
||||||
std::vector<uint32_t> dataWr;
|
std::vector<uint32_t> dataWr;
|
||||||
std::vector<uint32_t> dataRd;
|
std::vector<uint32_t> dataRd;
|
||||||
|
|
||||||
@ -149,78 +93,61 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double
|
|||||||
dataRd.resize(spiAddr.size());
|
dataRd.resize(spiAddr.size());
|
||||||
//backup registers
|
//backup registers
|
||||||
dataWr[0] = (uint32_t(0x0020) << 16);
|
dataWr[0] = (uint32_t(0x0020) << 16);
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), ®20, 1);
|
ReadLMS7002MSPI(dataWr.data(), ®20, 1, channel);
|
||||||
|
|
||||||
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write
|
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1);
|
WriteLMS7002MSPI(dataWr.data(), 1, channel);
|
||||||
|
|
||||||
for (int i = 0; i < bakRegCnt; ++i)
|
for (int i = 0; i < bakRegCnt; ++i)
|
||||||
dataWr[i] = (spiAddr[i] << 16);
|
dataWr[i] = (spiAddr[i] << 16);
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt);
|
ReadLMS7002MSPI(dataWr.data(),dataRd.data(), bakRegCnt, channel);
|
||||||
UpdateThreads(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rxInterfaceClk >= 5e6)
|
if(rxInterfaceClk >= 5e6)
|
||||||
{
|
{
|
||||||
if (phaseSearch)
|
if (phaseSearch)
|
||||||
{
|
{
|
||||||
const std::vector<uint32_t> spiData = { 0x0E9F, 0x07FF, 0x5550, 0xE4E4,
|
const std::vector<uint32_t> spiData = { 0x0E9F, 0x07FF, 0x5550, 0xE4E4, 0xE4E4, 0x0086,
|
||||||
0xE4E4, 0x0086, 0x028D, 0x00FF,
|
0x028D, 0x00FF, 0x5555, 0x02CD, 0xAAAA, 0x02ED};
|
||||||
0x5555, 0x02CD, 0xAAAA, 0x02ED};
|
|
||||||
//Load test config
|
//Load test config
|
||||||
const int setRegCnt = spiData.size();
|
const int setRegCnt = spiData.size();
|
||||||
for (int i = 0; i < setRegCnt; ++i)
|
for (int i = 0; i < setRegCnt; ++i)
|
||||||
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
|
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, setRegCnt);
|
WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel);
|
||||||
}
|
}
|
||||||
lime::fpga::FPGA_PLL_clock clocks[2];
|
lime::fpga::FPGA_PLL_clock clocks[2];
|
||||||
clocks[0].bypass = false;
|
|
||||||
clocks[0].index = 0;
|
clocks[0].index = 0;
|
||||||
clocks[0].outFrequency = rxInterfaceClk;
|
clocks[0].outFrequency = rxInterfaceClk;
|
||||||
clocks[0].phaseShift_deg = 0;
|
|
||||||
clocks[0].findPhase = false;
|
|
||||||
clocks[1].bypass = false;
|
|
||||||
clocks[1].index = 1;
|
clocks[1].index = 1;
|
||||||
clocks[1].outFrequency = rxInterfaceClk;
|
clocks[1].outFrequency = rxInterfaceClk;
|
||||||
if (this->chipVersion == 0x3841)
|
if (this->chipVersion == 0x3841)
|
||||||
clocks[1].phaseShift_deg = rxPhC1[1] + rxPhC2[1] * rxInterfaceClk;
|
clocks[1].phaseShift_deg = rxPhC1[1] + rxPhC2[1] * rxInterfaceClk;
|
||||||
else
|
else
|
||||||
clocks[1].phaseShift_deg = rxPhC1[0] + rxPhC2[0] * rxInterfaceClk;
|
clocks[1].phaseShift_deg = rxPhC1[0] + rxPhC2[0] * rxInterfaceClk;
|
||||||
|
|
||||||
if (phaseSearch)
|
if (phaseSearch)
|
||||||
{
|
|
||||||
clocks[1].findPhase = true;
|
clocks[1].findPhase = true;
|
||||||
}
|
status = lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2);
|
||||||
else
|
|
||||||
{
|
|
||||||
clocks[1].findPhase = false;
|
|
||||||
}
|
|
||||||
status = lime::fpga::SetPllFrequency(this, 1, rxInterfaceClk, clocks, 2);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
status = lime::fpga::SetDirectClocking(this, 1, rxInterfaceClk, 90);
|
status = lime::fpga::SetDirectClocking(this, pll_ind+1, rxInterfaceClk, 90);
|
||||||
|
|
||||||
if(txInterfaceClk >= 5e6)
|
if(txInterfaceClk >= 5e6)
|
||||||
{
|
{
|
||||||
if (phaseSearch)
|
if (phaseSearch)
|
||||||
{
|
{
|
||||||
const std::vector<uint32_t> spiData = {0x0E9F, 0x07FF, 0x5550, 0xE4E4,
|
const std::vector<uint32_t> spiData = {0x0E9F, 0x07FF, 0x5550, 0xE4E4, 0xE4E4, 0x0484};
|
||||||
0xE4E4, 0x0484};
|
|
||||||
WriteRegister(0x000A, 0x0000);
|
WriteRegister(0x000A, 0x0000);
|
||||||
//Load test config
|
//Load test config
|
||||||
const int setRegCnt = spiData.size();
|
const int setRegCnt = spiData.size();
|
||||||
for (int i = 0; i < setRegCnt; ++i)
|
for (int i = 0; i < setRegCnt; ++i)
|
||||||
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
|
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, setRegCnt);
|
WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
lime::fpga::FPGA_PLL_clock clocks[2];
|
lime::fpga::FPGA_PLL_clock clocks[2];
|
||||||
clocks[0].bypass = false;
|
|
||||||
clocks[0].index = 0;
|
clocks[0].index = 0;
|
||||||
clocks[0].outFrequency = txInterfaceClk;
|
clocks[0].outFrequency = txInterfaceClk;
|
||||||
clocks[0].phaseShift_deg = 0;
|
clocks[0].phaseShift_deg = 0;
|
||||||
clocks[0].findPhase = false;
|
|
||||||
clocks[1].bypass = false;
|
|
||||||
clocks[1].index = 1;
|
clocks[1].index = 1;
|
||||||
clocks[1].outFrequency = txInterfaceClk;
|
clocks[1].outFrequency = txInterfaceClk;
|
||||||
if (this->chipVersion == 0x3841)
|
if (this->chipVersion == 0x3841)
|
||||||
@ -233,27 +160,21 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double
|
|||||||
clocks[1].findPhase = true;
|
clocks[1].findPhase = true;
|
||||||
WriteRegister(0x000A, 0x0200);
|
WriteRegister(0x000A, 0x0200);
|
||||||
}
|
}
|
||||||
else
|
status = lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2);
|
||||||
{
|
|
||||||
clocks[1].findPhase = false;
|
|
||||||
}
|
|
||||||
status = lime::fpga::SetPllFrequency(this, 0, txInterfaceClk, clocks, 2);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
status = lime::fpga::SetDirectClocking(this, 0, txInterfaceClk, 90);
|
status = lime::fpga::SetDirectClocking(this, pll_ind, txInterfaceClk, 90);
|
||||||
|
|
||||||
if (phaseSearch)
|
if (phaseSearch)
|
||||||
{
|
{
|
||||||
//Restore registers
|
//Restore registers
|
||||||
for (int i = 0; i < bakRegCnt; ++i)
|
for (int i = 0; i < bakRegCnt; ++i)
|
||||||
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | dataRd[i]; //msbit 1=SPI write
|
dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | dataRd[i]; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, bakRegCnt);
|
WriteLMS7002MSPI(dataWr.data(), bakRegCnt, channel);
|
||||||
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write
|
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1);
|
WriteLMS7002MSPI(dataWr.data(), 1, channel);
|
||||||
WriteRegister(0x000A, 0);
|
WriteRegister(0x000A, 0);
|
||||||
UpdateThreads();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,57 +187,44 @@ int ConnectionSTREAM::ResetStreamBuffers()
|
|||||||
return TransferPacket(ctrPkt);
|
return TransferPacket(ctrPkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConnectionSTREAM::ReadRawStreamData(char* buffer, unsigned length, int timeout_ms)
|
int ConnectionSTREAM::ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms)
|
||||||
{
|
{
|
||||||
fpga::StopStreaming(this);
|
const unsigned char ep = 0x81;
|
||||||
|
fpga::StopStreaming(this, epIndex);
|
||||||
|
|
||||||
ResetStreamBuffers();
|
ResetStreamBuffers();
|
||||||
WriteRegister(0x0008, 0x0100 | 0x2);
|
WriteRegister(0x0008, 0x0100 | 0x2);
|
||||||
WriteRegister(0x0007, 1);
|
WriteRegister(0x0007, 1);
|
||||||
|
fpga::StartStreaming(this, epIndex);
|
||||||
|
|
||||||
fpga::StartStreaming(this);
|
int totalBytesReceived = ReceiveData(buffer,length, epIndex, timeout_ms);
|
||||||
|
fpga::StopStreaming(this, epIndex);
|
||||||
|
AbortReading(ep);
|
||||||
|
|
||||||
int handle = BeginDataReading(buffer, length);
|
return totalBytesReceived;
|
||||||
if (WaitForReading(handle, timeout_ms) == false)
|
|
||||||
{
|
|
||||||
AbortReading();
|
|
||||||
}
|
|
||||||
|
|
||||||
fpga::StopStreaming(this);
|
|
||||||
|
|
||||||
int totalBytesReceived = FinishDataReading(buffer, length, handle);
|
|
||||||
|
|
||||||
return totalBytesReceived;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Function dedicated for receiving data samples from board
|
/** @brief Function dedicated for receiving data samples from board
|
||||||
@param rxFIFO FIFO to store received data
|
@param stream a pointer to an active receiver stream
|
||||||
@param terminate periodically pooled flag to terminate thread
|
|
||||||
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
|
||||||
*/
|
*/
|
||||||
void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
void ConnectionSTREAM::ReceivePacketsLoop(Streamer* stream)
|
||||||
{
|
{
|
||||||
//auto dataPort = args.dataPort;
|
|
||||||
auto terminate = args.terminate;
|
|
||||||
auto dataRate_Bps = args.dataRate_Bps;
|
|
||||||
auto generateData = args.generateData;
|
|
||||||
auto safeToConfigInterface = args.safeToConfigInterface;
|
|
||||||
|
|
||||||
//at this point FPGA has to be already configured to output samples
|
//at this point FPGA has to be already configured to output samples
|
||||||
const uint8_t chCount = args.channels.size();
|
const uint8_t chCount = stream->mRxStreams.size();
|
||||||
const auto link = args.channels[0]->config.linkFormat;
|
const auto link = stream->mRxStreams[0]->config.linkFormat;
|
||||||
const uint32_t samplesInPacket = (link == StreamConfig::STREAM_12_BIT_COMPRESSED ? 1360 : 1020)/chCount;
|
const uint32_t samplesInPacket = (link == StreamConfig::STREAM_12_BIT_COMPRESSED ? 1360 : 1020)/chCount;
|
||||||
|
const unsigned char ep = 0x81;
|
||||||
|
const int chipID = stream->mChipID;
|
||||||
|
|
||||||
double latency=0;
|
float latency=0;
|
||||||
for (int i = 0; i < chCount; i++)
|
for (int i = 0; i < chCount; i++)
|
||||||
{
|
latency += stream->mRxStreams[i]->config.performanceLatency/chCount;
|
||||||
latency += args.channels[i]->config.performanceLatency/chCount;
|
|
||||||
}
|
|
||||||
const unsigned tmp_cnt = (latency * 6)+0.5;
|
const unsigned tmp_cnt = (latency * 6)+0.5;
|
||||||
|
|
||||||
const uint8_t packetsToBatch = (1<<tmp_cnt);
|
const uint8_t packetsToBatch = (1<<tmp_cnt);
|
||||||
const uint32_t bufferSize = packetsToBatch*sizeof(FPGA_DataPacket);
|
const uint32_t bufferSize = packetsToBatch*sizeof(FPGA_DataPacket);
|
||||||
const uint8_t buffersCount = (tmp_cnt < 3) ? 32 : 16; // must be power of 2
|
const uint8_t buffersCount = 16;
|
||||||
vector<int> handles(buffersCount, 0);
|
vector<int> handles(buffersCount, 0);
|
||||||
vector<char>buffers(buffersCount*bufferSize, 0);
|
vector<char>buffers(buffersCount*bufferSize, 0);
|
||||||
vector<StreamChannel::Frame> chFrames;
|
vector<StreamChannel::Frame> chFrames;
|
||||||
@ -330,24 +238,18 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t activeTransfers = 0;
|
int activeTransfers = 0;
|
||||||
for (int i = 0; i<buffersCount; ++i)
|
for (int i = 0; i<buffersCount; ++i)
|
||||||
{
|
{
|
||||||
handles[i] = this->BeginDataReading(&buffers[i*bufferSize], bufferSize);
|
handles[i] = this->BeginDataReading(&buffers[i*bufferSize], bufferSize, ep);
|
||||||
++activeTransfers;
|
++activeTransfers;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bi = 0;
|
int bi = 0;
|
||||||
unsigned long totalBytesReceived = 0; //for data rate calculation
|
unsigned long totalBytesReceived = 0; //for data rate calculation
|
||||||
int m_bufferFailures = 0;
|
|
||||||
int32_t droppedSamples = 0;
|
|
||||||
int32_t packetLoss = 0;
|
|
||||||
|
|
||||||
vector<uint32_t> samplesCollected(chCount, 0);
|
|
||||||
vector<uint32_t> samplesReceived(chCount, 0);
|
|
||||||
|
|
||||||
auto t1 = chrono::high_resolution_clock::now();
|
auto t1 = chrono::high_resolution_clock::now();
|
||||||
auto t2 = chrono::high_resolution_clock::now();
|
auto t2 = t1;
|
||||||
|
|
||||||
std::mutex txFlagsLock;
|
std::mutex txFlagsLock;
|
||||||
condition_variable resetTxFlags;
|
condition_variable resetTxFlags;
|
||||||
@ -360,24 +262,24 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
uint32_t reg9;
|
uint32_t reg9;
|
||||||
port->ReadRegister(0x0009, reg9);
|
port->ReadRegister(0x0009, reg9);
|
||||||
const uint32_t addr[] = {0x0009, 0x0009};
|
const uint32_t addr[] = {0x0009, 0x0009};
|
||||||
const uint32_t data[] = {reg9 | (1 << 1), reg9 & ~(1 << 1)};
|
const uint32_t data[] = {reg9 | (5 << 1), reg9 & ~(5 << 1)};
|
||||||
while (not terminate->load())
|
while (not terminate->load())
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lck(*spiLock);
|
std::unique_lock<std::mutex> lck(*spiLock);
|
||||||
doWork->wait(lck);
|
doWork->wait(lck);
|
||||||
port->WriteRegisters(addr, data, 2);
|
port->WriteRegisters(addr, data, 2);
|
||||||
}
|
}
|
||||||
}, this, terminate, &txFlagsLock, &resetTxFlags);
|
}, this, &stream->terminateRx, &txFlagsLock, &resetTxFlags);
|
||||||
|
|
||||||
int resetFlagsDelay = 128;
|
int resetFlagsDelay = 128;
|
||||||
uint64_t prevTs = 0;
|
uint64_t prevTs = 0;
|
||||||
while (terminate->load() == false)
|
while (stream->terminateRx.load() == false)
|
||||||
{
|
{
|
||||||
if(generateData->load())
|
if(stream->generateData.load())
|
||||||
{
|
{
|
||||||
if(activeTransfers == 0) //stop FPGA when last transfer completes
|
if(activeTransfers == 0) //stop FPGA when last transfer completes
|
||||||
fpga::StopStreaming(this);
|
fpga::StopStreaming(this, chipID);
|
||||||
safeToConfigInterface->notify_all(); //notify that it's safe to change chip config
|
stream->safeToConfigInterface.notify_all(); //notify that it's safe to change chip config
|
||||||
const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10;
|
const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10;
|
||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
for(int i=0; i<batchSize; ++i)
|
for(int i=0; i<batchSize; ++i)
|
||||||
@ -390,8 +292,7 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
chFrames[ch].samples[j].i = 0;
|
chFrames[ch].samples[j].i = 0;
|
||||||
chFrames[ch].samples[j].q = 0;
|
chFrames[ch].samples[j].q = 0;
|
||||||
}
|
}
|
||||||
uint32_t samplesPushed = args.channels[ch]->Write((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta);
|
uint32_t samplesPushed = stream->mRxStreams[ch]->Write((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta);
|
||||||
samplesReceived[ch] += chFrames[ch].samplesCount;
|
|
||||||
if(samplesPushed != chFrames[ch].samplesCount)
|
if(samplesPushed != chFrames[ch].samplesCount)
|
||||||
lime::warning("Rx samples pushed %i/%i", samplesPushed, chFrames[ch].samplesCount);
|
lime::warning("Rx samples pushed %i/%i", samplesPushed, chFrames[ch].samplesCount);
|
||||||
}
|
}
|
||||||
@ -401,13 +302,13 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
int32_t bytesReceived = 0;
|
int32_t bytesReceived = 0;
|
||||||
if(handles[bi] >= 0)
|
if(handles[bi] >= 0)
|
||||||
{
|
{
|
||||||
if (this->WaitForReading(handles[bi], 1000) == false)
|
if (this->WaitForReading(handles[bi], 1000) == true)
|
||||||
++m_bufferFailures;
|
bytesReceived = this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]);
|
||||||
bytesReceived = this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]);
|
|
||||||
--activeTransfers;
|
--activeTransfers;
|
||||||
totalBytesReceived += bytesReceived;
|
totalBytesReceived += bytesReceived;
|
||||||
if (bytesReceived != int32_t(bufferSize)) //data should come in full sized packets
|
if (bytesReceived != int32_t(bufferSize)) //data should come in full sized packets
|
||||||
++m_bufferFailures;
|
for(auto value: stream->mRxStreams)
|
||||||
|
value->underflow++;
|
||||||
}
|
}
|
||||||
bool txLate=false;
|
bool txLate=false;
|
||||||
for (uint8_t pktIndex = 0; pktIndex < bytesReceived / sizeof(FPGA_DataPacket); ++pktIndex)
|
for (uint8_t pktIndex = 0; pktIndex < bytesReceived / sizeof(FPGA_DataPacket); ++pktIndex)
|
||||||
@ -424,20 +325,23 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
lime::info("L %llu", (unsigned long long)pkt[pktIndex].counter);
|
lime::info("L %llu", (unsigned long long)pkt[pktIndex].counter);
|
||||||
resetTxFlags.notify_one();
|
resetTxFlags.notify_one();
|
||||||
resetFlagsDelay = packetsToBatch*buffersCount;
|
resetFlagsDelay = packetsToBatch*buffersCount;
|
||||||
if (args.reportLateTx) args.reportLateTx(pkt[pktIndex].counter);
|
stream->txLastLateTime.store(pkt[pktIndex].counter);
|
||||||
|
for(auto value: stream->mTxStreams)
|
||||||
|
value->pktLost++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t* pktStart = (uint8_t*)pkt[pktIndex].data;
|
uint8_t* pktStart = (uint8_t*)pkt[pktIndex].data;
|
||||||
if(pkt[pktIndex].counter - prevTs != samplesInPacket && pkt[pktIndex].counter != prevTs)
|
if(pkt[pktIndex].counter - prevTs != samplesInPacket && pkt[pktIndex].counter != prevTs)
|
||||||
{
|
{
|
||||||
|
int packetLoss = ((pkt[pktIndex].counter - prevTs)/samplesInPacket)-1;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
lime::debug("\tRx pktLoss@%i - ts diff: %li pktLoss: %.1f", pktIndex, pkt[pktIndex].counter - prevTs, float(pkt[pktIndex].counter - prevTs)/samplesInPacket);
|
printf("\tRx pktLoss: ts diff: %li pktLoss: %i\n", pkt[pktIndex].counter - prevTs, packetLoss);
|
||||||
#endif
|
#endif
|
||||||
packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket;
|
for(auto value: stream->mRxStreams)
|
||||||
|
value->pktLost += packetLoss;
|
||||||
}
|
}
|
||||||
prevTs = pkt[pktIndex].counter;
|
prevTs = pkt[pktIndex].counter;
|
||||||
if(args.lastTimestamp)
|
stream->rxLastTimestamp.store(prevTs);
|
||||||
args.lastTimestamp->store(pkt[pktIndex].counter);
|
|
||||||
//parse samples
|
//parse samples
|
||||||
vector<complex16_t*> dest(chCount);
|
vector<complex16_t*> dest(chCount);
|
||||||
for(uint8_t c=0; c<chCount; ++c)
|
for(uint8_t c=0; c<chCount; ++c)
|
||||||
@ -450,19 +354,19 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
meta.timestamp = pkt[pktIndex].counter;
|
meta.timestamp = pkt[pktIndex].counter;
|
||||||
meta.flags = RingFIFO::OVERWRITE_OLD;
|
meta.flags = RingFIFO::OVERWRITE_OLD;
|
||||||
uint32_t samplesPushed = args.channels[ch]->Write((const void*)chFrames[ch].samples, samplesCount, &meta, 100);
|
uint32_t samplesPushed = stream->mRxStreams[ch]->Write((const void*)chFrames[ch].samples, samplesCount, &meta, 100);
|
||||||
if(samplesPushed != samplesCount)
|
if(samplesPushed != samplesCount)
|
||||||
droppedSamples += samplesCount-samplesPushed;
|
stream->mRxStreams[ch]->overflow++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-submit this request to keep the queue full
|
// Re-submit this request to keep the queue full
|
||||||
if(not generateData->load())
|
if(not stream->generateData.load())
|
||||||
{
|
{
|
||||||
if(activeTransfers == 0) //reactivate FPGA and USB transfers
|
if(activeTransfers == 0) //reactivate FPGA and USB transfers
|
||||||
fpga::StartStreaming(this);
|
fpga::StartStreaming(this, chipID);
|
||||||
for(int i=0; i<buffersCount-activeTransfers; ++i)
|
for(int i=0; i<buffersCount-activeTransfers; ++i)
|
||||||
{
|
{
|
||||||
handles[bi] = this->BeginDataReading(&buffers[bi*bufferSize], bufferSize);
|
handles[bi] = this->BeginDataReading(&buffers[bi*bufferSize], bufferSize, ep);
|
||||||
bi = (bi + 1) & (buffersCount-1);
|
bi = (bi + 1) & (buffersCount-1);
|
||||||
++activeTransfers;
|
++activeTransfers;
|
||||||
}
|
}
|
||||||
@ -480,21 +384,13 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
//total number of bytes sent per second
|
//total number of bytes sent per second
|
||||||
double dataRate = 1000.0*totalBytesReceived / timePeriod;
|
double dataRate = 1000.0*totalBytesReceived / timePeriod;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
//each channel sample rate
|
printf("Rx: %.3f MB/s\n", dataRate / 1000000.0);
|
||||||
float samplingRate = 1000.0*samplesReceived[0] / timePeriod;
|
|
||||||
lime::debug("Rx: %.3f MB/s, Fs: %.3f MHz, overrun: %i, loss: %i", dataRate / 1000000.0, samplingRate / 1000000.0, droppedSamples, packetLoss);
|
|
||||||
#endif
|
#endif
|
||||||
samplesReceived[0] = 0;
|
|
||||||
totalBytesReceived = 0;
|
totalBytesReceived = 0;
|
||||||
m_bufferFailures = 0;
|
stream->rxDataRate_Bps.store((uint32_t)dataRate);
|
||||||
droppedSamples = 0;
|
|
||||||
packetLoss = 0;
|
|
||||||
|
|
||||||
if (dataRate_Bps)
|
|
||||||
dataRate_Bps->store((uint32_t)dataRate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->AbortReading();
|
AbortReading(ep);
|
||||||
for (int j = 0; j<buffersCount; j++)
|
for (int j = 0; j<buffersCount; j++)
|
||||||
{
|
{
|
||||||
if(handles[bi] >= 0)
|
if(handles[bi] >= 0)
|
||||||
@ -506,35 +402,27 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args)
|
|||||||
}
|
}
|
||||||
resetTxFlags.notify_one();
|
resetTxFlags.notify_one();
|
||||||
txReset.join();
|
txReset.join();
|
||||||
if (dataRate_Bps)
|
stream->rxDataRate_Bps.store(0);
|
||||||
dataRate_Bps->store(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Functions dedicated for transmitting packets to board
|
/** @brief Functions dedicated for transmitting packets to board
|
||||||
@param txFIFO data source FIFO
|
@param stream an active transmit stream
|
||||||
@param terminate periodically pooled flag to terminate thread
|
|
||||||
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
|
||||||
*/
|
*/
|
||||||
void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
void ConnectionSTREAM::TransmitPacketsLoop(Streamer* stream)
|
||||||
{
|
{
|
||||||
//auto dataPort = args.dataPort;
|
|
||||||
auto terminate = args.terminate;
|
|
||||||
auto dataRate_Bps = args.dataRate_Bps;
|
|
||||||
|
|
||||||
//at this point FPGA has to be already configured to output samples
|
//at this point FPGA has to be already configured to output samples
|
||||||
const uint8_t maxChannelCount = 2;
|
const uint8_t maxChannelCount = 2;
|
||||||
const uint8_t chCount = args.channels.size();
|
const uint8_t chCount = stream->mTxStreams.size();
|
||||||
const auto link = args.channels[0]->config.linkFormat;
|
const auto link = stream->mTxStreams[0]->config.linkFormat;
|
||||||
|
const unsigned char ep = 0x01;
|
||||||
|
|
||||||
double latency=0;
|
double latency=0;
|
||||||
for (int i = 0; i < chCount; i++)
|
for (int i = 0; i < chCount; i++)
|
||||||
{
|
latency += stream->mTxStreams[i]->config.performanceLatency/chCount;
|
||||||
latency += args.channels[i]->config.performanceLatency/chCount;
|
|
||||||
}
|
|
||||||
const unsigned tmp_cnt = (latency * 6)+0.5;
|
const unsigned tmp_cnt = (latency * 6)+0.5;
|
||||||
|
|
||||||
const uint8_t buffersCount = 16; // must be power of 2
|
const uint8_t buffersCount = 16; // must be power of 2
|
||||||
assert(buffersCount % 2 == 0);
|
|
||||||
const uint8_t packetsToBatch = (1<<tmp_cnt); //packets in single USB transfer
|
const uint8_t packetsToBatch = (1<<tmp_cnt); //packets in single USB transfer
|
||||||
const uint32_t bufferSize = packetsToBatch*4096;
|
const uint32_t bufferSize = packetsToBatch*4096;
|
||||||
const uint32_t popTimeout_ms = 100;
|
const uint32_t popTimeout_ms = 100;
|
||||||
@ -542,7 +430,6 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
|||||||
const int maxSamplesBatch = (link==StreamConfig::STREAM_12_BIT_COMPRESSED?1360:1020)/chCount;
|
const int maxSamplesBatch = (link==StreamConfig::STREAM_12_BIT_COMPRESSED?1360:1020)/chCount;
|
||||||
vector<int> handles(buffersCount, 0);
|
vector<int> handles(buffersCount, 0);
|
||||||
vector<bool> bufferUsed(buffersCount, 0);
|
vector<bool> bufferUsed(buffersCount, 0);
|
||||||
vector<uint32_t> bytesToSend(buffersCount, 0);
|
|
||||||
vector<complex16_t> samples[maxChannelCount];
|
vector<complex16_t> samples[maxChannelCount];
|
||||||
vector<char> buffers;
|
vector<char> buffers;
|
||||||
try
|
try
|
||||||
@ -553,49 +440,57 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
|||||||
}
|
}
|
||||||
catch (const std::bad_alloc& ex) //not enough memory for buffers
|
catch (const std::bad_alloc& ex) //not enough memory for buffers
|
||||||
{
|
{
|
||||||
lime::error("Error allocating Tx buffers, not enough memory");
|
return lime::error("Error allocating Tx buffers, not enough memory");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_bufferFailures = 0;
|
|
||||||
long totalBytesSent = 0;
|
long totalBytesSent = 0;
|
||||||
|
|
||||||
uint32_t samplesSent = 0;
|
|
||||||
|
|
||||||
auto t1 = chrono::high_resolution_clock::now();
|
auto t1 = chrono::high_resolution_clock::now();
|
||||||
auto t2 = chrono::high_resolution_clock::now();
|
auto t2 = t1;
|
||||||
|
|
||||||
uint8_t bi = 0; //buffer index
|
uint8_t bi = 0; //buffer index
|
||||||
while (terminate->load() != true)
|
while (stream->terminateTx.load() != true)
|
||||||
{
|
{
|
||||||
if (bufferUsed[bi])
|
if (bufferUsed[bi])
|
||||||
{
|
{
|
||||||
if (this->WaitForSending(handles[bi], 1000) == false)
|
unsigned bytesSent = 0;
|
||||||
++m_bufferFailures;
|
if (this->WaitForSending(handles[bi], 1000) == true) {
|
||||||
uint32_t bytesSent = this->FinishDataSending(&buffers[bi*bufferSize], bytesToSend[bi], handles[bi]);
|
bytesSent = this->FinishDataSending(&buffers[bi*bufferSize], bufferSize, handles[bi]);
|
||||||
totalBytesSent += bytesSent;
|
}
|
||||||
if (bytesSent != bytesToSend[bi])
|
|
||||||
++m_bufferFailures;
|
if (bytesSent != bufferSize) {
|
||||||
|
for (auto value : stream->mTxStreams) {
|
||||||
|
value->overflow++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
totalBytesSent += bytesSent;
|
||||||
|
}
|
||||||
bufferUsed[bi] = false;
|
bufferUsed[bi] = false;
|
||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
while(i<packetsToBatch && terminate->load() != true)
|
while(i<packetsToBatch && stream->terminateTx.load() != true)
|
||||||
{
|
{
|
||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
FPGA_DataPacket* pkt = reinterpret_cast<FPGA_DataPacket*>(&buffers[bi*bufferSize]);
|
FPGA_DataPacket* pkt = reinterpret_cast<FPGA_DataPacket*>(&buffers[bi*bufferSize]);
|
||||||
|
bool badSamples = false;
|
||||||
for(int ch=0; ch<chCount; ++ch)
|
for(int ch=0; ch<chCount; ++ch)
|
||||||
{
|
{
|
||||||
int samplesPopped = args.channels[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms);
|
int samplesPopped = stream->mTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms);
|
||||||
if (samplesPopped != maxSamplesBatch)
|
if (samplesPopped != maxSamplesBatch)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
badSamples = true;
|
||||||
lime::warning("popping from TX, samples popped %i/%i", samplesPopped, maxSamplesBatch);
|
stream->mTxStreams[ch]->underflow++;
|
||||||
#endif
|
stream->txDataRate_Bps.store(0);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("popping from TX, samples popped %i/%i\n", samplesPopped, maxSamplesBatch);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if(terminate->load() == true) //early termination
|
if (badSamples)
|
||||||
|
continue;
|
||||||
|
if(stream->terminateTx.load() == true) //early termination
|
||||||
break;
|
break;
|
||||||
pkt[i].counter = meta.timestamp;
|
pkt[i].counter = meta.timestamp;
|
||||||
pkt[i].reserved[0] = 0;
|
pkt[i].reserved[0] = 0;
|
||||||
@ -608,12 +503,10 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
|||||||
src[c] = (samples[c].data());
|
src[c] = (samples[c].data());
|
||||||
uint8_t* const dataStart = (uint8_t*)pkt[i].data;
|
uint8_t* const dataStart = (uint8_t*)pkt[i].data;
|
||||||
fpga::Samples2FPGAPacketPayload(src.data(), maxSamplesBatch, chCount, link, dataStart, nullptr);
|
fpga::Samples2FPGAPacketPayload(src.data(), maxSamplesBatch, chCount, link, dataStart, nullptr);
|
||||||
samplesSent += maxSamplesBatch;
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesToSend[bi] = bufferSize;
|
handles[bi] = this->BeginDataSending(&buffers[bi*bufferSize], bufferSize, ep);
|
||||||
handles[bi] = this->BeginDataSending(&buffers[bi*bufferSize], bytesToSend[bi]);
|
|
||||||
bufferUsed[bi] = true;
|
bufferUsed[bi] = true;
|
||||||
|
|
||||||
t2 = chrono::high_resolution_clock::now();
|
t2 = chrono::high_resolution_clock::now();
|
||||||
@ -622,23 +515,18 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
|||||||
{
|
{
|
||||||
//total number of bytes sent per second
|
//total number of bytes sent per second
|
||||||
float dataRate = 1000.0*totalBytesSent / timePeriod;
|
float dataRate = 1000.0*totalBytesSent / timePeriod;
|
||||||
if(dataRate_Bps)
|
stream->txDataRate_Bps.store(dataRate);
|
||||||
dataRate_Bps->store(dataRate);
|
|
||||||
m_bufferFailures = 0;
|
|
||||||
samplesSent = 0;
|
|
||||||
totalBytesSent = 0;
|
totalBytesSent = 0;
|
||||||
t1 = t2;
|
t1 = t2;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
//total number of samples from all channels per second
|
printf("Tx: %.3f MB/s\n", dataRate / 1000000.0);
|
||||||
float sampleRate = 1000.0*samplesSent / timePeriod;
|
|
||||||
lime::debug("Tx: %.3f MB/s, Fs: %.3f MHz, failures: %i", dataRate / 1000000.0, sampleRate / 1000000.0, m_bufferFailures);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
bi = (bi + 1) & (buffersCount-1);
|
bi = (bi + 1) & (buffersCount-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all the queued requests to be cancelled
|
// Wait for all the queued requests to be cancelled
|
||||||
this->AbortSending();
|
AbortSending(ep);
|
||||||
for (int j = 0; j<buffersCount; j++)
|
for (int j = 0; j<buffersCount; j++)
|
||||||
{
|
{
|
||||||
if (bufferUsed[bi])
|
if (bufferUsed[bi])
|
||||||
@ -648,7 +536,6 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args)
|
|||||||
}
|
}
|
||||||
bi = (bi + 1) & (buffersCount-1);
|
bi = (bi + 1) & (buffersCount-1);
|
||||||
}
|
}
|
||||||
if (dataRate_Bps)
|
stream->txDataRate_Bps.store(0);
|
||||||
dataRate_Bps->store(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,17 +48,8 @@ Connection_uLimeSDR::Connection_uLimeSDR(void *arg, const unsigned index, const
|
|||||||
{
|
{
|
||||||
RxLoopFunction = bind(&Connection_uLimeSDR::ReceivePacketsLoop, this, std::placeholders::_1);
|
RxLoopFunction = bind(&Connection_uLimeSDR::ReceivePacketsLoop, this, std::placeholders::_1);
|
||||||
TxLoopFunction = bind(&Connection_uLimeSDR::TransmitPacketsLoop, this, std::placeholders::_1);
|
TxLoopFunction = bind(&Connection_uLimeSDR::TransmitPacketsLoop, this, std::placeholders::_1);
|
||||||
mTimestampOffset = 0;
|
|
||||||
rxLastTimestamp.store(0);
|
|
||||||
mExpectedSampleRate = 0;
|
mExpectedSampleRate = 0;
|
||||||
generateData.store(false);
|
|
||||||
rxRunning.store(false);
|
|
||||||
txRunning.store(false);
|
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
terminateRx.store(false);
|
|
||||||
terminateTx.store(false);
|
|
||||||
rxDataRate_Bps.store(0);
|
|
||||||
txDataRate_Bps.store(0);
|
|
||||||
|
|
||||||
mStreamWrEndPtAddr = 0x03;
|
mStreamWrEndPtAddr = 0x03;
|
||||||
mStreamRdEndPtAddr = 0x83;
|
mStreamRdEndPtAddr = 0x83;
|
||||||
@ -83,15 +74,6 @@ Connection_uLimeSDR::Connection_uLimeSDR(void *arg, const unsigned index, const
|
|||||||
*/
|
*/
|
||||||
Connection_uLimeSDR::~Connection_uLimeSDR()
|
Connection_uLimeSDR::~Connection_uLimeSDR()
|
||||||
{
|
{
|
||||||
for(auto i : mTxStreams)
|
|
||||||
ControlStream((size_t)i, false);
|
|
||||||
for(auto i : mRxStreams)
|
|
||||||
ControlStream((size_t)i, false);
|
|
||||||
for(auto i : mTxStreams)
|
|
||||||
CloseStream((size_t)i);
|
|
||||||
for(auto i : mRxStreams)
|
|
||||||
CloseStream((size_t)i);
|
|
||||||
UpdateThreads();
|
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
|
@ -96,10 +96,10 @@ public:
|
|||||||
//hooks to update FPGA plls when baseband interface data rate is changed
|
//hooks to update FPGA plls when baseband interface data rate is changed
|
||||||
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate, const double txPhase, const double rxPhase)override;
|
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate, const double txPhase, const double rxPhase)override;
|
||||||
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate) override;
|
virtual int UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate) override;
|
||||||
int ReadRawStreamData(char* buffer, unsigned length, int timeout_ms = 100)override;
|
int ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms = 100)override;
|
||||||
protected:
|
protected:
|
||||||
virtual void ReceivePacketsLoop(const ThreadData args) override;
|
virtual void ReceivePacketsLoop(Streamer* args) override;
|
||||||
virtual void TransmitPacketsLoop(const ThreadData args) override;
|
virtual void TransmitPacketsLoop(Streamer* args) override;
|
||||||
|
|
||||||
virtual int BeginDataReading(char* buffer, uint32_t length);
|
virtual int BeginDataReading(char* buffer, uint32_t length);
|
||||||
virtual int WaitForReading(int contextHandle, unsigned int timeout_ms);
|
virtual int WaitForReading(int contextHandle, unsigned int timeout_ms);
|
||||||
|
@ -101,7 +101,6 @@ int Connection_uLimeSDR::UpdateExternalDataRate(const size_t channel, const doub
|
|||||||
for (int i = 0; i < bakRegCnt; ++i)
|
for (int i = 0; i < bakRegCnt; ++i)
|
||||||
dataWr[i] = (spiAddr[i] << 16);
|
dataWr[i] = (spiAddr[i] << 16);
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt);
|
TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt);
|
||||||
//UpdateThreads(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((txInterfaceClk >= 5e6) && (rxInterfaceClk >= 5e6))
|
if ((txInterfaceClk >= 5e6) && (rxInterfaceClk >= 5e6))
|
||||||
@ -186,29 +185,28 @@ int Connection_uLimeSDR::UpdateExternalDataRate(const size_t channel, const doub
|
|||||||
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write
|
dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write
|
||||||
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1);
|
TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1);
|
||||||
WriteRegister(0x000A, 0);
|
WriteRegister(0x000A, 0);
|
||||||
UpdateThreads();
|
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Connection_uLimeSDR::ReadRawStreamData(char* buffer, unsigned length, int timeout_ms)
|
int Connection_uLimeSDR::ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms)
|
||||||
{
|
{
|
||||||
int totalBytesReceived = 0;
|
int totalBytesReceived = 0;
|
||||||
fpga::StopStreaming(this);
|
fpga::StopStreaming(this, epIndex);
|
||||||
|
|
||||||
//ResetStreamBuffers();
|
//ResetStreamBuffers();
|
||||||
WriteRegister(0x0008, 0x0100 | 0x2);
|
WriteRegister(0x0008, 0x0100 | 0x2);
|
||||||
WriteRegister(0x0007, 1);
|
WriteRegister(0x0007, 1);
|
||||||
|
|
||||||
fpga::StartStreaming(this);
|
fpga::StartStreaming(this, epIndex);
|
||||||
|
|
||||||
int handle = BeginDataReading(buffer, length);
|
int handle = BeginDataReading(buffer, length);
|
||||||
if (WaitForReading(handle, timeout_ms))
|
if (WaitForReading(handle, timeout_ms))
|
||||||
totalBytesReceived = FinishDataReading(buffer, length, handle);
|
totalBytesReceived = FinishDataReading(buffer, length, handle);
|
||||||
|
|
||||||
AbortReading();
|
AbortReading();
|
||||||
fpga::StopStreaming(this);
|
fpga::StopStreaming(this, epIndex);
|
||||||
|
|
||||||
return totalBytesReceived;
|
return totalBytesReceived;
|
||||||
}
|
}
|
||||||
@ -235,23 +233,18 @@ int Connection_uLimeSDR::ResetStreamBuffers()
|
|||||||
@param terminate periodically pooled flag to terminate thread
|
@param terminate periodically pooled flag to terminate thread
|
||||||
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
||||||
*/
|
*/
|
||||||
void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadData args)
|
void Connection_uLimeSDR::ReceivePacketsLoop(Connection_uLimeSDR::Streamer* stream)
|
||||||
{
|
{
|
||||||
//auto dataPort = args.dataPort;
|
|
||||||
auto terminate = args.terminate;
|
|
||||||
auto dataRate_Bps = args.dataRate_Bps;
|
|
||||||
auto generateData = args.generateData;
|
|
||||||
auto safeToConfigInterface = args.safeToConfigInterface;
|
|
||||||
|
|
||||||
//at this point FPGA has to be already configured to output samples
|
//at this point FPGA has to be already configured to output samples
|
||||||
const uint8_t chCount = args.channels.size();
|
const uint8_t chCount = stream->mRxStreams.size();
|
||||||
const auto link = args.channels[0]->config.linkFormat;
|
const auto link =stream->mRxStreams[0]->config.linkFormat;
|
||||||
const uint32_t samplesInPacket = (link == StreamConfig::STREAM_12_BIT_COMPRESSED ? 1360 : 1020)/chCount;
|
const uint32_t samplesInPacket = (link == StreamConfig::STREAM_12_BIT_COMPRESSED ? 1360 : 1020)/chCount;
|
||||||
|
const int chipID = stream->mChipID;
|
||||||
|
|
||||||
double latency=0;
|
double latency=0;
|
||||||
for (int i = 0; i < chCount; i++)
|
for (int i = 0; i < chCount; i++)
|
||||||
{
|
{
|
||||||
latency += args.channels[i]->config.performanceLatency/chCount;
|
latency += stream->mRxStreams[i]->config.performanceLatency/chCount;
|
||||||
}
|
}
|
||||||
const unsigned tmp_cnt = (latency * 4)+0.5;
|
const unsigned tmp_cnt = (latency * 4)+0.5;
|
||||||
|
|
||||||
@ -308,17 +301,17 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
doWork->wait(lck);
|
doWork->wait(lck);
|
||||||
port->WriteRegisters(addr, data, 2);
|
port->WriteRegisters(addr, data, 2);
|
||||||
}
|
}
|
||||||
}, this, terminate, &txFlagsLock, &resetTxFlags);
|
}, this, &stream->terminateRx, &txFlagsLock, &resetTxFlags);
|
||||||
|
|
||||||
int resetFlagsDelay = 128;
|
int resetFlagsDelay = 128;
|
||||||
uint64_t prevTs = 0;
|
uint64_t prevTs = 0;
|
||||||
while (terminate->load() == false)
|
while (stream->terminateRx.load() == false)
|
||||||
{
|
{
|
||||||
if(generateData->load())
|
if(stream->generateData.load())
|
||||||
{
|
{
|
||||||
if(activeTransfers == 0) //stop FPGA when last transfer completes
|
if(activeTransfers == 0) //stop FPGA when last transfer completes
|
||||||
fpga::StopStreaming(this);
|
fpga::StopStreaming(this, chipID);
|
||||||
safeToConfigInterface->notify_all(); //notify that it's safe to change chip config
|
stream->safeToConfigInterface.notify_all(); //notify that it's safe to change chip config
|
||||||
const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10;
|
const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10;
|
||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
for(int i=0; i<batchSize; ++i)
|
for(int i=0; i<batchSize; ++i)
|
||||||
@ -331,7 +324,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
chFrames[ch].samples[j].i = 0;
|
chFrames[ch].samples[j].i = 0;
|
||||||
chFrames[ch].samples[j].q = 0;
|
chFrames[ch].samples[j].q = 0;
|
||||||
}
|
}
|
||||||
uint32_t samplesPushed = args.channels[ch]->Write((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta);
|
uint32_t samplesPushed = stream->mRxStreams[ch]->Write((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta);
|
||||||
samplesReceived[ch] += chFrames[ch].samplesCount;
|
samplesReceived[ch] += chFrames[ch].samplesCount;
|
||||||
if(samplesPushed != chFrames[ch].samplesCount)
|
if(samplesPushed != chFrames[ch].samplesCount)
|
||||||
printf("Rx samples pushed %i/%i\n", samplesPushed, chFrames[ch].samplesCount);
|
printf("Rx samples pushed %i/%i\n", samplesPushed, chFrames[ch].samplesCount);
|
||||||
@ -365,7 +358,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
printf("L");
|
printf("L");
|
||||||
resetTxFlags.notify_one();
|
resetTxFlags.notify_one();
|
||||||
resetFlagsDelay = packetsToBatch*buffersCount;
|
resetFlagsDelay = packetsToBatch*buffersCount;
|
||||||
if (args.reportLateTx) args.reportLateTx(pkt[pktIndex].counter);
|
stream->txLastLateTime.store(pkt[pktIndex].counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t* pktStart = (uint8_t*)pkt[pktIndex].data;
|
uint8_t* pktStart = (uint8_t*)pkt[pktIndex].data;
|
||||||
@ -377,8 +370,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket;
|
packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket;
|
||||||
}
|
}
|
||||||
prevTs = pkt[pktIndex].counter;
|
prevTs = pkt[pktIndex].counter;
|
||||||
if(args.lastTimestamp)
|
stream->rxLastTimestamp.store(pkt[pktIndex].counter);
|
||||||
args.lastTimestamp->store(pkt[pktIndex].counter);
|
|
||||||
//parse samples
|
//parse samples
|
||||||
vector<complex16_t*> dest(chCount);
|
vector<complex16_t*> dest(chCount);
|
||||||
for(uint8_t c=0; c<chCount; ++c)
|
for(uint8_t c=0; c<chCount; ++c)
|
||||||
@ -391,16 +383,16 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
meta.timestamp = pkt[pktIndex].counter;
|
meta.timestamp = pkt[pktIndex].counter;
|
||||||
meta.flags = RingFIFO::OVERWRITE_OLD;
|
meta.flags = RingFIFO::OVERWRITE_OLD;
|
||||||
uint32_t samplesPushed = args.channels[ch]->Write((const void*)chFrames[ch].samples, samplesCount, &meta, 100);
|
uint32_t samplesPushed = stream->mRxStreams[ch]->Write((const void*)chFrames[ch].samples, samplesCount, &meta, 100);
|
||||||
if(samplesPushed != samplesCount)
|
if(samplesPushed != samplesCount)
|
||||||
droppedSamples += samplesCount-samplesPushed;
|
droppedSamples += samplesCount-samplesPushed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-submit this request to keep the queue full
|
// Re-submit this request to keep the queue full
|
||||||
if(not generateData->load())
|
if(not stream->generateData.load())
|
||||||
{
|
{
|
||||||
if(activeTransfers == 0) //reactivate FPGA and USB transfers
|
if(activeTransfers == 0) //reactivate FPGA and USB transfers
|
||||||
fpga::StartStreaming(this);
|
fpga::StartStreaming(this, chipID);
|
||||||
for(int i=0; i<buffersCount-activeTransfers; ++i)
|
for(int i=0; i<buffersCount-activeTransfers; ++i)
|
||||||
{
|
{
|
||||||
handles[bi] = this->BeginDataReading(&buffers[bi*bufferSize], bufferSize);
|
handles[bi] = this->BeginDataReading(&buffers[bi*bufferSize], bufferSize);
|
||||||
@ -430,9 +422,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
m_bufferFailures = 0;
|
m_bufferFailures = 0;
|
||||||
droppedSamples = 0;
|
droppedSamples = 0;
|
||||||
packetLoss = 0;
|
packetLoss = 0;
|
||||||
|
stream->rxDataRate_Bps.store((uint32_t)dataRate);
|
||||||
if (dataRate_Bps)
|
|
||||||
dataRate_Bps->store((uint32_t)dataRate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->AbortReading();
|
this->AbortReading();
|
||||||
@ -447,8 +437,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
}
|
}
|
||||||
resetTxFlags.notify_one();
|
resetTxFlags.notify_one();
|
||||||
txReset.join();
|
txReset.join();
|
||||||
if (dataRate_Bps)
|
stream->rxDataRate_Bps.store(0);
|
||||||
dataRate_Bps->store(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Functions dedicated for transmitting packets to board
|
/** @brief Functions dedicated for transmitting packets to board
|
||||||
@ -456,21 +445,17 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa
|
|||||||
@param terminate periodically pooled flag to terminate thread
|
@param terminate periodically pooled flag to terminate thread
|
||||||
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
@param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second
|
||||||
*/
|
*/
|
||||||
void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadData args)
|
void Connection_uLimeSDR::TransmitPacketsLoop(Streamer* stream)
|
||||||
{
|
{
|
||||||
//auto dataPort = args.dataPort;
|
|
||||||
auto terminate = args.terminate;
|
|
||||||
auto dataRate_Bps = args.dataRate_Bps;
|
|
||||||
|
|
||||||
//at this point FPGA has to be already configured to output samples
|
//at this point FPGA has to be already configured to output samples
|
||||||
const uint8_t maxChannelCount = 2;
|
const uint8_t maxChannelCount = 2;
|
||||||
const uint8_t chCount = args.channels.size();
|
const uint8_t chCount = stream->mTxStreams.size();
|
||||||
const auto link = args.channels[0]->config.linkFormat;
|
const auto link = stream->mTxStreams[0]->config.linkFormat;
|
||||||
|
|
||||||
double latency=0;
|
double latency=0;
|
||||||
for (int i = 0; i < chCount; i++)
|
for (int i = 0; i < chCount; i++)
|
||||||
{
|
{
|
||||||
latency += args.channels[i]->config.performanceLatency/chCount;
|
latency += stream->mTxStreams[i]->config.performanceLatency/chCount;
|
||||||
}
|
}
|
||||||
const unsigned tmp_cnt = (latency * 4)+0.5;
|
const unsigned tmp_cnt = (latency * 4)+0.5;
|
||||||
|
|
||||||
@ -507,7 +492,7 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD
|
|||||||
auto t2 = chrono::high_resolution_clock::now();
|
auto t2 = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
uint8_t bi = 0; //buffer index
|
uint8_t bi = 0; //buffer index
|
||||||
while (terminate->load() != true)
|
while (stream->terminateTx.load() != true)
|
||||||
{
|
{
|
||||||
if (bufferUsed[bi])
|
if (bufferUsed[bi])
|
||||||
{
|
{
|
||||||
@ -521,13 +506,13 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD
|
|||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
while(i<packetsToBatch && terminate->load() != true)
|
while(i<packetsToBatch && stream->terminateTx.load() != true)
|
||||||
{
|
{
|
||||||
IStreamChannel::Metadata meta;
|
IStreamChannel::Metadata meta;
|
||||||
FPGA_DataPacket* pkt = reinterpret_cast<FPGA_DataPacket*>(&buffers[bi*bufferSize]);
|
FPGA_DataPacket* pkt = reinterpret_cast<FPGA_DataPacket*>(&buffers[bi*bufferSize]);
|
||||||
for(int ch=0; ch<chCount; ++ch)
|
for(int ch=0; ch<chCount; ++ch)
|
||||||
{
|
{
|
||||||
int samplesPopped = args.channels[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms);
|
int samplesPopped = stream->mTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms);
|
||||||
if (samplesPopped != maxSamplesBatch)
|
if (samplesPopped != maxSamplesBatch)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -536,7 +521,7 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if(terminate->load() == true) //early termination
|
if(stream->terminateTx.load() == true) //early termination
|
||||||
break;
|
break;
|
||||||
pkt[i].counter = meta.timestamp;
|
pkt[i].counter = meta.timestamp;
|
||||||
pkt[i].reserved[0] = 0;
|
pkt[i].reserved[0] = 0;
|
||||||
@ -563,8 +548,7 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD
|
|||||||
{
|
{
|
||||||
//total number of bytes sent per second
|
//total number of bytes sent per second
|
||||||
float dataRate = 1000.0*totalBytesSent / timePeriod;
|
float dataRate = 1000.0*totalBytesSent / timePeriod;
|
||||||
if(dataRate_Bps)
|
stream->txDataRate_Bps.store(dataRate);
|
||||||
dataRate_Bps->store(dataRate);
|
|
||||||
m_bufferFailures = 0;
|
m_bufferFailures = 0;
|
||||||
samplesSent = 0;
|
samplesSent = 0;
|
||||||
totalBytesSent = 0;
|
totalBytesSent = 0;
|
||||||
@ -589,6 +573,5 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD
|
|||||||
}
|
}
|
||||||
bi = (bi + 1) & (buffersCount-1);
|
bi = (bi + 1) & (buffersCount-1);
|
||||||
}
|
}
|
||||||
if (dataRate_Bps)
|
stream->txDataRate_Bps.store(0);
|
||||||
dataRate_Bps->store(0);
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ static const char *errToStr(const int errnum)
|
|||||||
strerror_r(errnum, buff, sizeof(buff));
|
strerror_r(errnum, buff, sizeof(buff));
|
||||||
#else
|
#else
|
||||||
//this version may decide to use its own internal string
|
//this version may decide to use its own internal string
|
||||||
//return strerror_r(errnum, buff, sizeof(buff)); MinGW
|
//return strerror_r(errnum, buff, sizeof(buff));
|
||||||
return buff;
|
return buff;
|
||||||
#endif
|
#endif
|
||||||
return buff;
|
return buff;
|
||||||
|
@ -103,7 +103,7 @@ void LMS7002M::Log(LogType type, const char *format, va_list argList)
|
|||||||
|
|
||||||
/** @brief Sets connection which is used for data communication with chip
|
/** @brief Sets connection which is used for data communication with chip
|
||||||
*/
|
*/
|
||||||
void LMS7002M::SetConnection(IConnection* port, const size_t devIndex, IConnection* samplesPort)
|
void LMS7002M::SetConnection(IConnection* port, const size_t devIndex)
|
||||||
{
|
{
|
||||||
controlPort = port;
|
controlPort = port;
|
||||||
mdevIndex = devIndex;
|
mdevIndex = devIndex;
|
||||||
@ -111,7 +111,6 @@ void LMS7002M::SetConnection(IConnection* port, const size_t devIndex, IConnecti
|
|||||||
if (controlPort != nullptr)
|
if (controlPort != nullptr)
|
||||||
{
|
{
|
||||||
unsigned byte_array_size = 0;
|
unsigned byte_array_size = 0;
|
||||||
addrLMS7002M = controlPort->GetDeviceInfo().addrsLMS7002M.at(devIndex);
|
|
||||||
if (controlPort->IsOpen())
|
if (controlPort->IsOpen())
|
||||||
{
|
{
|
||||||
unsigned chipRev = this->Get_SPI_Reg_bits(LMS7_MASK, true);
|
unsigned chipRev = this->Get_SPI_Reg_bits(LMS7_MASK, true);
|
||||||
@ -120,12 +119,8 @@ void LMS7002M::SetConnection(IConnection* port, const size_t devIndex, IConnecti
|
|||||||
else
|
else
|
||||||
byte_array_size = 1024 * 8;
|
byte_array_size = 1024 * 8;
|
||||||
}
|
}
|
||||||
mcuControl->Initialize(port, byte_array_size);
|
mcuControl->Initialize(port, mdevIndex, byte_array_size);
|
||||||
}
|
}
|
||||||
if(samplesPort == nullptr)
|
|
||||||
dataPort = controlPort;
|
|
||||||
else
|
|
||||||
dataPort = samplesPort;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Creates LMS7002M main control object.
|
/** @brief Creates LMS7002M main control object.
|
||||||
@ -136,8 +131,6 @@ LMS7002M::LMS7002M() :
|
|||||||
mValueCache(new CalibrationCache()),
|
mValueCache(new CalibrationCache()),
|
||||||
mRegistersMap(new LMS7002M_RegistersMap()),
|
mRegistersMap(new LMS7002M_RegistersMap()),
|
||||||
controlPort(nullptr),
|
controlPort(nullptr),
|
||||||
dataPort(nullptr),
|
|
||||||
addrLMS7002M(-1),
|
|
||||||
mdevIndex(0),
|
mdevIndex(0),
|
||||||
mSelfCalDepth(0)
|
mSelfCalDepth(0)
|
||||||
{
|
{
|
||||||
@ -205,7 +198,7 @@ LMS7002M::LMS7002M() :
|
|||||||
|
|
||||||
mRegistersMap->InitializeDefaultValues(LMS7parameterList);
|
mRegistersMap->InitializeDefaultValues(LMS7parameterList);
|
||||||
mcuControl = new MCU_BD();
|
mcuControl = new MCU_BD();
|
||||||
mcuControl->Initialize(controlPort);
|
mcuControl->Initialize(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LMS7002M::~LMS7002M()
|
LMS7002M::~LMS7002M()
|
||||||
@ -253,8 +246,6 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable)
|
|||||||
|
|
||||||
//--- ADC/DAC ---
|
//--- ADC/DAC ---
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_AFE), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_AFE), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_G_AFE), enable?1:0);
|
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(PD_AFE), enable?0:1);
|
|
||||||
if (ch == ChA)
|
if (ch == ChA)
|
||||||
{
|
{
|
||||||
if (isTx) this->Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE1), enable?0:1);
|
if (isTx) this->Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE1), enable?0:1);
|
||||||
@ -266,26 +257,43 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable)
|
|||||||
else this->Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), enable?0:1);
|
else this->Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), enable?0:1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int disabledChannels = (Get_SPI_Reg_bits(LMS7_PD_AFE.address,4,1)&0xF);//check if all channels are disabled
|
||||||
|
Modify_SPI_Reg_bits(LMS7param(EN_G_AFE),disabledChannels==0xF ? 0 : 1);
|
||||||
|
Modify_SPI_Reg_bits(LMS7param(PD_AFE), disabledChannels==0xF ? 1 : 0);
|
||||||
|
|
||||||
//--- digital ---
|
//--- digital ---
|
||||||
if (isTx)
|
if (isTx)
|
||||||
{
|
{
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_TXTSP), enable?1:0);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_TXTSP), enable?1:0);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(ISINC_BYP_TXTSP), enable?0:1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_TXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_TXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR2_BYP_TXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR2_BYP_TXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR1_BYP_TXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR1_BYP_TXTSP), 1);
|
||||||
|
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(CMIX_BYP_TXTSP), 1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_TXTSP), 1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(GC_BYP_TXTSP), 1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(PH_BYP_TXTSP), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_RXTSP), enable?1:0);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_RXTSP), enable?1:0);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), enable?0:1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(DCLOOP_STOP), enable?0:1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 2); //bypass
|
this->Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 2); //bypass
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(CMIX_BYP_RXTSP), 1);
|
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(AGC_BYP_RXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(AGC_BYP_RXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_RXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_RXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR2_BYP_RXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR2_BYP_RXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GFIR1_BYP_RXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(GFIR1_BYP_RXTSP), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 1);
|
if (!enable)
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(GC_BYP_RXTSP), 1);
|
{
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(PH_BYP_RXTSP), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(CMIX_BYP_RXTSP), 1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(GC_BYP_RXTSP), 1);
|
||||||
|
this->Modify_SPI_Reg_bits(LMS7param(PH_BYP_RXTSP), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- baseband ---
|
//--- baseband ---
|
||||||
@ -324,7 +332,7 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable)
|
|||||||
{
|
{
|
||||||
this->SetActiveChannel(ChSXT);
|
this->SetActiveChannel(ChSXT);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_G), enable?1:0);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_G), (disabledChannels&3) == 3?0:1);
|
||||||
if (ch == ChB) //enable LO to channel B
|
if (ch == ChB) //enable LO to channel B
|
||||||
{
|
{
|
||||||
this->SetActiveChannel(ChA);
|
this->SetActiveChannel(ChA);
|
||||||
@ -335,7 +343,7 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable)
|
|||||||
{
|
{
|
||||||
this->SetActiveChannel(ChSXR);
|
this->SetActiveChannel(ChSXR);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(EN_G), enable?1:0);
|
this->Modify_SPI_Reg_bits(LMS7param(EN_G), (disabledChannels&0xC)==0xC?0:1);
|
||||||
if (ch == ChB) //enable LO to channel B
|
if (ch == ChB) //enable LO to channel B
|
||||||
{
|
{
|
||||||
this->SetActiveChannel(ChA);
|
this->SetActiveChannel(ChA);
|
||||||
@ -695,9 +703,10 @@ int LMS7002M::SaveConfig(const char* filename)
|
|||||||
fout << "[lms7002_registers_b]" << endl;
|
fout << "[lms7002_registers_b]" << endl;
|
||||||
addrToRead.clear(); //add only B channel addresses
|
addrToRead.clear(); //add only B channel addresses
|
||||||
for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
|
for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
|
||||||
for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
|
if (i != RSSI_DC_CALIBRATION)
|
||||||
if (addr >= 0x0100)
|
for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
|
||||||
addrToRead.push_back(addr);
|
if (addr >= 0x0100)
|
||||||
|
addrToRead.push_back(addr);
|
||||||
|
|
||||||
this->SetActiveChannel(ChB);
|
this->SetActiveChannel(ChB);
|
||||||
for (uint16_t i = 0; i < addrToRead.size(); ++i)
|
for (uint16_t i = 0; i < addrToRead.size(); ++i)
|
||||||
@ -1876,8 +1885,7 @@ int LMS7002M::SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkConnection();
|
checkConnection();
|
||||||
|
return controlPort->WriteLMS7002MSPI(data.data(), cnt,mdevIndex);
|
||||||
return controlPort->TransactSPI(addrLMS7002M, data.data(), nullptr, cnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Batches multiple register reads into least amount of transactions
|
/** @brief Batches multiple register reads into least amount of transactions
|
||||||
@ -1897,7 +1905,8 @@ int LMS7002M::SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_
|
|||||||
dataWr[i] = (uint32_t(spiAddr[i]) << 16);
|
dataWr[i] = (uint32_t(spiAddr[i]) << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = controlPort->TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), cnt);
|
|
||||||
|
int status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), cnt,mdevIndex);
|
||||||
if (status != 0) return status;
|
if (status != 0) return status;
|
||||||
|
|
||||||
int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003;
|
int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003;
|
||||||
@ -1990,9 +1999,10 @@ int LMS7002M::RegistersTest(const char* fileName)
|
|||||||
ss << moduleNames[i] << " [" << chex << ":";
|
ss << moduleNames[i] << " [" << chex << ":";
|
||||||
sprintf(chex, "0x%04X", endAddr);
|
sprintf(chex, "0x%04X", endAddr);
|
||||||
ss << chex << "]";
|
ss << chex << "]";
|
||||||
if (startAddr >= 0x0100)
|
if (startAddr >= 0x0100) {
|
||||||
ss << " Ch." << (cc == 1 ? "A" : "B");
|
ss << " Ch." << (cc == 1 ? "A" : "B");
|
||||||
ss << endl;
|
}
|
||||||
|
ss << endl;
|
||||||
for (uint8_t p = 0; p < patternsCount; ++p)
|
for (uint8_t p = 0; p < patternsCount; ++p)
|
||||||
moduleTestsSuccess &= RegistersTestInterval(startAddr, endAddr, patterns[p], ss) == 0;
|
moduleTestsSuccess &= RegistersTestInterval(startAddr, endAddr, patterns[p], ss) == 0;
|
||||||
}
|
}
|
||||||
@ -2140,7 +2150,8 @@ bool LMS7002M::IsSynced()
|
|||||||
std::vector<uint32_t> dataRd(addrToRead.size());
|
std::vector<uint32_t> dataRd(addrToRead.size());
|
||||||
for(size_t i = 0; i < addrToRead.size(); ++i)
|
for(size_t i = 0; i < addrToRead.size(); ++i)
|
||||||
dataWr[i] = (uint32_t(addrToRead[i]) << 16);
|
dataWr[i] = (uint32_t(addrToRead[i]) << 16);
|
||||||
status = controlPort->TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), dataWr.size());
|
status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), dataWr.size(),mdevIndex);
|
||||||
|
|
||||||
for(size_t i=0; i<addrToRead.size(); ++i)
|
for(size_t i=0; i<addrToRead.size(); ++i)
|
||||||
dataReceived[i] = dataRd[i] & 0xFFFF;
|
dataReceived[i] = dataRd[i] & 0xFFFF;
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
@ -2178,7 +2189,7 @@ bool LMS7002M::IsSynced()
|
|||||||
dataRd.resize(addrToRead.size());
|
dataRd.resize(addrToRead.size());
|
||||||
for(size_t i = 0; i < addrToRead.size(); ++i)
|
for(size_t i = 0; i < addrToRead.size(); ++i)
|
||||||
dataWr[i] = (uint32_t(addrToRead[i]) << 16);
|
dataWr[i] = (uint32_t(addrToRead[i]) << 16);
|
||||||
status = controlPort->TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), dataWr.size());
|
status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), dataWr.size(),mdevIndex);
|
||||||
for(size_t i=0; i<addrToRead.size(); ++i)
|
for(size_t i=0; i<addrToRead.size(); ++i)
|
||||||
dataReceived[i] = dataRd[i] & 0xFFFF;
|
dataReceived[i] = dataRd[i] & 0xFFFF;
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
@ -2461,7 +2472,7 @@ bool LMS7002M::GetRxDCRemoval(void)
|
|||||||
int LMS7002M::SetTxDCOffset(const float_type I, const float_type Q)
|
int LMS7002M::SetTxDCOffset(const float_type I, const float_type Q)
|
||||||
{
|
{
|
||||||
const bool bypass = I == 0.0 and Q == 0.0;
|
const bool bypass = I == 0.0 and Q == 0.0;
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), bypass?1:0);
|
this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_TXTSP), bypass?1:0);
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(DCCORRI_TXTSP), std::lrint(I*128));
|
this->Modify_SPI_Reg_bits(LMS7param(DCCORRI_TXTSP), std::lrint(I*128));
|
||||||
this->Modify_SPI_Reg_bits(LMS7param(DCCORRQ_TXTSP), std::lrint(Q*128));
|
this->Modify_SPI_Reg_bits(LMS7param(DCCORRQ_TXTSP), std::lrint(Q*128));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -28,6 +28,7 @@ MCU_BD::MCU_BD()
|
|||||||
stepsDone = 0;
|
stepsDone = 0;
|
||||||
aborted = false;
|
aborted = false;
|
||||||
callback = nullptr;
|
callback = nullptr;
|
||||||
|
mChipID =0;
|
||||||
//ctor
|
//ctor
|
||||||
int i=0;
|
int i=0;
|
||||||
m_serPort=NULL;
|
m_serPort=NULL;
|
||||||
@ -50,9 +51,10 @@ MCU_BD::~MCU_BD()
|
|||||||
//dtor
|
//dtor
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCU_BD::Initialize(IConnection* pSerPort, unsigned size)
|
void MCU_BD::Initialize(IConnection* pSerPort, unsigned chipID, unsigned size)
|
||||||
{
|
{
|
||||||
m_serPort = pSerPort;
|
m_serPort = pSerPort;
|
||||||
|
mChipID = chipID;
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
byte_array_size = size;
|
byte_array_size = size;
|
||||||
}
|
}
|
||||||
@ -119,7 +121,7 @@ void MCU_BD:: mSPI_write(
|
|||||||
if(m_serPort == nullptr)
|
if(m_serPort == nullptr)
|
||||||
return;
|
return;
|
||||||
uint32_t wrdata = addr_reg << 16 | data_reg;
|
uint32_t wrdata = addr_reg << 16 | data_reg;
|
||||||
m_serPort->TransactSPI(0x10, &wrdata, nullptr, 1);
|
m_serPort->WriteLMS7002MSPI(&wrdata, 1, mChipID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -130,8 +132,9 @@ unsigned short MCU_BD:: mSPI_read(
|
|||||||
return 0;
|
return 0;
|
||||||
uint32_t wrdata = addr_reg << 16;
|
uint32_t wrdata = addr_reg << 16;
|
||||||
uint32_t rddata = 0;
|
uint32_t rddata = 0;
|
||||||
if(m_serPort->TransactSPI(0x10, &wrdata, &rddata, 1) != 0)
|
if(m_serPort->ReadLMS7002MSPI(&wrdata, &rddata, 1, mChipID)!=0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return rddata & 0xFFFF;
|
return rddata & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,18 +575,90 @@ int MCU_BD::Program_MCU(int m_iMode1, int m_iMode0)
|
|||||||
case 3: mode = IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM; break;
|
case 3: mode = IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM; break;
|
||||||
default: mode = IConnection::MCU_PROG_MODE::RESET; break;
|
default: mode = IConnection::MCU_PROG_MODE::RESET; break;
|
||||||
}
|
}
|
||||||
if(m_serPort)
|
return Program_MCU(byte_array,mode);
|
||||||
return m_serPort->ProgramMCU(byte_array, byte_array_size, mode, callback);
|
|
||||||
else
|
|
||||||
return ReportError(ENOLINK, "Device not connected");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MCU_BD::Program_MCU(const uint8_t* binArray, const IConnection::MCU_PROG_MODE mode)
|
int MCU_BD::Program_MCU(const uint8_t* buffer, const IConnection::MCU_PROG_MODE mode)
|
||||||
{
|
{
|
||||||
if(m_serPort)
|
if(!m_serPort)
|
||||||
return m_serPort->ProgramMCU(binArray, byte_array_size, mode, callback);
|
|
||||||
else
|
|
||||||
return ReportError(ENOLINK, "Device not connected");
|
return ReportError(ENOLINK, "Device not connected");
|
||||||
|
|
||||||
|
if (byte_array_size <= 8192)
|
||||||
|
return m_serPort->ProgramMCU(buffer, byte_array_size, mode, callback);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto timeStart = std::chrono::high_resolution_clock::now();
|
||||||
|
#endif
|
||||||
|
const auto timeout = std::chrono::milliseconds(100);
|
||||||
|
const uint32_t controlAddr = 0x0002 << 16;
|
||||||
|
const uint32_t statusReg = 0x0003 << 16;
|
||||||
|
const uint32_t addrDTM = 0x0004 << 16; //data to MCU
|
||||||
|
const uint16_t EMTPY_WRITE_BUFF = 1 << 0;
|
||||||
|
const uint16_t PROGRAMMED = 1 << 6;
|
||||||
|
const uint8_t fifoLen = 64;
|
||||||
|
uint32_t wrdata[fifoLen];
|
||||||
|
uint32_t rddata = 0;
|
||||||
|
int status;
|
||||||
|
bool abort = false;
|
||||||
|
//reset MCU, set mode
|
||||||
|
wrdata[0] = controlAddr | 0;
|
||||||
|
wrdata[1] = controlAddr | (mode & 0x3);
|
||||||
|
if((status = m_serPort->WriteLMS7002MSPI(wrdata, 2, mChipID))!=0)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if(callback)
|
||||||
|
abort = callback(0, byte_array_size, "");
|
||||||
|
|
||||||
|
for(uint16_t i=0; i<byte_array_size && !abort; i+=fifoLen)
|
||||||
|
{
|
||||||
|
//wait till EMPTY_WRITE_BUFF = 1
|
||||||
|
bool fifoEmpty = false;
|
||||||
|
wrdata[0] = statusReg;
|
||||||
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
auto t2 = t1;
|
||||||
|
do{
|
||||||
|
if((status = m_serPort->ReadLMS7002MSPI(wrdata, &rddata, 1, mChipID))!=0)
|
||||||
|
return status;
|
||||||
|
fifoEmpty = rddata & EMTPY_WRITE_BUFF;
|
||||||
|
t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
}while( (!fifoEmpty) && (t2-t1)<timeout);
|
||||||
|
|
||||||
|
if(!fifoEmpty)
|
||||||
|
return ReportError(ETIMEDOUT, "MCU FIFO full");
|
||||||
|
|
||||||
|
//write 32 bytes into FIFO
|
||||||
|
for(uint8_t j=0; j<fifoLen; ++j)
|
||||||
|
wrdata[j] = addrDTM | buffer[i+j];
|
||||||
|
if((status = m_serPort->WriteLMS7002MSPI(wrdata,fifoLen, mChipID))!=0)
|
||||||
|
return status;
|
||||||
|
if(callback)
|
||||||
|
abort = callback(i+fifoLen, byte_array_size, "");
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("MCU programming : %4i/%4li\r", i+fifoLen, long(byte_array_size));
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
if(abort)
|
||||||
|
return ReportError(-1, "operation aborted by user");
|
||||||
|
|
||||||
|
//wait until programmed flag
|
||||||
|
wrdata[0] = statusReg;
|
||||||
|
bool programmed = false;
|
||||||
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
auto t2 = t1;
|
||||||
|
do{
|
||||||
|
if((status = m_serPort->ReadLMS7002MSPI(wrdata, &rddata, 1, mChipID))!=0)
|
||||||
|
return status;
|
||||||
|
programmed = rddata & PROGRAMMED;
|
||||||
|
t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
}while( (!programmed) && (t2-t1)<timeout);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto timeEnd = std::chrono::high_resolution_clock::now();
|
||||||
|
printf("\nMCU Programming finished, %li ms\n",
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>
|
||||||
|
(timeEnd-timeStart).count());
|
||||||
|
#endif
|
||||||
|
if(!programmed)
|
||||||
|
return ReportError(ETIMEDOUT, "MCU not programmed");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCU_BD::Reset_MCU()
|
void MCU_BD::Reset_MCU()
|
||||||
|
@ -452,7 +452,7 @@ public:
|
|||||||
m_top = 0;
|
m_top = 0;
|
||||||
for (vi = m_chunks.begin(); vi < m_chunks.end(); vi++)
|
for (vi = m_chunks.begin(); vi < m_chunks.end(); vi++)
|
||||||
{
|
{
|
||||||
//m_top = m_top > vi->m_startAddress + vi->m_bytes.size() - 1 ? m_top : vi->m_startAddress + vi->m_bytes.size() - 1;
|
//m_top = max(m_top, vi->m_startAddress + vi->m_bytes.size() - 1);
|
||||||
m_top = MYMAX(m_top, vi->m_startAddress + vi->m_bytes.size() - 1);
|
m_top = MYMAX(m_top, vi->m_startAddress + vi->m_bytes.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ copy libhackrf\%1\libhackrf.dll %2
|
|||||||
copy librtlsdr\%1\librtlsdr.dll %2
|
copy librtlsdr\%1\librtlsdr.dll %2
|
||||||
copy libairspy\%1\libairspy.dll %2
|
copy libairspy\%1\libairspy.dll %2
|
||||||
copy libbladerf\%1\libbladerf.dll %2
|
copy libbladerf\%1\libbladerf.dll %2
|
||||||
REM copy libsqlite3\%1\libsqlite3.dll %2
|
copy libsqlite3\%1\libsqlite3.dll %2
|
||||||
REM copy liblimesuite\%1\liblimesuite.dll %2
|
copy liblimesuite\%1\liblimesuite.dll %2
|
||||||
copy %libusbdir%\dll\libusb-1.0.dll %2
|
copy %libusbdir%\dll\libusb-1.0.dll %2
|
||||||
copy %opencvdir%\opencv_ffmpeg2413_64.dll %2
|
copy %opencvdir%\opencv_ffmpeg2413_64.dll %2
|
||||||
copy %opencvdir%\libopencv_imgproc2413.dll %2
|
copy %opencvdir%\libopencv_imgproc2413.dll %2
|
||||||
@ -60,8 +60,8 @@ copy plugins\samplesource\rtlsdr\%1\inputrtlsdr.dll %2\plugins\samplesource
|
|||||||
copy plugins\samplesource\hackrfinput\%1\inputhackrf.dll %2\plugins\samplesource
|
copy plugins\samplesource\hackrfinput\%1\inputhackrf.dll %2\plugins\samplesource
|
||||||
copy plugins\samplesource\airspy\%1\inputairspy.dll %2\plugins\samplesource
|
copy plugins\samplesource\airspy\%1\inputairspy.dll %2\plugins\samplesource
|
||||||
copy plugins\samplesource\bladerfinput\%1\inputbladerf.dll %2\plugins\samplesource
|
copy plugins\samplesource\bladerfinput\%1\inputbladerf.dll %2\plugins\samplesource
|
||||||
REM copy plugins\samplesource\limesdrinput\%1\inputlimesdr.dll %2\plugins\samplesource
|
copy plugins\samplesource\limesdrinput\%1\inputlimesdr.dll %2\plugins\samplesource
|
||||||
copy plugins\samplesink\filesink\%1\outputfilesink.dll %2\plugins\samplesink
|
copy plugins\samplesink\filesink\%1\outputfilesink.dll %2\plugins\samplesink
|
||||||
copy plugins\samplesink\bladerfoutput\%1\outputbladerf.dll %2\plugins\samplesink
|
copy plugins\samplesink\bladerfoutput\%1\outputbladerf.dll %2\plugins\samplesink
|
||||||
copy plugins\samplesink\hackrfoutput\%1\outputhackrf.dll %2\plugins\samplesink
|
copy plugins\samplesink\hackrfoutput\%1\outputhackrf.dll %2\plugins\samplesink
|
||||||
REM copy plugins\samplesink\limesdroutput\%1\outputlimesdr.dll %2\plugins\samplesink
|
copy plugins\samplesink\limesdroutput\%1\outputlimesdr.dll %2\plugins\samplesink
|
||||||
|
Loading…
Reference in New Issue
Block a user