diff --git a/liblimesuite/liblimesuite.pro b/liblimesuite/liblimesuite.pro index 13e95e71c..db91fdb39 100644 --- a/liblimesuite/liblimesuite.pro +++ b/liblimesuite/liblimesuite.pro @@ -35,6 +35,7 @@ INCLUDEPATH += $$LIBLIMESUITESRC/external/cpp-feather-ini-parser SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\ $$LIBLIMESUITESRC/src/API/lms7_api.cpp\ $$LIBLIMESUITESRC/src/API/lms7_device.cpp\ + $$LIBLIMESUITESRC/src/API/qLimeSDR.cpp\ src/BuiltinConnections.cpp\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.cpp\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.cpp\ @@ -44,8 +45,8 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\ srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp\ srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp\ srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp\ - srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\ srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp\ + srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybus.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusEntry.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusing.cpp\ @@ -77,6 +78,7 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\ HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\ $$LIBLIMESUITESRC/src/API/lms7_device.h\ + $$LIBLIMESUITESRC/src/API/qLimeSDR.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/IConnection.h\ diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp index 792ff1737..bddf2f181 100644 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp +++ b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp @@ -28,8 +28,6 @@ using namespace std; 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::ctrlBulkInAddr = 0x8F; @@ -70,6 +68,9 @@ ConnectionSTREAM::ConnectionSTREAM(void *arg, const std::string &vidpid, const s OutCtrlEndPt3 = nullptr; InCtrlBulkEndPt = nullptr; OutCtrlBulkEndPt = nullptr; + for (int i = 0; i < MAX_EP_CNT; i++) + InEndPt[i] = OutEndPt[i] = nullptr; + #else dev_handle = nullptr; ctx = (libusb_context *)arg; @@ -178,15 +179,6 @@ double ConnectionSTREAM::DetectRefClk(void) */ 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(); #ifndef __unix__ delete USBDevicePrimary; @@ -230,22 +222,23 @@ int ConnectionSTREAM::Open(const std::string &vidpid, const std::string &serial, OutCtrlEndPt3->Index = CTR_W_INDEX; OutCtrlEndPt3->TimeOut = 3000; - for (int i=0; iEndPointCount(); i++) - if(USBDevicePrimary->EndPoints[i]->Address == streamBulkOutAddr) + for (int i = 0; i < USBDevicePrimary->EndPointCount(); i++) + { + auto adr = USBDevicePrimary->EndPoints[i]->Address; + if (adr < ctrlBulkOutAddr) { - OutEndPt = USBDevicePrimary->EndPoints[i]; - long len = OutEndPt->MaxPktSize * 64; - OutEndPt->SetXferSize(len); - break; + OutEndPt[adr] = USBDevicePrimary->EndPoints[i]; + long len = OutEndPt[adr]->MaxPktSize * 64; + OutEndPt[adr]->SetXferSize(len); } - for (int i=0; iEndPointCount(); i++) - if(USBDevicePrimary->EndPoints[i]->Address == streamBulkInAddr) + else if (adr < ctrlBulkInAddr) { - InEndPt = USBDevicePrimary->EndPoints[i]; - long len = InEndPt->MaxPktSize * 64; - InEndPt->SetXferSize(len); - break; + adr &= 0xF; + InEndPt[adr] = USBDevicePrimary->EndPoints[i]; + long len = InEndPt[adr]->MaxPktSize * 64; + InEndPt[adr]->SetXferSize(len); } + } InCtrlBulkEndPt = nullptr; for (int i=0; iEndPointCount(); i++) @@ -356,21 +349,21 @@ int ConnectionSTREAM::Open(const std::string &vidpid, const std::string &serial, void ConnectionSTREAM::Close() { #ifndef __unix__ - USBDevicePrimary->Close(); - InEndPt = nullptr; - OutEndPt = nullptr; - InCtrlBulkEndPt = nullptr; - OutCtrlBulkEndPt = nullptr; - if (InCtrlEndPt3) - { - delete InCtrlEndPt3; - InCtrlEndPt3 = nullptr; - } - if (OutCtrlEndPt3) - { - delete OutCtrlEndPt3; - OutCtrlEndPt3 = nullptr; - } + USBDevicePrimary->Close(); + for (int i = 0; i < MAX_EP_CNT; i++) + InEndPt[i] = OutEndPt[i] = nullptr; + InCtrlBulkEndPt = nullptr; + OutCtrlBulkEndPt = nullptr; + if (InCtrlEndPt3) + { + delete InCtrlEndPt3; + InCtrlEndPt3 = nullptr; + } + if (OutCtrlEndPt3) + { + delete OutCtrlEndPt3; + OutCtrlEndPt3 = nullptr; + } #else if(dev_handle != 0) { @@ -532,9 +525,10 @@ void callback_libusbtransfer(libusb_transfer *trans) @brief Starts asynchronous data reading from board @param *buffer buffer where to store received data @param length number of bytes to read + @param streamBulkInAddr endpoint index? @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; bool contextFound = false; @@ -554,8 +548,11 @@ int ConnectionSTREAM::BeginDataReading(char *buffer, uint32_t length) } contexts[i].used = true; #ifndef __unix__ - if(InEndPt) - contexts[i].context = InEndPt->BeginDataXfer((unsigned char*)buffer, length, contexts[i].inOvLap); + if (InEndPt[streamBulkInAddr & 0xF]) + { + contexts[i].EndPt = InEndPt[streamBulkInAddr & 0xF]; + contexts[i].context = contexts[i].EndPt->BeginDataXfer((unsigned char*)buffer, length, contexts[i].inOvLap); + } return i; #else unsigned int Timeout = 500; @@ -587,8 +584,7 @@ int ConnectionSTREAM::WaitForReading(int contextHandle, unsigned int timeout_ms) { #ifndef __unix__ int status = 0; - if(InEndPt) - status = InEndPt->WaitForXfer(contexts[contextHandle].inOvLap, timeout_ms); + status = contexts[contextHandle].EndPt->WaitForXfer(contexts[contextHandle].inOvLap, timeout_ms); return status; #else auto t1 = chrono::high_resolution_clock::now(); @@ -622,8 +618,7 @@ int ConnectionSTREAM::FinishDataReading(char *buffer, uint32_t length, int conte #ifndef __unix__ int status = 0; long len = length; - if(InEndPt) - status = InEndPt->FinishDataXfer((unsigned char*)buffer, len, contexts[contextHandle].inOvLap, contexts[contextHandle].context); + status = contexts[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contexts[contextHandle].inOvLap, contexts[contextHandle].context); contexts[contextHandle].used = false; contexts[contextHandle].reset(); return len; @@ -641,14 +636,16 @@ int ConnectionSTREAM::FinishDataReading(char *buffer, uint32_t length, int conte /** @brief Aborts reading operations */ -void ConnectionSTREAM::AbortReading() +void ConnectionSTREAM::AbortReading(int ep) { #ifndef __unix__ - InEndPt->Abort(); + for (int i = 0; i < MAX_EP_CNT; i++) + if (InEndPt[i] && InEndPt[i]->Address == ep) + InEndPt[i]->Abort(); #else for(int i=0; iendpoint == ep) libusb_cancel_transfer( contexts[i].transfer ); } #endif @@ -658,9 +655,10 @@ void ConnectionSTREAM::AbortReading() @brief Starts asynchronous data Sending to board @param *buffer buffer to send @param length number of bytes to send + @param streamBulkOutAddr endpoint index? @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; //find not used context @@ -677,8 +675,11 @@ int ConnectionSTREAM::BeginDataSending(const char *buffer, uint32_t length) return -1; contextsToSend[i].used = true; #ifndef __unix__ - if(OutEndPt) - contextsToSend[i].context = OutEndPt->BeginDataXfer((unsigned char*)buffer, length, contextsToSend[i].inOvLap); + if (OutEndPt[streamBulkOutAddr]) + { + contextsToSend[i].EndPt = OutEndPt[streamBulkOutAddr]; + contextsToSend[i].context = contextsToSend[i].EndPt->BeginDataXfer((unsigned char*)buffer, length, contextsToSend[i].inOvLap); + } return i; #else unsigned int Timeout = 500; @@ -708,12 +709,11 @@ int ConnectionSTREAM::WaitForSending(int contextHandle, unsigned int timeout_ms) { if( contextsToSend[contextHandle].used == true ) { - #ifndef __unix__ +# ifndef __unix__ int status = 0; - if(OutEndPt) - status = OutEndPt->WaitForXfer(contextsToSend[contextHandle].inOvLap, timeout_ms); + status = contextsToSend[contextHandle].EndPt->WaitForXfer(contextsToSend[contextHandle].inOvLap, timeout_ms); return status; - #else +# else auto t1 = 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(); } return contextsToSend[contextHandle].done == true; - #endif +# endif } else return 0; @@ -744,8 +744,7 @@ int ConnectionSTREAM::FinishDataSending(const char *buffer, uint32_t length, int { #ifndef __unix__ long len = length; - if(OutEndPt) - OutEndPt->FinishDataXfer((unsigned char*)buffer, len, contextsToSend[contextHandle].inOvLap, contextsToSend[contextHandle].context); + contextsToSend[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contextsToSend[contextHandle].inOvLap, contextsToSend[contextHandle].context); contextsToSend[contextHandle].used = false; contextsToSend[contextHandle].reset(); return len; @@ -763,19 +762,39 @@ int ConnectionSTREAM::FinishDataSending(const char *buffer, uint32_t length, int /** @brief Aborts sending operations */ -void ConnectionSTREAM::AbortSending() +void ConnectionSTREAM::AbortSending(int ep) { #ifndef __unix__ - OutEndPt->Abort(); + for (int i = 0; i < MAX_EP_CNT; i++) + if (OutEndPt[i] && OutEndPt[i]->Address == ep) + OutEndPt[i]->Abort(); #else for (int i = 0; iendpoint == ep) libusb_cancel_transfer(contextsToSend[i].transfer); } #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) { if (device == LMS64CProtocol::FX3 && programmingMode == 1) diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h index cd49bef66..a77f4c8f0 100644 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h +++ b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h @@ -48,6 +48,7 @@ public: memset(inOvLap, 0, sizeof(OVERLAPPED)); inOvLap->hEvent = CreateEvent(NULL, false, false, NULL); context = NULL; + EndPt = nullptr; #else transfer = libusb_alloc_transfer(0); bytesXfered = 0; @@ -80,6 +81,7 @@ public: static int idCounter; #ifndef __unix__ PUCHAR context; + CCyUSBEndPoint* EndPt; OVERLAPPED* inOvLap; #else libusb_transfer* transfer; @@ -106,27 +108,27 @@ public: 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 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 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 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 ReadRawStreamData(char* buffer, unsigned length, int timeout_ms = 100)override; + int ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms = 100)override; protected: - virtual void ReceivePacketsLoop(const ThreadData args) override; - virtual void TransmitPacketsLoop(const ThreadData args) override; + virtual void ReceivePacketsLoop(Streamer* 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 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 FinishDataSending(const char* buffer, uint32_t length, int contextHandle); - virtual void AbortSending(); + virtual void AbortSending(int ep); int ResetStreamBuffers() override; eConnectionType GetType(void) {return USB_PORT;} @@ -139,14 +141,15 @@ protected: bool isConnected; #ifndef __unix__ + static const int MAX_EP_CNT = 16; CCyFX3Device* USBDevicePrimary; //control endpoints CCyControlEndPoint* InCtrlEndPt3; CCyControlEndPoint* OutCtrlEndPt3; //end points for samples reading and writing - CCyUSBEndPoint* InEndPt; - CCyUSBEndPoint* OutEndPt; + CCyUSBEndPoint* InEndPt[MAX_EP_CNT]; + CCyUSBEndPoint* OutEndPt[MAX_EP_CNT]; CCyUSBEndPoint* InCtrlBulkEndPt; CCyUSBEndPoint* OutCtrlBulkEndPt; @@ -157,8 +160,6 @@ protected: int fx3_usbboot_download(unsigned char *buf, int len); int ram_write(unsigned char *buf, unsigned int ramAddress, int len); #endif - static const uint8_t streamBulkOutAddr; - static const uint8_t streamBulkInAddr; static const uint8_t ctrlBulkOutAddr; static const uint8_t ctrlBulkInAddr; static const std::set commandsToBulkCtrlHw1; diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp index 9f1ea63d8..cf68c3969 100644 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp +++ b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp @@ -1,4 +1,4 @@ - /** +/** @file ConnectionSTREAMing.cpp @author Lime Microsystems @brief Implementation of STREAM board connection (streaming API) @@ -20,93 +20,40 @@ using namespace lime; 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> 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 */ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz, const double txPhase, const double rxPhase) { -#ifndef NDEBUG - lime::debug("ConnectionSTREAM::ConfigureFPGA_PLL(tx=%gMHz, rx=%gMHz)", txRate_Hz/1e6, rxRate_Hz/1e6); -#endif + lime::fpga::FPGA_PLL_clock clocks[2]; + + 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 rxInterfaceClk = 2 * 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].outFrequency = rxInterfaceClk; - clocks[0].phaseShift_deg = 0; - clocks[0].findPhase = false; - clocks[1].bypass = false; clocks[1].index = 1; clocks[1].outFrequency = rxInterfaceClk; clocks[1].phaseShift_deg = rxPhase; - clocks[1].findPhase = false; - if (lime::fpga::SetPllFrequency(this, 1, rxInterfaceClk, clocks, 2)!=0) + if (lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2)!=0) return -1; - clocks[0].bypass = false; clocks[0].index = 0; clocks[0].outFrequency = txInterfaceClk; - clocks[0].phaseShift_deg = 0; - clocks[0].findPhase = false; - clocks[1].bypass = false; clocks[1].index = 1; clocks[1].outFrequency = txInterfaceClk; clocks[1].phaseShift_deg = txPhase; - clocks[1].findPhase = false; - if (lime::fpga::SetPllFrequency(this, 0, txInterfaceClk, clocks, 2)!=0) + if (lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2)!=0) return -1; 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) { -#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 rxInterfaceClk = 2 * rxRate_Hz; + const int pll_ind = (channel == 1) ? 2 : 0; int status = 0; uint32_t reg20; 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 txPhC2[] = { -3.0e-7, 2.71e-7 }; - const std::vector spiAddr = {0x0021, 0x0022, 0x0023, 0x0024, - 0x0027, 0x002A, 0x0400, 0x040C, - 0x040B, 0x0400, 0x040B, 0x0400}; + const std::vector spiAddr = { 0x021, 0x022, 0x023, 0x024, 0x027, 0x02A, + 0x400, 0x40C, 0x40B, 0x400, 0x40B, 0x400}; const int bakRegCnt = spiAddr.size() - 4; auto info = GetDeviceInfo(); - const int addrLMS7002M = info.addrsLMS7002M.at(0); bool phaseSearch = false; - if (this->chipVersion == 0x3841 && stoi(info.gatewareRevision) >= 7 && stoi(info.gatewareVersion) >= 2) //0x3840 LMS7002Mr2, 0x3841 LMS7002Mr3 - if(rxInterfaceClk >= 5e6 || txInterfaceClk >= 5e6) - phaseSearch = true; - mExpectedSampleRate = rxRate_Hz; + if (!(mStreamers.size() > channel && (mStreamers[channel]->rxRunning || mStreamers[channel]->txRunning))) + if (this->chipVersion == 0x3841 && stoi(info.gatewareRevision) >= 7 && stoi(info.gatewareVersion) >= 2) //0x3840 LMS7002Mr2, 0x3841 LMS7002Mr3 + if(rxInterfaceClk >= 5e6 || txInterfaceClk >= 5e6) + phaseSearch = true; + mExpectedSampleRate = rxRate_Hz; std::vector dataWr; std::vector dataRd; @@ -149,78 +93,61 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double dataRd.resize(spiAddr.size()); //backup registers 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 - TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1); + WriteLMS7002MSPI(dataWr.data(), 1, channel); for (int i = 0; i < bakRegCnt; ++i) dataWr[i] = (spiAddr[i] << 16); - TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt); - UpdateThreads(true); + ReadLMS7002MSPI(dataWr.data(),dataRd.data(), bakRegCnt, channel); } if(rxInterfaceClk >= 5e6) { if (phaseSearch) { - const std::vector spiData = { 0x0E9F, 0x07FF, 0x5550, 0xE4E4, - 0xE4E4, 0x0086, 0x028D, 0x00FF, - 0x5555, 0x02CD, 0xAAAA, 0x02ED}; + const std::vector spiData = { 0x0E9F, 0x07FF, 0x5550, 0xE4E4, 0xE4E4, 0x0086, + 0x028D, 0x00FF, 0x5555, 0x02CD, 0xAAAA, 0x02ED}; //Load test config const int setRegCnt = spiData.size(); for (int i = 0; i < setRegCnt; ++i) 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]; - clocks[0].bypass = false; clocks[0].index = 0; clocks[0].outFrequency = rxInterfaceClk; - clocks[0].phaseShift_deg = 0; - clocks[0].findPhase = false; - clocks[1].bypass = false; clocks[1].index = 1; clocks[1].outFrequency = rxInterfaceClk; if (this->chipVersion == 0x3841) clocks[1].phaseShift_deg = rxPhC1[1] + rxPhC2[1] * rxInterfaceClk; else clocks[1].phaseShift_deg = rxPhC1[0] + rxPhC2[0] * rxInterfaceClk; - if (phaseSearch) - { clocks[1].findPhase = true; - } - else - { - clocks[1].findPhase = false; - } - status = lime::fpga::SetPllFrequency(this, 1, rxInterfaceClk, clocks, 2); + status = lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2); } else - status = lime::fpga::SetDirectClocking(this, 1, rxInterfaceClk, 90); + status = lime::fpga::SetDirectClocking(this, pll_ind+1, rxInterfaceClk, 90); if(txInterfaceClk >= 5e6) { if (phaseSearch) { - const std::vector spiData = {0x0E9F, 0x07FF, 0x5550, 0xE4E4, - 0xE4E4, 0x0484}; + const std::vector spiData = {0x0E9F, 0x07FF, 0x5550, 0xE4E4, 0xE4E4, 0x0484}; WriteRegister(0x000A, 0x0000); //Load test config const int setRegCnt = spiData.size(); for (int i = 0; i < setRegCnt; ++i) 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]; - clocks[0].bypass = false; clocks[0].index = 0; clocks[0].outFrequency = txInterfaceClk; clocks[0].phaseShift_deg = 0; - clocks[0].findPhase = false; - clocks[1].bypass = false; clocks[1].index = 1; clocks[1].outFrequency = txInterfaceClk; if (this->chipVersion == 0x3841) @@ -233,27 +160,21 @@ int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double clocks[1].findPhase = true; WriteRegister(0x000A, 0x0200); } - else - { - clocks[1].findPhase = false; - } - status = lime::fpga::SetPllFrequency(this, 0, txInterfaceClk, clocks, 2); + status = lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2); } else - status = lime::fpga::SetDirectClocking(this, 0, txInterfaceClk, 90); + status = lime::fpga::SetDirectClocking(this, pll_ind, txInterfaceClk, 90); if (phaseSearch) { //Restore registers for (int i = 0; i < bakRegCnt; ++i) 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 - TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1); + WriteLMS7002MSPI(dataWr.data(), 1, channel); WriteRegister(0x000A, 0); - UpdateThreads(); } - return status; } @@ -266,57 +187,44 @@ int ConnectionSTREAM::ResetStreamBuffers() 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(); - WriteRegister(0x0008, 0x0100 | 0x2); - WriteRegister(0x0007, 1); + ResetStreamBuffers(); + WriteRegister(0x0008, 0x0100 | 0x2); + 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); - if (WaitForReading(handle, timeout_ms) == false) - { - AbortReading(); - } - - fpga::StopStreaming(this); - - int totalBytesReceived = FinishDataReading(buffer, length, handle); - - return totalBytesReceived; + return totalBytesReceived; } /** @brief Function dedicated for receiving data samples from board - @param rxFIFO FIFO to store received data - @param terminate periodically pooled flag to terminate thread - @param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second + @param stream a pointer to an active receiver stream */ -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 - const uint8_t chCount = args.channels.size(); - const auto link = args.channels[0]->config.linkFormat; + const uint8_t chCount = stream->mRxStreams.size(); + const auto link = stream->mRxStreams[0]->config.linkFormat; 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++) - { - latency += args.channels[i]->config.performanceLatency/chCount; - } + latency += stream->mRxStreams[i]->config.performanceLatency/chCount; + const unsigned tmp_cnt = (latency * 6)+0.5; const uint8_t packetsToBatch = (1< handles(buffersCount, 0); vectorbuffers(buffersCount*bufferSize, 0); vector chFrames; @@ -330,24 +238,18 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args) return; } - uint8_t activeTransfers = 0; + int activeTransfers = 0; for (int i = 0; iBeginDataReading(&buffers[i*bufferSize], bufferSize); + handles[i] = this->BeginDataReading(&buffers[i*bufferSize], bufferSize, ep); ++activeTransfers; } int bi = 0; unsigned long totalBytesReceived = 0; //for data rate calculation - int m_bufferFailures = 0; - int32_t droppedSamples = 0; - int32_t packetLoss = 0; - - vector samplesCollected(chCount, 0); - vector samplesReceived(chCount, 0); auto t1 = chrono::high_resolution_clock::now(); - auto t2 = chrono::high_resolution_clock::now(); + auto t2 = t1; std::mutex txFlagsLock; condition_variable resetTxFlags; @@ -360,24 +262,24 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args) uint32_t reg9; port->ReadRegister(0x0009, reg9); 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()) { std::unique_lock lck(*spiLock); doWork->wait(lck); port->WriteRegisters(addr, data, 2); } - }, this, terminate, &txFlagsLock, &resetTxFlags); + }, this, &stream->terminateRx, &txFlagsLock, &resetTxFlags); int resetFlagsDelay = 128; 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 - fpga::StopStreaming(this); - safeToConfigInterface->notify_all(); //notify that it's safe to change chip config + fpga::StopStreaming(this, chipID); + stream->safeToConfigInterface.notify_all(); //notify that it's safe to change chip config const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10; IStreamChannel::Metadata meta; for(int i=0; iWrite((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta); - samplesReceived[ch] += chFrames[ch].samplesCount; + uint32_t samplesPushed = stream->mRxStreams[ch]->Write((const void*)chFrames[ch].samples, chFrames[ch].samplesCount, &meta); if(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; if(handles[bi] >= 0) { - if (this->WaitForReading(handles[bi], 1000) == false) - ++m_bufferFailures; - bytesReceived = this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]); + if (this->WaitForReading(handles[bi], 1000) == true) + bytesReceived = this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]); --activeTransfers; totalBytesReceived += bytesReceived; if (bytesReceived != int32_t(bufferSize)) //data should come in full sized packets - ++m_bufferFailures; + for(auto value: stream->mRxStreams) + value->underflow++; } bool txLate=false; 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); resetTxFlags.notify_one(); 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; if(pkt[pktIndex].counter - prevTs != samplesInPacket && pkt[pktIndex].counter != prevTs) { + int packetLoss = ((pkt[pktIndex].counter - prevTs)/samplesInPacket)-1; #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 - packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket; + for(auto value: stream->mRxStreams) + value->pktLost += packetLoss; } prevTs = pkt[pktIndex].counter; - if(args.lastTimestamp) - args.lastTimestamp->store(pkt[pktIndex].counter); + stream->rxLastTimestamp.store(prevTs); //parse samples vector dest(chCount); for(uint8_t c=0; cWrite((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) - droppedSamples += samplesCount-samplesPushed; + stream->mRxStreams[ch]->overflow++; } } // 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 - fpga::StartStreaming(this); + fpga::StartStreaming(this, chipID); for(int i=0; iBeginDataReading(&buffers[bi*bufferSize], bufferSize); + handles[bi] = this->BeginDataReading(&buffers[bi*bufferSize], bufferSize, ep); bi = (bi + 1) & (buffersCount-1); ++activeTransfers; } @@ -480,21 +384,13 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args) //total number of bytes sent per second double dataRate = 1000.0*totalBytesReceived / timePeriod; #ifndef NDEBUG - //each channel sample rate - 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); + printf("Rx: %.3f MB/s\n", dataRate / 1000000.0); #endif - samplesReceived[0] = 0; totalBytesReceived = 0; - m_bufferFailures = 0; - droppedSamples = 0; - packetLoss = 0; - - if (dataRate_Bps) - dataRate_Bps->store((uint32_t)dataRate); + stream->rxDataRate_Bps.store((uint32_t)dataRate); } } - this->AbortReading(); + AbortReading(ep); for (int j = 0; j= 0) @@ -506,35 +402,27 @@ void ConnectionSTREAM::ReceivePacketsLoop(const ThreadData args) } resetTxFlags.notify_one(); txReset.join(); - if (dataRate_Bps) - dataRate_Bps->store(0); + stream->rxDataRate_Bps.store(0); } /** @brief Functions dedicated for transmitting packets to board - @param txFIFO data source FIFO - @param terminate periodically pooled flag to terminate thread - @param dataRate_Bps (optional) if not NULL periodically returns data rate in bytes per second + @param stream an active transmit stream */ -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 const uint8_t maxChannelCount = 2; - const uint8_t chCount = args.channels.size(); - const auto link = args.channels[0]->config.linkFormat; + const uint8_t chCount = stream->mTxStreams.size(); + const auto link = stream->mTxStreams[0]->config.linkFormat; + const unsigned char ep = 0x01; double latency=0; 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 * 6)+0.5; const uint8_t buffersCount = 16; // must be power of 2 - assert(buffersCount % 2 == 0); const uint8_t packetsToBatch = (1< handles(buffersCount, 0); vector bufferUsed(buffersCount, 0); - vector bytesToSend(buffersCount, 0); vector samples[maxChannelCount]; vector buffers; try @@ -553,49 +440,57 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args) } catch (const std::bad_alloc& ex) //not enough memory for buffers { - lime::error("Error allocating Tx buffers, not enough memory"); - return; + return lime::error("Error allocating Tx buffers, not enough memory"); } - int m_bufferFailures = 0; long totalBytesSent = 0; - - uint32_t samplesSent = 0; - auto t1 = chrono::high_resolution_clock::now(); - auto t2 = chrono::high_resolution_clock::now(); + auto t2 = t1; uint8_t bi = 0; //buffer index - while (terminate->load() != true) + while (stream->terminateTx.load() != true) { if (bufferUsed[bi]) { - if (this->WaitForSending(handles[bi], 1000) == false) - ++m_bufferFailures; - uint32_t bytesSent = this->FinishDataSending(&buffers[bi*bufferSize], bytesToSend[bi], handles[bi]); - totalBytesSent += bytesSent; - if (bytesSent != bytesToSend[bi]) - ++m_bufferFailures; + unsigned bytesSent = 0; + if (this->WaitForSending(handles[bi], 1000) == true) { + bytesSent = this->FinishDataSending(&buffers[bi*bufferSize], bufferSize, handles[bi]); + } + + if (bytesSent != bufferSize) { + for (auto value : stream->mTxStreams) { + value->overflow++; + } + } + else { + totalBytesSent += bytesSent; + } bufferUsed[bi] = false; } int i=0; - while(iload() != true) + while(iterminateTx.load() != true) { IStreamChannel::Metadata meta; FPGA_DataPacket* pkt = reinterpret_cast(&buffers[bi*bufferSize]); + bool badSamples = false; for(int ch=0; chRead(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); + int samplesPopped = stream->mTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); if (samplesPopped != maxSamplesBatch) { - #ifndef NDEBUG - lime::warning("popping from TX, samples popped %i/%i", samplesPopped, maxSamplesBatch); - #endif + badSamples = true; + stream->mTxStreams[ch]->underflow++; + 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; pkt[i].counter = meta.timestamp; pkt[i].reserved[0] = 0; @@ -608,12 +503,10 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args) src[c] = (samples[c].data()); uint8_t* const dataStart = (uint8_t*)pkt[i].data; fpga::Samples2FPGAPacketPayload(src.data(), maxSamplesBatch, chCount, link, dataStart, nullptr); - samplesSent += maxSamplesBatch; ++i; } - bytesToSend[bi] = bufferSize; - handles[bi] = this->BeginDataSending(&buffers[bi*bufferSize], bytesToSend[bi]); + handles[bi] = this->BeginDataSending(&buffers[bi*bufferSize], bufferSize, ep); bufferUsed[bi] = true; t2 = chrono::high_resolution_clock::now(); @@ -622,23 +515,18 @@ void ConnectionSTREAM::TransmitPacketsLoop(const ThreadData args) { //total number of bytes sent per second float dataRate = 1000.0*totalBytesSent / timePeriod; - if(dataRate_Bps) - dataRate_Bps->store(dataRate); - m_bufferFailures = 0; - samplesSent = 0; + stream->txDataRate_Bps.store(dataRate); totalBytesSent = 0; t1 = t2; #ifndef NDEBUG - //total number of samples from all channels per second - 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); + printf("Tx: %.3f MB/s\n", dataRate / 1000000.0); #endif } bi = (bi + 1) & (buffersCount-1); } // Wait for all the queued requests to be cancelled - this->AbortSending(); + AbortSending(ep); for (int j = 0; jstore(0); + stream->txDataRate_Bps.store(0); } diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp index a9fabccd4..0c30f3119 100644 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp +++ b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp @@ -48,17 +48,8 @@ Connection_uLimeSDR::Connection_uLimeSDR(void *arg, const unsigned index, const { RxLoopFunction = bind(&Connection_uLimeSDR::ReceivePacketsLoop, this, std::placeholders::_1); TxLoopFunction = bind(&Connection_uLimeSDR::TransmitPacketsLoop, this, std::placeholders::_1); - mTimestampOffset = 0; - rxLastTimestamp.store(0); mExpectedSampleRate = 0; - generateData.store(false); - rxRunning.store(false); - txRunning.store(false); isConnected = false; - terminateRx.store(false); - terminateTx.store(false); - rxDataRate_Bps.store(0); - txDataRate_Bps.store(0); mStreamWrEndPtAddr = 0x03; mStreamRdEndPtAddr = 0x83; @@ -83,15 +74,6 @@ Connection_uLimeSDR::Connection_uLimeSDR(void *arg, const unsigned index, const */ 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(); } #ifdef __unix__ diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.h b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.h index 7104e1609..076ac5581 100644 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.h +++ b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.h @@ -96,10 +96,10 @@ public: //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) 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: - virtual void ReceivePacketsLoop(const ThreadData args) override; - virtual void TransmitPacketsLoop(const ThreadData args) override; + virtual void ReceivePacketsLoop(Streamer* args) override; + virtual void TransmitPacketsLoop(Streamer* args) override; virtual int BeginDataReading(char* buffer, uint32_t length); virtual int WaitForReading(int contextHandle, unsigned int timeout_ms); diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp index d42c0dc6e..bc608c8eb 100644 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp +++ b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp @@ -101,7 +101,6 @@ int Connection_uLimeSDR::UpdateExternalDataRate(const size_t channel, const doub for (int i = 0; i < bakRegCnt; ++i) dataWr[i] = (spiAddr[i] << 16); TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt); - //UpdateThreads(true); } 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 TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1); WriteRegister(0x000A, 0); - UpdateThreads(); } 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; - fpga::StopStreaming(this); + fpga::StopStreaming(this, epIndex); //ResetStreamBuffers(); WriteRegister(0x0008, 0x0100 | 0x2); WriteRegister(0x0007, 1); - fpga::StartStreaming(this); + fpga::StartStreaming(this, epIndex); int handle = BeginDataReading(buffer, length); if (WaitForReading(handle, timeout_ms)) totalBytesReceived = FinishDataReading(buffer, length, handle); AbortReading(); - fpga::StopStreaming(this); + fpga::StopStreaming(this, epIndex); return totalBytesReceived; } @@ -235,23 +233,18 @@ int Connection_uLimeSDR::ResetStreamBuffers() @param terminate periodically pooled flag to terminate thread @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 - const uint8_t chCount = args.channels.size(); - const auto link = args.channels[0]->config.linkFormat; + const uint8_t chCount = stream->mRxStreams.size(); + const auto link =stream->mRxStreams[0]->config.linkFormat; const uint32_t samplesInPacket = (link == StreamConfig::STREAM_12_BIT_COMPRESSED ? 1360 : 1020)/chCount; + const int chipID = stream->mChipID; double latency=0; 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; @@ -308,17 +301,17 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa doWork->wait(lck); port->WriteRegisters(addr, data, 2); } - }, this, terminate, &txFlagsLock, &resetTxFlags); + }, this, &stream->terminateRx, &txFlagsLock, &resetTxFlags); int resetFlagsDelay = 128; 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 - fpga::StopStreaming(this); - safeToConfigInterface->notify_all(); //notify that it's safe to change chip config + fpga::StopStreaming(this, chipID); + stream->safeToConfigInterface.notify_all(); //notify that it's safe to change chip config const int batchSize = (this->mExpectedSampleRate/chFrames[0].samplesCount)/10; IStreamChannel::Metadata meta; for(int i=0; iWrite((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) 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"); resetTxFlags.notify_one(); 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; @@ -377,8 +370,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket; } prevTs = pkt[pktIndex].counter; - if(args.lastTimestamp) - args.lastTimestamp->store(pkt[pktIndex].counter); + stream->rxLastTimestamp.store(pkt[pktIndex].counter); //parse samples vector dest(chCount); for(uint8_t c=0; cWrite((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) droppedSamples += samplesCount-samplesPushed; } } // 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 - fpga::StartStreaming(this); + fpga::StartStreaming(this, chipID); for(int i=0; iBeginDataReading(&buffers[bi*bufferSize], bufferSize); @@ -430,9 +422,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa m_bufferFailures = 0; droppedSamples = 0; packetLoss = 0; - - if (dataRate_Bps) - dataRate_Bps->store((uint32_t)dataRate); + stream->rxDataRate_Bps.store((uint32_t)dataRate); } } this->AbortReading(); @@ -447,8 +437,7 @@ void Connection_uLimeSDR::ReceivePacketsLoop(const Connection_uLimeSDR::ThreadDa } resetTxFlags.notify_one(); txReset.join(); - if (dataRate_Bps) - dataRate_Bps->store(0); + stream->rxDataRate_Bps.store(0); } /** @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 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 const uint8_t maxChannelCount = 2; - const uint8_t chCount = args.channels.size(); - const auto link = args.channels[0]->config.linkFormat; + const uint8_t chCount = stream->mTxStreams.size(); + const auto link = stream->mTxStreams[0]->config.linkFormat; double latency=0; 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; @@ -507,7 +492,7 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD auto t2 = chrono::high_resolution_clock::now(); uint8_t bi = 0; //buffer index - while (terminate->load() != true) + while (stream->terminateTx.load() != true) { if (bufferUsed[bi]) { @@ -521,13 +506,13 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD } int i=0; - while(iload() != true) + while(iterminateTx.load() != true) { IStreamChannel::Metadata meta; FPGA_DataPacket* pkt = reinterpret_cast(&buffers[bi*bufferSize]); for(int ch=0; chRead(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); + int samplesPopped = stream->mTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); if (samplesPopped != maxSamplesBatch) { #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; pkt[i].counter = meta.timestamp; pkt[i].reserved[0] = 0; @@ -563,8 +548,7 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD { //total number of bytes sent per second float dataRate = 1000.0*totalBytesSent / timePeriod; - if(dataRate_Bps) - dataRate_Bps->store(dataRate); + stream->txDataRate_Bps.store(dataRate); m_bufferFailures = 0; samplesSent = 0; totalBytesSent = 0; @@ -589,6 +573,5 @@ void Connection_uLimeSDR::TransmitPacketsLoop(const Connection_uLimeSDR::ThreadD } bi = (bi + 1) & (buffersCount-1); } - if (dataRate_Bps) - dataRate_Bps->store(0); + stream->txDataRate_Bps.store(0); } diff --git a/liblimesuite/srcmw/ErrorReporting.cpp b/liblimesuite/srcmw/ErrorReporting.cpp index fab1ff634..f80285de3 100644 --- a/liblimesuite/srcmw/ErrorReporting.cpp +++ b/liblimesuite/srcmw/ErrorReporting.cpp @@ -33,7 +33,7 @@ static const char *errToStr(const int errnum) strerror_r(errnum, buff, sizeof(buff)); #else //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; #endif return buff; diff --git a/liblimesuite/srcmw/lms7002m/LMS7002M.cpp b/liblimesuite/srcmw/lms7002m/LMS7002M.cpp index 5d7e31f04..83c01dac6 100644 --- a/liblimesuite/srcmw/lms7002m/LMS7002M.cpp +++ b/liblimesuite/srcmw/lms7002m/LMS7002M.cpp @@ -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 */ -void LMS7002M::SetConnection(IConnection* port, const size_t devIndex, IConnection* samplesPort) +void LMS7002M::SetConnection(IConnection* port, const size_t devIndex) { controlPort = port; mdevIndex = devIndex; @@ -111,7 +111,6 @@ void LMS7002M::SetConnection(IConnection* port, const size_t devIndex, IConnecti if (controlPort != nullptr) { unsigned byte_array_size = 0; - addrLMS7002M = controlPort->GetDeviceInfo().addrsLMS7002M.at(devIndex); if (controlPort->IsOpen()) { 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 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. @@ -136,8 +131,6 @@ LMS7002M::LMS7002M() : mValueCache(new CalibrationCache()), mRegistersMap(new LMS7002M_RegistersMap()), controlPort(nullptr), - dataPort(nullptr), - addrLMS7002M(-1), mdevIndex(0), mSelfCalDepth(0) { @@ -205,7 +198,7 @@ LMS7002M::LMS7002M() : mRegistersMap->InitializeDefaultValues(LMS7parameterList); mcuControl = new MCU_BD(); - mcuControl->Initialize(controlPort); + mcuControl->Initialize(nullptr); } LMS7002M::~LMS7002M() @@ -253,8 +246,6 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable) //--- ADC/DAC --- 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 (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); } + 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 --- if (isTx) { 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(GFIR2_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 { 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(CMIX_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(GFIR2_BYP_RXTSP), 1); this->Modify_SPI_Reg_bits(LMS7param(GFIR1_BYP_RXTSP), 1); - this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 1); - this->Modify_SPI_Reg_bits(LMS7param(GC_BYP_RXTSP), 1); - this->Modify_SPI_Reg_bits(LMS7param(PH_BYP_RXTSP), 1); + if (!enable) + { + 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 --- @@ -324,7 +332,7 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable) { this->SetActiveChannel(ChSXT); 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 { this->SetActiveChannel(ChA); @@ -335,7 +343,7 @@ int LMS7002M::EnableChannel(const bool isTx, const bool enable) { this->SetActiveChannel(ChSXR); 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 { this->SetActiveChannel(ChA); @@ -695,9 +703,10 @@ int LMS7002M::SaveConfig(const char* filename) fout << "[lms7002_registers_b]" << endl; addrToRead.clear(); //add only B channel addresses for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) - if (addr >= 0x0100) - addrToRead.push_back(addr); + if (i != RSSI_DC_CALIBRATION) + for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) + if (addr >= 0x0100) + addrToRead.push_back(addr); this->SetActiveChannel(ChB); 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(); - - return controlPort->TransactSPI(addrLMS7002M, data.data(), nullptr, cnt); + return controlPort->WriteLMS7002MSPI(data.data(), cnt,mdevIndex); } /** @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); } - 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; int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003; @@ -1990,9 +1999,10 @@ int LMS7002M::RegistersTest(const char* fileName) ss << moduleNames[i] << " [" << chex << ":"; sprintf(chex, "0x%04X", endAddr); ss << chex << "]"; - if (startAddr >= 0x0100) + if (startAddr >= 0x0100) { ss << " Ch." << (cc == 1 ? "A" : "B"); - ss << endl; + } + ss << endl; for (uint8_t p = 0; p < patternsCount; ++p) moduleTestsSuccess &= RegistersTestInterval(startAddr, endAddr, patterns[p], ss) == 0; } @@ -2140,7 +2150,8 @@ bool LMS7002M::IsSynced() std::vector dataRd(addrToRead.size()); for(size_t i = 0; i < addrToRead.size(); ++i) 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; iTransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), dataWr.size()); + status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), dataWr.size(),mdevIndex); for(size_t i=0; iModify_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(DCCORRQ_TXTSP), std::lrint(Q*128)); return 0; diff --git a/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp b/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp index c11d0a99f..703b12005 100644 --- a/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp +++ b/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp @@ -28,6 +28,7 @@ MCU_BD::MCU_BD() stepsDone = 0; aborted = false; callback = nullptr; + mChipID =0; //ctor int i=0; m_serPort=NULL; @@ -50,9 +51,10 @@ MCU_BD::~MCU_BD() //dtor } -void MCU_BD::Initialize(IConnection* pSerPort, unsigned size) +void MCU_BD::Initialize(IConnection* pSerPort, unsigned chipID, unsigned size) { m_serPort = pSerPort; + mChipID = chipID; if (size > 0) byte_array_size = size; } @@ -119,7 +121,7 @@ void MCU_BD:: mSPI_write( if(m_serPort == nullptr) return; 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; uint32_t wrdata = addr_reg << 16; 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 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; default: mode = IConnection::MCU_PROG_MODE::RESET; break; } - if(m_serPort) - return m_serPort->ProgramMCU(byte_array, byte_array_size, mode, callback); - else - return ReportError(ENOLINK, "Device not connected"); + return Program_MCU(byte_array,mode); } -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) - return m_serPort->ProgramMCU(binArray, byte_array_size, mode, callback); - else + if(!m_serPort) 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; iReadLMS7002MSPI(wrdata, &rddata, 1, mChipID))!=0) + return status; + fifoEmpty = rddata & EMTPY_WRITE_BUFF; + t2 = std::chrono::high_resolution_clock::now(); + }while( (!fifoEmpty) && (t2-t1)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) + (timeEnd-timeStart).count()); +#endif + if(!programmed) + return ReportError(ETIMEDOUT, "MCU not programmed"); + return 0; } void MCU_BD::Reset_MCU() diff --git a/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h b/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h index 9b583b9f5..bc6b5d7c5 100644 --- a/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h +++ b/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h @@ -452,7 +452,7 @@ public: m_top = 0; 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); } } diff --git a/windows64.install.bat b/windows64.install.bat index 094ec4b0f..926237ed3 100644 --- a/windows64.install.bat +++ b/windows64.install.bat @@ -25,8 +25,8 @@ copy libhackrf\%1\libhackrf.dll %2 copy librtlsdr\%1\librtlsdr.dll %2 copy libairspy\%1\libairspy.dll %2 copy libbladerf\%1\libbladerf.dll %2 -REM copy libsqlite3\%1\libsqlite3.dll %2 -REM copy liblimesuite\%1\liblimesuite.dll %2 +copy libsqlite3\%1\libsqlite3.dll %2 +copy liblimesuite\%1\liblimesuite.dll %2 copy %libusbdir%\dll\libusb-1.0.dll %2 copy %opencvdir%\opencv_ffmpeg2413_64.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\airspy\%1\inputairspy.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\bladerfoutput\%1\outputbladerf.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