mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-30 20:40:20 -04:00 
			
		
		
		
	
		
			
	
	
		
			700 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			700 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /**
 | ||
|  | @file Connection_uLimeSDR.cpp | ||
|  | @author Lime Microsystems | ||
|  | @brief Implementation of uLimeSDR board connection. | ||
|  | */ | ||
|  | 
 | ||
|  | #include "Connection_uLimeSDR.h"
 | ||
|  | #include "ErrorReporting.h"
 | ||
|  | #include <cstring>
 | ||
|  | #include <iostream>
 | ||
|  | 
 | ||
|  | #include <thread>
 | ||
|  | #include <chrono>
 | ||
|  | #include <FPGA_common.h>
 | ||
|  | #include <LMS7002M.h>
 | ||
|  | #include <ciso646>
 | ||
|  | 
 | ||
|  | 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<std::mutex> 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<std::mutex> 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<Connection_uLimeSDR::USBTransferContext*>(trans->user_data); | ||
|  |     std::unique_lock<std::mutex> 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<USB_MAX_CONTEXTS; i++) | ||
|  |     { | ||
|  |         if(!contexts[i].used) | ||
|  |         { | ||
|  |             contextFound = true; | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  |     if(!contextFound) | ||
|  |     { | ||
|  |         printf("No contexts left for reading data\n"); | ||
|  |         return -1; | ||
|  |     } | ||
|  |     contexts[i].used = true; | ||
|  | 
 | ||
|  | #ifndef __unix__
 | ||
|  | 	if (length != rxSize) | ||
|  | 	{ | ||
|  | 		rxSize = length; | ||
|  | 		FT_SetStreamPipe(mFTHandle, FALSE, FALSE, mStreamRdEndPtAddr, rxSize); | ||
|  | 	} | ||
|  |     FT_InitializeOverlapped(mFTHandle, &contexts[i].inOvLap); | ||
|  | 	ULONG ulActual; | ||
|  |     FT_STATUS ftStatus = FT_OK; | ||
|  |     ftStatus = FT_ReadPipe(mFTHandle, mStreamRdEndPtAddr, (unsigned char*)buffer, length, &ulActual, &contexts[i].inOvLap); | ||
|  |     if (ftStatus != FT_IO_PENDING) | ||
|  |         return -1; | ||
|  | #else
 | ||
|  |     if (length != rxSize) | ||
|  |     { | ||
|  |         rxSize = length; | ||
|  |         FT_SetStreamPipe(mStreamRdEndPtAddr,rxSize); | ||
|  |     } | ||
|  |     unsigned int Timeout = 500; | ||
|  |     libusb_transfer *tr = contexts[i].transfer; | ||
|  |     libusb_fill_bulk_transfer(tr, dev_handle, mStreamRdEndPtAddr, (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) | ||
|  |     { | ||
|  |         printf("ERROR BEGIN DATA READING %s\n", 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 Connection_uLimeSDR::WaitForReading(int contextHandle, unsigned int timeout_ms) | ||
|  | { | ||
|  |     if(contextHandle >= 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<std::mutex> lck(contexts[contextHandle].transferLock); | ||
|  |         while(contexts[contextHandle].done.load() == false && std::chrono::duration_cast<std::chrono::milliseconds>(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<USB_MAX_CONTEXTS; ++i) | ||
|  |     { | ||
|  |         if(contexts[i].used) | ||
|  |             libusb_cancel_transfer(contexts[i].transfer); | ||
|  |     } | ||
|  |     FT_FlushPipe(mStreamRdEndPtAddr); | ||
|  |     rxSize = 0; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  | @brief Starts asynchronous data Sending to board | ||
|  | @param *buffer buffer to send | ||
|  | @param length number of bytes to send | ||
|  | @return handle of transfer context | ||
|  | */ | ||
|  | int Connection_uLimeSDR::BeginDataSending(const char *buffer, uint32_t length) | ||
|  | { | ||
|  |     int i = 0; | ||
|  |     //find not used context
 | ||
|  |     bool contextFound = false; | ||
|  |     for(i = 0; i<USB_MAX_CONTEXTS; i++) | ||
|  |     { | ||
|  |         if(!contextsToSend[i].used) | ||
|  |         { | ||
|  |             contextFound = true; | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  |     if(!contextFound) | ||
|  |         return -1; | ||
|  |     contextsToSend[i].used = true; | ||
|  | 
 | ||
|  | #ifndef __unix__
 | ||
|  | 	FT_STATUS ftStatus = FT_OK; | ||
|  | 	ULONG ulActualBytesSend; | ||
|  | 	if (length != txSize) | ||
|  | 	{ | ||
|  | 		txSize = length; | ||
|  | 		FT_SetStreamPipe(mFTHandle, FALSE, FALSE, mStreamWrEndPtAddr, txSize); | ||
|  | 	} | ||
|  |     FT_InitializeOverlapped(mFTHandle, &contextsToSend[i].inOvLap); | ||
|  | 	ftStatus = FT_WritePipe(mFTHandle, mStreamWrEndPtAddr, (unsigned char*)buffer, length, &ulActualBytesSend, &contextsToSend[i].inOvLap); | ||
|  | 	if (ftStatus != FT_IO_PENDING) | ||
|  | 		return -1; | ||
|  | #else
 | ||
|  |     if (length != txSize) | ||
|  |     { | ||
|  |         txSize = length; | ||
|  |         FT_SetStreamPipe(mStreamWrEndPtAddr,txSize); | ||
|  |     } | ||
|  |     unsigned int Timeout = 500; | ||
|  |     libusb_transfer *tr = contextsToSend[i].transfer; | ||
|  |     libusb_fill_bulk_transfer(tr, dev_handle, mStreamWrEndPtAddr, (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) | ||
|  |     { | ||
|  |         printf("ERROR BEGIN DATA SENDING %s\n", 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 Connection_uLimeSDR::WaitForSending(int contextHandle, unsigned int timeout_ms) | ||
|  | { | ||
|  |     if(contextsToSend[contextHandle].used == true) | ||
|  |     { | ||
|  | #ifndef __unix__
 | ||
|  |         DWORD dwRet = WaitForSingleObject(contextsToSend[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<std::mutex> lck(contextsToSend[contextHandle].transferLock); | ||
|  |         while(contextsToSend[contextHandle].done.load() == false && std::chrono::duration_cast<std::chrono::milliseconds>(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<USB_MAX_CONTEXTS; ++i) | ||
|  |     { | ||
|  |         if(contextsToSend[i].used) | ||
|  |             libusb_cancel_transfer(contextsToSend[i].transfer); | ||
|  |     } | ||
|  |     FT_FlushPipe(mStreamWrEndPtAddr); | ||
|  |     txSize = 0; | ||
|  | #endif
 | ||
|  | } |