diff --git a/liblimesuite/liblimesuite.pro b/liblimesuite/liblimesuite.pro index 7f66add20..dfaa49475 100644 --- a/liblimesuite/liblimesuite.pro +++ b/liblimesuite/liblimesuite.pro @@ -11,8 +11,8 @@ TARGET = liblimesuite DEFINES += ENOLINK=21 -CONFIG(MINGW32):QMAKE_CXXFLAGS += -fpermissive -CONFIG(MINGW32):QMAKE_CXXFLAGS += -std=c++11 +QMAKE_CXXFLAGS += -fpermissive +QMAKE_CXXFLAGS += -std=c++11 CONFIG(MINGW32):LIBLIMESUITESRC = "D:\softs\LimeSuite" CONFIG(MINGW64):LIBLIMESUITESRC = "D:\softs\LimeSuite" @@ -23,7 +23,6 @@ CONFIG(MINGW64):INCLUDEPATH += "D:\softs\libusb-1.0.20\include" CONFIG(MINGW32):INCLUDEPATH += "..\libsqlite3\src" CONFIG(MINGW64):INCLUDEPATH += "..\libsqlite3\src" -INCLUDEPATH += srcmw INCLUDEPATH += $$LIBLIMESUITESRC/src INCLUDEPATH += $$LIBLIMESUITESRC/src/ADF4002 INCLUDEPATH += $$LIBLIMESUITESRC/src/ConnectionRegistry @@ -43,13 +42,13 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.cpp\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.cpp\ $$LIBLIMESUITESRC/src/ConnectionRegistry/IConnection.cpp\ - srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp\ - srcmw/ConnectionSTREAM/ConnectionSTREAMImages.cpp\ - srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp\ - srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp\ - srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp\ - srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp\ - srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\ + $$LIBLIMESUITESRC/src/ConnectionSTREAM/ConnectionSTREAM.cpp\ + $$LIBLIMESUITESRC/src/ConnectionSTREAM/ConnectionSTREAMImages.cpp\ + $$LIBLIMESUITESRC/src/ConnectionSTREAM/ConnectionSTREAMing.cpp\ + $$LIBLIMESUITESRC/src/ConnectionSTREAM/ConnectionSTREAMEntry.cpp\ + $$LIBLIMESUITESRC/src/Connection_uLimeSDR/Connection_uLimeSDR.cpp\ + $$LIBLIMESUITESRC/src/Connection_uLimeSDR/Connection_uLimeSDRing.cpp\ + $$LIBLIMESUITESRC/src/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybus.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusEntry.cpp\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybusing.cpp\ @@ -63,18 +62,18 @@ SOURCES = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.cpp\ $$LIBLIMESUITESRC/src/lms7002m/CalibrationCache.cpp\ $$LIBLIMESUITESRC/src/lms7002m/goert.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_BaseCalibrations.cpp\ - srcmw/lms7002m/LMS7002M.cpp\ + $$LIBLIMESUITESRC/src/lms7002m/LMS7002M.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_filtersCalibration.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_gainCalibrations.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_parameters.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_RegistersMap.cpp\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_RxTxCalibrations.cpp\ $$LIBLIMESUITESRC/src/lms7002m/mcu_dc_iq_calibration.cpp\ - srcmw/lms7002m_mcu/MCU_BD.cpp\ + $$LIBLIMESUITESRC/src/lms7002m_mcu/MCU_BD.cpp\ $$LIBLIMESUITESRC/src/protocols/ILimeSDRStreaming.cpp\ $$LIBLIMESUITESRC/src/protocols/LMS64CProtocol.cpp\ $$LIBLIMESUITESRC/src/Si5351C/Si5351C.cpp\ - srcmw/ErrorReporting.cpp\ + $$LIBLIMESUITESRC/src/ErrorReporting.cpp\ $$LIBLIMESUITESRC/src/Logger.cpp\ src/SystemResources.cpp\ src/VersionInfo.cpp @@ -85,8 +84,8 @@ HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionHandle.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/ConnectionRegistry.h\ $$LIBLIMESUITESRC/src/ConnectionRegistry/IConnection.h\ - srcmw/ConnectionSTREAM/ConnectionSTREAM.h\ - srcmw/Connection_uLimeSDR/Connection_uLimeSDR.h\ + $$LIBLIMESUITESRC/src/ConnectionSTREAM/ConnectionSTREAM.h\ + $$LIBLIMESUITESRC/src/Connection_uLimeSDR/Connection_uLimeSDR.h\ $$LIBLIMESUITESRC/src/Connection_uLimeSDR/DRV_DriverInterface.h\ $$LIBLIMESUITESRC/src/Connection_uLimeSDR/FTD3XXLibrary/FTD3XX.h\ $$LIBLIMESUITESRC/src/ConnectionXillybus/ConnectionXillybus.h\ @@ -103,7 +102,7 @@ HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\ $$LIBLIMESUITESRC/src/lms7002m/LMS7002M_RegistersMap.h\ $$LIBLIMESUITESRC/src/lms7002m/mcu_programs.h\ $$LIBLIMESUITESRC/src/lms7002m_mcu/MCU_BD.h\ - srcmw/lms7002m_mcu/MCU_File.h\ + $$LIBLIMESUITESRC/src/lms7002m_mcu/MCU_File.h\ $$LIBLIMESUITESRC/src/protocols/ADCUnits.h\ $$LIBLIMESUITESRC/src/protocols/dataTypes.h\ $$LIBLIMESUITESRC/src/protocols/fifo.h\ @@ -112,7 +111,7 @@ HEADERS = $$LIBLIMESUITESRC/src/ADF4002/ADF4002.h\ $$LIBLIMESUITESRC/src/protocols/LMS64CProtocol.h\ $$LIBLIMESUITESRC/src/protocols/LMSBoards.h\ $$LIBLIMESUITESRC/src/Si5351C/Si5351C.h\ - srcmw/ErrorReporting.h\ + $$LIBLIMESUITESRC/src/ErrorReporting.h\ $$LIBLIMESUITESRC/src/Logger.h\ $$LIBLIMESUITESRC/src/SystemResources.h\ $$LIBLIMESUITESRC/src/VersionInfo.h\ diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp deleted file mode 100644 index bddf2f181..000000000 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.cpp +++ /dev/null @@ -1,945 +0,0 @@ -/** - @file ConnectionSTREAM.cpp - @author Lime Microsystems - @brief Implementation of STREAM board connection. -*/ - -#include "ConnectionSTREAM.h" -#include "ErrorReporting.h" -#include -#include "Si5351C.h" -#include "FPGA_common.h" -#include "LMS7002M.h" -#include "Logger.h" -#include -#include -#include -#include - -using namespace std; - -#define CTR_W_REQCODE 0xC1 -#define CTR_W_VALUE 0x0000 -#define CTR_W_INDEX 0x0000 - -#define CTR_R_REQCODE 0xC0 -#define CTR_R_VALUE 0x0000 -#define CTR_R_INDEX 0x0000 - -using namespace lime; - -const uint8_t ConnectionSTREAM::ctrlBulkOutAddr = 0x0F; -const uint8_t ConnectionSTREAM::ctrlBulkInAddr = 0x8F; - -//control commands to be send via bulk port for boards v1.1 and earlier -const std::set ConnectionSTREAM::commandsToBulkCtrlHw1 = -{ - CMD_BRDSPI_WR, CMD_BRDSPI_RD, - CMD_LMS7002_WR, CMD_LMS7002_RD, - CMD_LMS7002_RST, -}; -//control commands to be send via bulk port for boards v1.2 and later -const std::set ConnectionSTREAM::commandsToBulkCtrlHw2 = -{ - CMD_BRDSPI_WR, CMD_BRDSPI_RD, - CMD_LMS7002_WR, CMD_LMS7002_RD, - CMD_ANALOG_VAL_WR, CMD_ANALOG_VAL_RD, - CMD_ADF4002_WR, - CMD_LMS7002_RST, - CMD_GPIO_DIR_WR, CMD_GPIO_DIR_RD, - CMD_GPIO_WR, CMD_GPIO_RD, -}; - -/** @brief Initializes port type and object necessary to communicate to usb device. -*/ -ConnectionSTREAM::ConnectionSTREAM(void *arg, const std::string &vidpid, const std::string &serial, const unsigned index) -{ - bulkCtrlAvailable = false; - bulkCtrlInProgress = false; - RxLoopFunction = bind(&ConnectionSTREAM::ReceivePacketsLoop, this, std::placeholders::_1); - TxLoopFunction = bind(&ConnectionSTREAM::TransmitPacketsLoop, this, std::placeholders::_1); - isConnected = false; -#ifndef __unix__ - if(arg == nullptr) - USBDevicePrimary = new CCyFX3Device(); - else - USBDevicePrimary = new CCyFX3Device(*(CCyFX3Device*)arg); - InCtrlEndPt3 = nullptr; - 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; -#endif - if (this->Open(vidpid, serial, index) != 0) - lime::error(GetLastErrorMessage()); - - commandsToBulkCtrl = commandsToBulkCtrlHw2; - - LMSinfo info = this->GetInfo(); - - if (info.hardware <= 1) - { - commandsToBulkCtrl = commandsToBulkCtrlHw1; - } - - this->VersionCheck(); - - if (info.device == LMS_DEV_LIMESDR || info.device == LMS_DEV_LIMESDR_USB_SP || info.device == LMS_DEV_LMS7002M_ULTIMATE_EVB) - DetectRefClk(); - - GetChipVersion(); - //must configure synthesizer before using LimeSDR - if (info.device == LMS_DEV_LIMESDR && info.hardware < 4) - { - std::shared_ptr si5351module(new Si5351C()); - si5351module->Initialize(this); - si5351module->SetPLL(0, 25000000, 0); - si5351module->SetPLL(1, 25000000, 0); - si5351module->SetClock(0, 27000000, true, false); - si5351module->SetClock(1, 27000000, true, false); - for (int i = 2; i < 8; ++i) - si5351module->SetClock(i, 27000000, false, false); - Si5351C::Status status = si5351module->ConfigureClocks(); - if (status != Si5351C::SUCCESS) - { - lime::warning("Failed to configure Si5351C"); - return; - } - status = si5351module->UploadConfiguration(); - if (status != Si5351C::SUCCESS) - lime::warning("Failed to upload Si5351C configuration"); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); //some settle time - } -} - -double ConnectionSTREAM::DetectRefClk(void) -{ - const double fx3Clk = 100e6 * 1.008; //fx3 clock 100MHz (adjusted to 100.8 MHz based on measurement on multiple boards) - const double fx3Cnt = 16777210; //fixed fx3 counter in FPGA - const double clkTbl[] = { 30.72e6, 38.4e6, 40e6, 52e6 }; - const uint32_t addr[] = { 0x61, 0x63 }; - const uint32_t vals[] = { 0x0, 0x0 }; - if (this->WriteRegisters(addr, vals, 2) != 0) - { - return -1; - } - auto start = std::chrono::steady_clock::now(); - if (this->WriteRegister(0x61, 0x4) != 0) - { - return -1; - } - - while (1) //wait for test to finish - { - unsigned completed; - if (this->ReadRegister(0x65, completed) != 0) - { - return -1; - } - if (completed & 0x4) - break; - - auto end = std::chrono::steady_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - if (elapsed_seconds.count() > 0.5) //timeout - { - return -1; - } - } - - const uint32_t addr2[] = { 0x72, 0x73 }; - uint32_t vals2[2]; - if (this->ReadRegisters(addr2, vals2, 2) != 0) - { - return -1; - } - double count = (vals2[0] | (vals2[1] << 16)); //cock counter - count *= fx3Clk / fx3Cnt; //estimate ref clock based on FX3 Clock - lime::info("Estimated reference clock %1.4f MHz", count/1e6); - unsigned i = 0; - double delta = 100e6; - - while (i < sizeof(clkTbl) / sizeof(*clkTbl)) - if (delta < fabs(count - clkTbl[i])) - break; - else - delta = fabs(count - clkTbl[i++]); - - this->SetReferenceClockRate(clkTbl[i-1]); - lime::info("Selected reference clock %1.3f MHz", clkTbl[i - 1] / 1e6); - return clkTbl[i - 1]; -} - -/** @brief Closes connection to chip and deallocates used memory. -*/ -ConnectionSTREAM::~ConnectionSTREAM() -{ - Close(); -#ifndef __unix__ - delete USBDevicePrimary; -#endif -} - -/** @brief Tries to open connected USB device and find communication endpoints. - @return Returns 0-Success, other-EndPoints not found or device didn't connect. -*/ -int ConnectionSTREAM::Open(const std::string &vidpid, const std::string &serial, const unsigned index) -{ - bulkCtrlAvailable = false; -#ifndef __unix__ - if(index > USBDevicePrimary->DeviceCount()) - return ReportError(ERANGE, "ConnectionSTREAM: Device index out of range"); - - if(USBDevicePrimary->Open(index) == false) - return ReportError(-1, "ConnectionSTREAM: Failed to open device"); - - if (InCtrlEndPt3) - { - delete InCtrlEndPt3; - InCtrlEndPt3 = nullptr; - } - InCtrlEndPt3 = new CCyControlEndPoint(*USBDevicePrimary->ControlEndPt); - - if (OutCtrlEndPt3) - { - delete OutCtrlEndPt3; - OutCtrlEndPt3 = nullptr; - } - OutCtrlEndPt3 = new CCyControlEndPoint(*USBDevicePrimary->ControlEndPt); - - InCtrlEndPt3->ReqCode = CTR_R_REQCODE; - InCtrlEndPt3->Value = CTR_R_VALUE; - InCtrlEndPt3->Index = CTR_R_INDEX; - InCtrlEndPt3->TimeOut = 3000; - - OutCtrlEndPt3->ReqCode = CTR_W_REQCODE; - OutCtrlEndPt3->Value = CTR_W_VALUE; - OutCtrlEndPt3->Index = CTR_W_INDEX; - OutCtrlEndPt3->TimeOut = 3000; - - for (int i = 0; i < USBDevicePrimary->EndPointCount(); i++) - { - auto adr = USBDevicePrimary->EndPoints[i]->Address; - if (adr < ctrlBulkOutAddr) - { - OutEndPt[adr] = USBDevicePrimary->EndPoints[i]; - long len = OutEndPt[adr]->MaxPktSize * 64; - OutEndPt[adr]->SetXferSize(len); - } - else if (adr < ctrlBulkInAddr) - { - 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++) - if(USBDevicePrimary->EndPoints[i]->Address == ctrlBulkInAddr) - { - InCtrlBulkEndPt = USBDevicePrimary->EndPoints[i]; - InCtrlBulkEndPt->TimeOut = 1000; - bulkCtrlAvailable = true; - break; - } - OutCtrlBulkEndPt = nullptr; - for (int i=0; iEndPointCount(); i++) - if(USBDevicePrimary->EndPoints[i]->Address == ctrlBulkOutAddr) - { - OutCtrlBulkEndPt = USBDevicePrimary->EndPoints[i]; - OutCtrlBulkEndPt->TimeOut = 1000; - bulkCtrlAvailable = true; - break; - } - isConnected = true; - return 0; -#else - const auto splitPos = vidpid.find(":"); - const auto vid = std::stoi(vidpid.substr(0, splitPos), nullptr, 16); - const auto pid = std::stoi(vidpid.substr(splitPos+1), nullptr, 16); - - libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices - int usbDeviceCount = libusb_get_device_list(ctx, &devs); - - if (usbDeviceCount < 0) { - return ReportError(-1, "ConnectionSTREAM: libusb_get_device_list failed: %s", libusb_strerror(libusb_error(usbDeviceCount))); - } - - for(int i=0; i 0) - { - char data[255]; - r = libusb_get_string_descriptor_ascii(dev_handle,desc.iSerialNumber,(unsigned char*)data, sizeof(data)); - if(r<0) - lime::error("failed to get serial number"); - else - foundSerial = std::string(data, size_t(r)); - } - - if (serial == foundSerial) break; //found it - libusb_close(dev_handle); - dev_handle = nullptr; - } - libusb_free_device_list(devs, 1); - - if(dev_handle == nullptr) - return ReportError(-1, "ConnectionSTREAM: libusb_open failed"); - if(libusb_kernel_driver_active(dev_handle, 0) == 1) //find out if kernel driver is attached - { - lime::info("Kernel Driver Active"); - if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it - lime::info("Kernel Driver Detached!"); - } - int r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the first) of device - if(r < 0) - return ReportError(-1, "ConnectionSTREAM: Cannot claim interface - %s", libusb_strerror(libusb_error(r))); - - libusb_device* device = libusb_get_device(dev_handle); - libusb_config_descriptor* descriptor = nullptr; - if(libusb_get_active_config_descriptor(device, &descriptor) < 0) - { - lime::error("failed to get config descriptor"); - } - //check for 0x0F and 0x8F endpoints - if(descriptor->bNumInterfaces > 0) - { - libusb_interface_descriptor iface = descriptor->interface[0].altsetting[0]; - for(int i=0; iClose(); - 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) - { - libusb_release_interface(dev_handle, 0); - libusb_close(dev_handle); - dev_handle = 0; - } - #endif - isConnected = false; -} - -/** @brief Returns connection status - @return 1-connection open, 0-connection closed. -*/ -bool ConnectionSTREAM::IsOpen() -{ - #ifndef __unix__ - return USBDevicePrimary->IsOpen() && isConnected; - #else - return isConnected; - #endif -} - -/** @brief Sends given data buffer to chip through USB port. - @param buffer data buffer, must not be longer than 64 bytes. - @param length given buffer size. - @param timeout_ms timeout limit for operation in milliseconds - @return number of bytes sent. -*/ -int ConnectionSTREAM::Write(const unsigned char *buffer, const int length, int timeout_ms) -{ - std::lock_guard lock(mExtraUsbMutex); - long len = length; - if(IsOpen() == false) - return 0; - - unsigned char* wbuffer = new unsigned char[length]; - memcpy(wbuffer, buffer, length); - bulkCtrlInProgress = false; - #ifndef __unix__ - if(bulkCtrlAvailable - && commandsToBulkCtrl.find(buffer[0]) != commandsToBulkCtrl.end()) - { - bulkCtrlInProgress = true; - OutCtrlBulkEndPt->XferData(wbuffer, len); - } - else if(OutCtrlEndPt3) - OutCtrlEndPt3->Write(wbuffer, len); - else - len = 0; - #else - if(bulkCtrlAvailable - && commandsToBulkCtrl.find(buffer[0]) != commandsToBulkCtrl.end()) - { - bulkCtrlInProgress = true; - int actual = 0; - libusb_bulk_transfer(dev_handle, ctrlBulkOutAddr, wbuffer, length, &actual, timeout_ms); - len = actual; - } - else - len = libusb_control_transfer(dev_handle, LIBUSB_REQUEST_TYPE_VENDOR,CTR_W_REQCODE ,CTR_W_VALUE, CTR_W_INDEX, wbuffer, length, timeout_ms); - #endif - delete[] wbuffer; - return len; -} - -/** @brief Reads data coming from the chip through USB port. - @param buffer pointer to array where received data will be copied, array must be - big enough to fit received data. - @param length number of bytes to read from chip. - @param timeout_ms timeout limit for operation in milliseconds - @return number of bytes received. -*/ -int ConnectionSTREAM::Read(unsigned char *buffer, const int length, int timeout_ms) -{ - std::lock_guard lock(mExtraUsbMutex); - long len = length; - if(IsOpen() == false) - return 0; - -#ifndef __unix__ - if(bulkCtrlAvailable && bulkCtrlInProgress) - { - InCtrlBulkEndPt->XferData(buffer, len); - bulkCtrlInProgress = false; - } - else if(InCtrlEndPt3) - InCtrlEndPt3->Read(buffer, len); - else - len = 0; -#else - if(bulkCtrlAvailable && bulkCtrlInProgress) - { - int actual = 0; - libusb_bulk_transfer(dev_handle, ctrlBulkInAddr, buffer, len, &actual, timeout_ms); - len = actual; - bulkCtrlInProgress = false; - } - else - len = libusb_control_transfer(dev_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN ,CTR_R_REQCODE ,CTR_R_VALUE, CTR_R_INDEX, buffer, len, timeout_ms); -#endif - return len; -} - -#ifdef __unix__ -/** @brief Function for handling libusb callbacks -*/ -void callback_libusbtransfer(libusb_transfer *trans) -{ - USBTransferContext *context = reinterpret_cast(trans->user_data); - std::unique_lock lck(context->transferLock); - switch(trans->status) - { - case LIBUSB_TRANSFER_CANCELLED: - //lime::error("Transfer %i canceled", context->id); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - //context->reset(); - break; - case LIBUSB_TRANSFER_COMPLETED: - //if(trans->actual_length == context->bytesExpected) - { - context->bytesXfered = trans->actual_length; - context->done.store(true); - } - break; - case LIBUSB_TRANSFER_ERROR: - lime::error("TRANSFER ERRROR"); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - //lime::error("transfer timed out %i", context->id); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - - break; - case LIBUSB_TRANSFER_OVERFLOW: - lime::error("transfer overflow"); - - break; - case LIBUSB_TRANSFER_STALL: - lime::error("transfer stalled"); - break; - case LIBUSB_TRANSFER_NO_DEVICE: - lime::error("transfer no device"); - - break; - } - lck.unlock(); - context->cv.notify_one(); -} -#endif - -/** - @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, const uint8_t streamBulkInAddr) -{ - int i = 0; - bool contextFound = false; - //find not used context - for(i = 0; iBeginDataXfer((unsigned char*)buffer, length, contexts[i].inOvLap); - } - return i; - #else - unsigned int Timeout = 500; - libusb_transfer *tr = contexts[i].transfer; - libusb_fill_bulk_transfer(tr, dev_handle, streamBulkInAddr, (unsigned char*)buffer, length, callback_libusbtransfer, &contexts[i], Timeout); - contexts[i].done = false; - contexts[i].bytesXfered = 0; - contexts[i].bytesExpected = length; - int status = libusb_submit_transfer(tr); - if(status != 0) - { - lime::error("BEGIN DATA READING %s", libusb_error_name(status)); - contexts[i].used = false; - return -1; - } - #endif - return i; -} - -/** - @brief Waits for asynchronous data reception - @param contextHandle handle of which context data to wait - @param timeout_ms number of miliseconds to wait - @return 1-data received, 0-data not received -*/ -int ConnectionSTREAM::WaitForReading(int contextHandle, unsigned int timeout_ms) -{ - if(contextHandle >= 0 && contexts[contextHandle].used == true) - { - #ifndef __unix__ - int status = 0; - status = contexts[contextHandle].EndPt->WaitForXfer(contexts[contextHandle].inOvLap, timeout_ms); - return status; - #else - auto t1 = chrono::high_resolution_clock::now(); - auto t2 = chrono::high_resolution_clock::now(); - - std::unique_lock lck(contexts[contextHandle].transferLock); - while(contexts[contextHandle].done.load() == false && std::chrono::duration_cast(t2 - t1).count() < timeout_ms) - { - //blocking not to waste CPU - contexts[contextHandle].cv.wait_for(lck, chrono::milliseconds(timeout_ms)); - t2 = chrono::high_resolution_clock::now(); - } - return contexts[contextHandle].done.load() == true; - #endif - } - else - return 0; -} - -/** - @brief Finishes asynchronous data reading from board - @param buffer array where to store received data - @param length number of bytes to read - @param contextHandle handle of which context to finish - @return negative values failure, positive number of bytes received -*/ -int ConnectionSTREAM::FinishDataReading(char *buffer, uint32_t length, int contextHandle) -{ - if(contextHandle >= 0 && contexts[contextHandle].used == true) - { - #ifndef __unix__ - int status = 0; - long len = length; - status = contexts[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contexts[contextHandle].inOvLap, contexts[contextHandle].context); - contexts[contextHandle].used = false; - contexts[contextHandle].reset(); - return len; - #else - length = contexts[contextHandle].bytesXfered; - contexts[contextHandle].used = false; - contexts[contextHandle].reset(); - return length; - #endif - } - else - return 0; -} - -/** - @brief Aborts reading operations -*/ -void ConnectionSTREAM::AbortReading(int ep) -{ -#ifndef __unix__ - 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 -} - -/** - @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, const uint8_t streamBulkOutAddr) -{ - int i = 0; - //find not used context - bool contextFound = false; - for(i = 0; iBeginDataXfer((unsigned char*)buffer, length, contextsToSend[i].inOvLap); - } - return i; - #else - unsigned int Timeout = 500; - libusb_transfer *tr = contextsToSend[i].transfer; - libusb_fill_bulk_transfer(tr, dev_handle, streamBulkOutAddr, (unsigned char*)buffer, length, callback_libusbtransfer, &contextsToSend[i], Timeout); - contextsToSend[i].done = false; - contextsToSend[i].bytesXfered = 0; - contextsToSend[i].bytesExpected = length; - int status = libusb_submit_transfer(tr); - if(status != 0) - { - lime::error("BEGIN DATA SENDING %s", libusb_error_name(status)); - contextsToSend[i].used = false; - return -1; - } - #endif - return i; -} - -/** - @brief Waits for asynchronous data sending - @param contextHandle handle of which context data to wait - @param timeout_ms number of miliseconds to wait - @return 1-data received, 0-data not received -*/ -int ConnectionSTREAM::WaitForSending(int contextHandle, unsigned int timeout_ms) -{ - if( contextsToSend[contextHandle].used == true ) - { -# ifndef __unix__ - int status = 0; - status = contextsToSend[contextHandle].EndPt->WaitForXfer(contextsToSend[contextHandle].inOvLap, timeout_ms); - return status; -# else - auto t1 = chrono::high_resolution_clock::now(); - auto t2 = chrono::high_resolution_clock::now(); - - std::unique_lock lck(contextsToSend[contextHandle].transferLock); - while(contextsToSend[contextHandle].done.load() == false && std::chrono::duration_cast(t2 - t1).count() < timeout_ms) - { - //blocking not to waste CPU - contextsToSend[contextHandle].cv.wait_for(lck, chrono::milliseconds(timeout_ms)); - t2 = chrono::high_resolution_clock::now(); - } - return contextsToSend[contextHandle].done == true; -# endif - } - else - return 0; -} - -/** - @brief Finishes asynchronous data sending to board - @param buffer array where to store received data - @param length number of bytes to read, function changes this value to number of bytes acctually received - @param contextHandle handle of which context to finish - @return false failure, true number of bytes sent -*/ -int ConnectionSTREAM::FinishDataSending(const char *buffer, uint32_t length, int contextHandle) -{ - if( contextsToSend[contextHandle].used == true) - { -#ifndef __unix__ - long len = length; - contextsToSend[contextHandle].EndPt->FinishDataXfer((unsigned char*)buffer, len, contextsToSend[contextHandle].inOvLap, contextsToSend[contextHandle].context); - contextsToSend[contextHandle].used = false; - contextsToSend[contextHandle].reset(); - return len; -#else - length = contextsToSend[contextHandle].bytesXfered; - contextsToSend[contextHandle].used = false; - contextsToSend[contextHandle].reset(); - return length; -#endif - } - else - return 0; -} - -/** - @brief Aborts sending operations -*/ -void ConnectionSTREAM::AbortSending(int ep) -{ -#ifndef __unix__ - 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) - { -#ifdef __unix__ - libusb_device_descriptor desc; - int ret = libusb_get_device_descriptor(libusb_get_device(dev_handle), &desc); - if(ret<0) - lime::error("failed to get device description"); - else if (desc.idProduct == 243) -#else - if (USBDevicePrimary->ProductID == 243) -#endif - { -#ifdef __unix__ - return fx3_usbboot_download((unsigned char*)buffer,length); -#else - char* filename = "fx3fw_image_tmp.img"; - int ret = 0; - std::ofstream myfile(filename, ios::out | ios::binary | ios::trunc); - if (!myfile.is_open()) - { - ReportError("FX3 FW:Unable to create temporary file"); - return -1; - } - myfile.write(buffer,length); - if (myfile.fail()) - { - ReportError("FX3 FW:Unable to write to temporary file"); - ret = -1; - } - myfile.close(); - - if (ret != -1) - { - if ((ret=USBDevicePrimary->DownloadFw(filename, FX3_FWDWNLOAD_MEDIA_TYPE::RAM))!=0) - ReportError("FX3: Failed to upload FW to RAM"); - } - - std::remove(filename); - return ret; -#endif - } - else - { - ReportError("FX3 bootloader NOT detected"); - return -1; - } - } - return LMS64CProtocol::ProgramWrite(buffer,length,programmingMode,device,callback); -} - -#ifdef __unix__ - -#define MAX_FWIMG_SIZE (512 * 1024) // Maximum size of the firmware binary. -#define GET_LSW(v) ((unsigned short)((v) & 0xFFFF)) -#define GET_MSW(v) ((unsigned short)((v) >> 16)) - -#define VENDORCMD_TIMEOUT (5000) // Timeout for each vendor command is set to 5 seconds. - - -int ConnectionSTREAM::ram_write(unsigned char *buf, unsigned int ramAddress, int len) -{ - const int MAX_WRITE_SIZE = (2 * 1024); // Max. size of data that can be written through one vendor command. - int r; - int index = 0; - int size; - - while ( len > 0 ) - { - size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len; - r = libusb_control_transfer(dev_handle, 0x40, 0xA0, GET_LSW(ramAddress), GET_MSW(ramAddress),&buf[index], size, VENDORCMD_TIMEOUT); - if ( r != size ) - { - lime::error("Vendor write to FX3 RAM failed"); - return -1; - } - ramAddress += size; - index += size; - len -= size; - } - return 0; -} - -int ConnectionSTREAM::fx3_usbboot_download(unsigned char *fwBuf, int filesize) -{ - unsigned int *data_p; - unsigned int i, checksum; - unsigned int address, length; - int r, index; - - if ( filesize > MAX_FWIMG_SIZE ) { - ReportError("File size exceeds maximum firmware image size\n"); - return -2; - } - - if ( strncmp((char *)fwBuf,"CY",2) ) { - ReportError("Image does not have 'CY' at start. aborting\n"); - return -4; - } - - if ( fwBuf[2] & 0x01 ) { - ReportError("Image does not contain executable code\n"); - return -5; - } - - if ( !(fwBuf[3] == 0xB0) ) { - ReportError("Not a normal FW binary with checksum\n"); - return -6; - } - - // Run through each section of code, and use vendor commands to download them to RAM. - index = 4; - checksum = 0; - while ( index < filesize ) - { - data_p = (unsigned int *)(fwBuf + index); - length = data_p[0]; - address = data_p[1]; - if (length != 0) - { - for (i = 0; i < length; i++) - checksum += data_p[2 + i]; - r = ram_write(fwBuf + index + 8, address, length * 4); - if (r != 0) - { - ReportError("Failed to download data to FX3 RAM\n"); - return -3; - } - } - else - { - if (checksum != data_p[2]) { - ReportError ("Checksum error in firmware binary\n"); - return -4; - } - - r = libusb_control_transfer(dev_handle, 0x40, 0xA0, GET_LSW(address), GET_MSW(address), NULL,0, VENDORCMD_TIMEOUT); - if ( r != 0 ) - lime::error("Ignored error in control transfer: %d", r); - break; - } - index += (8 + length * 4); - } - - return 0; -} -#endif diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h deleted file mode 100644 index a77f4c8f0..000000000 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAM.h +++ /dev/null @@ -1,193 +0,0 @@ -/** - @file ConnectionSTREAM.h - @author Lime Microsystems - @brief Implementation of STREAM board connection. -*/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fifo.h" -#include - -#define __unix__ -#include "windows.h" - -#ifndef __unix__ -#include "windows.h" -#include "CyAPI.h" -#else -#include -#include -#include -#include -#endif - -namespace lime -{ - -#define USB_MAX_CONTEXTS 64 //maximum number of contexts for asynchronous transfers - -/** @brief Wrapper class for holding USB asynchronous transfers contexts -*/ -class USBTransferContext -{ -public: - USBTransferContext() : used(false) - { - id = idCounter++; -#ifndef __unix__ - inOvLap = new OVERLAPPED; - memset(inOvLap, 0, sizeof(OVERLAPPED)); - inOvLap->hEvent = CreateEvent(NULL, false, false, NULL); - context = NULL; - EndPt = nullptr; -#else - transfer = libusb_alloc_transfer(0); - bytesXfered = 0; - bytesExpected = 0; - done = 0; -#endif - } - ~USBTransferContext() - { -#ifndef __unix__ - CloseHandle(inOvLap->hEvent); - delete inOvLap; -#else - libusb_free_transfer(transfer); -#endif - } - bool reset() - { - if(used) - return false; -#ifndef __unix__ - CloseHandle(inOvLap->hEvent); - memset(inOvLap, 0, sizeof(OVERLAPPED)); - inOvLap->hEvent = CreateEvent(NULL, false, false, NULL); -#endif - return true; - } - bool used; - int id; - static int idCounter; -#ifndef __unix__ - PUCHAR context; - CCyUSBEndPoint* EndPt; - OVERLAPPED* inOvLap; -#else - libusb_transfer* transfer; - long bytesXfered; - long bytesExpected; - std::atomic done; - std::mutex transferLock; - std::condition_variable cv; -#endif -}; - -class ConnectionSTREAM : public ILimeSDRStreaming -{ -public: - ConnectionSTREAM(void* arg, const std::string &vidpid, const std::string &serial, const unsigned index); - ~ConnectionSTREAM(void); - void VersionCheck(void); - - int Open(const std::string &vidpid, const std::string &serial, const unsigned index); - void Close(); - bool IsOpen(); - int GetOpenedIndex(); - - 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; - - //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 epIndex, int timeout_ms = 100)override; -protected: - 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, 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(int ep); - - 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(int ep); - - int ResetStreamBuffers() override; - eConnectionType GetType(void) {return USB_PORT;} - - double DetectRefClk(void); - - USBTransferContext contexts[USB_MAX_CONTEXTS]; - USBTransferContext contextsToSend[USB_MAX_CONTEXTS]; - - 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[MAX_EP_CNT]; - CCyUSBEndPoint* OutEndPt[MAX_EP_CNT]; - - CCyUSBEndPoint* InCtrlBulkEndPt; - CCyUSBEndPoint* OutCtrlBulkEndPt; -#else - libusb_device_handle* dev_handle; //a device handle - libusb_context* ctx; //a libusb session - int read_firmware_image(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); -#endif - static const uint8_t ctrlBulkOutAddr; - static const uint8_t ctrlBulkInAddr; - static const std::set commandsToBulkCtrlHw1; - static const std::set commandsToBulkCtrlHw2; - std::set commandsToBulkCtrl; - bool bulkCtrlInProgress; - bool bulkCtrlAvailable; - std::mutex mExtraUsbMutex; -}; - -class ConnectionSTREAMEntry : public ConnectionRegistryEntry -{ -public: - ConnectionSTREAMEntry(void); - ConnectionSTREAMEntry(const std::string entryName); - virtual ~ConnectionSTREAMEntry(void); - virtual std::vector enumerate(const ConnectionHandle& hint); - virtual IConnection* make(const ConnectionHandle& handle); -protected: -#ifndef __unix__ - std::string DeviceName(unsigned int index); - void *ctx; //not used, just for mirroring unix -#else - libusb_context* ctx; //a libusb session - std::thread mUSBProcessingThread; - void handle_libusb_events(); - std::atomic mProcessUSBEvents; -#endif -}; - -} diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp deleted file mode 100644 index 20812abbc..000000000 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMEntry.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/** - @file ConnectionSTREAMEntry.cpp - @author Lime Microsystems - @brief Implementation of STREAM board connection. -*/ - -#include "ConnectionSTREAM.h" -#include "Logger.h" - -using namespace lime; - -#ifdef __unix__ -void ConnectionSTREAMEntry::handle_libusb_events() -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 250000; - while(mProcessUSBEvents.load() == true) - { - int r = libusb_handle_events_timeout_completed(ctx, &tv, NULL); - if(r != 0) lime::error("error libusb_handle_events %s", libusb_strerror(libusb_error(r))); - } -} -#endif // __UNIX__ - -//! make a static-initialized entry in the registry -void __loadConnectionSTREAMEntry(void) //TODO fixme replace with LoadLibrary/dlopen -{ -static ConnectionSTREAMEntry STREAMEntry; -} - -int USBTransferContext::idCounter = 0; - -ConnectionSTREAMEntry::ConnectionSTREAMEntry(void): - ConnectionRegistryEntry("STREAM") -{ -#ifdef __unix__ - int r = libusb_init(&ctx); //initialize the library for the session we just declared - if(r < 0) - lime::error("Init Error %i", r); //there was an error - libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation - mProcessUSBEvents.store(true); - mUSBProcessingThread = std::thread(&ConnectionSTREAMEntry::handle_libusb_events, this); -#endif -} - -ConnectionSTREAMEntry::ConnectionSTREAMEntry(const std::string entryName): - ConnectionRegistryEntry(entryName) -{ -#ifdef __unix__ - int r = libusb_init(&ctx); //initialize the library for the session we just declared - if(r < 0) - lime::error("Init Error %i", r); //there was an error - libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation - mProcessUSBEvents.store(true); - mUSBProcessingThread = std::thread(&ConnectionSTREAMEntry::handle_libusb_events, this); -#endif -} - -ConnectionSTREAMEntry::~ConnectionSTREAMEntry(void) -{ -#ifdef __unix__ - mProcessUSBEvents.store(false); - mUSBProcessingThread.join(); - libusb_exit(ctx); -#endif -} - -#ifndef __unix__ -/** @return name of usb device as string. - @param index device index in list -*/ -std::string ConnectionSTREAMEntry::DeviceName(unsigned int index) -{ - std::string name; - char tempName[USB_STRING_MAXLEN]; - CCyUSBDevice device; - if (index >= device.DeviceCount()) - return ""; - - for (int i = 0; i < USB_STRING_MAXLEN; ++i) - tempName[i] = device.DeviceName[i]; - if (device.bSuperSpeed == true) - name = "USB 3.0"; - else if (device.bHighSpeed == true) - name = "USB 2.0"; - else - name = "USB"; - name += " ("; - name += tempName; - name += ")"; - return name; -} -#endif - -std::vector ConnectionSTREAMEntry::enumerate(const ConnectionHandle &hint) -{ - std::vector handles; - -#ifndef __unix__ - CCyUSBDevice device; - if (device.DeviceCount()) - { - for (int i = 0; i= 0 && hint.index != i) - continue; - if (device.IsOpen()) - device.Close(); - device.Open(i); - ConnectionHandle handle; - handle.media = "USB"; - handle.name = DeviceName(i); - handle.index = i; - std::wstring ws(device.SerialNumber); - handle.serial = std::string(ws.begin(),ws.end()); - if (hint.serial.empty() or hint.serial == handle.serial) - { - handles.push_back(handle); //filter on serial - } - device.Close(); - } - } -#else - libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices - int usbDeviceCount = libusb_get_device_list(ctx, &devs); - - if (usbDeviceCount < 0) { - lime::error("failed to get libusb device list: %s", libusb_strerror(libusb_error(usbDeviceCount))); - return handles; - } - - for(int i=0; i 0) handle.name = std::string(data, size_t(r)); - - r = std::sprintf(data, "%.4x:%.4x", int(vid), int(pid)); - if (r > 0) handle.addr = std::string(data, size_t(r)); - - if (desc.iSerialNumber > 0) - { - r = libusb_get_string_descriptor_ascii(tempDev_handle,desc.iSerialNumber,(unsigned char*)data, sizeof(data)); - if(r<0) - lime::error("failed to get serial number"); - else - handle.serial = std::string(data, size_t(r)); - } - libusb_close(tempDev_handle); - - //add handle conditionally, filter by serial number - if (hint.serial.empty() or hint.serial == handle.serial) - { - handles.push_back(handle); - } - } - } - - libusb_free_device_list(devs, 1); -#endif - return handles; -} - -IConnection *ConnectionSTREAMEntry::make(const ConnectionHandle &handle) -{ - return new ConnectionSTREAM(ctx, handle.addr, handle.serial, handle.index); -} diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMImages.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMImages.cpp deleted file mode 100644 index d7a3f5f78..000000000 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMImages.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - @file ConnectionSTREAMImages.cpp - @author Lime Microsystems - @brief Image updating and version checking -*/ - -#include "ConnectionSTREAM.h" -#include "ErrorReporting.h" -#include "SystemResources.h" -#include "LMS64CProtocol.h" -#include "LMSBoards.h" -#include "Logger.h" -#include -#include - -using namespace lime; - -/*! - * The entry structure that describes a board revision and its fw/gw images - */ -struct ConnectionSTREAMImageEntry -{ - eLMS_DEV dev; - int hw_rev; - - int fw_ver; - const char *fw_img; - - int gw_ver; - int gw_rev; - const char *gw_rbf; -}; - -/*! - * Lookup the board information given hardware type and revision. - * Edit each entry for supported hardware and image updates. - */ -static const ConnectionSTREAMImageEntry &lookupImageEntry(const LMS64CProtocol::LMSinfo &info) -{ - static const std::vector imageEntries = { - ConnectionSTREAMImageEntry({LMS_DEV_UNKNOWN, -1, -1, "Unknown-USB.img", -1, -1, "Unknown-USB.rbf"}), - ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 4, 3, "LimeSDR-USB_HW_1.3_r3.0.img", 2, 8, "LimeSDR-USB_HW_1.4_r2.8.rbf"}), - ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 3, 3, "LimeSDR-USB_HW_1.3_r3.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}), - ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 2, 3, "LimeSDR-USB_HW_1.2_r3.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}), - ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 1, 7, "LimeSDR-USB_HW_1.1_r7.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}), - ConnectionSTREAMImageEntry({LMS_DEV_STREAM, 3, 8, "STREAM-USB_HW_1.1_r8.0.img", 1, 2, "STREAM-USB_HW_1.3_r1.2.rbf"})}; - - for(const auto &iter : imageEntries) - { - if (info.device == iter.dev and info.hardware == iter.hw_rev) - { - return iter; - } - } - - return imageEntries.front(); //the -1 unknown entry -} - -void ConnectionSTREAM::VersionCheck(void) -{ - const auto info = this->GetInfo(); - const auto &entry = lookupImageEntry(info); - - //an entry match was not found - if (entry.dev == LMS_DEV_UNKNOWN) - { - lime::error("Unsupported hardware connected: %s[HW=%d]", GetDeviceName(info.device), info.hardware); - return; - } - - //check and warn about firmware mismatch problems - if (info.firmware != entry.fw_ver) lime::warning( - "Firmware version mismatch!\n" - " Expected firmware version %d, but found version %d\n" - " Follow the FW and FPGA upgrade instructions:\n" - " http://wiki.myriadrf.org/Lime_Suite#Flashing_images\n" - " Or run update on the command line: LimeUtil --update\n", - entry.fw_ver, info.firmware); - - //check and warn about gateware mismatch problems - const auto fpgaInfo = this->GetFPGAInfo(); - if (fpgaInfo.gatewareVersion != entry.gw_ver - || fpgaInfo.gatewareRevision != entry.gw_rev) lime::warning( - "Gateware version mismatch!\n" - " Expected gateware version %d, revision %d\n" - " But found version %d, revision %d\n" - " Follow the FW and FPGA upgrade instructions:\n" - " http://wiki.myriadrf.org/Lime_Suite#Flashing_images\n" - " Or run update on the command line: LimeUtil --update\n", - entry.gw_ver, entry.gw_rev, fpgaInfo.gatewareVersion, fpgaInfo.gatewareRevision); -} - -static bool programmingCallbackStream( - int bsent, int btotal, const char* progressMsg, - const std::string &image, - IConnection::ProgrammingCallback callback) -{ - const auto msg = std::string(progressMsg) + " (" + image + ")"; - return callback(bsent, btotal, msg.c_str()); -} - -int ConnectionSTREAM::ProgramUpdate(const bool download, IConnection::ProgrammingCallback callback) -{ - const auto info = this->GetInfo(); - const auto &entry = lookupImageEntry(info); - - //an entry match was not found - if (entry.dev == LMS_DEV_UNKNOWN) - { - return lime::ReportError("Unsupported hardware connected: %s[HW=%d]", GetDeviceName(info.device), info.hardware); - } - - //download images when missing - if (download) - { - const std::vector images = {entry.fw_img, entry.gw_rbf}; - for (const auto &image : images) - { - if (not lime::locateImageResource(image).empty()) continue; - const std::string msg("Downloading: " + image); - if (callback) callback(0, 1, msg.c_str()); - int ret = lime::downloadImageResource(image); - if (ret != 0) return ret; //error set by download call - if (callback) callback(1, 1, "Done!"); - } - } - - //load firmware into flash - { - //open file - std::ifstream file; - const auto path = lime::locateImageResource(entry.fw_img); - file.open(path.c_str(), std::ios::in | std::ios::binary); - if (not file.good()) return lime::ReportError("Error opening %s", path.c_str()); - - //read file - std::streampos fileSize; - file.seekg(0, std::ios::end); - fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector progData(fileSize, 0); - file.read(progData.data(), fileSize); - - int device = LMS64CProtocol::FX3; //FX3 - int progMode = 2; //Firmware to FLASH - using namespace std::placeholders; - const auto cb = std::bind(&programmingCallbackStream, _1, _2, _3, path, callback); - auto status = this->ProgramWrite(progData.data(), progData.size(), progMode, device, cb); - if (status != 0) return status; - } - - //load gateware into flash - { - //open file - std::ifstream file; - const auto path = lime::locateImageResource(entry.gw_rbf); - file.open(path.c_str(), std::ios::in | std::ios::binary); - if (not file.good()) return lime::ReportError("Error opening %s", path.c_str()); - - //read file - std::streampos fileSize; - file.seekg(0, std::ios::end); - fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector progData(fileSize, 0); - file.read(progData.data(), fileSize); - - int device = LMS64CProtocol::FPGA; //Altera FPGA - int progMode = 1; //Bitstream to FLASH - using namespace std::placeholders; - const auto cb = std::bind(&programmingCallbackStream, _1, _2, _3, path, callback); - auto status = this->ProgramWrite(progData.data(), progData.size(), progMode, device, cb); - if (status != 0) return status; - } - - //Reset FX3, FPGA should be reloaded on boot - { - int device = LMS64CProtocol::FX3; //FX3 - auto status = this->ProgramWrite(nullptr, 0, 0, device, nullptr); - if (status != 0) return status; - } - - return 0; -} diff --git a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp b/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp deleted file mode 100644 index cf68c3969..000000000 --- a/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMing.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/** - @file ConnectionSTREAMing.cpp - @author Lime Microsystems - @brief Implementation of STREAM board connection (streaming API) -*/ - -#include "ConnectionSTREAM.h" -#include "fifo.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "ErrorReporting.h" -#include "Logger.h" - -using namespace lime; -using namespace std; - -/** @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) -{ - 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; - - clocks[0].index = 0; - clocks[0].outFrequency = rxInterfaceClk; - clocks[1].index = 1; - clocks[1].outFrequency = rxInterfaceClk; - clocks[1].phaseShift_deg = rxPhase; - if (lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2)!=0) - return -1; - - clocks[0].index = 0; - clocks[0].outFrequency = txInterfaceClk; - clocks[1].index = 1; - clocks[1].outFrequency = txInterfaceClk; - clocks[1].phaseShift_deg = txPhase; - if (lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2)!=0) - return -1; - - return 0; -} - -/** @brief Configures FPGA PLLs to LimeLight interface frequency -*/ -int ConnectionSTREAM::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz) -{ - 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 }; - const double rxPhC2[] = { -1 / 6e6, 1.24e-6 }; - const double txPhC1[] = { 89.75, 89.61 }; - const double txPhC2[] = { -3.0e-7, 2.71e-7 }; - - 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(); - bool phaseSearch = false; - 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; - - if (phaseSearch) - { - dataWr.resize(spiAddr.size()); - dataRd.resize(spiAddr.size()); - //backup registers - dataWr[0] = (uint32_t(0x0020) << 16); - ReadLMS7002MSPI(dataWr.data(), ®20, 1, channel); - - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write - WriteLMS7002MSPI(dataWr.data(), 1, channel); - - for (int i = 0; i < bakRegCnt; ++i) - dataWr[i] = (spiAddr[i] << 16); - 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}; - //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 - WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel); - } - lime::fpga::FPGA_PLL_clock clocks[2]; - clocks[0].index = 0; - clocks[0].outFrequency = rxInterfaceClk; - 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; - status = lime::fpga::SetPllFrequency(this, pll_ind+1, rxInterfaceClk, clocks, 2); - } - else - 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}; - 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 - WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel); - } - - lime::fpga::FPGA_PLL_clock clocks[2]; - clocks[0].index = 0; - clocks[0].outFrequency = txInterfaceClk; - clocks[0].phaseShift_deg = 0; - clocks[1].index = 1; - clocks[1].outFrequency = txInterfaceClk; - if (this->chipVersion == 0x3841) - clocks[1].phaseShift_deg = txPhC1[1] + txPhC2[1] * txInterfaceClk; - else - clocks[1].phaseShift_deg = txPhC1[0] + txPhC2[0] * txInterfaceClk; - - if (phaseSearch) - { - clocks[1].findPhase = true; - WriteRegister(0x000A, 0x0200); - } - status = lime::fpga::SetPllFrequency(this, pll_ind, txInterfaceClk, clocks, 2); - } - else - 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 - WriteLMS7002MSPI(dataWr.data(), bakRegCnt, channel); - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write - WriteLMS7002MSPI(dataWr.data(), 1, channel); - WriteRegister(0x000A, 0); - } - return status; -} - -int ConnectionSTREAM::ResetStreamBuffers() -{ - //USB FIFO reset - LMS64CProtocol::GenericPacket ctrPkt; - ctrPkt.cmd = CMD_USB_FIFO_RST; - ctrPkt.outBuffer.push_back(0x00); - return TransferPacket(ctrPkt); -} - -int ConnectionSTREAM::ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms) -{ - const unsigned char ep = 0x81; - fpga::StopStreaming(this, epIndex); - - ResetStreamBuffers(); - WriteRegister(0x0008, 0x0100 | 0x2); - WriteRegister(0x0007, 1); - fpga::StartStreaming(this, epIndex); - - int totalBytesReceived = ReceiveData(buffer,length, epIndex, timeout_ms); - fpga::StopStreaming(this, epIndex); - AbortReading(ep); - - return totalBytesReceived; -} - -/** @brief Function dedicated for receiving data samples from board - @param stream a pointer to an active receiver stream -*/ -void ConnectionSTREAM::ReceivePacketsLoop(Streamer* stream) -{ - //at this point FPGA has to be already configured to output samples - 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; - - float latency=0; - for (int i = 0; i < chCount; i++) - 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; - try - { - chFrames.resize(chCount); - } - catch (const std::bad_alloc &ex) - { - ReportError("Error allocating Rx buffers, not enough memory"); - return; - } - - int activeTransfers = 0; - for (int i = 0; iBeginDataReading(&buffers[i*bufferSize], bufferSize, ep); - ++activeTransfers; - } - - int bi = 0; - unsigned long totalBytesReceived = 0; //for data rate calculation - - auto t1 = chrono::high_resolution_clock::now(); - auto t2 = t1; - - std::mutex txFlagsLock; - condition_variable resetTxFlags; - //worker thread for reseting late Tx packet flags - std::thread txReset([](ILimeSDRStreaming* port, - atomic *terminate, - mutex *spiLock, - condition_variable *doWork) - { - uint32_t reg9; - port->ReadRegister(0x0009, reg9); - const uint32_t addr[] = {0x0009, 0x0009}; - 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, &stream->terminateRx, &txFlagsLock, &resetTxFlags); - - int resetFlagsDelay = 128; - uint64_t prevTs = 0; - while (stream->terminateRx.load() == false) - { - if(stream->generateData.load()) - { - if(activeTransfers == 0) //stop FPGA when last transfer completes - 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; imRxStreams[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); - } - } - this_thread::sleep_for(chrono::milliseconds(100)); - } - int32_t bytesReceived = 0; - if(handles[bi] >= 0) - { - 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 - for(auto value: stream->mRxStreams) - value->underflow++; - } - bool txLate=false; - for (uint8_t pktIndex = 0; pktIndex < bytesReceived / sizeof(FPGA_DataPacket); ++pktIndex) - { - const FPGA_DataPacket* pkt = (FPGA_DataPacket*)&buffers[bi*bufferSize]; - const uint8_t byte0 = pkt[pktIndex].reserved[0]; - if ((byte0 & (1 << 3)) != 0 && !txLate) //report only once per batch - { - txLate = true; - if(resetFlagsDelay > 0) - --resetFlagsDelay; - else - { - lime::info("L %llu", (unsigned long long)pkt[pktIndex].counter); - resetTxFlags.notify_one(); - resetFlagsDelay = packetsToBatch*buffersCount; - 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 - printf("\tRx pktLoss: ts diff: %li pktLoss: %i\n", pkt[pktIndex].counter - prevTs, packetLoss); -#endif - for(auto value: stream->mRxStreams) - value->pktLost += packetLoss; - } - prevTs = pkt[pktIndex].counter; - stream->rxLastTimestamp.store(prevTs); - //parse samples - vector dest(chCount); - for(uint8_t c=0; cmRxStreams[ch]->Write((const void*)chFrames[ch].samples, samplesCount, &meta, 100); - if(samplesPushed != samplesCount) - stream->mRxStreams[ch]->overflow++; - } - } - // Re-submit this request to keep the queue full - if(not stream->generateData.load()) - { - if(activeTransfers == 0) //reactivate FPGA and USB transfers - fpga::StartStreaming(this, chipID); - for(int i=0; iBeginDataReading(&buffers[bi*bufferSize], bufferSize, ep); - bi = (bi + 1) & (buffersCount-1); - ++activeTransfers; - } - } - else - { - handles[bi] = -1; - bi = (bi + 1) & (buffersCount-1); - } - t2 = chrono::high_resolution_clock::now(); - auto timePeriod = std::chrono::duration_cast(t2 - t1).count(); - if (timePeriod >= 1000) - { - t1 = t2; - //total number of bytes sent per second - double dataRate = 1000.0*totalBytesReceived / timePeriod; -#ifndef NDEBUG - printf("Rx: %.3f MB/s\n", dataRate / 1000000.0); -#endif - totalBytesReceived = 0; - stream->rxDataRate_Bps.store((uint32_t)dataRate); - } - } - AbortReading(ep); - for (int j = 0; j= 0) - { - this->WaitForReading(handles[bi], 1000); - this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]); - } - bi = (bi + 1) & (buffersCount-1); - } - resetTxFlags.notify_one(); - txReset.join(); - stream->rxDataRate_Bps.store(0); -} - -/** @brief Functions dedicated for transmitting packets to board - @param stream an active transmit stream -*/ -void ConnectionSTREAM::TransmitPacketsLoop(Streamer* stream) -{ - //at this point FPGA has to be already configured to output samples - const uint8_t maxChannelCount = 2; - 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 += stream->mTxStreams[i]->config.performanceLatency/chCount; - - const unsigned tmp_cnt = (latency * 6)+0.5; - - const uint8_t buffersCount = 16; // must be power of 2 - const uint8_t packetsToBatch = (1< handles(buffersCount, 0); - vector bufferUsed(buffersCount, 0); - vector samples[maxChannelCount]; - vector buffers; - try - { - for(int i=0; iterminateTx.load() != true) - { - if (bufferUsed[bi]) - { - 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(iterminateTx.load() != true) - { - IStreamChannel::Metadata meta; - FPGA_DataPacket* pkt = reinterpret_cast(&buffers[bi*bufferSize]); - bool badSamples = false; - for(int ch=0; chmTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); - if (samplesPopped != maxSamplesBatch) - { - 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 (badSamples) - continue; - if(stream->terminateTx.load() == true) //early termination - break; - pkt[i].counter = meta.timestamp; - pkt[i].reserved[0] = 0; - //by default ignore timestamps - const int ignoreTimestamp = !(meta.flags & IStreamChannel::Metadata::SYNC_TIMESTAMP); - pkt[i].reserved[0] |= ((int)ignoreTimestamp << 4); //ignore timestamp - - vector src(chCount); - for(uint8_t c=0; cBeginDataSending(&buffers[bi*bufferSize], bufferSize, ep); - bufferUsed[bi] = true; - - t2 = chrono::high_resolution_clock::now(); - auto timePeriod = std::chrono::duration_cast(t2 - t1).count(); - if (timePeriod >= 1000) - { - //total number of bytes sent per second - float dataRate = 1000.0*totalBytesSent / timePeriod; - stream->txDataRate_Bps.store(dataRate); - totalBytesSent = 0; - t1 = t2; -#ifndef NDEBUG - printf("Tx: %.3f MB/s\n", dataRate / 1000000.0); -#endif - } - bi = (bi + 1) & (buffersCount-1); - } - - // Wait for all the queued requests to be cancelled - AbortSending(ep); - for (int j = 0; jWaitForSending(handles[bi], 1000); - this->FinishDataSending(&buffers[bi*bufferSize], bufferSize, handles[bi]); - } - bi = (bi + 1) & (buffersCount-1); - } - stream->txDataRate_Bps.store(0); -} - diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp deleted file mode 100644 index 0c30f3119..000000000 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDR.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/** -@file Connection_uLimeSDR.cpp -@author Lime Microsystems -@brief Implementation of uLimeSDR board connection. -*/ - -#include "Connection_uLimeSDR.h" -#include "ErrorReporting.h" -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace lime; - -#define __unix__ - -Connection_uLimeSDR::Connection_uLimeSDR(void *arg) -{ - RxLoopFunction = bind(&Connection_uLimeSDR::ReceivePacketsLoop, this, std::placeholders::_1); - TxLoopFunction = bind(&Connection_uLimeSDR::TransmitPacketsLoop, this, std::placeholders::_1); - - isConnected = false; - - mStreamWrEndPtAddr = 0x03; - mStreamRdEndPtAddr = 0x83; - isConnected = false; - txSize = 0; - rxSize = 0; -#ifndef __unix__ - mFTHandle = NULL; -#else - dev_handle = 0; - devs = 0; - mUsbCounter = 0; - ctx = (libusb_context *)arg; -#endif -} - -/** @brief Initializes port type and object necessary to communicate to usb device. -*/ -Connection_uLimeSDR::Connection_uLimeSDR(void *arg, const unsigned index, const int vid, const int pid) -{ - RxLoopFunction = bind(&Connection_uLimeSDR::ReceivePacketsLoop, this, std::placeholders::_1); - TxLoopFunction = bind(&Connection_uLimeSDR::TransmitPacketsLoop, this, std::placeholders::_1); - mExpectedSampleRate = 0; - isConnected = false; - - mStreamWrEndPtAddr = 0x03; - mStreamRdEndPtAddr = 0x83; - isConnected = false; - txSize = 0; - rxSize = 0; -#ifndef __unix__ - mFTHandle = NULL; -#else - dev_handle = 0; - devs = 0; - mUsbCounter = 0; - ctx = (libusb_context *)arg; -#endif - if (this->Open(index, vid, pid) != 0) - std::cerr << GetLastErrorMessage() << std::endl; - this->SetReferenceClockRate(52e6); - GetChipVersion(); -} - -/** @brief Closes connection to chip and deallocates used memory. -*/ -Connection_uLimeSDR::~Connection_uLimeSDR() -{ - Close(); -} -#ifdef __unix__ -int Connection_uLimeSDR::FT_FlushPipe(unsigned char ep) -{ - int actual = 0; - unsigned char wbuffer[20]={0}; - - mUsbCounter++; - wbuffer[0] = (mUsbCounter)&0xFF; - wbuffer[1] = (mUsbCounter>>8)&0xFF; - wbuffer[2] = (mUsbCounter>>16)&0xFF; - wbuffer[3] = (mUsbCounter>>24)&0xFF; - wbuffer[4] = ep; - libusb_bulk_transfer(dev_handle, 0x01, wbuffer, 20, &actual, 1000); - if (actual != 20) - return -1; - - mUsbCounter++; - wbuffer[0] = (mUsbCounter)&0xFF; - wbuffer[1] = (mUsbCounter>>8)&0xFF; - wbuffer[2] = (mUsbCounter>>16)&0xFF; - wbuffer[3] = (mUsbCounter>>24)&0xFF; - wbuffer[4] = ep; - wbuffer[5] = 0x03; - libusb_bulk_transfer(dev_handle, 0x01, wbuffer, 20, &actual, 1000); - if (actual != 20) - return -1; - return 0; -} - -int Connection_uLimeSDR::FT_SetStreamPipe(unsigned char ep, size_t size) -{ - - int actual = 0; - unsigned char wbuffer[20]={0}; - - mUsbCounter++; - wbuffer[0] = (mUsbCounter)&0xFF; - wbuffer[1] = (mUsbCounter>>8)&0xFF; - wbuffer[2] = (mUsbCounter>>16)&0xFF; - wbuffer[3] = (mUsbCounter>>24)&0xFF; - wbuffer[4] = ep; - libusb_bulk_transfer(dev_handle, 0x01, wbuffer, 20, &actual, 1000); - if (actual != 20) - return -1; - - mUsbCounter++; - wbuffer[0] = (mUsbCounter)&0xFF; - wbuffer[1] = (mUsbCounter>>8)&0xFF; - wbuffer[2] = (mUsbCounter>>16)&0xFF; - wbuffer[3] = (mUsbCounter>>24)&0xFF; - wbuffer[5] = 0x02; - wbuffer[8] = (size)&0xFF; - wbuffer[9] = (size>>8)&0xFF; - wbuffer[10] = (size>>16)&0xFF; - wbuffer[11] = (size>>24)&0xFF; - libusb_bulk_transfer(dev_handle, 0x01, wbuffer, 20, &actual, 1000); - if (actual != 20) - return -1; - return 0; -} -#endif - -/** @brief Tries to open connected USB device and find communication endpoints. -@return Returns 0-Success, other-EndPoints not found or device didn't connect. -*/ -int Connection_uLimeSDR::Open(const unsigned index, const int vid, const int pid) -{ -#ifndef __unix__ - DWORD devCount; - FT_STATUS ftStatus = FT_OK; - DWORD dwNumDevices = 0; - // Open a device - ftStatus = FT_Create(0, FT_OPEN_BY_INDEX, &mFTHandle); - if (FT_FAILED(ftStatus)) - { - ReportError(ENODEV, "Failed to list USB Devices"); - return -1; - } - FT_AbortPipe(mFTHandle, mStreamRdEndPtAddr); - FT_AbortPipe(mFTHandle, 0x82); - FT_AbortPipe(mFTHandle, 0x02); - FT_AbortPipe(mFTHandle, mStreamWrEndPtAddr); - FT_SetStreamPipe(mFTHandle, FALSE, FALSE, 0x82, 64); - FT_SetStreamPipe(mFTHandle, FALSE, FALSE, 0x02, 64); - FT_SetPipeTimeout(mFTHandle, 0x02, 500); - FT_SetPipeTimeout(mFTHandle, 0x82, 500); - isConnected = true; - return 0; -#else - dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); - - if(dev_handle == nullptr) - return ReportError(ENODEV, "libusb_open failed"); - libusb_reset_device(dev_handle); - if(libusb_kernel_driver_active(dev_handle, 1) == 1) //find out if kernel driver is attached - { - printf("Kernel Driver Active\n"); - if(libusb_detach_kernel_driver(dev_handle, 1) == 0) //detach it - printf("Kernel Driver Detached!\n"); - } - int r = libusb_claim_interface(dev_handle, 1); //claim interface 0 (the first) of device - if(r < 0) - { - printf("Cannot Claim Interface\n"); - return ReportError(-1, "Cannot claim interface - %s", libusb_strerror(libusb_error(r))); - } - r = libusb_claim_interface(dev_handle, 1); //claim interface 0 (the first) of device - if(r < 0) - { - printf("Cannot Claim Interface\n"); - return ReportError(-1, "Cannot claim interface - %s", libusb_strerror(libusb_error(r))); - } - printf("Claimed Interface\n"); - - FT_SetStreamPipe(0x82,64); - FT_SetStreamPipe(0x02,64); - isConnected = true; - return 0; -#endif -} - -/** @brief Closes communication to device. -*/ -void Connection_uLimeSDR::Close() -{ -#ifndef __unix__ - FT_Close(mFTHandle); -#else - if(dev_handle != 0) - { - FT_FlushPipe(mStreamRdEndPtAddr); - FT_FlushPipe(0x82); - libusb_release_interface(dev_handle, 1); - libusb_close(dev_handle); - dev_handle = 0; - } -#endif - isConnected = false; -} - -/** @brief Returns connection status -@return 1-connection open, 0-connection closed. -*/ -bool Connection_uLimeSDR::IsOpen() -{ - return isConnected; -} - -#ifndef __unix__ -int Connection_uLimeSDR::ReinitPipe(unsigned char ep) -{ - FT_AbortPipe(mFTHandle, ep); - FT_FlushPipe(mFTHandle, ep); - FT_SetStreamPipe(mFTHandle, FALSE, FALSE, ep, 64); - return 0; -} -#endif - -/** @brief Sends given data buffer to chip through USB port. -@param buffer data buffer, must not be longer than 64 bytes. -@param length given buffer size. -@param timeout_ms timeout limit for operation in milliseconds -@return number of bytes sent. -*/ -int Connection_uLimeSDR::Write(const unsigned char *buffer, const int length, int timeout_ms) -{ - std::lock_guard lock(mExtraUsbMutex); - long len = 0; - if (IsOpen() == false) - return 0; - -#ifndef __unix__ - // Write to channel 1 ep 0x02 - ULONG ulBytesWrite = 0; - FT_STATUS ftStatus = FT_OK; - OVERLAPPED vOverlapped = { 0 }; - FT_InitializeOverlapped(mFTHandle, &vOverlapped); - ftStatus = FT_WritePipe(mFTHandle, 0x02, (unsigned char*)buffer, length, &ulBytesWrite, &vOverlapped); - if (ftStatus != FT_IO_PENDING) - { - FT_ReleaseOverlapped(mFTHandle, &vOverlapped); - ReinitPipe(0x02); - return -1; - } - - DWORD dwRet = WaitForSingleObject(vOverlapped.hEvent, timeout_ms); - if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_TIMEOUT) - { - if (GetOverlappedResult(mFTHandle, &vOverlapped, &ulBytesWrite, FALSE) == FALSE) - { - ReinitPipe(0x02); - ulBytesWrite = -1; - } - } - else - { - ReinitPipe(0x02); - ulBytesWrite = -1; - } - FT_ReleaseOverlapped(mFTHandle, &vOverlapped); - return ulBytesWrite; -#else - unsigned char* wbuffer = new unsigned char[length]; - memcpy(wbuffer, buffer, length); - int actual = 0; - libusb_bulk_transfer(dev_handle, 0x02, wbuffer, length, &actual, timeout_ms); - len = actual; - delete[] wbuffer; - return len; -#endif -} - -/** @brief Reads data coming from the chip through USB port. -@param buffer pointer to array where received data will be copied, array must be -big enough to fit received data. -@param length number of bytes to read from chip. -@param timeout_ms timeout limit for operation in milliseconds -@return number of bytes received. -*/ - -int Connection_uLimeSDR::Read(unsigned char *buffer, const int length, int timeout_ms) -{ - std::lock_guard lock(mExtraUsbMutex); - long len = length; - if(IsOpen() == false) - return 0; -#ifndef __unix__ - // - // Read from channel 1 ep 0x82 - // - ULONG ulBytesRead = 0; - FT_STATUS ftStatus = FT_OK; - OVERLAPPED vOverlapped = { 0 }; - FT_InitializeOverlapped(mFTHandle, &vOverlapped); - ftStatus = FT_ReadPipe(mFTHandle, 0x82, buffer, length, &ulBytesRead, &vOverlapped); - if (ftStatus != FT_IO_PENDING) - { - FT_ReleaseOverlapped(mFTHandle, &vOverlapped); - ReinitPipe(0x82); - return -1;; - } - - DWORD dwRet = WaitForSingleObject(vOverlapped.hEvent, timeout_ms); - if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_TIMEOUT) - { - if (GetOverlappedResult(mFTHandle, &vOverlapped, &ulBytesRead, FALSE)==FALSE) - { - ReinitPipe(0x82); - ulBytesRead = -1; - } - } - else - { - ReinitPipe(0x82); - ulBytesRead = -1; - } - FT_ReleaseOverlapped(mFTHandle, &vOverlapped); - return ulBytesRead; -#else - int actual = 0; - libusb_bulk_transfer(dev_handle, 0x82, buffer, len, &actual, timeout_ms); - len = actual; -#endif - return len; -} - -#ifdef __unix__ -/** @brief Function for handling libusb callbacks -*/ -static void callback_libusbtransfer(libusb_transfer *trans) -{ - Connection_uLimeSDR::USBTransferContext *context = reinterpret_cast(trans->user_data); - std::unique_lock lck(context->transferLock); - switch(trans->status) - { - case LIBUSB_TRANSFER_CANCELLED: - //printf("Transfer %i canceled\n", context->id); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - //context->reset(); - break; - case LIBUSB_TRANSFER_COMPLETED: - //if(trans->actual_length == context->bytesExpected) - { - context->bytesXfered = trans->actual_length; - context->done.store(true); - } - break; - case LIBUSB_TRANSFER_ERROR: - printf("TRANSFER ERRRO\n"); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - //printf("transfer timed out %i\n", context->id); - context->bytesXfered = trans->actual_length; - context->done.store(true); - //context->used = false; - - break; - case LIBUSB_TRANSFER_OVERFLOW: - printf("transfer overflow\n"); - - break; - case LIBUSB_TRANSFER_STALL: - printf("transfer stalled\n"); - break; - case LIBUSB_TRANSFER_NO_DEVICE: - printf("transfer no device\n"); - - break; - } - lck.unlock(); - context->cv.notify_one(); -} -#endif - -/** -@brief Starts asynchronous data reading from board -@param *buffer buffer where to store received data -@param length number of bytes to read -@return handle of transfer context -*/ -int Connection_uLimeSDR::BeginDataReading(char *buffer, uint32_t length) -{ - int i = 0; - bool contextFound = false; - //find not used context - for(i = 0; i= 0 && contexts[contextHandle].used == true) - { -#ifndef __unix__ - DWORD dwRet = WaitForSingleObject(contexts[contextHandle].inOvLap.hEvent, timeout_ms); - if (dwRet == WAIT_OBJECT_0) - return 1; -#else - auto t1 = chrono::high_resolution_clock::now(); - auto t2 = chrono::high_resolution_clock::now(); - - std::unique_lock lck(contexts[contextHandle].transferLock); - while(contexts[contextHandle].done.load() == false && std::chrono::duration_cast(t2 - t1).count() < timeout_ms) - { - //blocking not to waste CPU - contexts[contextHandle].cv.wait_for(lck, chrono::milliseconds(timeout_ms)); - t2 = chrono::high_resolution_clock::now(); - } - return contexts[contextHandle].done.load() == true; -#endif - } - return 0; -} - -/** -@brief Finishes asynchronous data reading from board -@param buffer array where to store received data -@param length number of bytes to read -@param contextHandle handle of which context to finish -@return false failure, true number of bytes received -*/ -int Connection_uLimeSDR::FinishDataReading(char *buffer, uint32_t length, int contextHandle) -{ - if(contextHandle >= 0 && contexts[contextHandle].used == true) - { -#ifndef __unix__ - ULONG ulActualBytesTransferred; - FT_STATUS ftStatus = FT_OK; - - ftStatus = FT_GetOverlappedResult(mFTHandle, &contexts[contextHandle].inOvLap, &ulActualBytesTransferred, FALSE); - if (ftStatus != FT_OK) - length = 0; - else - length = ulActualBytesTransferred; - FT_ReleaseOverlapped(mFTHandle, &contexts[contextHandle].inOvLap); - contexts[contextHandle].used = false; - return length; -#else - length = contexts[contextHandle].bytesXfered; - contexts[contextHandle].used = false; - contexts[contextHandle].reset(); - return length; -#endif - } - else - return 0; -} - -/** -@brief Aborts reading operations -*/ -void Connection_uLimeSDR::AbortReading() -{ -#ifndef __unix__ - FT_AbortPipe(mFTHandle, mStreamRdEndPtAddr); - for (int i = 0; i < USB_MAX_CONTEXTS; ++i) - { - if (contexts[i].used == true) - { - FT_ReleaseOverlapped(mFTHandle, &contexts[i].inOvLap); - contexts[i].used = false; - } - } - FT_FlushPipe(mFTHandle, mStreamRdEndPtAddr); - rxSize = 0; -#else - - for(int i = 0; i lck(contextsToSend[contextHandle].transferLock); - while(contextsToSend[contextHandle].done.load() == false && std::chrono::duration_cast(t2 - t1).count() < timeout_ms) - { - //blocking not to waste CPU - contextsToSend[contextHandle].cv.wait_for(lck, chrono::milliseconds(timeout_ms)); - t2 = chrono::high_resolution_clock::now(); - } - return contextsToSend[contextHandle].done == true; -#endif - } - return 0; -} - -/** -@brief Finishes asynchronous data sending to board -@param buffer array where to store received data -@param length number of bytes to read -@param contextHandle handle of which context to finish -@return false failure, true number of bytes sent -*/ -int Connection_uLimeSDR::FinishDataSending(const char *buffer, uint32_t length, int contextHandle) -{ - if(contextsToSend[contextHandle].used == true) - { -#ifndef __unix__ - ULONG ulActualBytesTransferred ; - FT_STATUS ftStatus = FT_OK; - ftStatus = FT_GetOverlappedResult(mFTHandle, &contextsToSend[contextHandle].inOvLap, &ulActualBytesTransferred, FALSE); - if (ftStatus != FT_OK) - length = 0; - else - length = ulActualBytesTransferred; - FT_ReleaseOverlapped(mFTHandle, &contextsToSend[contextHandle].inOvLap); - contextsToSend[contextHandle].used = false; - return length; -#else - length = contextsToSend[contextHandle].bytesXfered; - contextsToSend[contextHandle].used = false; - contextsToSend[contextHandle].reset(); - return length; -#endif - } - else - return 0; -} - -/** -@brief Aborts sending operations -*/ -void Connection_uLimeSDR::AbortSending() -{ -#ifndef __unix__ - FT_AbortPipe(mFTHandle, mStreamWrEndPtAddr); - for (int i = 0; i < USB_MAX_CONTEXTS; ++i) - { - if (contextsToSend[i].used == true) - { - FT_ReleaseOverlapped(mFTHandle, &contextsToSend[i].inOvLap); - contextsToSend[i].used = false; - } - } - txSize = 0; -#else - for(int i = 0; i -#include -#include -#include -#include -#include -#include -#include -#include "fifo.h" - -#define __unix__ -#include "windows.h" - -#ifndef __unix__ -#include "windows.h" -#include "FTD3XXLibrary/FTD3XX.h" -#else -#include -#include -#include -#include -#endif - -namespace lime{ - -#define USB_MAX_CONTEXTS 64 //maximum number of contexts for asynchronous transfers - -class Connection_uLimeSDR : public ILimeSDRStreaming -{ -public: - /** @brief Wrapper class for holding USB asynchronous transfers contexts - */ - class USBTransferContext - { - public: - USBTransferContext() : used(false) - { - id = idCounter++; -#ifndef __unix__ - context = NULL; -#else - transfer = libusb_alloc_transfer(0); - bytesXfered = 0; - bytesExpected = 0; - done = 0; -#endif - } - ~USBTransferContext() - { -#ifdef __unix__ - libusb_free_transfer(transfer); -#endif - } - bool reset() - { - if(used) - return false; - return true; - } - bool used; - int id; - static int idCounter; -#ifndef __unix__ - PUCHAR context; - OVERLAPPED inOvLap; -#else - libusb_transfer* transfer; - long bytesXfered; - long bytesExpected; - std::atomic done; - std::mutex transferLock; - std::condition_variable cv; -#endif - }; - - Connection_uLimeSDR(void *arg); - Connection_uLimeSDR(void *ctx, const unsigned index, const int vid = -1, const int pid = -1); - - virtual ~Connection_uLimeSDR(void); - - int Open(const unsigned index, const int vid, const int pid); - void Close(); - bool IsOpen(); - int GetOpenedIndex(); - - 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; - - //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 epIndex, int timeout_ms = 100)override; -protected: - 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); - virtual int FinishDataReading(char* buffer, uint32_t length, int contextHandle); - virtual void AbortReading(); - - virtual int BeginDataSending(const char* buffer, uint32_t length); - virtual int WaitForSending(int contextHandle, uint32_t timeout_ms); - virtual int FinishDataSending(const char* buffer, uint32_t length, int contextHandle); - virtual void AbortSending(); - - int ResetStreamBuffers() override; - - eConnectionType GetType(void) {return USB_PORT;} - - USBTransferContext contexts[USB_MAX_CONTEXTS]; - USBTransferContext contextsToSend[USB_MAX_CONTEXTS]; - - bool isConnected; - - int mCtrlWrEndPtAddr; - int mCtrlRdEndPtAddr; - int mStreamWrEndPtAddr; - int mStreamRdEndPtAddr; - - uint32_t txSize; - uint32_t rxSize; -#ifndef __unix__ - FT_HANDLE mFTHandle; - int ReinitPipe(unsigned char ep); -#else - int FT_SetStreamPipe(unsigned char ep, size_t size); - int FT_FlushPipe(unsigned char ep); - uint32_t mUsbCounter; - libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices - libusb_device_handle *dev_handle; //a device handle - libusb_context *ctx; //a libusb session -#endif - - std::mutex mExtraUsbMutex; -}; - - - -class Connection_uLimeSDREntry : public ConnectionRegistryEntry -{ -public: - Connection_uLimeSDREntry(void); - ~Connection_uLimeSDREntry(void); - std::vector enumerate(const ConnectionHandle &hint); - IConnection *make(const ConnectionHandle &handle); -private: -#ifndef __unix__ - FT_HANDLE* mFTHandle; -#else - libusb_context *ctx; //a libusb session - std::thread mUSBProcessingThread; - void handle_libusb_events(); - std::atomic mProcessUSBEvents; -#endif -}; - -} diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp deleted file mode 100644 index 0d6132a21..000000000 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDREntry.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - @file Connection_uLimeSDREntry.cpp - @author Lime Microsystems - @brief Implementation of uLimeSDR board connection. -*/ - -#include "Connection_uLimeSDR.h" -using namespace lime; - -#ifdef __unix__ -void Connection_uLimeSDREntry::handle_libusb_events() -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 250000; - while(mProcessUSBEvents.load() == true) - { - int r = libusb_handle_events_timeout_completed(ctx, &tv, NULL); - if(r != 0) printf("error libusb_handle_events %s\n", libusb_strerror(libusb_error(r))); - } -} -#endif // __UNIX__ - -int Connection_uLimeSDR::USBTransferContext::idCounter=0; - -//! make a static-initialized entry in the registry -void __loadConnection_uLimeSDREntry(void) //TODO fixme replace with LoadLibrary/dlopen -{ -static Connection_uLimeSDREntry uLimeSDREntry; -} - -Connection_uLimeSDREntry::Connection_uLimeSDREntry(void): - ConnectionRegistryEntry("uLimeSDR") -{ -#ifndef __unix__ - //m_pDriver = new CDriverInterface(); -#else - int r = libusb_init(&ctx); //initialize the library for the session we just declared - if(r < 0) - printf("Init Error %i\n", r); //there was an error - libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation - mProcessUSBEvents.store(true); - mUSBProcessingThread = std::thread(&Connection_uLimeSDREntry::handle_libusb_events, this); -#endif -} - -Connection_uLimeSDREntry::~Connection_uLimeSDREntry(void) -{ -#ifndef __unix__ - //delete m_pDriver; -#else - mProcessUSBEvents.store(false); - mUSBProcessingThread.join(); - libusb_exit(ctx); -#endif -} - -std::vector Connection_uLimeSDREntry::enumerate(const ConnectionHandle &hint) -{ - std::vector handles; - -#ifndef __unix__ - DWORD devCount = 0; - FT_STATUS ftStatus = FT_OK; - ftStatus = FT_ListDevices(&devCount, NULL, FT_LIST_NUMBER_ONLY); - if(FT_FAILED(ftStatus)) - return handles; - if (devCount > 0) - { - for(int i = 0; i 0) - handle.name = std::string(data, size_t(st)); - handle.addr = std::to_string(int(pid))+":"+std::to_string(int(vid)); - - if (desc.iSerialNumber > 0) - { - r = libusb_get_string_descriptor_ascii(tempDev_handle,desc.iSerialNumber,(unsigned char*)data, sizeof(data)); - if(r<0) - printf("failed to get serial number\n"); - else - handle.serial = std::string(data, size_t(r)); - } - libusb_close(tempDev_handle); - - //add handle conditionally, filter by serial number - if (hint.serial.empty() or hint.serial == handle.serial) - { - handles.push_back(handle); - } - } - } - } - - libusb_free_device_list(devs, 1); -#endif - return handles; -} - -IConnection *Connection_uLimeSDREntry::make(const ConnectionHandle &handle) -{ -#ifndef __unix__ - return new Connection_uLimeSDR(mFTHandle, handle.index); -#else - const auto pidvid = handle.addr; - const auto splitPos = pidvid.find(":"); - const auto pid = std::stoi(pidvid.substr(0, splitPos)); - const auto vid = std::stoi(pidvid.substr(splitPos+1)); - return new Connection_uLimeSDR(ctx, handle.index, vid, pid); -#endif -} diff --git a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp b/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp deleted file mode 100644 index bc608c8eb..000000000 --- a/liblimesuite/srcmw/Connection_uLimeSDR/Connection_uLimeSDRing.cpp +++ /dev/null @@ -1,577 +0,0 @@ -/** - @file Connection_uLimeSDRing.cpp - @author Lime Microsystems - @brief Implementation of uLimeSDR board connection (streaming API) -*/ - -#include "Connection_uLimeSDR.h" -#include "fifo.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ErrorReporting.h" - -using namespace lime; -using namespace std; - -#define __unix__ - -/** @brief Configures FPGA PLLs to LimeLight interface frequency -*/ -int Connection_uLimeSDR::UpdateExternalDataRate(const size_t channel, const double txRate, const double rxRate, const double txPhase, const double rxPhase) -{ - const float txInterfaceClk = 2 * txRate; - const float rxInterfaceClk = 2 * rxRate; - int status = 0; - - mExpectedSampleRate = rxRate; - - lime::fpga::FPGA_PLL_clock clocks[4]; - - 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].findPhase = false; - clocks[1].phaseShift_deg = txPhase; - clocks[2].bypass = false; - clocks[2].index = 2; - clocks[2].outFrequency = rxInterfaceClk; - clocks[2].phaseShift_deg = 0; - clocks[2].findPhase = false; - clocks[3].bypass = false; - clocks[3].index = 3; - clocks[3].outFrequency = rxInterfaceClk; - clocks[3].findPhase = false; - clocks[3].phaseShift_deg = rxPhase; - - status = lime::fpga::SetPllFrequency(this, 0, rxInterfaceClk, clocks, 4); - - return status; -} - -/** @brief Configures FPGA PLLs to LimeLight interface frequency -*/ -int Connection_uLimeSDR::UpdateExternalDataRate(const size_t channel, const double txRate_Hz, const double rxRate_Hz) -{ - const float txInterfaceClk = 2 * txRate_Hz; - const float rxInterfaceClk = 2 * rxRate_Hz; - int status = 0; - uint32_t reg20; - const double rxPhC1[] = { 91.08, 89.46 }; - const double rxPhC2[] = { -1 / 6e6, 1.24e-6 }; - 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 int bakRegCnt = spiAddr.size() - 4; - auto info = GetDeviceInfo(); - const int addrLMS7002M = info.addrsLMS7002M.at(0); - bool phaseSearch = false; - //if (this->chipVersion == 0x3841) //0x3840 LMS7002Mr2, 0x3841 LMS7002Mr3 - /*if (rxInterfaceClk >= 5e6 || txInterfaceClk >= 5e6) - phaseSearch = true;*/ - mExpectedSampleRate = rxRate_Hz; - std::vector dataWr; - std::vector dataRd; - - if (phaseSearch) - { - dataWr.resize(spiAddr.size()); - dataRd.resize(spiAddr.size()); - //backup registers - dataWr[0] = (uint32_t(0x0020) << 16); - TransactSPI(addrLMS7002M, dataWr.data(), ®20, 1); - - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write - TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1); - - for (int i = 0; i < bakRegCnt; ++i) - dataWr[i] = (spiAddr[i] << 16); - TransactSPI(addrLMS7002M, dataWr.data(), dataRd.data(), bakRegCnt); - } - - if ((txInterfaceClk >= 5e6) && (rxInterfaceClk >= 5e6)) - { - lime::fpga::FPGA_PLL_clock clocks[4]; - - 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].findPhase = false; - if (this->chipVersion == 0x3841) - clocks[1].phaseShift_deg = txPhC1[1] + txPhC2[1] * txInterfaceClk; - else - clocks[1].phaseShift_deg = txPhC1[0] + txPhC2[0] * txInterfaceClk; - clocks[2].bypass = false; - clocks[2].index = 2; - clocks[2].outFrequency = rxInterfaceClk; - clocks[2].phaseShift_deg = 0; - clocks[2].findPhase = false; - clocks[3].bypass = false; - clocks[3].index = 3; - clocks[3].outFrequency = rxInterfaceClk; - clocks[3].findPhase = false; - if (this->chipVersion == 0x3841) - clocks[3].phaseShift_deg = rxPhC1[1] + rxPhC2[1] * rxInterfaceClk; - else - clocks[3].phaseShift_deg = rxPhC1[0] + rxPhC2[0] * rxInterfaceClk; - - if (phaseSearch) - { - { -#ifndef NDEBUG - printf("RX phase config:\n"); -#endif - clocks[3].findPhase = true; - 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); - status = lime::fpga::SetPllFrequency(this, 0, rxInterfaceClk, clocks, 4); - } - { -#ifndef NDEBUG - printf("TX phase config:\n"); -#endif - clocks[3].findPhase = false; - 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); - clocks[1].findPhase = true; - WriteRegister(0x000A, 0x0200); - - } - } - status = lime::fpga::SetPllFrequency(this, 0, rxInterfaceClk, clocks, 4); - } - else - { - status = lime::fpga::SetDirectClocking(this, 0, rxInterfaceClk, 90); - if (status == 0) - status = lime::fpga::SetDirectClocking(this, 1, rxInterfaceClk, 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); - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write - TransactSPI(addrLMS7002M, dataWr.data(), nullptr, 1); - WriteRegister(0x000A, 0); - } - return status; -} - - -int Connection_uLimeSDR::ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms) -{ - int totalBytesReceived = 0; - fpga::StopStreaming(this, epIndex); - - //ResetStreamBuffers(); - WriteRegister(0x0008, 0x0100 | 0x2); - WriteRegister(0x0007, 1); - - fpga::StartStreaming(this, epIndex); - - int handle = BeginDataReading(buffer, length); - if (WaitForReading(handle, timeout_ms)) - totalBytesReceived = FinishDataReading(buffer, length, handle); - - AbortReading(); - fpga::StopStreaming(this, epIndex); - - return totalBytesReceived; -} - -int Connection_uLimeSDR::ResetStreamBuffers() -{ - rxSize = 0; - txSize = 0; -#ifndef __unix__ - if (FT_AbortPipe(mFTHandle, mStreamRdEndPtAddr)!=FT_OK) - return -1; - if (FT_AbortPipe(mFTHandle, mStreamWrEndPtAddr)!=FT_OK) - return -1; - if (FT_FlushPipe(mFTHandle, mStreamRdEndPtAddr)!=FT_OK) - return -1; -#else - return FT_FlushPipe(mStreamRdEndPtAddr); -#endif - return 0; -} - -/** @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 -*/ -void Connection_uLimeSDR::ReceivePacketsLoop(Connection_uLimeSDR::Streamer* stream) -{ - //at this point FPGA has to be already configured to output samples - 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 += stream->mRxStreams[i]->config.performanceLatency/chCount; - } - const unsigned tmp_cnt = (latency * 4)+0.5; - - const uint8_t packetsToBatch = (1< handles(buffersCount, 0); - vectorbuffers(buffersCount*bufferSize, 0); - vector chFrames; - try - { - chFrames.resize(chCount); - } - catch (const std::bad_alloc &ex) - { - ReportError("Error allocating Rx buffers, not enough memory"); - return; - } - - uint8_t activeTransfers = 0; - for (int i = 0; iBeginDataReading(&buffers[i*bufferSize], bufferSize); - ++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(); - - std::mutex txFlagsLock; - condition_variable resetTxFlags; - //worker thread for reseting late Tx packet flags - std::thread txReset([](ILimeSDRStreaming* port, - atomic *terminate, - mutex *spiLock, - condition_variable *doWork) - { - uint32_t reg9; - port->ReadRegister(0x0009, reg9); - const uint32_t addr[] = {0x0009, 0x0009}; - const uint32_t data[] = {reg9 | (1 << 1), reg9 & ~(1 << 1)}; - while (not terminate->load()) - { - std::unique_lock lck(*spiLock); - doWork->wait(lck); - port->WriteRegisters(addr, data, 2); - } - }, this, &stream->terminateRx, &txFlagsLock, &resetTxFlags); - - int resetFlagsDelay = 128; - uint64_t prevTs = 0; - while (stream->terminateRx.load() == false) - { - if(stream->generateData.load()) - { - if(activeTransfers == 0) //stop FPGA when last transfer completes - 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; imRxStreams[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); - } - } - this_thread::sleep_for(chrono::milliseconds(100)); - } - 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]); - --activeTransfers; - totalBytesReceived += bytesReceived; - if (bytesReceived != int32_t(bufferSize)) //data should come in full sized packets - ++m_bufferFailures; - } - bool txLate=false; - for (uint8_t pktIndex = 0; pktIndex < bytesReceived / sizeof(FPGA_DataPacket); ++pktIndex) - { - const FPGA_DataPacket* pkt = (FPGA_DataPacket*)&buffers[bi*bufferSize]; - const uint8_t byte0 = pkt[pktIndex].reserved[0]; - if ((byte0 & (1 << 3)) != 0 && !txLate) //report only once per batch - { - txLate = true; - if(resetFlagsDelay > 0) - --resetFlagsDelay; - else - { - printf("L"); - resetTxFlags.notify_one(); - resetFlagsDelay = packetsToBatch*buffersCount; - stream->txLastLateTime.store(pkt[pktIndex].counter); - } - } - uint8_t* pktStart = (uint8_t*)pkt[pktIndex].data; - if(pkt[pktIndex].counter - prevTs != samplesInPacket && pkt[pktIndex].counter != prevTs) - { -#ifndef NDEBUG - printf("\tRx pktLoss ts diff %lli\n", (long long)pkt[pktIndex].counter - prevTs); -#endif - packetLoss += (pkt[pktIndex].counter - prevTs)/samplesInPacket; - } - prevTs = pkt[pktIndex].counter; - stream->rxLastTimestamp.store(pkt[pktIndex].counter); - //parse samples - vector dest(chCount); - for(uint8_t c=0; cmRxStreams[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 stream->generateData.load()) - { - if(activeTransfers == 0) //reactivate FPGA and USB transfers - fpga::StartStreaming(this, chipID); - for(int i=0; iBeginDataReading(&buffers[bi*bufferSize], bufferSize); - bi = (bi + 1) & (buffersCount-1); - ++activeTransfers; - } - } - else - { - handles[bi] = -1; - bi = (bi + 1) & (buffersCount-1); - } - t2 = chrono::high_resolution_clock::now(); - auto timePeriod = std::chrono::duration_cast(t2 - t1).count(); - if (timePeriod >= 1000) - { - t1 = t2; - //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; - printf("Rx: %.3f MB/s, Fs: %.3f MHz, overrun: %i, loss: %i \n", dataRate / 1000000.0, samplingRate / 1000000.0, droppedSamples, packetLoss); -#endif - samplesReceived[0] = 0; - totalBytesReceived = 0; - m_bufferFailures = 0; - droppedSamples = 0; - packetLoss = 0; - stream->rxDataRate_Bps.store((uint32_t)dataRate); - } - } - this->AbortReading(); - for (int j = 0; j= 0) - { - this->WaitForReading(handles[bi], 1000); - this->FinishDataReading(&buffers[bi*bufferSize], bufferSize, handles[bi]); - } - bi = (bi + 1) & (buffersCount-1); - } - resetTxFlags.notify_one(); - txReset.join(); - 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 -*/ -void Connection_uLimeSDR::TransmitPacketsLoop(Streamer* stream) -{ - //at this point FPGA has to be already configured to output samples - const uint8_t maxChannelCount = 2; - 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 += stream->mTxStreams[i]->config.performanceLatency/chCount; - } - const unsigned tmp_cnt = (latency * 4)+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 - { - for(int i=0; iterminateTx.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; - bufferUsed[bi] = false; - } - int i=0; - - while(iterminateTx.load() != true) - { - IStreamChannel::Metadata meta; - FPGA_DataPacket* pkt = reinterpret_cast(&buffers[bi*bufferSize]); - for(int ch=0; chmTxStreams[ch]->Read(samples[ch].data(), maxSamplesBatch, &meta, popTimeout_ms); - if (samplesPopped != maxSamplesBatch) - { - #ifndef NDEBUG - printf("Warning popping from TX, samples popped %i/%i\n", samplesPopped, maxSamplesBatch); - #endif - } - - } - if(stream->terminateTx.load() == true) //early termination - break; - pkt[i].counter = meta.timestamp; - pkt[i].reserved[0] = 0; - //by default ignore timestamps - const int ignoreTimestamp = !(meta.flags & IStreamChannel::Metadata::SYNC_TIMESTAMP); - pkt[i].reserved[0] |= ((int)ignoreTimestamp << 4); //ignore timestamp - - vector src(chCount); - for(uint8_t c=0; cBeginDataSending(&buffers[bi*bufferSize], bytesToSend[bi]); - bufferUsed[bi] = true; - - t2 = chrono::high_resolution_clock::now(); - auto timePeriod = std::chrono::duration_cast(t2 - t1).count(); - if (timePeriod >= 1000) - { - //total number of bytes sent per second - float dataRate = 1000.0*totalBytesSent / timePeriod; - stream->txDataRate_Bps.store(dataRate); - m_bufferFailures = 0; - samplesSent = 0; - totalBytesSent = 0; - t1 = t2; -#ifndef NDEBUG - //total number of samples from all channels per second - float sampleRate = 1000.0*samplesSent / timePeriod; - printf("Tx: %.3f MB/s, Fs: %.3f MHz, failures: %i\n", dataRate / 1000000.0, sampleRate / 1000000.0, m_bufferFailures); -#endif - } - bi = (bi + 1) & (buffersCount-1); - } - - // Wait for all the queued requests to be cancelled - this->AbortSending(); - for (int j = 0; jWaitForSending(handles[bi], 1000); - this->FinishDataSending(&buffers[bi*bufferSize], bufferSize, handles[bi]); - } - bi = (bi + 1) & (buffersCount-1); - } - stream->txDataRate_Bps.store(0); -} diff --git a/liblimesuite/srcmw/ErrorReporting.cpp b/liblimesuite/srcmw/ErrorReporting.cpp deleted file mode 100644 index f80285de3..000000000 --- a/liblimesuite/srcmw/ErrorReporting.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** -@file ErrorReporting.cpp -@author Lime Microsystems -@brief API for reporting error codes and error messages. -*/ - -#include "ErrorReporting.h" -#include //strerror -#include - -#ifdef _MSC_VER - #define thread_local __declspec( thread ) - #include -#endif - -#ifdef __APPLE__ - #define thread_local __thread -#endif - -#define MAX_MSG_LEN 1024 -thread_local int _reportedErrorCode; -thread_local char _reportedErrorMessage[MAX_MSG_LEN]; - -static const char *errToStr(const int errnum) -{ - thread_local static char buff[MAX_MSG_LEN]; - #ifdef _MSC_VER - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buff, sizeof(buff), NULL); - return buff; - #else - //http://linux.die.net/man/3/strerror_r - #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) || __APPLE__ - strerror_r(errnum, buff, sizeof(buff)); - #else - //this version may decide to use its own internal string - //return strerror_r(errnum, buff, sizeof(buff)); - return buff; - #endif - return buff; - #endif -} - -int lime::GetLastError(void) -{ - return _reportedErrorCode; -} - -const char *lime::GetLastErrorMessage(void) -{ - return _reportedErrorMessage; -} - -int lime::ReportError(const int errnum) -{ - return lime::ReportError(errnum, errToStr(errnum)); -} - -int lime::ReportError(const int errnum, const char *format, va_list argList) -{ - _reportedErrorCode = errnum; - vsnprintf(_reportedErrorMessage, MAX_MSG_LEN, format, argList); - return errnum; -} diff --git a/liblimesuite/srcmw/ErrorReporting.h b/liblimesuite/srcmw/ErrorReporting.h deleted file mode 100644 index a9557598b..000000000 --- a/liblimesuite/srcmw/ErrorReporting.h +++ /dev/null @@ -1,85 +0,0 @@ -/** -@file ErrorReporting.h -@author Lime Microsystems -@brief API for reporting error codes and error messages. -All calls are thread-safe using thread-local storage. -Code returning with an error should use: -return lime::ReportError(code, message, ...); -*/ - -#ifndef LIMESUITE_ERROR_REPORTING_H -#define LIMESUITE_ERROR_REPORTING_H - -#include -#include -#include -#include -#include - -namespace lime -{ - -/*! - * Get the error code reported. - */ -LIME_API int GetLastError(void); - -/*! - * Get the error code to string + any optional message reported. - */ -LIME_API const char *GetLastErrorMessage(void); - -/*! - * Report a typical errno style error. - * The resulting error message comes from strerror(). - * \param errnum a recognized error code - * \return a non-zero status code to return - */ -LIME_API int ReportError(const int errnum); - -/*! - * Report an error as an integer code and a formatted message string. - * \param errnum a recognized error code - * \param format a format string followed by args - * \return a non-zero status code to return - */ -inline int ReportError(const int errnum, const char *format, ...); - -/*! - * Report an error as a formatted message string. - * The reported errnum is 0 - no relevant error code. - * \param format a format string followed by args - * \return a non-zero status code to return - */ -inline int ReportError(const char *format, ...); - -/*! - * Report an error as an integer code and message format arguments - * \param errnum a recognized error code - * \param format a printf-style format string - * \param argList the format string args as a va_list - * \return a non-zero status code to return - */ -LIME_API int ReportError(const int errnum, const char *format, va_list argList); - -} - -inline int lime::ReportError(const int errnum, const char *format, ...) -{ - va_list argList; - va_start(argList, format); - int status = lime::ReportError(errnum, format, argList); - va_end(argList); - return status; -} - -inline int lime::ReportError(const char *format, ...) -{ - va_list argList; - va_start(argList, format); - int status = lime::ReportError(-1, format, argList); - va_end(argList); - return status; -} - -#endif //LIMESUITE_ERROR_REPORTING_H diff --git a/liblimesuite/srcmw/lms7002m/LMS7002M.cpp b/liblimesuite/srcmw/lms7002m/LMS7002M.cpp deleted file mode 100644 index 83c01dac6..000000000 --- a/liblimesuite/srcmw/lms7002m/LMS7002M.cpp +++ /dev/null @@ -1,2653 +0,0 @@ -/** -@file LMS7002M.cpp -@author Lime Microsystems (www.limemicro.com) -@brief Implementation of LMS7002M transceiver configuring -*/ - -#define _USE_MATH_DEFINES -#include -#include - -#include "vasprintf.h" - -#include "LMS7002M.h" -#include -#include -#include "IConnection.h" -#include "ErrorReporting.h" -#include "INI.h" -#include -#include -#include -#include -#include "LMS7002M_RegistersMap.h" -#include "CalibrationCache.h" -#include -#include -#include -#include -#include "Logger.h" - -#include "MCU_BD.h" -const static uint16_t MCU_PARAMETER_ADDRESS = 0x002D; //register used to pass parameter values to MCU -#define MCU_ID_DC_IQ_CALIBRATIONS 0x01 -#define MCU_FUNCTION_CALIBRATE_TX 1 -#define MCU_FUNCTION_CALIBRATE_RX 2 - -using namespace std; -using namespace lime; - -#include "MCU_BD.h" - -float_type LMS7002M::gVCO_frequency_table[3][2] = { { 3800e6, 5222e6 }, { 4961e6, 6754e6 }, {6306e6, 7714e6} }; -float_type LMS7002M::gCGEN_VCO_frequencies[2] = {1950e6, 2900e6}; - -///define for parameter enumeration if prefix might be needed -extern std::vector LMS7parameterList; - -//module addresses needs to be sorted in ascending order -const uint16_t LMS7002M::readOnlyRegisters[] = { 0x002F, 0x008C, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x0123, 0x0209, 0x020A, 0x020B, 0x040E, 0x040F }; -const uint16_t LMS7002M::readOnlyRegistersMasks[] = { 0x0000, 0x0FFF, 0x007F, 0x0000, 0x0000, 0x0000, 0x0000, 0x003F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; - -/** @brief Simple logging function to print status messages - @param text message to print - @param type message type for filtering specific information -*/ -void LMS7002M::Log(const char* text, LogType type) -{ - switch(type) - { - case LOG_INFO: - lime::info(text); - if(log_callback) - log_callback(text, type); - break; - case LOG_WARNING: - lime::warning(text); - if(log_callback) - log_callback(text, type); - break; - case LOG_ERROR: - lime::error(text); - if(log_callback) - log_callback(text, type); - break; - case LOG_DATA: - lime::debug(text); - if(log_callback) - log_callback(text, type); - break; - } -} - -//Compatibility for vasprintf under MSVC -#ifdef _MSC_VER -int vasprintf(char **strp, const char *fmt, va_list ap) -{ - int r = _vscprintf(fmt, ap); - if (r < 0) return r; - *strp = (char *)malloc(r+1); - return vsprintf_s(*strp, r+1, fmt, ap); -} -#endif - -void LMS7002M::Log(LogType type, const char *format, va_list argList) -{ - char *message = NULL; - if (vasprintf(&message, format, argList) != -1) - { - Log(message, type); - free(message); - } -} - -/** @brief Sets connection which is used for data communication with chip -*/ -void LMS7002M::SetConnection(IConnection* port, const size_t devIndex) -{ - controlPort = port; - mdevIndex = devIndex; - - if (controlPort != nullptr) - { - unsigned byte_array_size = 0; - if (controlPort->IsOpen()) - { - unsigned chipRev = this->Get_SPI_Reg_bits(LMS7_MASK, true); - if (chipRev >= 1) - byte_array_size = 1024 * 16; - else - byte_array_size = 1024 * 8; - } - mcuControl->Initialize(port, mdevIndex, byte_array_size); - } -} - -/** @brief Creates LMS7002M main control object. -It requires IConnection to be set by SetConnection() to communicate with chip -*/ -LMS7002M::LMS7002M() : - useCache(0), - mValueCache(new CalibrationCache()), - mRegistersMap(new LMS7002M_RegistersMap()), - controlPort(nullptr), - mdevIndex(0), - mSelfCalDepth(0) -{ - mCalibrationByMCU = true; - - //memory intervals for registers tests and calibration algorithms - MemorySectionAddresses[LimeLight][0] = 0x0020; - MemorySectionAddresses[LimeLight][1] = 0x002F; - MemorySectionAddresses[EN_DIR][0] = 0x0081; - MemorySectionAddresses[EN_DIR][1] = 0x0081; - MemorySectionAddresses[AFE][0] = 0x0082; - MemorySectionAddresses[AFE][1] = 0x0082; - MemorySectionAddresses[BIAS][0] = 0x0084; - MemorySectionAddresses[BIAS][1] = 0x0084; - MemorySectionAddresses[XBUF][0] = 0x0085; - MemorySectionAddresses[XBUF][1] = 0x0085; - MemorySectionAddresses[CGEN][0] = 0x0086; - MemorySectionAddresses[CGEN][1] = 0x008C; - MemorySectionAddresses[LDO][0] = 0x0092; - MemorySectionAddresses[LDO][1] = 0x00A7; - MemorySectionAddresses[BIST][0] = 0x00A8; - MemorySectionAddresses[BIST][1] = 0x00AC; - MemorySectionAddresses[CDS][0] = 0x00AD; - MemorySectionAddresses[CDS][1] = 0x00AE; - MemorySectionAddresses[TRF][0] = 0x0100; - MemorySectionAddresses[TRF][1] = 0x0104; - MemorySectionAddresses[TBB][0] = 0x0105; - MemorySectionAddresses[TBB][1] = 0x010A; - MemorySectionAddresses[RFE][0] = 0x010C; - MemorySectionAddresses[RFE][1] = 0x0114; - MemorySectionAddresses[RBB][0] = 0x0115; - MemorySectionAddresses[RBB][1] = 0x011A; - MemorySectionAddresses[SX][0] = 0x011C; - MemorySectionAddresses[SX][1] = 0x0124; - MemorySectionAddresses[TxTSP][0] = 0x0200; - MemorySectionAddresses[TxTSP][1] = 0x020C; - MemorySectionAddresses[TxNCO][0] = 0x0240; - MemorySectionAddresses[TxNCO][1] = 0x0261; - MemorySectionAddresses[TxGFIR1][0] = 0x0280; - MemorySectionAddresses[TxGFIR1][1] = 0x02A7; - MemorySectionAddresses[TxGFIR2][0] = 0x02C0; - MemorySectionAddresses[TxGFIR2][1] = 0x02E7; - MemorySectionAddresses[TxGFIR3a][0] = 0x0300; - MemorySectionAddresses[TxGFIR3a][1] = 0x0327; - MemorySectionAddresses[TxGFIR3b][0] = 0x0340; - MemorySectionAddresses[TxGFIR3b][1] = 0x0367; - MemorySectionAddresses[TxGFIR3c][0] = 0x0380; - MemorySectionAddresses[TxGFIR3c][1] = 0x03A7; - MemorySectionAddresses[RxTSP][0] = 0x0400; - MemorySectionAddresses[RxTSP][1] = 0x040F; - MemorySectionAddresses[RxNCO][0] = 0x0440; - MemorySectionAddresses[RxNCO][1] = 0x0461; - MemorySectionAddresses[RxGFIR1][0] = 0x0480; - MemorySectionAddresses[RxGFIR1][1] = 0x04A7; - MemorySectionAddresses[RxGFIR2][0] = 0x04C0; - MemorySectionAddresses[RxGFIR2][1] = 0x04E7; - MemorySectionAddresses[RxGFIR3a][0] = 0x0500; - MemorySectionAddresses[RxGFIR3a][1] = 0x0527; - MemorySectionAddresses[RxGFIR3b][0] = 0x0540; - MemorySectionAddresses[RxGFIR3b][1] = 0x0567; - MemorySectionAddresses[RxGFIR3c][0] = 0x0580; - MemorySectionAddresses[RxGFIR3c][1] = 0x05A7; - MemorySectionAddresses[RSSI_DC_CALIBRATION][0] = 0x05C0; - MemorySectionAddresses[RSSI_DC_CALIBRATION][1] = 0x05CC; - - mRegistersMap->InitializeDefaultValues(LMS7parameterList); - mcuControl = new MCU_BD(); - mcuControl->Initialize(nullptr); -} - -LMS7002M::~LMS7002M() -{ - delete mcuControl; - delete mRegistersMap; -} - -void LMS7002M::SetActiveChannel(const Channel ch) -{ - if (ch == this->GetActiveChannel(false)) return; - this->Modify_SPI_Reg_bits(LMS7param(MAC), int(ch)); -} - -LMS7002M::Channel LMS7002M::GetActiveChannel(bool fromChip) -{ - auto ch = Get_SPI_Reg_bits(LMS7param(MAC), fromChip); - return Channel(ch); -} - -size_t LMS7002M::GetActiveChannelIndex(bool fromChip) -{ - switch (this->GetActiveChannel(fromChip)) - { - case ChB: return mdevIndex*2 + 1; - default: return mdevIndex*2 + 0; - } -} - -int LMS7002M::EnableChannel(const bool isTx, const bool enable) -{ - Channel ch = this->GetActiveChannel(); - - //--- LML --- - if (ch == ChA) - { - if (isTx) this->Modify_SPI_Reg_bits(LMS7param(TXEN_A), enable?1:0); - else this->Modify_SPI_Reg_bits(LMS7param(RXEN_A), enable?1:0); - } - else - { - if (isTx) this->Modify_SPI_Reg_bits(LMS7param(TXEN_B), enable?1:0); - else this->Modify_SPI_Reg_bits(LMS7param(RXEN_B), enable?1:0); - } - - //--- ADC/DAC --- - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_AFE), 1); - if (ch == ChA) - { - if (isTx) this->Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE1), enable?0:1); - else this->Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE1), enable?0:1); - } - else - { - if (isTx) this->Modify_SPI_Reg_bits(LMS7param(PD_TX_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 --- - 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(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); - 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 --- - if (isTx) - { - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_TBB), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G_TBB), enable?1:0); - } - else - { - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_RBB), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G_RBB), enable?1:0); - this->Modify_SPI_Reg_bits(LMS7param(PD_PGA_RBB), enable?0:1); - } - - //--- frontend --- - if (isTx) - { - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_TRF), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G_TRF), enable?1:0); - this->Modify_SPI_Reg_bits(LMS7param(PD_TLOBUF_TRF), enable?0:1); - this->Modify_SPI_Reg_bits(LMS7param(PD_TXPAD_TRF), enable?0:1); - } - else - { - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_RFE), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G_RFE), enable?1:0); - this->Modify_SPI_Reg_bits(LMS7param(PD_MXLOBUF_RFE), enable?0:1); - this->Modify_SPI_Reg_bits(LMS7param(PD_QGEN_RFE), enable?0:1); - this->Modify_SPI_Reg_bits(LMS7param(PD_TIA_RFE), enable?0:1); - this->Modify_SPI_Reg_bits(LMS7param(PD_LNA_RFE), enable?0:1); - } - - //--- synthesizers --- - if (isTx) - { - this->SetActiveChannel(ChSXT); - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G), (disabledChannels&3) == 3?0:1); - if (ch == ChB) //enable LO to channel B - { - this->SetActiveChannel(ChA); - this->Modify_SPI_Reg_bits(LMS7param(EN_NEXTTX_TRF), enable?1:0); - } - } - else - { - this->SetActiveChannel(ChSXR); - this->Modify_SPI_Reg_bits(LMS7param(EN_DIR_SXRSXT), 1); - this->Modify_SPI_Reg_bits(LMS7param(EN_G), (disabledChannels&0xC)==0xC?0:1); - if (ch == ChB) //enable LO to channel B - { - this->SetActiveChannel(ChA); - this->Modify_SPI_Reg_bits(LMS7param(EN_NEXTRX_RFE), enable?1:0); - } - } - this->SetActiveChannel(ch); - - return 0; -} - -/*! - * Helpful macro to check the connection before doing SPI work. - */ -#define checkConnection() { \ - if (controlPort == nullptr) return ReportError(ENOTCONN, "no connection object"); \ - if (not controlPort->IsOpen()) return ReportError(ENOTCONN, "connection is not open"); \ -} - -/** @brief Sends reset signal to chip, after reset enables B channel controls - @return 0-success, other-failure -*/ -int LMS7002M::ResetChip() -{ - checkConnection(); - - int status = controlPort->DeviceReset(); - if (status == 0) Modify_SPI_Reg_bits(LMS7param(MIMO_SISO), 0); //enable B channel after reset - return status; -} - -int LMS7002M::SoftReset() -{ - auto reg_0x0020 = this->SPI_read(0x0020, true); - auto reg_0x002E = this->SPI_read(0x002E, true); - this->SPI_write(0x0020, 0x0); - this->SPI_write(0x0020, reg_0x0020); - this->SPI_write(0x002E, reg_0x002E);//must write - return 0; -} - -int LMS7002M::LoadConfigLegacyFile(const char* filename) -{ - ifstream f(filename); - if (f.good() == false) //file not found - { - f.close(); - return ReportError(ENOENT, "LoadConfigLegacyFile(%s) - file not found", filename); - } - f.close(); - uint16_t addr = 0; - uint16_t value = 0; - Channel ch = this->GetActiveChannel(); //remember used channel - int status; - typedef INI ini_t; - ini_t parser(filename, true); - if (parser.select("FILE INFO") == false) - return ReportError(EINVAL, "LoadConfigLegacyFile(%s) - invalid format, missing FILE INFO section", filename); - - string type = ""; - type = parser.get("type", "undefined"); - stringstream ss; - if (type.find("LMS7002 configuration") == string::npos) - { - ss << "File " << filename << " not recognized" << endl; - return ReportError(EINVAL, "LoadConfigLegacyFile(%s) - invalid format, missing LMS7002 configuration", filename); - } - - int fileVersion = 0; - fileVersion = parser.get("version", 0); - - vector addrToWrite; - vector dataToWrite; - if (fileVersion == 1) - { - if (parser.select("Reference clocks")) - { - this->SetReferenceClk_SX(Rx, parser.get("SXR reference frequency MHz", 30.72) * 1e6); - this->SetReferenceClk_SX(Tx, parser.get("SXT reference frequency MHz", 30.72) * 1e6); - } - - if (parser.select("LMS7002 registers ch.A") == true) - { - ini_t::sectionsit_t section = parser.sections.find("LMS7002 registers ch.A"); - - uint16_t x0020_value = 0; - this->SetActiveChannel(ChA); //select A channel - for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++) - { - sscanf(pairs->first.c_str(), "%hx", &addr); - sscanf(pairs->second.c_str(), "%hx", &value); - if (addr == LMS7param(MAC).address) //skip register containing channel selection - { - x0020_value = value; - continue; - } - addrToWrite.push_back(addr); - dataToWrite.push_back(value); - } - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0 && controlPort != nullptr) - return status; - - //parse FCW or PHO - if (parser.select("NCO Rx ch.A") == true) - { - char varname[64]; - int mode = Get_SPI_Reg_bits(LMS7param(MODE_RX)); - if (mode == 0) //FCW - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "FCW%02i", i); - SetNCOFrequency(LMS7002M::Rx, i, parser.get(varname, 0.0)); - } - } - else - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "PHO%02i", i); - SetNCOPhaseOffset(LMS7002M::Rx, i, parser.get(varname, 0.0)); - } - } - } - if (parser.select("NCO Tx ch.A") == true) - { - char varname[64]; - int mode = Get_SPI_Reg_bits(LMS7param(MODE_TX)); - if (mode == 0) //FCW - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "FCW%02i", i); - SetNCOFrequency(LMS7002M::Tx, i, parser.get(varname, 0.0)); - } - } - else - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "PHO%02i", i); - SetNCOPhaseOffset(LMS7002M::Tx, i, parser.get(varname, 0.0)); - } - } - } - status = SPI_write(0x0020, x0020_value); - if (status != 0 && controlPort != nullptr) - return status; - } - - this->SetActiveChannel(ChB); - - if (parser.select("LMS7002 registers ch.B") == true) - { - addrToWrite.clear(); - dataToWrite.clear(); - ini_t::sectionsit_t section = parser.sections.find("LMS7002 registers ch.B"); - for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++) - { - sscanf(pairs->first.c_str(), "%hx", &addr); - sscanf(pairs->second.c_str(), "%hx", &value); - addrToWrite.push_back(addr); - dataToWrite.push_back(value); - } - this->SetActiveChannel(ChB); //select B channel - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0 && controlPort != nullptr) - return status; - - //parse FCW or PHO - if (parser.select("NCO Rx ch.B") == true) - { - char varname[64]; - int mode = Get_SPI_Reg_bits(LMS7param(MODE_RX)); - if (mode == 0) //FCW - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "FCW%02i", i); - SetNCOFrequency(LMS7002M::Rx, i, parser.get(varname, 0.0)); - } - } - else - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "PHO%02i", i); - SetNCOPhaseOffset(LMS7002M::Rx, i, parser.get(varname, 0.0)); - } - } - } - if (parser.select("NCO Tx ch.A") == true) - { - char varname[64]; - int mode = Get_SPI_Reg_bits(LMS7param(MODE_TX)); - if (mode == 0) //FCW - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "FCW%02i", i); - SetNCOFrequency(LMS7002M::Tx, i, parser.get(varname, 0.0)); - } - } - else - { - for (int i = 0; i < 16; ++i) - { - sprintf(varname, "PHO%02i", i); - SetNCOPhaseOffset(LMS7002M::Tx, i, parser.get(varname, 0.0)); - } - } - } - } - this->SetActiveChannel(ch); - return 0; - } - return ReportError(EINVAL, "LoadConfigLegacyFile(%s) - invalid format", filename); -} - -/** @brief Reads configuration file and uploads registers to chip - @param filename Configuration source file - @return 0-success, other-failure -*/ -int LMS7002M::LoadConfig(const char* filename) -{ - ifstream f(filename); - if (f.good() == false) //file not found - { - f.close(); - return ReportError(ENOENT, "LoadConfig(%s) - file not found", filename); - } - f.close(); - uint16_t addr = 0; - uint16_t value = 0; - Channel ch = this->GetActiveChannel(); //remember used channel - - int status; - typedef INI ini_t; - ini_t parser(filename, true); - if (parser.select("file_info") == false) - { - //try loading as legacy format - status = LoadConfigLegacyFile(filename); - this->SetActiveChannel(ChA); - return status; - } - string type = ""; - type = parser.get("type", "undefined"); - stringstream ss; - if (type.find("lms7002m_minimal_config") == string::npos) - { - ss << "File " << filename << " not recognized" << endl; - return ReportError(EINVAL, "LoadConfig(%s) - invalid format, missing lms7002m_minimal_config", filename); - } - - int fileVersion = 0; - fileVersion = parser.get("version", 0); - - vector addrToWrite; - vector dataToWrite; - - if (fileVersion == 1) - { - if(parser.select("lms7002_registers_a") == true) - { - ini_t::sectionsit_t section = parser.sections.find("lms7002_registers_a"); - - uint16_t x0020_value = 0; - this->SetActiveChannel(ChA); //select A channel - for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++) - { - sscanf(pairs->first.c_str(), "%hx", &addr); - sscanf(pairs->second.c_str(), "%hx", &value); - if (addr == LMS7param(MAC).address) //skip register containing channel selection - { - x0020_value = value; - continue; - } - addrToWrite.push_back(addr); - dataToWrite.push_back(value); - } - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0 && controlPort != nullptr) - return status; - status = SPI_write(0x0020, x0020_value); - if (status != 0 && controlPort != nullptr) - return status; - this->SetActiveChannel(ChB); - if (status != 0 && controlPort != nullptr) - return status; - } - - if (parser.select("lms7002_registers_b") == true) - { - addrToWrite.clear(); - dataToWrite.clear(); - ini_t::sectionsit_t section = parser.sections.find("lms7002_registers_b"); - for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++) - { - sscanf(pairs->first.c_str(), "%hx", &addr); - sscanf(pairs->second.c_str(), "%hx", &value); - addrToWrite.push_back(addr); - dataToWrite.push_back(value); - } - this->SetActiveChannel(ChB); //select B channel - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0 && controlPort != nullptr) - return status; - } - this->SetActiveChannel(ch); - - parser.select("reference_clocks"); - this->SetReferenceClk_SX(Rx, parser.get("sxr_ref_clk_mhz", 30.72) * 1e6); - this->SetReferenceClk_SX(Tx, parser.get("sxt_ref_clk_mhz", 30.72) * 1e6); - } - - this->SetActiveChannel(ChA); - checkConnection(); - return 0; -} - -/** @brief Reads all registers from chip and saves to file - @param filename destination filename - @return 0-success, other failure -*/ -int LMS7002M::SaveConfig(const char* filename) -{ - ofstream fout; - fout.open(filename); - fout << "[file_info]" << endl; - fout << "type=lms7002m_minimal_config" << endl; - fout << "version=1" << endl; - - char addr[80]; - char value[80]; - - Channel ch = this->GetActiveChannel(); - - vector addrToRead; - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) - addrToRead.push_back(addr); - vector dataReceived; - dataReceived.resize(addrToRead.size(), 0); - - fout << "[lms7002_registers_a]" << endl; - this->SetActiveChannel(ChA); - for (uint16_t i = 0; i < addrToRead.size(); ++i) - { - dataReceived[i] = Get_SPI_Reg_bits(addrToRead[i], 15, 0, false); - sprintf(addr, "0x%04X", addrToRead[i]); - sprintf(value, "0x%04X", dataReceived[i]); - fout << addr << "=" << value << endl; - } - - fout << "[lms7002_registers_b]" << endl; - addrToRead.clear(); //add only B channel addresses - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - 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) - { - dataReceived[i] = Get_SPI_Reg_bits(addrToRead[i], 15, 0, false); - sprintf(addr, "0x%04X", addrToRead[i]); - sprintf(value, "0x%04X", dataReceived[i]); - fout << addr << "=" << value << endl; - } - - this->SetActiveChannel(ch); //retore previously used channel - - fout << "[reference_clocks]" << endl; - fout << "sxt_ref_clk_mhz=" << this->GetReferenceClk_SX(Tx) / 1e6 << endl; - fout << "sxr_ref_clk_mhz=" << this->GetReferenceClk_SX(Rx) / 1e6 << endl; - fout.close(); - return 0; -} - -int LMS7002M::SetRBBPGA_dB(const float_type value) -{ - int g_pga_rbb = (int)(value + 12.5); - if (g_pga_rbb > 0x1f) g_pga_rbb = 0x1f; - if (g_pga_rbb < 0) g_pga_rbb = 0; - int ret = this->Modify_SPI_Reg_bits(LMS7param(G_PGA_RBB), g_pga_rbb); - - int rcc_ctl_pga_rbb = (430.0*pow(0.65, (g_pga_rbb/10.0))-110.35)/20.4516 + 16; - - int c_ctl_pga_rbb = 0; - if (0 <= g_pga_rbb && g_pga_rbb < 8) c_ctl_pga_rbb = 3; - if (8 <= g_pga_rbb && g_pga_rbb < 13) c_ctl_pga_rbb = 2; - if (13 <= g_pga_rbb && g_pga_rbb < 21) c_ctl_pga_rbb = 1; - if (21 <= g_pga_rbb) c_ctl_pga_rbb = 0; - - ret |= this->Modify_SPI_Reg_bits(LMS7param(RCC_CTL_PGA_RBB), rcc_ctl_pga_rbb); - ret |= this->Modify_SPI_Reg_bits(LMS7param(C_CTL_PGA_RBB), c_ctl_pga_rbb); - return ret; -} - -float_type LMS7002M::GetRBBPGA_dB(void) -{ - auto g_pga_rbb = this->Get_SPI_Reg_bits(LMS7param(G_PGA_RBB)); - return g_pga_rbb - 12; -} - -int LMS7002M::SetRFELNA_dB(const float_type value) -{ - const double gmax = 30; - double val = value - gmax; - - int g_lna_rfe = 0; - if (val >= 0) g_lna_rfe = 15; - else if (val >= -1) g_lna_rfe = 14; - else if (val >= -2) g_lna_rfe = 13; - else if (val >= -3) g_lna_rfe = 12; - else if (val >= -4) g_lna_rfe = 11; - else if (val >= -5) g_lna_rfe = 10; - else if (val >= -6) g_lna_rfe = 9; - else if (val >= -9) g_lna_rfe = 8; - else if (val >= -12) g_lna_rfe = 7; - else if (val >= -15) g_lna_rfe = 6; - else if (val >= -18) g_lna_rfe = 5; - else if (val >= -21) g_lna_rfe = 4; - else if (val >= -24) g_lna_rfe = 3; - else if (val >= -27) g_lna_rfe = 2; - else g_lna_rfe = 1; - - return this->Modify_SPI_Reg_bits(LMS7param(G_LNA_RFE), g_lna_rfe); -} - -float_type LMS7002M::GetRFELNA_dB(void) -{ - const double gmax = 30; - auto g_lna_rfe = this->Get_SPI_Reg_bits(LMS7param(G_LNA_RFE)); - switch (g_lna_rfe) - { - case 15: return gmax-0; - case 14: return gmax-1; - case 13: return gmax-2; - case 12: return gmax-3; - case 11: return gmax-4; - case 10: return gmax-5; - case 9: return gmax-6; - case 8: return gmax-9; - case 7: return gmax-12; - case 6: return gmax-15; - case 5: return gmax-18; - case 4: return gmax-21; - case 3: return gmax-24; - case 2: return gmax-27; - case 1: return gmax-30; - } - return 0.0; -} - -int LMS7002M::SetRFELoopbackLNA_dB(const float_type gain) -{ - const double gmax = 40; - double val = gain - gmax; - - int g_rxloopb_rfe = 0; - if (val >= 0) g_rxloopb_rfe = 15; - else if (val >= -0.5) g_rxloopb_rfe = 14; - else if (val >= -1) g_rxloopb_rfe = 13; - else if (val >= -1.6) g_rxloopb_rfe = 12; - else if (val >= -2.4) g_rxloopb_rfe = 11; - else if (val >= -3) g_rxloopb_rfe = 10; - else if (val >= -4) g_rxloopb_rfe = 9; - else if (val >= -5) g_rxloopb_rfe = 8; - else if (val >= -6.2) g_rxloopb_rfe = 7; - else if (val >= -7.5) g_rxloopb_rfe = 6; - else if (val >= -9) g_rxloopb_rfe = 5; - else if (val >= -11) g_rxloopb_rfe = 4; - else if (val >= -14) g_rxloopb_rfe = 3; - else if (val >= -17) g_rxloopb_rfe = 2; - else if (val >= -24) g_rxloopb_rfe = 1; - else g_rxloopb_rfe = 0; - - return this->Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), g_rxloopb_rfe); -} - -float_type LMS7002M::GetRFELoopbackLNA_dB(void) -{ - const double gmax = 40; - auto g_rxloopb_rfe = this->Get_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE)); - switch (g_rxloopb_rfe) - { - case 15: return gmax-0; - case 14: return gmax-0.5; - case 13: return gmax-1; - case 12: return gmax-1.6; - case 11: return gmax-2.4; - case 10: return gmax-3; - case 9: return gmax-4; - case 8: return gmax-5; - case 7: return gmax-6.2; - case 6: return gmax-7.5; - case 5: return gmax-9; - case 4: return gmax-11; - case 3: return gmax-14; - case 2: return gmax-17; - case 1: return gmax-24; - } - return 0.0; -} - -int LMS7002M::SetRFETIA_dB(const float_type value) -{ - const double gmax = 12; - double val = value - gmax; - - int g_tia_rfe = 0; - if (val >= 0) g_tia_rfe = 3; - else if (val >= -3) g_tia_rfe = 2; - else g_tia_rfe = 1; - - return this->Modify_SPI_Reg_bits(LMS7param(G_TIA_RFE), g_tia_rfe); -} - -float_type LMS7002M::GetRFETIA_dB(void) -{ - const double gmax = 12; - auto g_tia_rfe = this->Get_SPI_Reg_bits(LMS7param(G_TIA_RFE)); - switch (g_tia_rfe) - { - case 3: return gmax-0; - case 2: return gmax-3; - case 1: return gmax-12; - } - return 0.0; -} - -int LMS7002M::SetTRFPAD_dB(const float_type value) -{ - const double pmax = 0; - double loss = pmax-value; - - //different scaling realm - if (loss > 10) loss = (loss+10)/2; - - //clip - if (loss > 31) loss = 31; - if (loss < 0) loss = 0; - - //integer round - int loss_int = (int)(loss + 0.5); - - int ret = 0; - ret |= this->Modify_SPI_Reg_bits(LMS7param(LOSS_LIN_TXPAD_TRF), loss_int); - ret |= this->Modify_SPI_Reg_bits(LMS7param(LOSS_MAIN_TXPAD_TRF), loss_int); - return ret; -} - -float_type LMS7002M::GetTRFPAD_dB(void) -{ - const double pmax = 0; - auto loss_int = this->Get_SPI_Reg_bits(LMS7param(LOSS_LIN_TXPAD_TRF)); - if (loss_int > 10) return pmax-10-2*(loss_int-10); - return pmax-loss_int; -} - -int LMS7002M::SetTRFLoopbackPAD_dB(const float_type gain) -{ - //there are 4 discrete gain values, use the midpoints - int val = 0; - if (gain >= (-1.4-0)/2) val = 0; - else if (gain >= (-1.4-3.3)/2) val = 1; - else if (gain >= (-3.3-4.3)/2) val = 2; - else val = 3; - - return this->Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), val); -} - -float_type LMS7002M::GetTRFLoopbackPAD_dB(void) -{ - switch (this->Get_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF))) - { - case 0: return 0.0; - case 1: return -1.4; - case 2: return -3.3; - case 3: return -4.3; - } - return 0.0; -} - -int LMS7002M::SetPathRFE(PathRFE path) -{ - int sel_path_rfe = 0; - switch (path) - { - case PATH_RFE_NONE: sel_path_rfe = 0; break; - case PATH_RFE_LNAH: sel_path_rfe = 1; break; - case PATH_RFE_LNAL: sel_path_rfe = 2; break; - case PATH_RFE_LNAW: sel_path_rfe = 3; break; - case PATH_RFE_LB1: sel_path_rfe = 3; break; - case PATH_RFE_LB2: sel_path_rfe = 2; break; - } - - int pd_lna_rfe = 1; - switch (path) - { - case PATH_RFE_LNAH: - case PATH_RFE_LNAL: - case PATH_RFE_LNAW: pd_lna_rfe = 0; break; - default: break; - } - - int pd_rloopb_1_rfe = (path == PATH_RFE_LB1)?0:1; - int pd_rloopb_2_rfe = (path == PATH_RFE_LB2)?0:1; - int en_inshsw_l_rfe = (path == PATH_RFE_LNAL)?0:1; - int en_inshsw_w_rfe = (path == PATH_RFE_LNAW)?0:1; - int en_inshsw_lb1_rfe = (path == PATH_RFE_LB1)?0:1; - int en_inshsw_lb2_rfe = (path == PATH_RFE_LB2)?0:1; - - this->Modify_SPI_Reg_bits(LMS7param(PD_LNA_RFE), pd_lna_rfe); - this->Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_1_RFE), pd_rloopb_1_rfe); - this->Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_2_RFE), pd_rloopb_2_rfe); - this->Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB1_RFE), en_inshsw_lb1_rfe); - this->Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB2_RFE), en_inshsw_lb2_rfe); - this->Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_L_RFE), en_inshsw_l_rfe); - this->Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_W_RFE), en_inshsw_w_rfe); - this->Modify_SPI_Reg_bits(LMS7param(SEL_PATH_RFE), sel_path_rfe); - - //enable/disable the loopback path - const bool loopback = (path == PATH_RFE_LB1) or (path == PATH_RFE_LB2); - this->Modify_SPI_Reg_bits(LMS7param(EN_LOOPB_TXPAD_TRF), loopback?1:0); - - //update external band-selection to match - this->UpdateExternalBandSelect(); - - return 0; -} - -LMS7002M::PathRFE LMS7002M::GetPathRFE(void) -{ - if (this->Get_SPI_Reg_bits(LMS7param(EN_INSHSW_LB1_RFE)) == 0) return PATH_RFE_LB1; - if (this->Get_SPI_Reg_bits(LMS7param(EN_INSHSW_LB2_RFE)) == 0) return PATH_RFE_LB2; - if (this->Get_SPI_Reg_bits(LMS7param(EN_INSHSW_L_RFE)) == 0) return PATH_RFE_LNAL; - if (this->Get_SPI_Reg_bits(LMS7param(EN_INSHSW_W_RFE)) == 0) return PATH_RFE_LNAW; - if (this->Get_SPI_Reg_bits(LMS7param(PD_LNA_RFE)) == 0) return PATH_RFE_NONE; - return PATH_RFE_LNAH; -} - -int LMS7002M::SetBandTRF(const int band) -{ - this->Modify_SPI_Reg_bits(LMS7param(SEL_BAND1_TRF), (band==1)?1:0); - this->Modify_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF), (band==2)?1:0); - - //update external band-selection to match - this->UpdateExternalBandSelect(); - - return 0; -} - -int LMS7002M::GetBandTRF(void) -{ - if (this->Get_SPI_Reg_bits(LMS7param(SEL_BAND1_TRF)) == 1) return 1; - if (this->Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF)) == 1) return 2; - return 0; -} - -void LMS7002M::UpdateExternalBandSelect(void) -{ - if(controlPort) - return controlPort->UpdateExternalBandSelect( - this->GetActiveChannelIndex(), - this->GetBandTRF(), - int(this->GetPathRFE())); -} - -int LMS7002M::SetReferenceClk_SX(bool tx, float_type freq_Hz) -{ - if(controlPort == nullptr) - return ReportError(ENODEV, "Device not connected"); - if (tx) - return controlPort->SetTxReferenceClockRate(freq_Hz); - else - return controlPort->SetReferenceClockRate(freq_Hz); -} - -/** @brief Returns reference clock in Hz used for SXT or SXR - @param Tx transmitter or receiver selection -*/ -float_type LMS7002M::GetReferenceClk_SX(bool tx) -{ - if(controlPort == nullptr) - return 30.72e6; //return default reference clock - return (tx ? controlPort->GetTxReferenceClockRate() : controlPort->GetReferenceClockRate()); -} - -/** @return Current CLKGEN frequency in Hz - Returned frequency depends on reference clock used for Receiver -*/ -float_type LMS7002M::GetFrequencyCGEN() -{ - float_type dMul = (GetReferenceClk_SX(Rx)/2.0)/(Get_SPI_Reg_bits(LMS7param(DIV_OUTCH_CGEN), true)+1); //DIV_OUTCH_CGEN - uint16_t gINT = Get_SPI_Reg_bits(0x0088, 13, 0, true); //read whole register to reduce SPI transfers - uint32_t gFRAC = ((gINT & 0xF) * 65536) | Get_SPI_Reg_bits(0x0087, 15, 0, true); - return dMul * (((gINT>>4) + 1 + gFRAC/1048576.0)); -} - -/** @brief Returns TSP reference frequency - @param tx TxTSP or RxTSP selection - @return TSP reference frequency in Hz -*/ -float_type LMS7002M::GetReferenceClk_TSP(bool tx) -{ - float_type cgenFreq = GetFrequencyCGEN(); - float_type clklfreq = cgenFreq/pow(2.0, Get_SPI_Reg_bits(LMS7param(CLKH_OV_CLKL_CGEN))); - if(Get_SPI_Reg_bits(LMS7param(EN_ADCCLKH_CLKGN)) == 0) - return tx ? clklfreq : cgenFreq/4.0; - else - return tx ? cgenFreq : clklfreq/4.0; -} - -/** @brief Sets CLKGEN frequency, calculations use receiver'r reference clock - @param freq_Hz desired frequency in Hz - @param retainNCOfrequencies recalculate NCO coefficients to keep currently set frequencies - @param output if not null outputs calculated CGEN parameters - @return 0-succes, other-cannot deliver desired frequency -*/ -int LMS7002M::SetFrequencyCGEN(const float_type freq_Hz, const bool retainNCOfrequencies, CGEN_details* output) -{ - stringstream ss; - LMS7002M_SelfCalState state(this); - float_type dFvco; - float_type dFrac; - int16_t iHdiv; - - //remember NCO frequencies - Channel chBck = this->GetActiveChannel(); - vector > rxNCO(2); - vector > txNCO(2); - bool rxModeNCO = false; - bool txModeNCO = false; - if(retainNCOfrequencies) - { - rxModeNCO = Get_SPI_Reg_bits(LMS7param(MODE_RX), true); - txModeNCO = Get_SPI_Reg_bits(LMS7param(MODE_TX), true); - for (int ch = 0; ch < 2; ++ch) - { - this->SetActiveChannel((ch == 0)?ChA:ChB); - for (int i = 0; i < 16 && rxModeNCO == 0; ++i) - rxNCO[ch].push_back(GetNCOFrequency(LMS7002M::Rx, i, false)); - for (int i = 0; i < 16 && txModeNCO == 0; ++i) - txNCO[ch].push_back(GetNCOFrequency(LMS7002M::Tx, i, false)); - } - } - //VCO frequency selection according to F_CLKH - vector vcoFreqs; - for (iHdiv = 0; iHdiv < 256; ++iHdiv) - { - dFvco = 2 * (iHdiv + 1) * freq_Hz; - if (dFvco >= gCGEN_VCO_frequencies[0] && dFvco <= gCGEN_VCO_frequencies[1]) - vcoFreqs.push_back(dFvco); - } - if (vcoFreqs.size() == 0) - return ReportError(ERANGE, "SetFrequencyCGEN(%g MHz) - cannot deliver requested frequency", freq_Hz / 1e6); - dFvco = vcoFreqs[vcoFreqs.size() / 2]; - iHdiv = dFvco / freq_Hz / 2 - 1; - //Integer division - uint16_t gINT = (uint16_t)(dFvco/GetReferenceClk_SX(Rx) - 1); - - //Fractional division - dFrac = dFvco/GetReferenceClk_SX(Rx) - (uint32_t)(dFvco/GetReferenceClk_SX(Rx)); - uint32_t gFRAC = (uint32_t)(dFrac * 1048576); - - Modify_SPI_Reg_bits(LMS7param(INT_SDM_CGEN), gINT); //INT_SDM_CGEN - Modify_SPI_Reg_bits(0x0087, 15, 0, gFRAC&0xFFFF); //INT_SDM_CGEN[15:0] - Modify_SPI_Reg_bits(0x0088, 3, 0, gFRAC>>16); //INT_SDM_CGEN[19:16] - Modify_SPI_Reg_bits(LMS7param(DIV_OUTCH_CGEN), iHdiv); //DIV_OUTCH_CGEN - - ss << "INT: " << gINT << "\tFRAC: " << gFRAC - << "\tDIV_OUTCH_CGEN: " << (uint16_t)iHdiv << endl; - ss << "VCO: " << dFvco/1e6 << " MHz"; - ss << "\tRefClk: " << GetReferenceClk_SX(Rx)/1e6 << " MHz" << endl; - - if (output) - { - output->frequency = freq_Hz; - output->frequencyVCO = dFvco; - output->referenceClock = GetReferenceClk_SX(LMS7002M::Rx); - output->INT = gINT; - output->FRAC = gFRAC; - output->div_outch_cgen = iHdiv; - output->success = true; - } - - //recalculate NCO - for (int ch = 0; ch < 2 && retainNCOfrequencies; ++ch) - { - this->SetActiveChannel((ch == 0)?ChA:ChB); - for (int i = 0; i < 16 && rxModeNCO == 0; ++i) - SetNCOFrequency(LMS7002M::Rx, i, rxNCO[ch][i]); - for (int i = 0; i < 16 && txModeNCO == 0; ++i) - SetNCOFrequency(LMS7002M::Tx, i, txNCO[ch][i]); - } - this->SetActiveChannel(chBck); -#ifndef NDEBUG - printf("CGEN: Freq=%g MHz, VCO=%g GHz, INT=%i, FRAC=%i, DIV_OUTCH_CGEN=%i\n", freq_Hz/1e6, dFvco/1e9, gINT, gFRAC, iHdiv); -#endif // NDEBUG - //adjust VCO bias current to lock on 491.52 MHz - if(abs(freq_Hz - 491.52e6) < 2e6) - { - if(Modify_SPI_Reg_bits(LMS7param(ICT_VCO_CGEN), 31) == 0) - { -#ifndef NDEBUG - printf("CGEN ICT_VCO_CGEN changed to %i\n", 31); -#endif // NDEBUG - } - } - if(TuneVCO(VCO_CGEN) != 0) - { - if (output) - { - output->success = false; - output->csw = Get_SPI_Reg_bits(LMS7param(CSW_VCO_CGEN)); - } - ss << GetLastErrorMessage(); - return ReportError(-1, "SetFrequencyCGEN(%g MHz) failed:\n%s", freq_Hz/1e6, ss.str().c_str()); - } - if (output) - output->csw = Get_SPI_Reg_bits(LMS7param(CSW_VCO_CGEN)); - return 0; -} - -bool LMS7002M::GetCGENLocked(void) -{ - return (Get_SPI_Reg_bits(LMS7param(VCO_CMPHO_CGEN).address, 13, 12, true) & 0x3) == 2; -} - -bool LMS7002M::GetSXLocked(bool tx) -{ - SetActiveChannel(tx?ChSXT:ChSXR); - return (Get_SPI_Reg_bits(LMS7param(VCO_CMPHO).address, 13, 12, true) & 0x3) == 2; -} - -/** @brief Performs VCO tuning operations for CLKGEN, SXR, SXT modules - @param module module selection for tuning 0-cgen, 1-SXR, 2-SXT - @return 0-success, other-failure -*/ -int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT -{ - auto settlingTime = chrono::microseconds(50); //can be lower - struct CSWInteval - { - int16_t high; - int16_t low; - }; - CSWInteval cswSearch[2]; - stringstream ss; //tune progress report - const char* moduleName = (module == VCO_CGEN) ? "CGEN" : ((module == VCO_SXR) ? "SXR" : "SXT"); - checkConnection(); - uint8_t cmphl; //comparators - uint16_t addrVCOpd; // VCO power down address - uint16_t addrCSW_VCO; - uint16_t addrCMP; //comparator address - uint8_t lsb; //SWC lsb index - uint8_t msb; //SWC msb index - - Channel ch = this->GetActiveChannel(); //remember used channel - - if(module != VCO_CGEN) //set addresses to SX module - { - this->SetActiveChannel(Channel(module)); - addrVCOpd = LMS7param(PD_VCO).address; - addrCSW_VCO = LMS7param(CSW_VCO).address; - lsb = LMS7param(CSW_VCO).lsb; - msb = LMS7param(CSW_VCO).msb; - addrCMP = LMS7param(VCO_CMPHO).address; - ss << "ICT_VCO: " << Get_SPI_Reg_bits(LMS7param(ICT_VCO)) << endl; - } - else //set addresses to CGEN module - { - addrVCOpd = LMS7param(PD_VCO_CGEN).address; - addrCSW_VCO = LMS7param(CSW_VCO_CGEN).address; - lsb = LMS7param(CSW_VCO_CGEN).lsb; - msb = LMS7param(CSW_VCO_CGEN).msb; - addrCMP = LMS7param(VCO_CMPHO_CGEN).address; - ss << "ICT_VCO_CGEN: " << Get_SPI_Reg_bits(LMS7param(ICT_VCO_CGEN)) << endl; - } - // Initialization activate VCO and comparator - if(int status = Modify_SPI_Reg_bits (addrVCOpd, 2, 1, 0) != 0) - return status; - if (Get_SPI_Reg_bits(addrVCOpd, 2, 1) != 0) - return ReportError(-1, "TuneVCO(%s) - VCO is powered down", moduleName); - - //check if lock is within VCO range - { - Modify_SPI_Reg_bits (addrCSW_VCO , msb, lsb , 0); - this_thread::sleep_for(settlingTime); - cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - if(cmphl == 3) //VCO too high - { - this->SetActiveChannel(ch); //restore previously used channel - return ReportError(-1, "TuneVCO(%s) - VCO too high", moduleName); - } - Modify_SPI_Reg_bits (addrCSW_VCO , msb, lsb , 255); - this_thread::sleep_for(settlingTime); - cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - if(cmphl == 0) //VCO too low - { - this->SetActiveChannel(ch); //restore previously used channel - return ReportError(-1, "TuneVCO(%s) - VCO too low", moduleName); - } - } - - //search intervals [0-127][128-255] - for(int t=0; t<2; ++t) - { - cswSearch[t].low = 128*(t+1); - cswSearch[t].high = 128*t; //search interval lowest value - Modify_SPI_Reg_bits (addrCSW_VCO , msb, lsb , cswSearch[t].high); - for(int i=6; i>=0; --i) - { - cswSearch[t].high |= 1 << i; //CSW_VCO=1 - Modify_SPI_Reg_bits (addrCSW_VCO, msb, lsb, cswSearch[t].high); - this_thread::sleep_for(settlingTime); - cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - ss << "csw=" << cswSearch[t].high << "\t" << "cmphl=" << (int16_t)cmphl << endl; - if(cmphl & 0x01) // reduce CSW - cswSearch[t].high &= ~(1 << i); //CSW_VCO=0 - if(cmphl == 2 && cswSearch[t].high < cswSearch[t].low) - cswSearch[t].low = cswSearch[t].high; - } - while(cswSearch[t].low <= cswSearch[t].high && cswSearch[t].low > t*128) - { - --cswSearch[t].low; - Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, cswSearch[t].low); - this_thread::sleep_for(settlingTime); - if(Get_SPI_Reg_bits(addrCMP, 13, 12, true) != 2) - { - ++cswSearch[t].low; - break; - } - } - if(cmphl == 2) - { - ss << "CSW_lowest =" << cswSearch[t].low << endl; - ss << "CSW_highest =" << cswSearch[t].high << endl; - ss << "CSW_selected=" << cswSearch[t].low+(cswSearch[t].high-cswSearch[t].low)/2 << endl; - } - else - ss << "Failed to lock" << endl; - } - - //check if the intervals are joined - int16_t cswHigh, cswLow; - if(cswSearch[0].high == cswSearch[1].low-1) - { - cswHigh = cswSearch[1].high; - cswLow = cswSearch[0].low; - } - //compare which interval is wider - else - { - uint8_t intervalIndex = (cswSearch[1].high-cswSearch[1].low > cswSearch[0].high-cswSearch[0].low); - cswHigh = cswSearch[intervalIndex].high; - cswLow = cswSearch[intervalIndex].low; - } - - if(cswHigh-cswLow == 1) - { - //check which of two values really locks - Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, cswLow); - this_thread::sleep_for(settlingTime); - cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - if(cmphl != 2) - Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, cswHigh); - } - else - Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, cswLow+(cswHigh-cswLow)/2); - this_thread::sleep_for(settlingTime); - cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - ss << " cmphl=" << (uint16_t)cmphl; - this->SetActiveChannel(ch); //restore previously used channel - if(cmphl == 2) - return 0; - return ReportError(EINVAL, "TuneVCO(%s) - failed to lock (cmphl != 2)\n%s", moduleName, ss.str().c_str()); -} - -/** @brief Returns given parameter value from chip register - @param param LMS7002M control parameter - @param fromChip read directly from chip - @return parameter value -*/ -uint16_t LMS7002M::Get_SPI_Reg_bits(const LMS7Parameter ¶m, bool fromChip) -{ - return Get_SPI_Reg_bits(param.address, param.msb, param.lsb, fromChip); -} - -/** @brief Returns given parameter value from chip register - @param address register address - @param msb most significant bit index - @param lsb least significant bit index - @param fromChip read directly from chip - @return register bits from selected interval, shifted to right by lsb bits -*/ -uint16_t LMS7002M::Get_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, bool fromChip) -{ - return (SPI_read(address, fromChip) & (~(~0<<(msb+1)))) >> lsb; //shift bits to LSB -} - -/** @brief Change given parameter value - @param param LMS7002M control parameter - @param fromChip read initial value directly from chip - @param value new parameter value -*/ -int LMS7002M::Modify_SPI_Reg_bits(const LMS7Parameter ¶m, const uint16_t value, bool fromChip) -{ - return Modify_SPI_Reg_bits(param.address, param.msb, param.lsb, value, fromChip); -} - -/** @brief Change given parameter value - @param address register address - @param value new bits value, the value is shifted left by lsb bits - @param fromChip read initial value directly from chip -*/ -int LMS7002M::Modify_SPI_Reg_bits(const uint16_t address, const uint8_t msb, const uint8_t lsb, const uint16_t value, bool fromChip) -{ - uint16_t spiDataReg = SPI_read(address, fromChip); //read current SPI reg data - uint16_t spiMask = (~(~0 << (msb - lsb + 1))) << (lsb); // creates bit mask - spiDataReg = (spiDataReg & (~spiMask)) | ((value << lsb) & spiMask);//clear bits - return SPI_write(address, spiDataReg); //write modified data back to SPI reg -} - -/** @brief Modifies given registers with values applied using masks - @param addr array of register addresses - @param masks array of applied masks - @param values array of values to be written - @param start starting index of given arrays - @param stop end index of given arrays -*/ -int LMS7002M::Modify_SPI_Reg_mask(const uint16_t *addr, const uint16_t *masks, const uint16_t *values, uint8_t start, uint8_t stop) -{ - int status; - uint16_t reg_data; - vector addresses; - vector data; - while (start <= stop) - { - reg_data = SPI_read(addr[start], true, &status); //read current SPI reg data - reg_data &= ~masks[start];//clear bits - reg_data |= (values[start] & masks[start]); - addresses.push_back(addr[start]); - data.push_back(reg_data); - ++start; - } - if (status != 0) - return status; - SPI_write_batch(&addresses[0], &data[0], addresses.size()); - return status; -} - -/** @brief Sets SX frequency - @param Tx Rx/Tx module selection - @param freq_Hz desired frequency in Hz - @param output if not null outputs intermediate calculation values - @return 0-success, other-cannot deliver requested frequency -*/ -int LMS7002M::SetFrequencySX(bool tx, float_type freq_Hz, SX_details* output) -{ - stringstream ss; //VCO tuning report - const char* vcoNames[] = {"VCOL", "VCOM", "VCOH"}; - checkConnection(); - const uint8_t sxVCO_N = 2; //number of entries in VCO frequencies - const float_type m_dThrF = 5500e6; //threshold to enable additional divider - float_type VCOfreq; - int8_t div_loch; - int8_t sel_vco; - bool canDeliverFrequency = false; - uint16_t integerPart; - uint32_t fractionalPart; - int16_t csw_value; - uint32_t boardId = controlPort->GetDeviceInfo().boardSerialNumber; - - //find required VCO frequency - for (div_loch = 6; div_loch >= 0; --div_loch) - { - VCOfreq = (1 << (div_loch + 1)) * freq_Hz; - if ((VCOfreq >= gVCO_frequency_table[0][0]) && (VCOfreq <= gVCO_frequency_table[2][sxVCO_N - 1])) - { - canDeliverFrequency = true; - break; - } - } - if (canDeliverFrequency == false) - return ReportError(ERANGE, "SetFrequencySX%s(%g MHz) - required VCO frequency is out of range [%g-%g] MHz", - tx?"T":"R", freq_Hz / 1e6, - gVCO_frequency_table[0][0]/1e6, - gVCO_frequency_table[2][sxVCO_N - 1]/1e6); - - const float_type refClk_Hz = GetReferenceClk_SX(tx); - integerPart = (uint16_t)(VCOfreq / (refClk_Hz * (1 + (VCOfreq > m_dThrF))) - 4); - fractionalPart = (uint32_t)((VCOfreq / (refClk_Hz * (1 + (VCOfreq > m_dThrF))) - (uint32_t)(VCOfreq / (refClk_Hz * (1 + (VCOfreq > m_dThrF))))) * 1048576); - - Channel ch = this->GetActiveChannel(); - this->SetActiveChannel(tx?ChSXT:ChSXR); - Modify_SPI_Reg_bits(LMS7param(EN_INTONLY_SDM), 0); - Modify_SPI_Reg_bits(LMS7param(INT_SDM), integerPart); //INT_SDM - Modify_SPI_Reg_bits(0x011D, 15, 0, fractionalPart & 0xFFFF); //FRAC_SDM[15:0] - Modify_SPI_Reg_bits(0x011E, 3, 0, (fractionalPart >> 16)); //FRAC_SDM[19:16] - Modify_SPI_Reg_bits(LMS7param(DIV_LOCH), div_loch); //DIV_LOCH - Modify_SPI_Reg_bits(LMS7param(EN_DIV2_DIVPROG), (VCOfreq > m_dThrF)); //EN_DIV2_DIVPROG - - ss << "INT: " << integerPart << "\tFRAC: " << fractionalPart << endl; - ss << "DIV_LOCH: " << (int16_t)div_loch << "\t EN_DIV2_DIVPROG: " << (VCOfreq > m_dThrF) << endl; - ss << "VCO: " << VCOfreq/1e6 << "MHz\tRefClk: " << refClk_Hz/1e6 << " MHz" << endl; - - if (output) - { - output->frequency = freq_Hz; - output->frequencyVCO = VCOfreq; - output->referenceClock = GetReferenceClk_SX(tx); - output->INT = integerPart; - output->FRAC = fractionalPart; - output->en_div2_divprog = (VCOfreq > m_dThrF); - output->div_loch = div_loch; - } - - //find which VCO supports required frequency - Modify_SPI_Reg_bits(LMS7param(PD_VCO), 0); // - Modify_SPI_Reg_bits(LMS7param(PD_VCO_COMP), 0); // - - bool foundInCache = false; - int vco_query; - int csw_query; - if(useCache) - { - foundInCache = (mValueCache->GetVCO_CSW(boardId, freq_Hz, mdevIndex, tx, &vco_query, &csw_query) == 0); - } - if(foundInCache) - { - printf("SetFrequency using cache values vco:%i, csw:%i\n", vco_query, csw_query); - sel_vco = vco_query; - csw_value = csw_query; - } - else - { - canDeliverFrequency = false; - int tuneScore[] = { -128, -128, -128 }; //best is closest to 0 - for (sel_vco = 0; sel_vco < 3; ++sel_vco) - { - Modify_SPI_Reg_bits(LMS7param(SEL_VCO), sel_vco); - int status = TuneVCO(tx ? VCO_SXT : VCO_SXR); - if(status == 0) - { - tuneScore[sel_vco] = -128 + Get_SPI_Reg_bits(LMS7param(CSW_VCO), true); - canDeliverFrequency = true; - } - ss << vcoNames[sel_vco] << " : csw=" << tuneScore[sel_vco]+128 << " "; - ss << (status == 0 ? "tune ok" : "tune fail") << endl; - } - if (abs(tuneScore[0]) < abs(tuneScore[1])) - { - if (abs(tuneScore[0]) < abs(tuneScore[2])) - sel_vco = 0; - else - sel_vco = 2; - } - else - { - if (abs(tuneScore[1]) < abs(tuneScore[2])) - sel_vco = 1; - else - sel_vco = 2; - } - csw_value = tuneScore[sel_vco] + 128; - ss << "\tSelected : " << vcoNames[sel_vco] << endl; - } - if(useCache && !foundInCache) - { - mValueCache->InsertVCO_CSW(boardId, freq_Hz, mdevIndex, tx, sel_vco, csw_value); - } - if (output) - { - if (canDeliverFrequency) - output->success = true; - output->sel_vco = sel_vco; - output->csw = csw_value; - } - Modify_SPI_Reg_bits(LMS7param(SEL_VCO), sel_vco); - Modify_SPI_Reg_bits(LMS7param(CSW_VCO), csw_value); - this->SetActiveChannel(ch); //restore used channel - - if (canDeliverFrequency == false) - return ReportError(EINVAL, "SetFrequencySX%s(%g MHz) - cannot deliver frequency\n%s", tx?"T":"R", freq_Hz / 1e6, ss.str().c_str()); - return 0; -} - -/** @brief Sets SX frequency with Reference clock spur cancelation - @param Tx Rx/Tx module selection - @param freq_Hz desired frequency in Hz - @return 0-success, other-cannot deliver requested frequency -*/ -int LMS7002M::SetFrequencySXWithSpurCancelation(bool tx, float_type freq_Hz, float_type BW) -{ - const float BWOffset = 2e6; - BW += BWOffset; //offset to avoid ref clock on BW edge - bool needCancelation = false; - float_type refClk = GetReferenceClk_SX(false); - int low = (freq_Hz-BW/2)/refClk; - int high = (freq_Hz+BW/2)/refClk; - if(low != high) - needCancelation = true; - - int status; - float newFreq; - if(needCancelation) - { - newFreq = (int)(freq_Hz/refClk+0.5)*refClk; - TuneRxFilter(BW-BWOffset+2*abs(freq_Hz-newFreq)); - status = SetFrequencySX(tx, newFreq); - } - else - status = SetFrequencySX(tx, freq_Hz); - if(status != 0) - return status; - const int ch = Get_SPI_Reg_bits(LMS7param(MAC)); - for(int i=0; i<2; ++i) - { - Modify_SPI_Reg_bits(LMS7param(MAC), i+1); - SetNCOFrequency(LMS7002M::Rx, 15, 0); - } - if(needCancelation) - { - Modify_SPI_Reg_bits(LMS7param(MAC), ch); - Modify_SPI_Reg_bits(LMS7param(EN_INTONLY_SDM), 1); - - /*uint16_t gINT = Get_SPI_Reg_bits(0x011E, 13, 0); // read whole register to reduce SPI transfers - uint32_t gFRAC = ((gINT&0xF) * 65536) | Get_SPI_Reg_bits(0x011D, 15, 0); - bool upconvert = gFRAC > (1 << 19); - gINT = gINT >> 4; - if(upconvert) - { - gINT+=; - Modify_SPI_Reg_bits(LMS7param(INT_SDM), gINT); - } - Modify_SPI_Reg_bits(0x011D, 15, 0, 0); - Modify_SPI_Reg_bits(0x011E, 3, 0, 0);*/ - //const float_type refClk_Hz = GetReferenceClk_SX(tx); - //float actualFreq = (float_type)refClk_Hz / (1 << (Get_SPI_Reg_bits(LMS7param(DIV_LOCH)) + 1)); - //actualFreq *= (gINT + 4) * (Get_SPI_Reg_bits(LMS7param(EN_DIV2_DIVPROG)) + 1); - float actualFreq = newFreq; - float userFreq = freq_Hz; - bool upconvert = actualFreq > userFreq; - for(int i=0; i<2; ++i) - { - Modify_SPI_Reg_bits(LMS7param(MAC), i+1); - Modify_SPI_Reg_bits(LMS7param(CMIX_SC_RXTSP), !upconvert); - Modify_SPI_Reg_bits(LMS7param(CMIX_BYP_RXTSP), 0); - Modify_SPI_Reg_bits(LMS7param(SEL_RX), 15); - Modify_SPI_Reg_bits(LMS7param(CMIX_GAIN_RXTSP), 1); - SetNCOFrequency(LMS7002M::Rx, 14, 0); - SetNCOFrequency(LMS7002M::Rx, 15, abs(actualFreq-userFreq)); - } - } - - Modify_SPI_Reg_bits(LMS7param(MAC), ch); - return 0; -} - -/** @brief Returns currently set SXR/SXT frequency - @return SX frequency Hz -*/ -float_type LMS7002M::GetFrequencySX(bool tx) -{ - Channel ch = this->GetActiveChannel(); //remember previously used channel - float_type dMul; - this->SetActiveChannel(tx?ChSXT:ChSXR); - uint16_t gINT = Get_SPI_Reg_bits(0x011E, 13, 0); // read whole register to reduce SPI transfers - uint32_t gFRAC = ((gINT&0xF) * 65536) | Get_SPI_Reg_bits(0x011D, 15, 0); - - const float_type refClk_Hz = GetReferenceClk_SX(tx); - dMul = (float_type)refClk_Hz / (1 << (Get_SPI_Reg_bits(LMS7param(DIV_LOCH)) + 1)); - //Calculate real frequency according to the calculated parameters - dMul = dMul * ((gINT >> 4) + 4 + (float_type)gFRAC / 1048576.0) * (Get_SPI_Reg_bits(LMS7param(EN_DIV2_DIVPROG)) + 1); - this->SetActiveChannel(ch); //restore used channel - return dMul; -} - -/** @brief Sets chosen NCO's frequency - @param tx transmitter or receiver selection - @param index NCO index from 0 to 15 - @param freq_Hz desired NCO frequency - @return 0-success, other-failure -*/ -int LMS7002M::SetNCOFrequency(bool tx, uint8_t index, float_type freq_Hz) -{ - if(index > 15) - return ReportError(ERANGE, "SetNCOFrequency(index = %d) - index out of range [0, 15]", int(index)); - float_type refClk_Hz = GetReferenceClk_TSP(tx); - if(freq_Hz < 0 || freq_Hz/refClk_Hz > 0.5) - return ReportError(ERANGE, "SetNCOFrequency(index = %d) - Frequency(%g MHz) out of range [0-%g) MHz", int(index), freq_Hz/1e6, refClk_Hz/2e6); - uint16_t addr = tx ? 0x0240 : 0x0440; - uint32_t fcw = uint32_t((freq_Hz/refClk_Hz)*4294967296); - SPI_write(addr+2+index*2, (fcw >> 16)); //NCO frequency control word register MSB part. - SPI_write(addr+3+index*2, fcw); //NCO frequency control word register LSB part. - return 0; -} - -/** @brief Returns chosen NCO's frequency in Hz - @param tx transmitter or receiver selection - @param index NCO index from 0 to 15 - @param fromChip read frequency directly from chip or local registers - @return NCO frequency in Hz -*/ -float_type LMS7002M::GetNCOFrequency(bool tx, uint8_t index, bool fromChip) -{ - if(index > 15) - return ReportError(ERANGE, "GetNCOFrequency_MHz(index = %d) - index out of range [0, 15]", int(index)); - float_type refClk_Hz = GetReferenceClk_TSP(tx); - uint16_t addr = tx ? 0x0240 : 0x0440; - uint32_t fcw = 0; - fcw |= SPI_read(addr + 2 + index * 2, fromChip) << 16; //NCO frequency control word register MSB part. - fcw |= SPI_read(addr + 3 + index * 2, fromChip); //NCO frequency control word register LSB part. - return refClk_Hz*(fcw/4294967296.0); -} - -/** @brief Sets chosen NCO phase offset angle when memory table MODE is 0 -@param tx transmitter or receiver selection -@param angle_deg phase offset angle in degrees -@return 0-success, other-failure -*/ -int LMS7002M::SetNCOPhaseOffsetForMode0(bool tx, float_type angle_deg) -{ - uint16_t addr = tx ? 0x0241 : 0x0441; - uint16_t pho = (uint16_t)(65536 * (angle_deg / 360 )); - SPI_write(addr, pho); - return 0; -} - -/** @brief Sets chosen NCO's phase offset angle - @param tx transmitter or receiver selection - @param index PHO index from 0 to 15 - @param angle_deg phase offset angle in degrees - @return 0-success, other-failure -*/ -int LMS7002M::SetNCOPhaseOffset(bool tx, uint8_t index, float_type angle_deg) -{ - if(index > 15) - return ReportError(ERANGE, "SetNCOPhaseOffset(index = %d) - index out of range [0, 15]", int(index)); - uint16_t addr = tx ? 0x0244 : 0x0444; - uint16_t pho = (uint16_t)(65536*(angle_deg / 360)); - SPI_write(addr+index, pho); - return 0; -} - -/** @brief Returns chosen NCO's phase offset angle in radians - @param tx transmitter or receiver selection - @param index PHO index from 0 to 15 - @return phase offset angle in degrees -*/ -float_type LMS7002M::GetNCOPhaseOffset_Deg(bool tx, uint8_t index) -{ - if(index > 15) - return ReportError(ERANGE, "GetNCOPhaseOffset_Deg(index = %d) - index out of range [0, 15]", int(index)); - uint16_t addr = tx ? 0x0244 : 0x0444; - uint16_t pho = SPI_read(addr+index); - float_type angle = 360*pho/65536.0; - return angle; -} - -/** @brief Uploads given FIR coefficients to chip - @param tx Transmitter or receiver selection - @param GFIR_index GIR index from 0 to 2 - @param coef array of coefficients - @param coefCount number of coefficients - @return 0-success, other-failure - - This function does not change GFIR*_L or GFIR*_N parameters, they have to be set manually -*/ -int LMS7002M::SetGFIRCoefficients(bool tx, uint8_t GFIR_index, const int16_t *coef, uint8_t coefCount) -{ - uint8_t index; - uint8_t coefLimit; - uint16_t startAddr; - if (GFIR_index == 0) - startAddr = 0x0280; - else if (GFIR_index == 1) - startAddr = 0x02C0; - else - startAddr = 0x0300; - - if (tx == false) - startAddr += 0x0200; - if (GFIR_index < 2) - coefLimit = 40; - else - coefLimit = 120; - if (coefCount > coefLimit) - return ReportError(ERANGE, "SetGFIRCoefficients(coefCount=%d) - exceeds coefLimit=%d", int(coefCount), int(coefLimit)); - vector addresses; - for (index = 0; index < coefCount; ++index) - addresses.push_back(startAddr + index + 24 * (index / 40)); - SPI_write_batch(&addresses[0], (uint16_t*)coef, coefCount); - return 0; -} - -/** @brief Returns currently loaded FIR coefficients - @param tx Transmitter or receiver selection - @param GFIR_index GIR index from 0 to 2 - @param coef array of returned coefficients - @param coefCount number of coefficients to read - @return 0-success, other-failure -*/ -int LMS7002M::GetGFIRCoefficients(bool tx, uint8_t GFIR_index, int16_t *coef, uint8_t coefCount) -{ - checkConnection(); - - int status = -1; - uint8_t index; - uint8_t coefLimit; - uint16_t startAddr; - if(GFIR_index == 0) - startAddr = 0x0280; - else if (GFIR_index == 1) - startAddr = 0x02C0; - else - startAddr = 0x0300; - - if (tx == false) - startAddr += 0x0200; - if (GFIR_index < 2) - coefLimit = 40; - else - coefLimit = 120; - if (coefCount > coefLimit) - return ReportError(ERANGE, "GetGFIRCoefficients(coefCount=%d) - exceeds coefLimit=%d", int(coefCount), int(coefLimit)); - - std::vector addresses; - for (index = 0; index < coefCount; ++index) - addresses.push_back(startAddr + index + 24 * (index / 40)); - uint16_t spiData[120]; - memset(spiData, 0, 120 * sizeof(uint16_t)); - if (controlPort->IsOpen()) - { - status = SPI_read_batch(&addresses[0], spiData, coefCount); - for (index = 0; index < coefCount; ++index) - coef[index] = spiData[index]; - } - else - { - const int channel = Get_SPI_Reg_bits(LMS7param(MAC), false) > 1 ? 1 : 0; - for (index = 0; index < coefCount; ++index) - coef[index] = mRegistersMap->GetValue(channel, addresses[index]); - status = 0; - } - - return status; -} - -/** @brief Write given data value to whole register - @param address SPI address - @param data new register value - @return 0-succes, other-failure -*/ -int LMS7002M::SPI_write(uint16_t address, uint16_t data) -{ - if(address == 0x0640 || address == 0x0641) - { - MCU_BD* mcu = GetMCUControls(); - SPI_write(0x002D, address); - SPI_write(0x020C, data); - mcu->RunProcedure(7); - mcu->WaitForMCU(50); - return SPI_read(0x040B); - } - else - return this->SPI_write_batch(&address, &data, 1); -} - -/** @brief Reads whole register value from given address - @param address SPI address - @param status operation status(optional) - @param fromChip read value directly from chip - @return register value -*/ -uint16_t LMS7002M::SPI_read(uint16_t address, bool fromChip, int *status) -{ - if (!controlPort || fromChip == false) - { - if (status && !controlPort) - *status = ReportError(ENOTCONN, "chip not connected"); - int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003; - int regNo = (mac == 2)? 1 : 0; //only when MAC is B -> use register space B - if (address < 0x0100) regNo = 0; //force A when below MAC mapped register space - return mRegistersMap->GetValue(regNo, address); - } - if(controlPort) - { - uint16_t data = 0; - int st; - if(address == 0x0640 || address == 0x0641) - { - MCU_BD* mcu = GetMCUControls(); - SPI_write(0x002D, address); - mcu->RunProcedure(8); - mcu->WaitForMCU(50); - uint16_t rdVal = SPI_read(0x040B, true, status); - return rdVal; - } - else - st = this->SPI_read_batch(&address, &data, 1); - if (status != nullptr) *status = st; - return data; - } - return 0; -} - -/** @brief Batches multiple register writes into least ammount of transactions - @param spiAddr spi register addresses to be written - @param spiData registers data to be written - @param cnt number of registers to write - @return 0-success, other-failure -*/ -int LMS7002M::SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt) -{ - int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003; - std::vector data(cnt); - for (size_t i = 0; i < cnt; ++i) - { - data[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write - - //write which register cache based on MAC bits - //or always when below the MAC mapped register space - bool wr0 = ((mac & 0x1) != 0) or (spiAddr[i] < 0x0100); - bool wr1 = ((mac & 0x2) != 0) and (spiAddr[i] >= 0x0100); - - if (wr0) mRegistersMap->SetValue(0, spiAddr[i], spiData[i]); - if (wr1) mRegistersMap->SetValue(1, spiAddr[i], spiData[i]); - - //refresh mac, because batch might also change active channel - if(spiAddr[i] == LMS7param(MAC).address) - mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003; - } - - checkConnection(); - return controlPort->WriteLMS7002MSPI(data.data(), cnt,mdevIndex); -} - -/** @brief Batches multiple register reads into least amount of transactions - @param spiAddr SPI addresses to read - @param spiData array for read data - @param cnt number of registers to read - @return 0-success, other-failure -*/ -int LMS7002M::SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt) -{ - checkConnection(); - - std::vector dataWr(cnt); - std::vector dataRd(cnt); - for (size_t i = 0; i < cnt; ++i) - { - dataWr[i] = (uint32_t(spiAddr[i]) << 16); - } - - - int status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), cnt,mdevIndex); - if (status != 0) return status; - - int mac = mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003; - - for (size_t i = 0; i < cnt; ++i) - { - spiData[i] = dataRd[i] & 0xffff; - - //write which register cache based on MAC bits - //or always when below the MAC mapped register space - bool wr0 = ((mac & 0x1) != 0) or (spiAddr[i] < 0x0100); - bool wr1 = ((mac & 0x2) != 0) and (spiAddr[i] >= 0x0100); - - if (wr0) mRegistersMap->SetValue(0, spiAddr[i], spiData[i]); - if (wr1) mRegistersMap->SetValue(1, spiAddr[i], spiData[i]); - } - return 0; -} - -/** @brief Performs registers test by writing known data and confirming readback data - @return 0-registers test passed, other-failure -*/ -int LMS7002M::RegistersTest(const char* fileName) -{ - char chex[16]; - checkConnection(); - - int status; - Channel ch = this->GetActiveChannel(); - - //backup both channel data for restoration after test - vector ch1Addresses; - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) - ch1Addresses.push_back(addr); - vector ch1Data; - ch1Data.resize(ch1Addresses.size(), 0); - - //backup A channel - this->SetActiveChannel(ChA); - status = SPI_read_batch(&ch1Addresses[0], &ch1Data[0], ch1Addresses.size()); - if (status != 0) - return status; - - vector ch2Addresses; - 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) - ch2Addresses.push_back(addr); - vector ch2Data; - ch2Data.resize(ch2Addresses.size(), 0); - - this->SetActiveChannel(ChB); - status = SPI_read_batch(&ch2Addresses[0], &ch2Data[0], ch2Addresses.size()); - if (status != 0) - return status; - - //test registers - ResetChip(); - Modify_SPI_Reg_bits(LMS7param(MIMO_SISO), 0); - Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), 0); - Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE2), 0); - this->SetActiveChannel(ChA); - - stringstream ss; - - //check single channel memory sections - vector modulesToCheck = { AFE, BIAS, XBUF, CGEN, LDO, BIST, CDS, TRF, TBB, RFE, RBB, SX, - TxTSP, TxNCO, TxGFIR1, TxGFIR2, TxGFIR3a, TxGFIR3b, TxGFIR3c, - RxTSP, RxNCO, RxGFIR1, RxGFIR2, RxGFIR3a, RxGFIR3b, RxGFIR3c, LimeLight }; - const char* moduleNames[] = { "AFE", "BIAS", "XBUF", "CGEN", "LDO", "BIST", "CDS", "TRF", "TBB", "RFE", "RBB", "SX", - "TxTSP", "TxNCO", "TxGFIR1", "TxGFIR2", "TxGFIR3a", "TxGFIR3b", "TxGFIR3c", - "RxTSP", "RxNCO", "RxGFIR1", "RxGFIR2", "RxGFIR3a", "RxGFIR3b", "RxGFIR3c", "LimeLight" }; - - const uint16_t patterns[] = { 0xAAAA, 0x5555 }; - const uint8_t patternsCount = 2; - - bool allTestSuccess = true; - - for (unsigned i = 0; i < modulesToCheck.size(); ++i) - { - bool moduleTestsSuccess = true; - uint16_t startAddr = MemorySectionAddresses[modulesToCheck[i]][0]; - uint16_t endAddr = MemorySectionAddresses[modulesToCheck[i]][1]; - uint8_t channelCount = startAddr >= 0x0100 ? 2 : 1; - for (int cc = 1; cc <= channelCount; ++cc) - { - Modify_SPI_Reg_bits(LMS7param(MAC), cc); - sprintf(chex, "0x%04X", startAddr); - ss << moduleNames[i] << " [" << chex << ":"; - sprintf(chex, "0x%04X", endAddr); - ss << chex << "]"; - if (startAddr >= 0x0100) { - ss << " Ch." << (cc == 1 ? "A" : "B"); - } - ss << endl; - for (uint8_t p = 0; p < patternsCount; ++p) - moduleTestsSuccess &= RegistersTestInterval(startAddr, endAddr, patterns[p], ss) == 0; - } - allTestSuccess &= moduleTestsSuccess; - } - - //restore register values - this->SetActiveChannel(ChA); - SPI_write_batch(&ch1Addresses[0], &ch1Data[0], ch1Addresses.size()); - this->SetActiveChannel(ChB); - SPI_write_batch(&ch2Addresses[0], &ch2Data[0], ch2Addresses.size()); - this->SetActiveChannel(ch); - - if (fileName) - { - fstream fout; - fout.open(fileName, ios::out); - fout << ss.str() << endl; - fout.close(); - } - - if (allTestSuccess) return 0; - ReportError(-1, "RegistersTest() failed - %s", GetLastErrorMessage()); - return -1; -} - -/** @brief Performs registers test for given address interval by writing given pattern data - @param startAddr first register address - @param endAddr last reigster address - @param pattern data to be written into registers - @return 0-register test passed, other-failure -*/ -int LMS7002M::RegistersTestInterval(uint16_t startAddr, uint16_t endAddr, uint16_t pattern, stringstream &ss) -{ - vector addrToWrite; - vector dataToWrite; - vector dataReceived; - vector dataMasks; - - for (uint16_t addr = startAddr; addr <= endAddr; ++addr) - { - addrToWrite.push_back(addr); - } - dataMasks.resize(addrToWrite.size(), 0xFFFF); - for (uint16_t j = 0; j < sizeof(readOnlyRegisters)/sizeof(uint16_t); ++j) - for (uint16_t k = 0; k < addrToWrite.size(); ++k) - if (readOnlyRegisters[j] == addrToWrite[k]) - { - dataMasks[k] = readOnlyRegistersMasks[j]; - break; - } - - dataToWrite.clear(); - dataReceived.clear(); - for (uint16_t j = 0; j < addrToWrite.size(); ++j) - { - if (addrToWrite[j] == 0x00A6) - dataToWrite.push_back(0x1 | (pattern & ~0x2)); - else if (addrToWrite[j] == 0x0084) - dataToWrite.push_back(pattern & ~0x19); - else - dataToWrite.push_back(pattern & dataMasks[j]); - } - dataReceived.resize(addrToWrite.size(), 0); - int status; - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0) - return status; - status = SPI_read_batch(&addrToWrite[0], &dataReceived[0], addrToWrite.size()); - if (status != 0) - return status; - bool registersMatch = true; - char ctemp[16]; - for (uint16_t j = 0; j < dataToWrite.size(); ++j) - { - if (dataToWrite[j] != (dataReceived[j] & dataMasks[j])) - { - registersMatch = false; - sprintf(ctemp, "0x%04X", addrToWrite[j]); - ss << "\t" << ctemp << "(wr/rd): "; - sprintf(ctemp, "0x%04X", dataToWrite[j]); - ss << ctemp << "/"; - sprintf(ctemp, "0x%04X", dataReceived[j]); - ss << ctemp << endl; - } - } - if (registersMatch) - { - sprintf(ctemp, "0x%04X", pattern); - ss << "\tRegisters OK (" << ctemp << ")\n"; - } - if (registersMatch) return 0; - return ReportError(-1, "RegistersTestInterval(startAddr=0x%x, endAddr=0x%x) - failed", startAddr, endAddr); -} - -/** @brief Sets Rx Dc offsets by converting two's complementary numbers to sign and magnitude -*/ -void LMS7002M::SetRxDCOFF(int8_t offsetI, int8_t offsetQ) -{ - uint16_t valToSend = 0; - if (offsetI < 0) - valToSend |= 0x40; - valToSend |= labs(offsetI); - valToSend = valToSend << 7; - if (offsetQ < 0) - valToSend |= 0x40; - valToSend |= labs(offsetQ); - SPI_write(0x010E, valToSend); -} - -/** @brief Sets given module registers to default values - @return 0-success, other-failure -*/ -int LMS7002M::SetDefaults(MemorySection module) -{ - int status = 0; - vector addrs; - vector values; - for(uint32_t address = MemorySectionAddresses[module][0]; address <= MemorySectionAddresses[module][1]; ++address) - { - addrs.push_back(address); - values.push_back(mRegistersMap->GetDefaultValue(address)); - } - status = SPI_write_batch(&addrs[0], &values[0], addrs.size()); - return status; -} - -/** @brief Reads all chip configuration and checks if it matches with local registers copy -*/ -bool LMS7002M::IsSynced() -{ - if (!controlPort || controlPort->IsOpen() == false) - return false; - bool isSynced = true; - int status; - - Channel ch = this->GetActiveChannel(); - - vector addrToRead = mRegistersMap->GetUsedAddresses(0); - vector dataReceived; - dataReceived.resize(addrToRead.size(), 0); - - this->SetActiveChannel(ChA); - std::vector dataWr(addrToRead.size()); - std::vector dataRd(addrToRead.size()); - for(size_t i = 0; i < addrToRead.size(); ++i) - dataWr[i] = (uint32_t(addrToRead[i]) << 16); - status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), dataWr.size(),mdevIndex); - - for(size_t i=0; iGetValue(0, addrToRead[i]); - if(addrToRead[i] <= readOnlyRegisters[sizeof(readOnlyRegisters)/sizeof(uint16_t)-1] && addrToRead[i] >= readOnlyRegisters[0]) - { - //mask out readonly bits - for (uint16_t j = 0; j < sizeof(readOnlyRegisters) / sizeof(uint16_t); ++j) - if (readOnlyRegisters[j] == addrToRead[i]) - { - dataReceived[i] &= readOnlyRegistersMasks[j]; - regValue &= readOnlyRegistersMasks[j]; - break; - } - } - if (dataReceived[i] != regValue) - { - printf("Addr: 0x%04X gui: 0x%04X chip: 0x%04X\n", addrToRead[i], regValue, dataReceived[i]); - isSynced = false; - goto isSyncedEnding; - } - } - - addrToRead.clear(); //add only B channel addresses - addrToRead = mRegistersMap->GetUsedAddresses(1); - dataWr.resize(addrToRead.size()); - dataRd.resize(addrToRead.size()); - for(size_t i = 0; i < addrToRead.size(); ++i) - dataWr[i] = (uint32_t(addrToRead[i]) << 16); - status = controlPort->ReadLMS7002MSPI(dataWr.data(), dataRd.data(), dataWr.size(),mdevIndex); - for(size_t i=0; iSetActiveChannel(ChB); - - //check if local copy matches chip - for (uint16_t i = 0; i < addrToRead.size(); ++i) - { - uint16_t regValue = mRegistersMap->GetValue(1, addrToRead[i]); - if(addrToRead[i] <= readOnlyRegisters[sizeof(readOnlyRegisters)/sizeof(uint16_t)-1] && addrToRead[i] >= readOnlyRegisters[0]) - { - //mask out readonly bits - for (uint16_t j = 0; j < sizeof(readOnlyRegisters) / sizeof(uint16_t); ++j) - if (readOnlyRegisters[j] == addrToRead[i]) - { - dataReceived[i] &= readOnlyRegistersMasks[j]; - regValue &= readOnlyRegistersMasks[j]; - break; - } - } - if (dataReceived[i] != regValue) - { - printf("Addr: 0x%04X gui: 0x%04X chip: 0x%04X\n", addrToRead[i], regValue, dataReceived[i]); - isSynced = false; - goto isSyncedEnding; - } - } -isSyncedEnding: - this->SetActiveChannel(ch); //restore previously used channel - return isSynced; -} - -/** @brief Writes all registers from host to chip - -*/ -int LMS7002M::UploadAll() -{ - checkConnection(); - - Channel ch = this->GetActiveChannel(); //remember used channel - - int status; - - vector addrToWrite; - vector dataToWrite; - - uint16_t x0020_value = mRegistersMap->GetValue(0, 0x0020); - this->SetActiveChannel(ChA); //select A channel - - addrToWrite = mRegistersMap->GetUsedAddresses(0); - //remove 0x0020 register from list, to not change MAC - addrToWrite.erase( find(addrToWrite.begin(), addrToWrite.end(), 0x0020) ); - for (auto address : addrToWrite) - dataToWrite.push_back(mRegistersMap->GetValue(0, address)); - - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0) - return status; - //after all channel A registers have been written, update 0x0020 register value - status = SPI_write(0x0020, x0020_value); - if (status != 0) - return status; - this->SetActiveChannel(ChB); - if (status != 0) - return status; - - addrToWrite = mRegistersMap->GetUsedAddresses(1); - dataToWrite.clear(); - for (auto address : addrToWrite) - { - dataToWrite.push_back(mRegistersMap->GetValue(1, address)); - } - this->SetActiveChannel(ChB); //select B channel - status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size()); - if (status != 0) - return status; - this->SetActiveChannel(ch); //restore last used channel - - //update external band-selection to match - this->UpdateExternalBandSelect(); - - return 0; -} - -/** @brief Reads all registers from the chip to host - -*/ -int LMS7002M::DownloadAll() -{ - checkConnection(); - int status; - Channel ch = this->GetActiveChannel(false); - - vector addrToRead = mRegistersMap->GetUsedAddresses(0); - vector dataReceived; - dataReceived.resize(addrToRead.size(), 0); - this->SetActiveChannel(ChA); - status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size()); - if (status != 0) - return status; - - for (uint16_t i = 0; i < addrToRead.size(); ++i) - { - mRegistersMap->SetValue(0, addrToRead[i], dataReceived[i]); - } - - addrToRead.clear(); //add only B channel addresses - addrToRead = mRegistersMap->GetUsedAddresses(1); - dataReceived.resize(addrToRead.size(), 0); - - this->SetActiveChannel(ChB); - status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size()); - if (status != 0) - return status; - for (uint16_t i = 0; i < addrToRead.size(); ++i) - mRegistersMap->SetValue(1, addrToRead[i], dataReceived[i]); - - this->SetActiveChannel(ch); //retore previously used channel - - //update external band-selection to match - this->UpdateExternalBandSelect(); - - return 0; -} - -/** @brief Configures interfaces for desired frequency - @return 0-success, other-failure - Sets interpolation and decimation, changes MCLK sources and TSP clock dividers accordingly to selected interpolation and decimation -*/ -int LMS7002M::SetInterfaceFrequency(float_type cgen_freq_Hz, const uint8_t interpolation, const uint8_t decimation) -{ - int status = 0; - LMS7002M_SelfCalState state(this); - status = Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), decimation); - if(status != 0) - return status; - Modify_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP), interpolation); - - //clock rate already set because the readback frequency is pretty-close, - //dont set the cgen frequency again to save time due to VCO selection - const auto freqDiff = std::abs(this->GetFrequencyCGEN() - cgen_freq_Hz); - if (not this->GetCGENLocked() or freqDiff > 10.0) - { - status = SetFrequencyCGEN(cgen_freq_Hz); - if (status != 0) return status; - } - - int mclk2src = Get_SPI_Reg_bits(LMS7param(MCLK2SRC)); - if (decimation == 7 || decimation == 0) //bypass - { - Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), 0); - Modify_SPI_Reg_bits(LMS7param(RXDIVEN), false); - Modify_SPI_Reg_bits(LMS7param(MCLK2SRC), (mclk2src & 1) | 0x2); - } - else - { - uint8_t divider = (uint8_t)pow(2.0, decimation); - if (divider > 1) - Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), (divider / 2) - 1); - else - Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), 0); - Modify_SPI_Reg_bits(LMS7param(RXDIVEN), true); - Modify_SPI_Reg_bits(LMS7param(MCLK2SRC), mclk2src & 1); - } - int mclk1src = Get_SPI_Reg_bits(LMS7param(MCLK1SRC)); - if (interpolation == 7 || interpolation == 0) //bypass - { - Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), 0); - Modify_SPI_Reg_bits(LMS7param(TXDIVEN), false); - Modify_SPI_Reg_bits(LMS7param(MCLK1SRC), (mclk1src & 1) | 0x2); - } - else - { - uint8_t divider = (uint8_t)pow(2.0, interpolation); - if (divider > 1) - Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), (divider / 2) - 1); - else - Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), 0); - Modify_SPI_Reg_bits(LMS7param(TXDIVEN), true); - Modify_SPI_Reg_bits(LMS7param(MCLK1SRC), mclk1src & 1); - } - - return status; -} - -float_type LMS7002M::GetSampleRate(bool tx, Channel ch) -{ - float_type interface_Hz; - auto chBck = GetActiveChannel(); - SetActiveChannel(ch); - //if decimation/interpolation is 0(2^1) or 7(bypass), interface clocks should not be divided - if (tx) - { - int interpolation = Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP)); - float_type interfaceTx_Hz = GetReferenceClk_TSP(LMS7002M::Tx); - if (interpolation != 7) - interfaceTx_Hz /= 2*pow(2.0, interpolation); - interface_Hz = interfaceTx_Hz; - } - else - { - int decimation = Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP)); - float_type interfaceRx_Hz = GetReferenceClk_TSP(LMS7002M::Rx); - if (decimation != 7) - interfaceRx_Hz /= 2*pow(2.0, decimation); - interface_Hz = interfaceRx_Hz; - } - SetActiveChannel(chBck); - return interface_Hz; -} - -void LMS7002M::ConfigureLML_RF2BB( - const LMLSampleSource s0, - const LMLSampleSource s1, - const LMLSampleSource s2, - const LMLSampleSource s3) -{ - //map a sample source to a position - std::map m; - m[AI] = 1; - m[AQ] = 0; - m[BI] = 3; - m[BQ] = 2; - - //load the same config on both LMLs - //only one will get used based on direction - this->Modify_SPI_Reg_bits(LMS7param(LML1_S3S), m[s3]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S2S), m[s2]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S1S), m[s1]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S0S), m[s0]); - - this->Modify_SPI_Reg_bits(LMS7param(LML2_S3S), m[s3]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S2S), m[s2]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S1S), m[s1]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S0S), m[s0]); -} - -void LMS7002M::ConfigureLML_BB2RF( - const LMLSampleSource s0, - const LMLSampleSource s1, - const LMLSampleSource s2, - const LMLSampleSource s3) -{ - //map a sample source to a position - std::map m; - m[s3] = 2; - m[s2] = 3; - m[s0] = 1; - m[s1] = 0; - - //load the same config on both LMLs - //only one will get used based on direction - this->Modify_SPI_Reg_bits(LMS7param(LML1_BQP), m[BQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_BIP), m[BI]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_AQP), m[AQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_AIP), m[AI]); - - this->Modify_SPI_Reg_bits(LMS7param(LML2_BQP), m[BQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_BIP), m[BI]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_AQP), m[AQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_AIP), m[AI]); -} - -int LMS7002M::SetRxDCRemoval(const bool enable) -{ - this->Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), enable?0:1); - this->Modify_SPI_Reg_bits(LMS7param(DCCORR_AVG_RXTSP), 0x7); - return 0; -} - -bool LMS7002M::GetRxDCRemoval(void) -{ - return this->Get_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP)) == 0; -} - -int LMS7002M::SetTxDCOffset(const float_type I, const float_type Q) -{ - const bool bypass = I == 0.0 and Q == 0.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; -} - -void LMS7002M::GetTxDCOffset(float_type &I, float_type &Q) -{ - I = int8_t(this->Get_SPI_Reg_bits(LMS7param(DCCORRI_TXTSP)))/128.0; //signed 8-bit - Q = int8_t(this->Get_SPI_Reg_bits(LMS7param(DCCORRQ_TXTSP)))/128.0; //signed 8-bit -} - -int LMS7002M::SetIQBalance(const bool tx, const float_type phase, const float_type gainI, const float_type gainQ) -{ - const bool bypassPhase = (phase == 0.0); - const bool bypassGain = ((gainI == 1.0) and (gainQ == 1.0)) or ((gainI == 0.0) and (gainQ == 0.0)); - int iqcorr = std::lrint(2047*(phase/(M_PI/2))); - int gcorri = std::lrint(2047*gainI); - int gcorrq = std::lrint(2047*gainQ); - - this->Modify_SPI_Reg_bits(tx?LMS7param(PH_BYP_TXTSP):LMS7param(PH_BYP_RXTSP), bypassPhase?1:0); - this->Modify_SPI_Reg_bits(tx?LMS7param(GC_BYP_TXTSP):LMS7param(GC_BYP_RXTSP), bypassGain?1:0); - this->Modify_SPI_Reg_bits(tx?LMS7param(IQCORR_TXTSP):LMS7param(IQCORR_RXTSP), iqcorr); - this->Modify_SPI_Reg_bits(tx?LMS7param(GCORRI_TXTSP):LMS7param(GCORRI_RXTSP), gcorri); - this->Modify_SPI_Reg_bits(tx?LMS7param(GCORRQ_TXTSP):LMS7param(GCORRQ_RXTSP), gcorrq); - return 0; -} - -void LMS7002M::GetIQBalance(const bool tx, float_type &phase, float_type &gainI, float_type &gainQ) -{ - int iqcorr = int16_t(this->Get_SPI_Reg_bits(tx?LMS7param(IQCORR_TXTSP):LMS7param(IQCORR_RXTSP)) << 4) >> 4; //sign extend 12-bit - int gcorri = int16_t(this->Get_SPI_Reg_bits(tx?LMS7param(GCORRI_TXTSP):LMS7param(GCORRI_RXTSP))); //unsigned 11-bit - int gcorrq = int16_t(this->Get_SPI_Reg_bits(tx?LMS7param(GCORRQ_TXTSP):LMS7param(GCORRQ_RXTSP))); //unsigned 11-bit - - phase = (M_PI/2)*iqcorr/2047.0; - gainI = gcorri/2047.0; - gainQ = gcorrq/2047.0; -} - -void LMS7002M::EnterSelfCalibration(void) -{ - if (controlPort && mSelfCalDepth == 0) - { - controlPort->EnterSelfCalibration(this->GetActiveChannelIndex()); - } - mSelfCalDepth++; -} - -void LMS7002M::ExitSelfCalibration(void) -{ - mSelfCalDepth--; - if (controlPort && mSelfCalDepth == 0) - controlPort->ExitSelfCalibration(this->GetActiveChannelIndex()); -} - -LMS7002M_SelfCalState::LMS7002M_SelfCalState(LMS7002M *rfic): - rfic(rfic) -{ - rfic->EnterSelfCalibration(); -} - -LMS7002M_SelfCalState::~LMS7002M_SelfCalState(void) -{ - rfic->ExitSelfCalibration(); -} - -void LMS7002M::EnableValuesCache(bool enabled) -{ - useCache = enabled; -} - -bool LMS7002M::IsValuesCacheEnabled() -{ - return useCache; -} - -MCU_BD* LMS7002M::GetMCUControls() const -{ - return mcuControl; -} - -void LMS7002M::EnableCalibrationByMCU(bool enabled) -{ - mCalibrationByMCU = enabled; -} - -float_type LMS7002M::GetTemperature() -{ - Modify_SPI_Reg_bits(LMS7_RSSI_PD, 0); - Modify_SPI_Reg_bits(LMS7_RSSI_RSSIMODE, 0); - Modify_SPI_Reg_bits(LMS7_DAC_CLKDIV, 32); - uint16_t biasMux = Get_SPI_Reg_bits(LMS7_MUX_BIAS_OUT); - Modify_SPI_Reg_bits(LMS7_MUX_BIAS_OUT, 2); - - this_thread::sleep_for(chrono::microseconds(250)); - const uint16_t reg606 = SPI_read(0x0606, true); - float Vtemp = (reg606 >> 8) & 0xFF; - Vtemp *= 3.515625; - float Vptat = reg606 & 0xFF; - Vptat *= 3.515625; - float Vdiff = Vptat-Vtemp; - Vdiff /= 3.9; - float temperature = 40.5+Vdiff; - Modify_SPI_Reg_bits(LMS7_MUX_BIAS_OUT, biasMux); - printf("Vtemp 0x%04X, Vptat 0x%04X, Vdiff = %.2f, temp= %.3f\n", (reg606 >> 8) & 0xFF, reg606 & 0xFF, Vdiff, temperature); - return temperature; -} - -void LMS7002M::SetLogCallback(std::function callback) -{ - log_callback = callback; -} - -int LMS7002M::CopyChannelRegisters(const Channel src, const Channel dest, const bool copySX) -{ - Channel ch = this->GetActiveChannel(); //remember used channel - - vector addrToWrite; - addrToWrite = mRegistersMap->GetUsedAddresses(1); - if(!copySX) - { - for(uint32_t address = MemorySectionAddresses[SX][0]; address <= MemorySectionAddresses[SX][1]; ++address) - addrToWrite.erase( find(addrToWrite.begin(), addrToWrite.end(), address)); - } - for (auto address : addrToWrite) - { - uint16_t data = mRegistersMap->GetValue(src == ChA ? 0 : 1, address); - mRegistersMap->SetValue(dest == ChA ? 0 : 1, address, data); - } - if(controlPort) - UploadAll(); - this->SetActiveChannel(ch); - //update external band-selection to match - this->UpdateExternalBandSelect(); - return 0; -} - -int LMS7002M::CalibrateAnalogRSSI_DC_Offset() -{ - Modify_SPI_Reg_bits(LMS7param(PD_RSSI_RFE), 0); - Modify_SPI_Reg_bits(LMS7param(PD_TIA_RFE), 0); - Modify_SPI_Reg_bits(LMS7param(RSSIDC_RSEL), 26); - int value = -63; - uint8_t wrValue = abs(value); - if(value < 0) - wrValue |= 0x40; - Modify_SPI_Reg_bits(LMS7param(RSSIDC_DCO1), wrValue, true); - uint8_t cmp = Get_SPI_Reg_bits(LMS7param(RSSIDC_CMPSTATUS), true); - uint8_t cmpPrev = cmp; - vector edges; - for(value = -63; value < 64; ++value) - { - wrValue = abs(value); - if(value < 0) - wrValue |= 0x40; - Modify_SPI_Reg_bits(LMS7param(RSSIDC_DCO1), wrValue, true); - this_thread::sleep_for(chrono::microseconds(5)); - cmp = Get_SPI_Reg_bits(LMS7param(RSSIDC_CMPSTATUS), true); - if(cmp != cmpPrev) - { - edges.push_back(value); - cmpPrev = cmp; - } - if(edges.size() > 1) - break; - } - if(edges.size() != 2) - { - printf("Not found\n"); - return ReportError(EINVAL, "Failed to find value"); - } - int8_t found = (edges[0]+edges[1])/2; - wrValue = abs(found); - if(found < 0) - wrValue |= 0x40; - Modify_SPI_Reg_bits(LMS7param(RSSIDC_DCO1), wrValue, true); - printf("Found %i\n", found); - return 0; -} diff --git a/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp b/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp deleted file mode 100644 index 703b12005..000000000 --- a/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp +++ /dev/null @@ -1,1130 +0,0 @@ -/** -@file MCU_BD.cpp -@author Lime Microsystems -@brief Implementation of interacting with on board MCU -*/ - -#include "MCU_BD.h" -using namespace std; -#include -#include "MCU_File.h" -#include -#include -#include "LMS64CProtocol.h" -#include -#include -#include -#include "ErrorReporting.h" -#include "LMS7002M.h" - -using namespace lime; - -MCU_BD::MCU_BD() -{ - mLoadedProgramFilename = ""; - m_bLoadedDebug = 0; - m_bLoadedProd = 0; - stepsTotal = 0; - stepsDone = 0; - aborted = false; - callback = nullptr; - mChipID =0; - //ctor - int i=0; - m_serPort=NULL; - //default value, - //must be verified during program exploatation - m_iLoopTries=20; - byte_array_size = cMaxFWSize; - // array initiallization - for (i=0; i<=255; i++){ - m_SFR[i]=0x00; - m_IRAM[i]=0x00; - } - for (i=0; i 0) - byte_array_size = size; -} - -/** @brief Read program code from file into memory - @param inFileName source file path - @param bin binary or hex file - @return 0:success, -1:file not found -*/ -int MCU_BD:: GetProgramCode(const char* inFileName, bool bin) -{ - unsigned char ch=0x00; - bool find_byte=false; - int i=0; - - if(!bin) - { - MCU_File inFile(inFileName, "rb"); - if (inFile.FileOpened() == false) - return -1; - - mLoadedProgramFilename = inFileName; - try - { - inFile.ReadHex(byte_array_size-1); - } - catch (...) - { - return -1; - } - - for (i=0; iWriteLMS7002MSPI(&wrdata, 1, mChipID); -} - - -unsigned short MCU_BD:: mSPI_read( - unsigned short addr_reg) // takes 16 bit address -{// returns 16 bit value - if(m_serPort == nullptr) - return 0; - uint32_t wrdata = addr_reg << 16; - uint32_t rddata = 0; - if(m_serPort->ReadLMS7002MSPI(&wrdata, &rddata, 1, mChipID)!=0) - return 0; - - return rddata & 0xFFFF; -} - -int MCU_BD::WaitUntilWritten(){ - - // waits if WRITE_REQ (REG3[2]) flag is equal to '1' - // this means that write operation is in progress - unsigned short tempi=0x0000; - int countDown=m_iLoopTries; // Time out value - tempi=mSPI_read(0x0003); // REG3 read - - while (( (tempi&0x0004) == 0x0004) && (countDown>0)) - { - tempi=mSPI_read(0x0003); // REG3 read - countDown--; - } - if (countDown==0) - return -1; // an error occured, timer elapsed - else - return 0; // Finished regularly - // pass if WRITE_REQ is '0' -} - -int MCU_BD::ReadOneByte(unsigned char * data) -{ - unsigned short tempi=0x0000; - int countDown=m_iLoopTries; - - // waits when READ_REQ (REG3[3]) flag is equal to '0' - // this means that there is nothing to read - tempi=mSPI_read(0x0003); // REG3 read - - while (((tempi&0x0008)==0x0000) && (countDown>0)) - { - // wait if READ_REQ is '0' - tempi=mSPI_read(0x0003); // REG3 read - countDown--; - } - - if (countDown>0) - { // Time out has not occured - tempi=mSPI_read(0x0005); // REG5 read - // return the read byte - (* data) = (unsigned char) (tempi); - } - else - (* data) =0; - // return the zero, default value - - if (countDown==0) - return -1; // an error occured - else - return 0; // finished regularly -} - -int MCU_BD::One_byte_command(unsigned short data1, unsigned char * rdata1) -{ - unsigned char tempc=0x00; - int retval=0; - *rdata1=0x00; //default return value - - // sends the one byte command - mSPI_write(0x8004, data1); //REG4 write - retval=WaitUntilWritten(); - if (retval==-1) return -1; - // error if operation executes too long - - // gets the one byte answer - retval=ReadOneByte(&tempc); - if (retval==-1) return -1; - // error if operation takes too long - - *rdata1=tempc; - return 0; -} - - -int MCU_BD::Three_byte_command( - unsigned char data1,unsigned char data2,unsigned char data3, - unsigned char * rdata1,unsigned char * rdata2,unsigned char * rdata3){ - - - int retval=0; - *rdata1=0x00; - *rdata2=0x00; - *rdata3=0x00; - - mSPI_write(0x8004, (unsigned short)(data1)); //REG4 write - retval=WaitUntilWritten(); - if (retval==-1) return -1; - - mSPI_write(0x8004, (unsigned short)(data2)); //REG4 write - retval=WaitUntilWritten(); - if (retval==-1) return -1; - - mSPI_write(0x8004, (unsigned short)(data3)); //REG4 write - retval=WaitUntilWritten(); - if (retval==-1) return -1; - - retval= ReadOneByte(rdata1); - if (retval==-1) return -1; - - retval= ReadOneByte(rdata2); - if (retval==-1) return -1; - - retval= ReadOneByte(rdata3); - if (retval==-1) return -1; - - return 0; -} - -int MCU_BD::Change_MCUFrequency(unsigned char data) { - - unsigned char tempc1, tempc2, tempc3=0x00; - int retval=0; - // code 0x7E is for writing the SFR registers - retval=Three_byte_command(0x7E, 0x8E, data, &tempc1, &tempc2, &tempc3); - // PMSR register, address 0x8E - return retval; -} - -int MCU_BD::Read_IRAM() -{ - unsigned char tempc1, tempc2, tempc3=0x00; - int i=0; - int retval=0; - - //default - //IRAM array initialization - for (i=0; i<=255; i++) - m_IRAM[i]=0x00; - - stepsTotal.store(256); - stepsDone.store(0); - aborted.store(false); - for (i=0; i<=255; i++) - { - // code 0x78 is for reading the IRAM locations - retval=Three_byte_command(0x78, ((unsigned char)(i)), 0x00,&tempc1, &tempc2, &tempc3); - if (retval==0) - m_IRAM[i]=tempc3; - else - { - i=256; // error, stop - aborted.store(true); - } - ++stepsDone; -#ifndef NDEBUG - printf("MCU reading IRAM: %2i/256\r", stepsDone.load()); -#endif - Wait_CLK_Cycles(64); - } -#ifndef NDEBUG - printf("\nMCU reading IRAM finished\n"); -#endif - return retval; -} - -int MCU_BD::Erase_IRAM() -{ - unsigned char tempc1, tempc2, tempc3=0x00; - int retval=0; - int i=0; - - //default ini. - for (i=0; i<=255; i++) - m_IRAM[i]=0x00; - - stepsTotal.store(256); - stepsDone.store(0); - aborted.store(false); - for (i=0; i<=255; i++) - { - m_IRAM[i]=0x00; - // code 0x7C is for writing the IRAM locations - retval=Three_byte_command(0x7C, ((unsigned char)(i)), 0x00,&tempc1, &tempc2, &tempc3); - if (retval == -1) - { - i = 256; - aborted.store(true); - } - ++stepsDone; -#ifndef NDEBUG - printf("MCU erasing IRAM: %2i/256\r", stepsDone.load()); -#endif - } -#ifndef NDEBUG - printf("\nMCU erasing IRAM finished\n"); -#endif - return retval; -} - -int MCU_BD::Read_SFR() -{ - int i=0; - unsigned char tempc1, tempc2, tempc3=0x00; - int retval=0; - - stepsTotal.store(48); - stepsDone.store(0); - aborted.store(false); - - //default m_SFR array initialization - for (i=0; i<=255; i++) - m_SFR[i]=0x00; - - // code 0x7A is for reading the SFR registers - retval=Three_byte_command(0x7A, 0x80, 0x00, &tempc1, &tempc2, &tempc3); // P0 - if (retval==-1) return -1; - m_SFR[0x80]=tempc3; - - retval=Three_byte_command(0x7A, 0x81, 0x00, &tempc1, &tempc2, &tempc3); // SP - if (retval==-1) return -1; - m_SFR[0x81]=tempc3; - - retval=Three_byte_command(0x7A, 0x82, 0x00, &tempc1, &tempc2, &tempc3); // DPL0 - if (retval==-1) return -1; - m_SFR[0x82]=tempc3; - - retval=Three_byte_command(0x7A, 0x83, 0x00, &tempc1, &tempc2, &tempc3); // DPH0 - if (retval==-1) return -1; - m_SFR[0x83]=tempc3; - - retval=Three_byte_command(0x7A, 0x84, 0x00, &tempc1, &tempc2, &tempc3); // DPL1 - if (retval==-1) return -1; - m_SFR[0x84]=tempc3; - - retval=Three_byte_command(0x7A, 0x85, 0x00, &tempc1, &tempc2, &tempc3); // DPH1 - if (retval==-1) return -1; - m_SFR[0x85]=tempc3; - - stepsDone.store(6); - - retval=Three_byte_command(0x7A, 0x86, 0x00, &tempc1, &tempc2, &tempc3); // DPS - if (retval==-1) return -1; - m_SFR[0x86]=tempc3; - - retval=Three_byte_command(0x7A, 0x87, 0x00, &tempc1, &tempc2, &tempc3); // PCON - if (retval==-1) return -1; - m_SFR[0x87]=tempc3; - - retval=Three_byte_command(0x7A, 0x88, 0x00, &tempc1, &tempc2, &tempc3); // TCON - if (retval==-1) return -1; - m_SFR[0x88]=tempc3; - - retval=Three_byte_command(0x7A, 0x89, 0x00, &tempc1, &tempc2, &tempc3); // TMOD - if (retval==-1) return -1; - m_SFR[0x89]=tempc3; - - retval=Three_byte_command(0x7A, 0x8A, 0x00, &tempc1, &tempc2, &tempc3); // TL0 - if (retval==-1) return -1; - m_SFR[0x8A]=tempc3; - - retval=Three_byte_command(0x7A, 0x8B, 0x00, &tempc1, &tempc2, &tempc3); // TL1 - if (retval==-1) return -1; - m_SFR[0x8B]=tempc3; - - stepsDone.store(12); - - retval=Three_byte_command(0x7A, 0x8C, 0x00, &tempc1, &tempc2, &tempc3); // TH0 - if (retval==-1) return -1; - m_SFR[0x8C]=tempc3; - - retval=Three_byte_command(0x7A, 0x8D, 0x00, &tempc1, &tempc2, &tempc3); // TH1 - if (retval==-1) return -1; - m_SFR[0x8D]=tempc3; - - retval=Three_byte_command(0x7A, 0x8E, 0x00, &tempc1, &tempc2, &tempc3); // PMSR - if (retval==-1) return -1; - m_SFR[0x8E]=tempc3; - - retval=Three_byte_command(0x7A, 0x90, 0x00, &tempc1, &tempc2, &tempc3); // P1 - if (retval==-1) return -1; - m_SFR[0x90]=tempc3; - - retval=Three_byte_command(0x7A, 0x91, 0x00, &tempc1, &tempc2, &tempc3); // DIR1 - if (retval==-1) return -1; - m_SFR[0x91]=tempc3; - - retval=Three_byte_command(0x7A, 0x98, 0x00, &tempc1, &tempc2, &tempc3); // SCON - if (retval==-1) return -1; - m_SFR[0x98]=tempc3; - - stepsDone.store(18); - - retval=Three_byte_command(0x7A, 0x99, 0x00, &tempc1, &tempc2, &tempc3); // SBUF - if (retval==-1) return -1; - m_SFR[0x99]=tempc3; - - retval=Three_byte_command(0x7A, 0xA0, 0x00, &tempc1, &tempc2, &tempc3); // P2 - if (retval==-1) return -1; - m_SFR[0xA0]=tempc3; - - retval=Three_byte_command(0x7A, 0xA1, 0x00, &tempc1, &tempc2, &tempc3); // DIR2 - if (retval==-1) return -1; - m_SFR[0xA1]=tempc3; - - retval=Three_byte_command(0x7A, 0xA2, 0x00, &tempc1, &tempc2, &tempc3); // DIR0 - if (retval==-1) return -1; - m_SFR[0xA2]=tempc3; - - retval=Three_byte_command(0x7A, 0xA8, 0x00, &tempc1, &tempc2, &tempc3); // IEN0 - if (retval==-1) return -1; - m_SFR[0xA8]=tempc3; - - stepsDone.store(24); - - retval=Three_byte_command(0x7A, 0xA9, 0x00, &tempc1, &tempc2, &tempc3); // IEN1 - if (retval==-1) return -1; - m_SFR[0xA9]=tempc3; - - retval=Three_byte_command(0x7A, 0xB0, 0x00, &tempc1, &tempc2, &tempc3); // EECTRL - if (retval==-1) return -1; - m_SFR[0xB0]=tempc3; - - retval=Three_byte_command(0x7A, 0xB1, 0x00, &tempc1, &tempc2, &tempc3); // EEDATA - if (retval==-1) return -1; - m_SFR[0xB1]=tempc3; - - retval=Three_byte_command(0x7A, 0xB8, 0x00, &tempc1, &tempc2, &tempc3); // IP0 - if (retval==-1) return -1; - m_SFR[0xB8]=tempc3; - - retval=Three_byte_command(0x7A, 0xB9, 0x00, &tempc1, &tempc2, &tempc3); // IP1 - if (retval==-1) return -1; - m_SFR[0xB9]=tempc3; - - retval=Three_byte_command(0x7A, 0xBF, 0x00, &tempc1, &tempc2, &tempc3); // USR2 - if (retval==-1) return -1; - m_SFR[0xBF]=tempc3; - - stepsDone.store(30); - - retval=Three_byte_command(0x7A, 0xC0, 0x00, &tempc1, &tempc2, &tempc3); // IRCON - if (retval==-1) return -1; - m_SFR[0xC0]=tempc3; - - retval=Three_byte_command(0x7A, 0xC8, 0x00, &tempc1, &tempc2, &tempc3); // T2CON - if (retval==-1) return -1; - m_SFR[0xC8]=tempc3; - - retval=Three_byte_command(0x7A, 0xCA, 0x00, &tempc1, &tempc2, &tempc3); // RCAP2L - if (retval==-1) return -1; - m_SFR[0xCA]=tempc3; - - retval=Three_byte_command(0x7A, 0xCB, 0x00, &tempc1, &tempc2, &tempc3); // RCAP2H - if (retval==-1) return -1; - m_SFR[0xCB]=tempc3; - - retval=Three_byte_command(0x7A, 0xCC, 0x00, &tempc1, &tempc2, &tempc3); // TL2 - if (retval==-1) return -1; - m_SFR[0xCC]=tempc3; - - retval=Three_byte_command(0x7A, 0xCD, 0x00, &tempc1, &tempc2, &tempc3); // TH2 - if (retval==-1) return -1; - m_SFR[0xCD]=tempc3; - - stepsDone.store(36); - - retval=Three_byte_command(0x7A, 0xD0, 0x00, &tempc1, &tempc2, &tempc3); // PSW - if (retval==-1) return -1; - m_SFR[0xD0]=tempc3; - - retval=Three_byte_command(0x7A, 0xE0, 0x00, &tempc1, &tempc2, &tempc3); // ACC - if (retval==-1) return -1; - m_SFR[0xE0]=tempc3; - - retval=Three_byte_command(0x7A, 0xF0, 0x00, &tempc1, &tempc2, &tempc3); // B - if (retval==-1) return -1; - m_SFR[0xF0]=tempc3; - - retval=Three_byte_command(0x7A, 0xEC, 0x00, &tempc1, &tempc2, &tempc3); // REG0 - if (retval==-1) return -1; - m_SFR[0xEC]=tempc3; - - retval=Three_byte_command(0x7A, 0xED, 0x00, &tempc1, &tempc2, &tempc3); // REG1 - if (retval==-1) return -1; - m_SFR[0xED]=tempc3; - - retval=Three_byte_command(0x7A, 0xEE, 0x00, &tempc1, &tempc2, &tempc3); // REG2 - if (retval==-1) return -1; - m_SFR[0xEE]=tempc3; - - stepsDone.store(42); - - retval=Three_byte_command(0x7A, 0xEF, 0x00, &tempc1, &tempc2, &tempc3); // REG3 - if (retval==-1) return -1; - m_SFR[0xEF]=tempc3; - - retval=Three_byte_command(0x7A, 0xF4, 0x00, &tempc1, &tempc2, &tempc3); // REG4 - if (retval==-1) return -1; - m_SFR[0xF4]=tempc3; - - retval=Three_byte_command(0x7A, 0xF5, 0x00, &tempc1, &tempc2, &tempc3); // REG5 - if (retval==-1) return -1; - m_SFR[0xF5]=tempc3; - - retval=Three_byte_command(0x7A, 0xF6, 0x00, &tempc1, &tempc2, &tempc3); // REG6 - if (retval==-1) return -1; - m_SFR[0xF6]=tempc3; - - retval=Three_byte_command(0x7A, 0xF7, 0x00, &tempc1, &tempc2, &tempc3); // REG7 - if (retval==-1) return -1; - m_SFR[0xF7]=tempc3; - - retval=Three_byte_command(0x7A, 0xFC, 0x00, &tempc1, &tempc2, &tempc3); // REG8 - if (retval==-1) return -1; - m_SFR[0xFC]=tempc3; - - retval=Three_byte_command(0x7A, 0xFD, 0x00, &tempc1, &tempc2, &tempc3); // REG9 - if (retval==-1) return -1; - m_SFR[0xFD]=tempc3; - - stepsDone.store(48); - - return 0; -} - -void MCU_BD::Wait_CLK_Cycles(int delay) -{ - //// some delay - int i=0; - for (i=0;i<(delay/64);i++) - mSPI_read(0x0003); -} - -/** @brief Upload program code from memory into MCU - @return 0:success, -1:failed -*/ -int MCU_BD::Program_MCU(int m_iMode1, int m_iMode0) -{ - IConnection::MCU_PROG_MODE mode; - switch(m_iMode1 << 1 | m_iMode0) - { - case 0: mode = IConnection::MCU_PROG_MODE::RESET; break; - case 1: mode = IConnection::MCU_PROG_MODE::EEPROM_AND_SRAM; break; - case 2: mode = IConnection::MCU_PROG_MODE::SRAM; break; - case 3: mode = IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM; break; - default: mode = IConnection::MCU_PROG_MODE::RESET; break; - } - return Program_MCU(byte_array,mode); -} - -int MCU_BD::Program_MCU(const uint8_t* buffer, const IConnection::MCU_PROG_MODE mode) -{ - 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() -{ - unsigned short tempi=0x0000; // was 0x0000 - mSPI_write(0x8002, tempi); - tempi=0x0000; - mSPI_write(0x8000, tempi); -} - -int MCU_BD::RunProductionTest_MCU() -{ - string temps; - unsigned short tempi = 0x0080; // was 0x0000 - int m_iMode1_ = 0; - int m_iMode0_ = 0; - - if (m_bLoadedProd == 0) - { - if (GetProgramCode("lms7suite_mcu/ptest.hex", false) != 0) - return -1; - } - //MCU gets control over SPI switch - mSPI_write(0x0006, 0x0001); //REG6 write - - // reset MCU - tempi = 0x0080; - mSPI_write(0x8002, tempi); // REG2 - tempi = 0x0000; - mSPI_write(0x8000, tempi); // REG0 - - if (m_bLoadedProd == 0) - { - //select programming mode "01" for SRAM and EEPROM - m_iMode1_ = 0; m_iMode0_ = 1; - } - else - { - //boot from EEPROM - m_iMode1_ = 1; m_iMode0_ = 1; - } - - //upload hex file - if (Program_MCU(m_iMode1_, m_iMode0_) != 0) - return -1; //failed to program - - if (m_bLoadedProd == 0) - { - Wait_CLK_Cycles(256 * 100); // for programming mode, prog.code has been already loaded into MCU - m_iMode1_ = 0; m_iMode0_ = 1; - } - else - { - Wait_CLK_Cycles(256 * 400); - // for booting from EEPROM mode, must wait for some longer delay, at least 8kB/(80kb/s)=0.1s - m_iMode1_ = 1; m_iMode0_ = 1; - } - - // global variable - m_bLoadedProd = 1; // the ptest.hex has been loaded - m_bLoadedDebug = 0; - - //tempi = 0x0000; - // EXT_INT2=1, external interrupt 2 is raised - mSPI_write(0x8002, formREG2command(0, 0, 0, 1, m_iMode1_, m_iMode0_)); // EXT_INT2=1 - // here you can put any Delay function - Wait_CLK_Cycles(256); - // EXT_INT2=0, external interrupt 2 is pulled down - mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT2=0 - - // wait for some time MCU to execute the tests - // the time is approximately 20ms - // here you can put any Delay function - Wait_CLK_Cycles(256 * 100); - - unsigned short retval = 0; - retval = mSPI_read(1); //REG1 read - - // show the return value at the MCU Control Panel - //int temps = wxString::Format("Result is: 0x%02X", retval); - //ReadResult->SetLabel(temps); - - if (retval == 0x10) - { - tempi = 0x0055; - mSPI_write(0x8000, tempi); // P0=0x55; - // EXT_INT3=1, external interrupt 3 is raised - mSPI_write(0x8002, formREG2command(0, 0, 1, 0, m_iMode1_, m_iMode0_)); // EXT_INT3=1 - // here you can put any Delay function - Wait_CLK_Cycles(256); - // EXT_INT3=0, external interrupt 3 is pulled down - mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT3=0 - Wait_CLK_Cycles(256 * 5); - retval = mSPI_read(1); //REG1 read - if (retval != 0x55) - temps = "Ext. interrupt 3 test failed."; - else - { - tempi = 0x00AA; - mSPI_write(0x8000, tempi); // P0=0xAA; - // EXT_INT4=1, external interrupt 4 is raised - mSPI_write(0x8002, formREG2command(0, 1, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT4=1 - // here you can put any Delay function - Wait_CLK_Cycles(256); - // EXT_INT4=0, external interrupt 4 is pulled down - mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT4=0 - Wait_CLK_Cycles(256 * 5); - retval = mSPI_read(1); //REG1 read - if (retval != 0xAA) temps = "Ext. interrupt 4 test failed."; - else { - tempi = 0x0055; - mSPI_write(0x8000, tempi); // P0=0x55; - // EXT_INT5=1, external interrupt 5 is raised - mSPI_write(0x8002, formREG2command(1, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT5=1 - // here you can put any Delay function - Wait_CLK_Cycles(256); - // EXT_INT5=0, external interrupt 5 is pulled down - mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT5=0 - Wait_CLK_Cycles(256 * 5); - retval = mSPI_read(1); //REG1 read - if (retval != 0x55) - { - temps = "Ext. interrupt 5 test failed."; - return -1; - } - else - { - temps = "Production test finished. MCU is OK."; - return 0; - } - } - } - } - else - { - if ((retval & 0xF0) == 0x30) - { // detected error code - if ((retval & 0x0F) > 0) - { - char ctemp[64]; - sprintf(ctemp, "Test %i failed", (retval & 0x0F)); - temps = ctemp; - return -1; - } - else - { - temps = "Test failed"; - return -1; - } - } - else - { - // test too long. Failure. - temps = "Test failed."; - return -1; - } - } - - //Baseband gets back the control over SPI switch - mSPI_write(0x0006, 0x0000); //REG6 write - - return 0; -} - -void MCU_BD::RunTest_MCU(int m_iMode1, int m_iMode0, unsigned short test_code, int m_iDebug) { - - int i=0; - int limit=0; - unsigned short tempi=0x0000; - unsigned short basei=0x0000; - - if (test_code<=15) basei=(test_code<<4); - else basei=0x0000; - - basei=basei&0xFFF0; // not necessery - // 4 LSBs are zeros - - // variable basei contains test no. value at bit positions 7-4 - // used for driving the P0 input - // P0 defines the test no. - - if ((test_code>7)||(test_code==0)) - limit=1; - else - limit=50; - - // tests 8 to 14 have short duration - - if (m_iDebug==1) return; // normal MCU operating mode required - - // EXT_INT2=1, external interrupt 2 is raised - tempi=0x0000; // changed - int m_iExt2=1; - - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - - // tempi variable is driving the mspi_REG2 - - mSPI_write(0x8002, tempi); // REG2 write - - // generating waveform - for (i=0; i<=limit; i++) - { - tempi=basei|0x000C; - mSPI_write(0x8000, tempi); - // REG0 write - Wait_CLK_Cycles(256); - tempi=basei|0x000D; - mSPI_write(0x8000, tempi); - // REG0 write - P0(0) set - Wait_CLK_Cycles(256); - tempi=basei|0x000C; - mSPI_write(0x8000, tempi); - // REG0 write - Wait_CLK_Cycles(256); - tempi=basei|0x000E; - mSPI_write(0x8000, tempi); - // REG0 write - PO(1) set - Wait_CLK_Cycles(256); - - if (i==0) { - // EXT_INT2=0 - // external interrupt 2 is pulled down - tempi=0x0000; // changed - m_iExt2=0; - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - mSPI_write(0x8002, tempi); - // REG2 write - } - } -} - - -void MCU_BD::RunFabTest_MCU(int m_iMode1, int m_iMode0, int m_iDebug) { - - unsigned short tempi=0x0000; - - if (m_iDebug==1) return; // normal MCU operating mode required - - // EXT_INT2=1, external interrupt 2 is raised - tempi=0x0000; // changed - int m_iExt2=1; - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - mSPI_write(0x8002, tempi); // REG2 write - - Wait_CLK_Cycles(256); - - // EXT_INT2=0, external interrupt 2 is pulled down - tempi=0x0000; // changed - m_iExt2=0; - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - mSPI_write(0x8002, tempi); - - Wait_CLK_Cycles(256); - -} - -void MCU_BD::DebugModeSet_MCU(int m_iMode1, int m_iMode0) -{ - unsigned short tempi=0x00C0; - // bit DEBUG is set - int m_iExt2=0; - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - - // Select debug mode - mSPI_write(0x8002, tempi); - // REG2 write -} - - void MCU_BD::DebugModeExit_MCU(int m_iMode1, int m_iMode0) -{ - - unsigned short tempi=0x0000; // bit DEBUG is zero - int m_iExt2=0; - - if (m_iExt2==1) tempi=tempi|0x0004; - if (m_iMode1==1) tempi=tempi|0x0002; - if (m_iMode0==1) tempi=tempi|0x0001; - // To run mode - mSPI_write(0x8002, tempi); // REG2 write -} - -int MCU_BD::ResetPC_MCU() -{ - unsigned char tempc1=0x00; - int retval=0; - retval=One_byte_command(0x70, &tempc1); - return retval; -} - -int MCU_BD::RunInstr_MCU(unsigned short * pPCVAL) -{ - unsigned char tempc1, tempc2, tempc3=0x00; - int retval=0; - retval=Three_byte_command(0x74, 0x00, 0x00, &tempc1, &tempc2, &tempc3); - if (retval==-1) (*pPCVAL)=0; - else (*pPCVAL)=tempc2*256+tempc3; - return retval; -} - -void MCU_BD::Log(const char* msg) -{ - printf("%s", msg); -} - -/** @brief Returns information about programming or reading data progress -*/ -MCU_BD::ProgressInfo MCU_BD::GetProgressInfo() const -{ - ProgressInfo info; - info.stepsDone = stepsDone.load(); - info.stepsTotal = stepsTotal.load(); - info.aborted = aborted.load(); - return info; -} - -unsigned int MCU_BD::formREG2command(int m_iExt5, int m_iExt4, int m_iExt3, int m_iExt2, int m_iMode1, int m_iMode0) { - unsigned int tempi = 0x0000; - if (m_iExt5 == 1) tempi = tempi | 0x0020; - if (m_iExt4 == 1) tempi = tempi | 0x0010; - if (m_iExt3 == 1) tempi = tempi | 0x0008; - if (m_iExt2 == 1) tempi = tempi | 0x0004; - if (m_iMode1 == 1) tempi = tempi | 0x0002; - if (m_iMode0 == 1) tempi = tempi | 0x0001; - return(tempi); -} - -std::string MCU_BD::GetProgramFilename() const -{ - return mLoadedProgramFilename; -} - -/** @brief Starts algorithm in MCU -*/ -void MCU_BD::RunProcedure(uint8_t id) -{ - mSPI_write(0x0006, id != 0); - mSPI_write(0x0000, id); - uint8_t x0002reg = mSPI_read(0x0002); - const uint8_t interupt6 = 0x08; - mSPI_write(0x0002, x0002reg | interupt6); - mSPI_write(0x0002, x0002reg & ~interupt6); - std::this_thread::sleep_for(std::chrono::microseconds(10)); -} - - -/** @brief Waits for MCU to finish executing program -@return 0 success, 255 idle, 244 running, else algorithm status -*/ -int MCU_BD::WaitForMCU(uint32_t timeout_ms) -{ - auto t1 = std::chrono::high_resolution_clock::now(); - auto t2 = t1; - unsigned short value = 0; - std::this_thread::sleep_for(std::chrono::microseconds(50)); - do { - value = mSPI_read(0x0001) & 0xFF; - if (value != 0xFF) //working - break; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - t2 = std::chrono::high_resolution_clock::now(); - }while (std::chrono::duration_cast(t2 - t1).count() < timeout_ms); - mSPI_write(0x0006, 0); //return SPI control to PC - //if((value & 0x7f) != 0) - std::printf("MCU algorithm time: %li ms\n", std::chrono::duration_cast(t2 - t1).count()); - return value & 0x7F; -} - -void MCU_BD::SetParameter(MCU_Parameter param, float value) -{ - uint8_t inputRegs[3]; - value /= 1e6; - inputRegs[0] = (uint8_t)value; //frequency integer part - - uint16_t fracPart = value * 1000.0 - inputRegs[0]*1000.0; - inputRegs[1] = (fracPart >> 8) & 0xFF; - inputRegs[2] = fracPart & 0xFF; - const uint8_t x0002reg = mSPI_read(0x0002); - const uint8_t interupt7 = 0x04; - for(uint8_t i = 0; i < 3; ++i) - { - mSPI_write(0, inputRegs[2-i]); - mSPI_write(0x0002, x0002reg | interupt7); - mSPI_write(0x0002, x0002reg & ~interupt7); - this_thread::sleep_for(chrono::microseconds(5)); - } - if(param==MCU_REF_CLK) - RunProcedure(4); - if(param == MCU_BW) - RunProcedure(3); -} - -/** @brief Switches MCU into debug mode, MCU program execution is halted - @param mode MCU memory initialization mode - @return Operation status -*/ -MCU_BD::OperationStatus MCU_BD::SetDebugMode(bool enabled, IConnection::MCU_PROG_MODE mode) -{ - uint8_t regValue = 0; - switch (mode) - { - case IConnection::MCU_PROG_MODE::RESET: - break; - case IConnection::MCU_PROG_MODE::EEPROM_AND_SRAM: - regValue |= 0x01; break; - case IConnection::MCU_PROG_MODE::SRAM: - regValue |= 0x02; break; - case IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM: - regValue |= 0x03; break; - } - if (enabled) - regValue |= 0xC0; - mSPI_write(0x8002, regValue); - return SUCCESS; -} - -MCU_BD::OperationStatus MCU_BD::readIRAM(const uint8_t *addr, uint8_t* values, const uint8_t count) -{ - uint8_t cmd = 0x78; // - int retval; - for (int i = 0; i < count; ++i) - { - mSPI_write(0x8004, cmd); //REG4 write cmd - retval = WaitUntilWritten(); - if (retval == -1) return FAILURE; - - mSPI_write(0x8004, addr[i]); //REG4 write IRAM address - retval = WaitUntilWritten(); - if (retval == -1) return FAILURE; - - mSPI_write(0x8004, 0); //REG4 nop - retval = WaitUntilWritten(); - if (retval == -1) return FAILURE; - - uint8_t result = 0; - retval = ReadOneByte(&result); - if (retval == -1) return FAILURE; - - retval = ReadOneByte(&result); - if (retval == -1) return FAILURE; - - retval = ReadOneByte(&result); - if (retval == -1) return FAILURE; - values[i] = result; - } - return SUCCESS; -} - -MCU_BD::OperationStatus MCU_BD::writeIRAM(const uint8_t *addr, const uint8_t* values, const uint8_t count) -{ - return FAILURE; -} - -uint8_t MCU_BD::ReadMCUProgramID() -{ - RunProcedure(255); - auto statusMcu = WaitForMCU(10); - return statusMcu & 0x7F; -} diff --git a/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h b/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h deleted file mode 100644 index bc6b5d7c5..000000000 --- a/liblimesuite/srcmw/lms7002m_mcu/MCU_File.h +++ /dev/null @@ -1,535 +0,0 @@ -#include -#include -#include -#include - -#if !(defined(max)) && _MSC_VER - // VC fix - #define max __max -#endif - -#define MYMAX(a, b) (a) > (b) ? (a) : (b) - -using namespace std; - -class MemBlock -{ -public: - unsigned long m_startAddress; - vector m_bytes; -}; - -class MCU_File -{ -public: - explicit MCU_File(const char *fileName, const char *mode) - { - m_file = fopen(fileName, mode); - if (m_file != NULL) - { - return; - } - - cout << "Error opening"; - //string errorStr = "Error opening "; - //errorStr += fileName; - //errorStr += "\n"; - //throw errorStr; - } - - ~MCU_File() - { - if (m_file) - fclose(m_file); - } - - bool FileOpened() - { - return m_file != NULL; - } - - // Read binary file - void ReadBin(unsigned long limit) - { - m_top = 0; - - m_chunks.push_back(MemBlock()); - m_chunks.back().m_startAddress = 0; - - cout << "Reading binary file\n"; - - int tmp = fgetc(m_file); - - while (!feof(m_file)) - { - m_chunks.back().m_bytes.push_back(tmp); - - if (m_chunks.back().m_bytes.size() > limit + 1) - { - m_chunks.back().m_bytes.pop_back(); - m_top = m_chunks.back().m_bytes.size() - 1; - cout << "Ignoring data above address space!\n"; - cout << " Limit: " << limit << "\n"; - return; - } - - tmp = fgetc(m_file); - } - - m_top = m_chunks.back().m_bytes.size() - 1; - - if (!m_chunks.back().m_bytes.size()) - { - cout << "No data!\n"; - - m_chunks.pop_back(); - } - } - - // Read hex file - void ReadHex(unsigned long limit) - { - char szLine[1024]; - bool formatDetected = false; - bool intel = false; - bool endSeen = false; - bool linear = true; // Only used for intel hex - unsigned long addressBase = 0; // Only used for intel hex - unsigned long dataRecords = 0; // Only used for s-record - while (!feof(m_file)) - { - if (fgets(szLine, 1024, m_file) == 0) - { - if (ferror(m_file)) - { - throw "Error reading input!\n"; - } - continue; - } - - if (szLine[strlen(szLine) - 1] == 0xA || szLine[strlen(szLine) - 1] == 0xD) - { - szLine[strlen(szLine) - 1] = 0; - } - - if (szLine[strlen(szLine) - 1] == 0xA || szLine[strlen(szLine) - 1] == 0xD) - { - szLine[strlen(szLine) - 1] = 0; - } - - if (strlen(szLine) == 1023) - { - throw "Hex file lines to long!\n"; - } - // Ignore blank lines - if (szLine[0] == '\n') - { - continue; - } - // Detect format and warn if garbage lines are found - if (!formatDetected) - { - if (szLine[0] != ':' && szLine[0] != 'S') - { - cout << "Ignoring garbage line!\n"; - continue; - } - if (szLine[0] == 'S') - { - intel = false; - cout << "Detected S-Record\n"; - } - else - { - intel = true; - cout << "Detected intel hex file\n"; - } - formatDetected = true; - } - else if ((intel && szLine[0] != ':') || - (!intel && szLine[0] != 'S')) - { - cout << "Ignoring garbage line!\n"; - continue; - } - - if (endSeen) - { - throw "Hex line after end of file record!\n"; - } - - if (intel) - { - unsigned long dataBytes; - unsigned long startAddress; - unsigned long type; - if (sscanf(&szLine[1], "%2lx%4lx%2lx", &dataBytes, &startAddress, &type) != 3) - { - throw "Hex line beginning corrupt!\n"; - } - // Check line length - if (szLine[11 + dataBytes * 2] != '\n' && szLine[11 + dataBytes * 2] != 0) - { - throw "Hex line length incorrect!\n"; - } - // Check line checksum - unsigned char checkSum = 0; - unsigned long tmp; - for (unsigned int i = 0; i <= dataBytes + 4; ++i) - { - if (sscanf(&szLine[1 + i * 2], "%2lx", &tmp) != 1) - { - throw "Hex line data corrupt!\n"; - } - checkSum += tmp; - } - if (checkSum != 0) - { - throw "Hex line checksum error!\n"; - } - - switch (type) - { - case 0: - // Data record - if (!linear) - { - // Segmented - unsigned long test = startAddress; - test += dataBytes; - if (test > 0xffff) - { - throw "Can't handle wrapped segments!\n"; - } - } - if (!m_chunks.size() || - m_chunks.back().m_startAddress + m_chunks.back().m_bytes.size() != - addressBase + startAddress) - { - m_chunks.push_back(MemBlock()); - m_chunks.back().m_startAddress = addressBase + startAddress; - } - { - unsigned char i = 0; - for (i = 0; i < dataBytes; ++i) - { - sscanf(&szLine[9 + i * 2], "%2lx", &tmp); - if (addressBase + startAddress + i > limit) - { - cout << "Ignoring data above address space!\n"; - cout << "Data address: " << addressBase + startAddress + i; - cout << " Limit: " << limit << "\n"; - if (!m_chunks.back().m_bytes.size()) - { - m_chunks.pop_back(); - } - continue; - } - m_chunks.back().m_bytes.push_back(tmp); - } - } - break; - - case 1: - // End-of-file record - if (dataBytes != 0) - { - cout << "Warning: End of file record not zero length!\n"; - } - if (startAddress != 0) - { - cout << "Warning: End of file record address not zero!\n"; - } - endSeen = true; - break; - - case 2: - // Extended segment address record - if (dataBytes != 2) - { - throw "Length field must be 2 in extended segment address record!\n"; - } - if (startAddress != 0) - { - throw "Address field must be zero in extended segment address record!\n"; - } - sscanf(&szLine[9], "%4lx", &startAddress); - addressBase = startAddress << 4; - linear = false; - break; - - case 3: - // Start segment address record - if (dataBytes != 4) - { - cout << "Warning: Length field must be 4 in start segment address record!\n"; - } - if (startAddress != 0) - { - cout << "Warning: Address field must be zero in start segment address record!\n"; - } - if (dataBytes == 4) - { - unsigned long ssa; - char ssaStr[16]; - sscanf(&szLine[9], "%8lx", &ssa); - sprintf(ssaStr, "%08lX\n", ssa); - cout << "Segment start address (CS/IP): "; - cout << ssaStr; - } - break; - - case 4: - // Extended linear address record - if (dataBytes != 2) - { - throw "Length field must be 2 in extended linear address record!\n"; - } - if (startAddress != 0) - { - throw "Address field must be zero in extended linear address record!\n"; - } - sscanf(&szLine[9], "%4lx", &startAddress); - addressBase = ((unsigned long)startAddress) << 16; - linear = true; - break; - - case 5: - // Start linear address record - if (dataBytes != 4) - { - cout << "Warning: Length field must be 4 in start linear address record!\n"; - } - if (startAddress != 0) - { - cout << "Warning: Address field must be zero in start linear address record!\n"; - } - if (dataBytes == 4) - { - unsigned long lsa; - char lsaStr[16]; - sscanf(&szLine[9], "%8lx", &lsa); - sprintf(lsaStr, "%08lX\n", lsa); - cout << "Linear start address: "; - cout << lsaStr; - } - break; - - default: - cout << "Waring: Unknown record found!\n"; - } - } - else - { - // S-record - unsigned long count; - char type; - if (sscanf(&szLine[1], "%c%2lx", &type, &count) != 2) - { - throw "Hex line beginning corrupt!\n"; - } - // Check line length - if (szLine[4 + count * 2] != '\n' && szLine[4 + count * 2] != 0) - { - throw "Hex line length incorrect!\n"; - } - // Check line checksum - unsigned char checkSum = 0; - unsigned long tmp; - for (unsigned int i = 0; i < count + 1; ++i) - { - if (sscanf(&szLine[2 + i * 2], "%2lx", &tmp) != 1) - { - throw "Hex line data corrupt!\n"; - } - checkSum += tmp; - } - if (checkSum != 255) - { - throw "Hex line checksum error!\n"; - } - - switch (type) - { - case '0': - // Header record - { - char header[256]; - uint8_t i = 0; - for (i = 0; uint8_t(i + 3) < count; ++i) - { - sscanf(&szLine[8 + i * 2], "%2lx", &tmp); - header[i] = tmp; - } - header[i] = 0; - if (i > 0) - { - cout << "Module name: " << header << "\n"; - } - } - break; - - case '1': - case '2': - case '3': - // Data record - { - dataRecords++; - unsigned long startAddress; - if (type == '1') - { - sscanf(&szLine[4], "%4lx", &startAddress); - } - else if (type == '2') - { - sscanf(&szLine[4], "%6lx", &startAddress); - } - else - { - sscanf(&szLine[4], "%8lx", &startAddress); - } - - if (!m_chunks.size() || - m_chunks.back().m_startAddress + m_chunks.back().m_bytes.size() != - startAddress) - { - m_chunks.push_back(MemBlock()); - m_chunks.back().m_startAddress = startAddress; - } - unsigned char i = 0; - for (i = uint8_t(type - '1'); uint8_t(i + 3) < count; ++i) - { - sscanf(&szLine[8 + i * 2], "%2lx", &tmp); - if (startAddress + i > limit) - { - cout << "Ignoring data above address space!\n"; - cout << "Data address: " << startAddress + i; - cout << " Limit: " << limit << "\n"; - if (!m_chunks.back().m_bytes.size()) - { - m_chunks.pop_back(); - } - continue; - } - m_chunks.back().m_bytes.push_back(tmp); - } - } - break; - - case '5': - // Count record - { - unsigned long address; - sscanf(&szLine[4], "%4lx", &address); - if (address != dataRecords) - { - throw "Wrong number of data records!\n"; - } - } - break; - - case '7': - case '8': - case '9': - // Start address record - cout << "Ignoring start address record!\n"; - break; - - default: - cout << "Unknown record found!\n"; - } - } - } - if (intel && !endSeen) - { - cout << "No end of file record!\n"; - } - if (!m_chunks.size()) - { - throw "No data in file!\n"; - } - vector::iterator vi; - m_top = 0; - for (vi = m_chunks.begin(); vi < m_chunks.end(); vi++) - { - //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); - } - } - - // Rather inefficient this one, fix sometime - bool GetByte(const unsigned long address, unsigned char &chr) - { - vector::iterator vi; - - for (vi = m_chunks.begin(); vi < m_chunks.end(); vi++) - { - if (vi->m_startAddress + vi->m_bytes.size() > address && vi->m_startAddress <= address) - { - break; - } - } - if (vi == m_chunks.end()) - { - return false; - } - chr = vi->m_bytes[address - vi->m_startAddress]; - return true; - } - - bool BitString(const unsigned long address, const unsigned char bits, const bool lEndian, string &str) - { - bool ok = false; - long i; - unsigned char chr; - unsigned long data = 0; - unsigned long tmp; - - if (lEndian) - { - for (i = 0; i < (bits + 7) / 8; ++i) - { - ok |= GetByte(address + i, chr); - tmp = chr; - data |= tmp << (8 * i); - } - } - else - { - for (i = 0; i < (bits + 7) / 8; ++i) - { - ok |= GetByte(address + i, chr); - tmp = chr; - data |= tmp << (8 * ((bits + 7) / 8 - i - 1)); - } - } - - if (!ok) - { - return false; - } - - unsigned long mask = 1; - - str = ""; - for (i = 0; i < bits; i++) - { - if (data & mask) - { - str.insert(0,"1"); - } - else - { - str.insert(0,"0"); - } - mask <<= 1; - } - return true; - } - - FILE *Handle() { return m_file; }; - vector m_chunks; - unsigned long m_top; -private: - FILE *m_file; -}; diff --git a/liblimesuite/srcmw/vasprintf.h b/liblimesuite/srcmw/vasprintf.h deleted file mode 100644 index 5825c8d65..000000000 --- a/liblimesuite/srcmw/vasprintf.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * vasprintf.h - * - * Created on: 9 May 2017 - * Author: egriffiths - */ - -#ifndef LIBLIMESUITE_SRCMW_VASPRINTF_H_ -#define LIBLIMESUITE_SRCMW_VASPRINTF_H_ - - -#define _GNU_SOURCE -#define __CRT__NO_INLINE - -#include -#include -#include - -int my_vasprintf(char ** __restrict__ ret, - const char * __restrict__ format, - va_list ap) { - int len; - /* Get Length */ - len = _vsnprintf(NULL,0,format,ap); - if (len < 0) return -1; - /* +1 for \0 terminator. */ - *ret = (char *) malloc(len + 1); - /* Check malloc fail*/ - if (!*ret) return -1; - /* Write String */ - _vsnprintf(*ret,len+1,format,ap); - /* Terminate explicitly */ - (*ret)[len] = '\0'; - return len; -} - - -#endif /* LIBLIMESUITE_SRCMW_VASPRINTF_H_ */