mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-27 02:09:14 -05:00
718 lines
21 KiB
C++
718 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);
|
|
mTimestampOffset = 0;
|
|
rxLastTimestamp.store(0);
|
|
mExpectedSampleRate = 0;
|
|
generateData.store(false);
|
|
rxRunning.store(false);
|
|
txRunning.store(false);
|
|
isConnected = false;
|
|
terminateRx.store(false);
|
|
terminateTx.store(false);
|
|
rxDataRate_Bps.store(0);
|
|
txDataRate_Bps.store(0);
|
|
|
|
mStreamWrEndPtAddr = 0x03;
|
|
mStreamRdEndPtAddr = 0x83;
|
|
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()
|
|
{
|
|
for(auto i : mTxStreams)
|
|
ControlStream((size_t)i, false);
|
|
for(auto i : mRxStreams)
|
|
ControlStream((size_t)i, false);
|
|
for(auto i : mTxStreams)
|
|
CloseStream((size_t)i);
|
|
for(auto i : mRxStreams)
|
|
CloseStream((size_t)i);
|
|
UpdateThreads();
|
|
Close();
|
|
}
|
|
#ifdef __unix__
|
|
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
|
|
}
|