mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -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
 | |
| }
 |