Re: Porting libusbK software to Linux/Mac
Isaac Abbott <[email protected]> Tue, 7 Jun 2016 12:09:10 +0000
| Newsgroups | gmane.comp.lib.libusb.devel.windows |
|---|---|
| Message-ID | <141AAF51821A9347ADD1E35BF7F25191B3A8FCF8@Exchange.mtiinstruments.local> |
Hi Chris, I did something similar for a project last year. I use both UsbK and StmK to communicate to a device with two bulk endpoints. The device uses one endpoint for 2-way command-response channel and the second endpoint for a higher speed 1-way “streaming” data only channel. I ported over to libusb-1.0 for a Linux application. The source is separated by #define USE_LIBUSBK. There is no direct equivalent to StmK, so I had to do a lot more work to replicate the same functionality ( see StreamThread() ). I provide my source as a reference only and make no guarantees as to its correctness or robustness. Best Regards, Isaac From: Chris E [mailto:[email protected]] Sent: Tuesday, June 07, 2016 2:28 AM To: [email protected] Subject: [Libusb-win32-devel] Porting libusbK software to Linux/Mac Hi guys. As the title suggests, I need to port some libusbK code to a different library in order to make it cross-platform. The software uses both control requests handled by UsbK, and isochronous requests handled by StmK. I've looked into libusb-1.0, and it looks like it will be simple to port the UsbK code. However, I couldn't see any immediate equivalent to StmK. Is there a way to set up something similar to StmK in libusb-1.0? Alternatively, is there another library with cross-platform support and an StmK-like module? Thanks, ~Chris ------------------------------------------------------------------------------ What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic patterns at an interface-level. Reveals which users, apps, and protocols are consuming the most bandwidth. Provides multi-vendor support for NetFlow, J-Flow, sFlow and other flows. Make informed decisions using capacity planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e _______________________________________________ Libusb-win32-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/libusb-win32-devel
USBCommunicationsInterface.cpp
(text/plain, 54.1 KB)
/////////////////////////////////////////////////////////////////////////////
// USBCommunicationsInterface.cpp : implementation file
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "USBCommunicationsInterface.h"
#include "mti_lib/cpp/common/HighResolutionTimer.h"
////////////////////////////////////////////////////////////////////////////
// DECLARATIONS
////////////////////////////////////////////////////////////////////////////
#define COMMAND_EP_WRITE 0x01
#define COMMAND_EP_READ 0x81
#define STREAM_EP_READ 0x82
//----------------------------------------
// STREAMING
//
// It is unclear what the ideal values for
// these parameters are. These values were
// copied directly from an example because
// they work.
//----------------------------------------
#define MAX_XFER_SIZE 4096 // Maximum number of bytes transferred at once (see UsbK_GetPipePolicy)
#define MAX_PEND_XFERS 128 // Maximum number of transfers to store at one time
#define MAX_PEND_IO 3 // Maximum number of overlapped IO transfers pending at one time
CUSBCommunicationsInterface::CUSBCommunicationsInterface(void)
//=====================================================================
//=====================================================================
{
mpDeviceNames = 0;
mpDeviceModel = 0;
mpDeviceSerial = 0;
mpDeviceVersion = 0;
mDeviceCount = 0;
mDeviceIndex = -1;
#ifdef USE_LIBUSBK
mpKDeviceList = 0;
mKDeviceList = NULL;
mKHandle = NULL;
mKStmHandle = NULL;
#else
mHandle = NULL;
mpStreamThread = 0;
mStreamState = 0;
mPartialDataIndex = 0;
mPartialDataItem = NULL;
mPendingIO = 0;
mPendingTransfer = 0;
libusb_init(NULL);
libusb_set_debug(NULL, 3);
#if defined LINUX_TARGET
sem_init(&mStopStream, 0, 0);
sem_init(&mStreamStartStop, 0, 0);
pthread_mutex_init(&mCS, NULL);
#endif
#endif
mVID = MTI_VID; //MTII
mPID = DACC_PID; //default to DACC
mPrintTraceMessages = TRUE;
}
CUSBCommunicationsInterface::~CUSBCommunicationsInterface(void)
//=====================================================================
//=====================================================================
{
if(mpDeviceNames)
{
delete[] mpDeviceNames;
mpDeviceNames = 0;
}
if(mpDeviceModel)
{
delete[] mpDeviceModel;
mpDeviceModel = 0;
}
if(mpDeviceSerial)
{
delete[] mpDeviceSerial;
mpDeviceSerial = 0;
}
if(mpDeviceVersion)
{
delete[] mpDeviceVersion;
mpDeviceVersion = 0;
}
mDeviceCount = 0;
mDeviceIndex = -1;
#ifdef USE_LIBUSBK
if(mKStmHandle)
{
StmK_Free(mKStmHandle);
mKStmHandle = 0;
}
if(mKHandle)
{
mKUsb.Free(mKHandle);
mKHandle = NULL;
}
if(mKDeviceList)
{
LstK_Free(mKDeviceList);
mKDeviceList = NULL;
}
if(mpKDeviceList)
{
delete[] mpKDeviceList;
mpKDeviceList = 0;
}
#else
if(mHandle)
{
libusb_close(mHandle);
mHandle = NULL;
}
libusb_exit(NULL);
#if defined LINUX_TARGET
pthread_mutex_destroy(&mCS);
#endif
#endif
}
int CUSBCommunicationsInterface::GetDeviceIndex( CString name )
//=====================================================================
// GetDeviceIndex - Scan our list of USB Devices
// for one with name.
//
// Return -1 if not found
// Index number if found
//=====================================================================
{
for(int i=0; i<mDeviceCount; i++)
{
if( mpDeviceNames[i].Compare(name) == 0 )
{
return i;
}
}
return -1;
}
CString CUSBCommunicationsInterface::GetDeviceName( int index )
//=====================================================================
// GetDeviceName - Return the name string at index.
//
// Return NULL if bad index
//=====================================================================
{
if(index < mDeviceCount)
{
return mpDeviceNames[index];
}
else
{
return CString("");
}
}
CString CUSBCommunicationsInterface::GetDeviceModelNumber( int index )
//=====================================================================
// GetDeviceModelNumber - Return the model number string at index.
//
// Return NULL if bad index
//=====================================================================
{
if(index < mDeviceCount)
{
return mpDeviceModel[index];
}
else
{
return CString("");
}
}
CString CUSBCommunicationsInterface::GetDeviceSerialNumber( int index )
//=====================================================================
// GetDeviceSerialNumber - Return the serial number string at index.
//
// Return NULL if bad index
//=====================================================================
{
if(index < mDeviceCount)
{
return mpDeviceSerial[index];
}
else
{
return CString("");
}
}
CString CUSBCommunicationsInterface::GetDeviceSoftwareVersion( int index )
//=====================================================================
// GetDeviceSoftwareVersion - Return the software version string at index.
//
// Return NULL if bad index
//=====================================================================
{
if(index < mDeviceCount)
{
return mpDeviceVersion[index];
}
else
{
return CString("");
}
}
int CUSBCommunicationsInterface::ConnectToDevice( CString name )
//=====================================================================
// ConnectToDevice - Attempt to open a connection to device by name
//
// Return 0 if success
//=====================================================================
{
int index = GetDeviceIndex(name);
if(index >= 0)
{
return ConnectToDevice(index);
}
else
{
return 1;
}
}
void CUSBCommunicationsInterface::Disconnect(void)
//=====================================================================
// Disconnect - Disconnect from all USB devices & free handle
//=====================================================================
{
StopStream();
//------------------------------------------------------------------
// Release the interface
//------------------------------------------------------------------
#ifdef USE_LIBUSBK
if(mKHandle)
{
mKUsb.ReleaseInterface(mKHandle,0,TRUE);
mKUsb.Free(mKHandle);
mKHandle = NULL;
}
#else
if(mHandle)
{
libusb_release_interface(mHandle, 0);
libusb_close(mHandle);
mHandle = NULL;
}
#endif
mDeviceIndex = -1;
}
bool CUSBCommunicationsInterface::IsConnected(void)
//=====================================================================
//=====================================================================
{
#ifdef USE_LIBUSBK
if(mKHandle != NULL && mDeviceIndex != -1)
#else
if(mHandle != NULL && mDeviceIndex != -1)
#endif
{
return true;
}
else
{
return false;
}
}
bool CUSBCommunicationsInterface::ReadyToStream(void)
//=====================================================================
//=====================================================================
{
#ifdef USE_LIBUSBK
if(mKStmHandle != NULL)
#else
if( mStreamState == 1 )
#endif
{
return true;
}
else
{
return false;
}
}
int CUSBCommunicationsInterface::WriteCommand(const char *buffer, int bytesToWrite, int *bytesWritten)
//=====================================================================
// Write - Write data to USB port
//
// INPUTS: buffer - buffer contining data to write
// bytesToWrite - number of bytes to write
//
// OUTPUTS: bytesWritten - bytes actually written
//
// RETURNS: status code
// 0 = OK
// -1 = device not open
// 8 = Error From WritePipe
// 10 = Write Timeout
//=====================================================================
{
if(bytesWritten)
*bytesWritten = 0;
#ifdef USE_LIBUSBK
if(!mKHandle)
#else
if(!mHandle)
#endif
{
return -1;
}
if( bytesToWrite <= 0 )
{
return 0;
}
//------------------------------------------------------------------
// Set the Timeout of WritePipe() for the Command OUT endpoint
//------------------------------------------------------------------
#ifdef USE_LIBUSBK
UINT newPipeTimeout = 1000;
BOOL success = mKUsb.SetPipePolicy(mKHandle, COMMAND_EP_WRITE, PIPE_TRANSFER_TIMEOUT, sizeof(UINT), &newPipeTimeout);
if (!success)
{
if(mPrintTraceMessages)
{
TRACE("Error From SetPipePolicy(USB)=%d\n", GetLastError());
}
return 9;
}
#endif
#ifdef USE_LIBUSBK
PUCHAR sendBuffer = (PUCHAR)buffer;
UINT bufferLength = bytesToWrite;
UINT lengthTransferred = 0;
success = mKUsb.WritePipe(mKHandle, COMMAND_EP_WRITE, sendBuffer, bufferLength, &lengthTransferred, NULL);
if(success)
{
*bytesWritten = lengthTransferred;
return 0;
}
else
{
return 8;
}
#else
unsigned char * sendBuffer = (unsigned char *)buffer;
int bufferLength = bytesToWrite;
int lengthTransferred = 0;
int rc = libusb_bulk_transfer(mHandle, COMMAND_EP_WRITE, sendBuffer, bufferLength, &lengthTransferred, 1000);
if(rc == 0)
{
*bytesWritten = lengthTransferred;
return 0;
}
else if(rc == LIBUSB_ERROR_TIMEOUT)
{
return 10;
}
else
{
return 8;
}
#endif
}
int CUSBCommunicationsInterface::ReadResponse(char *buffer, int maxBytesToRead, int *bytesRead, int tmo)
//=====================================================================
// Read - Read a line from USB command IN endpoint
//
// INPUTS: buffer - read buffer
// maxBytesToRead - max size of read buffer
// timeout - timeout (milliseconds)
//
// OUTPUTS: bytesRead - bytes actually read
//
// RETURNS: status code
// 0 = OK
// -1 = Port not open
// 9 = Error From ReadPipe
// 10 = Read Timeout
//=====================================================================
{
CString text;
if(bytesRead)
*bytesRead = 0;
if(buffer)
memset(buffer, 0, maxBytesToRead);
#ifdef USE_LIBUSBK
if(!mKHandle)
#else
if(!mHandle)
#endif
{
return -1;
}
if( maxBytesToRead <= 0 )
{
return 0;
}
#ifdef USE_LIBUSBK
//------------------------------------------------------------------
// Set the Timeout of ReadPipe() for the Command IN endpoint
//------------------------------------------------------------------
UINT newPipeTimeout = tmo;
BOOL success = mKUsb.SetPipePolicy(mKHandle, COMMAND_EP_READ, PIPE_TRANSFER_TIMEOUT, sizeof(UINT), &newPipeTimeout);
if (!success)
{
if(mPrintTraceMessages)
{
TRACE("Usb.SetPipePolicy failed. (0x%08X)\n", GetLastError());
}
return 9;
}
#endif
CHighResolutionTimer timer;
timer.StartTimer();
unsigned char internalBuffer[64];
int count = 0;
#ifdef USE_LIBUSBK
UINT numRead = 0;
while(1)
{
success = mKUsb.ReadPipe(mKHandle, COMMAND_EP_READ, &internalBuffer[0], 1, &numRead, NULL);
if( !success )
{
if(mPrintTraceMessages)
{
text.Format("Error From ReadPipe(USB)=%d\n", GetLastError());
TRACE((const char*)text);
}
*bytesRead = count;
return 9;
}
else if(numRead == 0)
{
if(mPrintTraceMessages)
{
text.Format("Timeout From ReadPipe(USB)=%d\n", GetLastError());
TRACE((const char*)text);
}
*bytesRead = count;
return 10;
}
else if(internalBuffer[0] < ' ')
{
if(internalBuffer[0] == '\n')
{
*bytesRead = count;
break;
}
}
else if(*bytesRead < maxBytesToRead)
{
buffer[count] = internalBuffer[0];
count += numRead;
}
// Check for timeout
if( tmo > 0 )
{
if( timer.GetTimeInMilliSeconds() > (double)tmo )
{
*bytesRead = count;
return 10;
}
}
}
#else
int numRead = 0;
while(1)
{
int rc = libusb_bulk_transfer(mHandle, COMMAND_EP_READ, &internalBuffer[0], 64, &numRead, (unsigned int)tmo);
if( rc == LIBUSB_ERROR_TIMEOUT)
{
if(mPrintTraceMessages)
{
text.Format("Timeout From ReadPipe(USB)=%d\n", rc);
TRACE((const char*)text);
}
*bytesRead = count;
return 10;
}
else if( rc != 0 )
{
if(mPrintTraceMessages)
{
text.Format("Error From ReadPipe(USB)=%d\n", rc);
TRACE((const char*)text);
}
*bytesRead = count;
return 9;
}
else
{
if(numRead == 0)
{
if(mPrintTraceMessages)
{
text.Format("No Data From ReadPipe(USB)=%d\n", rc);
TRACE((const char*)text);
}
*bytesRead = count;
return 9;
}
else if(internalBuffer[numRead-1] < ' ')
{
if(internalBuffer[numRead-1] == '\n')
{
memcpy(&buffer[count], &internalBuffer[0], numRead-1);
count += (numRead-1);
*bytesRead = count;
break;
}
}
else if(*bytesRead < maxBytesToRead)
{
memcpy(&buffer[count], &internalBuffer[0], numRead);
count += numRead;
}
}
// Check for timeout
if( tmo > 0 )
{
if( timer.GetTimeInMilliSeconds() > (double)tmo )
{
*bytesRead = count;
return 10;
}
}
}
#endif
return 0;
}
int CUSBCommunicationsInterface::ReadStreaming(char *buffer, int minBytesToRead, int maxBytesToRead, int *bytesRead, int tmo)
//=====================================================================
// ReadStreaming - Read data from USB Streaming IN endpoint.
//
// INPUTS: buffer - read buffer
// minBytesToRead - min number of bytes to read before returning (set to -1 if unused)
// maxBytesToRead - max size of read buffer
// timeout - timeout (milliseconds)
//
// OUTPUTS: bytesRead - bytes actually read
//
// RETURNS: status code
// 0 = OK
// -1 = Port not open
// 9 = Error From ReadPipe
// 10 = Read Timeout
//=====================================================================
{
if(bytesRead)
*bytesRead = 0;
#ifdef USE_LIBUSBK
if(!mKStmHandle)
#else
if(!mpStreamThread)
#endif
{
return -1;
}
if( maxBytesToRead <= 0 || minBytesToRead <= 0 )
{
return 0;
}
if(buffer)
memset(buffer, 0, maxBytesToRead);
CHighResolutionTimer timer;
timer.StartTimer();
int retVal = 0;
unsigned char * recBuffer = (unsigned char *)buffer;
UINT bufferLength = maxBytesToRead;
int totalTransferred = 0;
while( totalTransferred < minBytesToRead )
{
UINT transferred = 0;
#ifdef USE_LIBUSBK
BOOL success = StmK_Read(mKStmHandle, recBuffer, 0, bufferLength, &transferred);
if(success)
{
totalTransferred += transferred;
bufferLength -= transferred;
recBuffer = (PUCHAR)&buffer[totalTransferred];
}
else
{
// If the return result is ERROR_NO_MORE_ITEMS then there is no more data
// to read. Other errors indicate a problem.
if (GetLastError() != ERROR_NO_MORE_ITEMS)
{
retVal = 9;
break;
}
// Handle ERROR_NO_MORE_ITEMS:
// Do nothing
}
#else
int rc = StreamRead(recBuffer, bufferLength, &transferred);
if(rc == 0)
{
totalTransferred += transferred;
bufferLength -= transferred;
recBuffer = (unsigned char *)&buffer[totalTransferred];
}
else
{
// If the return result is ERROR_NO_MORE_ITEMS then there is no more data
// to read. Other errors indicate a problem.
if (rc != 1)
{
retVal = 9;
break;
}
// Handle ERROR_NO_MORE_ITEMS:
// Do nothing
}
#endif
// Check for timeout
if( tmo > 0 )
{
if( timer.GetTimeInMilliSeconds() > (double)tmo )
{
retVal = 10;
break;
}
}
}
*bytesRead = totalTransferred;
return retVal;
}
int CUSBCommunicationsInterface::FlushCommand(void)
//=====================================================================
// FlushCommand - Flush command endpoint input and output pipes
//
// INPUTS: none
//
// OUTPUTS: none
//
// RETURNS: status code
// -1 = Port not open
// 0 = OK
// 7 = Error From FlushPipe
//=====================================================================
{
#ifdef USE_LIBUSBK
if(!mKHandle)
{
return -1;
}
if( mKUsb.FlushPipe(mKHandle, COMMAND_EP_READ) == false )
{
return 7;
}
if( mKUsb.FlushPipe(mKHandle, COMMAND_EP_WRITE) == false )
{
return 7;
}
#endif
return 0;
}
int CUSBCommunicationsInterface::FlushStreaming(void)
//=====================================================================
// FlushStreaming - Flush streaming endpoint input pipe
//
// Note: This is not normally called
//
// INPUTS: none
//
// OUTPUTS: none
//
// RETURNS: status code
// -1 = Port not open
// 0 = OK
// 7 = Error From FlushPipe
//=====================================================================
{
#ifdef USE_LIBUSBK
if(!mKHandle)
{
return -1;
}
if( mKUsb.FlushPipe(mKHandle, STREAM_EP_READ) == false )
{
return 7;
}
#endif
return 0;
}
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
// LIBUSBK
#ifdef USE_LIBUSBK
//int CUSBCommunicationsInterface::FindAllDevices(int maxDevices)
//{
//}
int CUSBCommunicationsInterface::FindAllDevices(int maxDevices)
//=====================================================================
// FindAllUSBDevices - Scan USB Devices for ones that match
// MTII USB VID and PID.
//
// Allocate and build list of USB Devices
// Return number of devices found
//=====================================================================
{
BYTE buffer1[128];
BYTE buffer2[128];
//---------------------------
// Delete previous nodes list
//---------------------------
if(mpKDeviceList)
{
delete[] mpKDeviceList;
mpKDeviceList = 0;
}
if(mpDeviceNames)
{
delete[] mpDeviceNames;
mpDeviceNames = 0;
}
if(mpDeviceModel)
{
delete[] mpDeviceModel;
mpDeviceModel = 0;
}
if(mpDeviceSerial)
{
delete[] mpDeviceSerial;
mpDeviceSerial = 0;
}
if(mpDeviceVersion)
{
delete[] mpDeviceVersion;
mpDeviceVersion = 0;
}
mDeviceCount = 0;
//-----------------------
// Allocate new device list
//-----------------------
if(maxDevices > 0)
{
mpKDeviceList = new KLST_DEVINFO_HANDLE[maxDevices];
mpDeviceNames = new CString[maxDevices];
mpDeviceModel = new CString[maxDevices];
mpDeviceSerial = new CString[maxDevices];
mpDeviceVersion = new CString[maxDevices];
}
//------------------------------------------------------------------
// Get the device list & make sure one or more devices were found
//------------------------------------------------------------------
UINT deviceCount = 0;
KLST_DEVINFO_HANDLE deviceInfo = NULL;
if ( !LstK_Init(&mKDeviceList, (KLST_FLAG)0) )
{
if(mPrintTraceMessages)
{
TRACE("Error Initializing USB Device List.\n");
}
return 0;
}
LstK_Count(mKDeviceList, &deviceCount);
if(deviceCount == 0)
{
if(mPrintTraceMessages)
{
TRACE("Device list empty.\n");
}
SetLastError(ERROR_DEVICE_NOT_CONNECTED);
// If LstK_Init returns TRUE, the list must be freed.
LstK_Free(mKDeviceList);
return 0;
}
//------------------------------------------------------------------
// Look For MTII USB devices
//------------------------------------------------------------------
if(mPrintTraceMessages)
{
TRACE("Looking for USB Devices by vid/pid %04X/%04X..\n", mVID, mPID);
}
//------------------------------------------------------------------
// Enumerate the device list using it's internal "current" position.
//------------------------------------------------------------------
unsigned int lengthTransferred;
LstK_MoveReset(mKDeviceList); //Reset the device list position
//------------------------------------------------------------------
// Call LstK_MoveNext after a LstK_MoveReset to advance to the first element.
//------------------------------------------------------------------
while( LstK_MoveNext(mKDeviceList, &deviceInfo) && ( mDeviceCount < maxDevices) )
{
if( deviceInfo->Common.Vid == mVID && deviceInfo->Common.Pid == mPID )
{
//------------------------------------------------------------------
// Load the device driver
//------------------------------------------------------------------
LibK_LoadDriverAPI(&mKUsb, deviceInfo->DriverID);
//------------------------------------------------------------------
// Initialize the device
//------------------------------------------------------------------
mKUsb.Init(&mKHandle, deviceInfo);
//------------------------------------------------------------------
// Get the Friendly Name of the device
//
// 0x0409 is the USB-IF language index for American English
//------------------------------------------------------------------
memset(buffer1, 0, sizeof(buffer1));
BOOL fname_retv = mKUsb.GetDescriptor(mKHandle, USB_DESCRIPTOR_TYPE_STRING, 6, 0x0409, buffer1, sizeof(buffer1), &lengthTransferred);
PUSB_STRING_DESCRIPTOR name = (PUSB_STRING_DESCRIPTOR)buffer1;
//------------------------------------------------------------------
// Get the model number of the device
//
// 0x0409 is the USB-IF language index for American English
//------------------------------------------------------------------
memset(buffer2, 0, sizeof(buffer2));
BOOL model_retv = mKUsb.GetDescriptor(mKHandle, USB_DESCRIPTOR_TYPE_STRING, 7, 0x0409, buffer2, sizeof(buffer2), &lengthTransferred);
PUSB_STRING_DESCRIPTOR model = (PUSB_STRING_DESCRIPTOR)buffer2;
//------------------------------------------------------------------
// Save Serial Number
//------------------------------------------------------------------
mpDeviceSerial[mDeviceCount] = deviceInfo->SerialNumber;
//------------------------------------------------------------------
// Free the device handle
//------------------------------------------------------------------
mKUsb.Free(mKHandle);
//------------------------------------------------------------------
// Save the friendly name of the device & deviceInfo pointer
//------------------------------------------------------------------
mpKDeviceList[mDeviceCount] = deviceInfo;
if(fname_retv)
mpDeviceNames[mDeviceCount] = name->bString;
else
mpDeviceNames[mDeviceCount] = "unavailable";
if(model_retv)
mpDeviceModel[mDeviceCount] = model->bString;
else
mpDeviceModel[mDeviceCount] = "unavailable";
mpDeviceVersion[mDeviceCount] = "";
++mDeviceCount;
//------------------------------------------------------------------
// print some information about the device.
//------------------------------------------------------------------
if(mPrintTraceMessages)
{
TRACE("[%d]: %ls %04X:%04X (%s-%s): %s - %s\n",
mDeviceCount,
name->bString,
deviceInfo->Common.Vid,
deviceInfo->Common.Pid,
deviceInfo->Common.InstanceID,
deviceInfo->SerialNumber,
deviceInfo->DeviceDesc,
deviceInfo->Mfg);
}
}
}
return mDeviceCount;
}
int CUSBCommunicationsInterface::ConnectToDevice( int index )
//=====================================================================
// ConnectToDevice - Attempt to open a connection to device by index
//
// Return 0 if success
// 1 if set-up failure
// 2 if device busy
//=====================================================================
{
if(index >= mDeviceCount)
{
return 1;
}
//------------------------------------------------------------------
// Load the device driver
//------------------------------------------------------------------
if( !LibK_LoadDriverAPI(&mKUsb, mpKDeviceList[index]->DriverID) )
{
if(mPrintTraceMessages)
{
TRACE("LibK_LoadDriverAPI failed. ErrorCode: %08Xh\n", GetLastError());
}
return 1;
}
//------------------------------------------------------------------
// Initialize the device
//------------------------------------------------------------------
if (!mKUsb.Init(&mKHandle, mpKDeviceList[index]))
{
if(mPrintTraceMessages)
{
TRACE("Usb.Init failed. ErrorCode: %08Xh\n", GetLastError());
}
return 1;
}
mDeviceIndex = index;
//------------------------------------------------------------------
// Claim the interface
// - This step is not necessary when using WinUSB, but is included
// for completeness
//------------------------------------------------------------------
BOOL success = mKUsb.ClaimInterface(mKHandle,0,TRUE);
if( !success )
{
DWORD err = GetLastError();
if( err == ERROR_BUSY )
{
TRACE("Usb.ClaimInterface failed - Device Busy");
return 2;
}
else
{
TRACE("Usb.ClaimInterface failed. (0x%08X)\n", err);
return 1;
}
}
//------------------------------------------------------------------
// Set the Timeout of ReadPipe() for the Command IN endpoint
//------------------------------------------------------------------
UINT newPipeTimeout = 10000; //Time-out in milliseconds
success = mKUsb.SetPipePolicy(mKHandle, COMMAND_EP_READ, PIPE_TRANSFER_TIMEOUT, sizeof(UINT), &newPipeTimeout);
if (!success && mPrintTraceMessages)
{
TRACE("Usb.SetPipePolicy failed. (0x%08X)\n", GetLastError());
}
//------------------------------------------------------------------
// Start streaming thread on Streaming IN endpoint
//------------------------------------------------------------------
int rc = StartStream();
if( rc != 0 && mPrintTraceMessages)
{
TRACE("StartStream() failed. ErrorCode: %08Xh\n", rc);
}
if(mPrintTraceMessages)
{
TRACE("Device opened successfully!\n");
}
return 0;
}
int CUSBCommunicationsInterface::StartStream(void)
//=====================================================================
// ConnectToStream - Initialize the Stream
//
// INPUTS: none
//
// RETURNS: status code
// 0 = OK
// -1 = device not open
// 1 = error from Init
// 2 = error from Start
//=====================================================================
{
if(mKStmHandle)
{
return 0;
}
if(!mKHandle)
{
return -1;
}
CString text;
BOOL success;
//------------------------------------------------------------------
// Initialize the stream.
//------------------------------------------------------------------
success = StmK_Init(&mKStmHandle, mKHandle, STREAM_EP_READ,
MAX_XFER_SIZE, MAX_PEND_XFERS, MAX_PEND_IO,
NULL, KSTM_FLAG_NONE);
if (!success)
{
if(mPrintTraceMessages)
{
text.Format("StmK_Init failed. ErrorCode: %08Xh\n", GetLastError());
TRACE((const char*)text);
}
return 1;
}
//------------------------------------------------------------------
// Start the stream.
//------------------------------------------------------------------
success = StmK_Start(mKStmHandle);
if (!success)
{
StmK_Free(mKStmHandle);
mKStmHandle = 0;
if(mPrintTraceMessages)
{
text.Format("StmK_Start failed. ErrorCode: %08Xh\n", GetLastError());
TRACE((const char*)text);
}
return 2;
}
return 0;
}
void CUSBCommunicationsInterface::StopStream(void)
//=====================================================================
// StopStream - Stop the stream and free resources.
//
// According to the documentation StmK_Free will also stop the stream
// before freeing resources, but I found that if the device has been
// disconnected StmK_Stop will fail and StmK_Free will crash the program.
//=====================================================================
{
BOOL success;
CString text;
if(mKStmHandle)
{
success = StmK_Stop(mKStmHandle, 0);
if (!success)
{
if(mPrintTraceMessages)
{
text.Format("StmK_Stop failed. ErrorCode: %08Xh\n", GetLastError());
TRACE((const char*)text);
}
}
else
{
StmK_Free(mKStmHandle);
}
mKStmHandle = 0;
}
}
int CUSBCommunicationsInterface::ReadCommand(char *buffer, int maxBytesToRead, int *bytesRead, int tmo)
//=====================================================================
// Read - Read data from USB command IN endpoint
//
// INPUTS: buffer - read buffer
// maxBytesToRead - max size of read buffer
// timeout - timeout (milliseconds)
//
// OUTPUTS: bytesRead - bytes actually read
//
// RETURNS: status code
// 0 = OK
// -1 = Port not open
// 9 = Error From ReadPipe
// 10 = Read Timeout
//
//
// ---- THIS FUNCTION IS UNUSED ----
//=====================================================================
{
if(bytesRead)
*bytesRead = 0;
if(buffer)
memset(buffer, 0, maxBytesToRead);
if(!mKHandle)
{
return -1;
}
if( maxBytesToRead <= 0 )
{
return 0;
}
PUCHAR recBuffer = (PUCHAR)buffer;
UINT bufferLength = maxBytesToRead;
UINT lengthTransferred;
BOOL success = mKUsb.ReadPipe(mKHandle, COMMAND_EP_READ, recBuffer, bufferLength, &lengthTransferred, NULL);
if(success)
{
*bytesRead = lengthTransferred;
return 0;
}
else
{
return 9;
}
}
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
//**********************************************************************************
// LibUsb 1.0
#else
int CUSBCommunicationsInterface::FindAllDevices(int maxDevices)
//=====================================================================
// FindAllUSBDevices - Scan USB Devices for ones that match
// MTII USB VID and PID.
//
// Allocate and build list of USB Devices
// Return number of devices found
//=====================================================================
{
const char * buffer1[128];
//---------------------------
// Delete previous nodes list
//---------------------------
if(mpDeviceNames)
{
delete[] mpDeviceNames;
mpDeviceNames = 0;
}
if(mpDeviceModel)
{
delete[] mpDeviceModel;
mpDeviceModel = 0;
}
if(mpDeviceSerial)
{
delete[] mpDeviceSerial;
mpDeviceSerial = 0;
}
if(mpDeviceVersion)
{
delete[] mpDeviceVersion;
mpDeviceVersion = 0;
}
mDeviceCount = 0;
//-----------------------
// Allocate new device list
//-----------------------
if(maxDevices > 0)
{
mpDeviceNames = new CString[maxDevices];
mpDeviceModel = new CString[maxDevices];
mpDeviceSerial = new CString[maxDevices];
mpDeviceVersion = new CString[maxDevices];
}
//------------------------------------------------------------------
// Get the device list & make sure one or more devices were found
//------------------------------------------------------------------
libusb_device **devs;
ssize_t cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
{
if(mPrintTraceMessages)
{
TRACE("Error Initializing USB Device List.\n");
}
return 0;
}
else if(cnt == 0)
{
if(mPrintTraceMessages)
{
TRACE("Device list empty.\n");
}
libusb_free_device_list(devs, 1);
return 0;
}
//------------------------------------------------------------------
// Look For MTII USB devices
//------------------------------------------------------------------
if(mPrintTraceMessages)
{
TRACE("Looking for USB Devices by vid/pid %04X/%04X..\n", mVID, mPID);
}
libusb_device *dev;
int i = 0;
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r == 0)
{
if( desc.idVendor == mVID && desc.idProduct == mPID )
{
libusb_device_handle *handle;
r = libusb_open(dev, &handle);
if (r == 0)
{
//*******************************
// String descriptors
//*******************************
// 0 g_pLangDescriptor,
// 1 g_pManufacturerString,
// 2 g_pProductString,
// 3 g_pSerialNumberString,
// 4 g_pConfigString,
// 5 g_pInterfaceString,
// 6 g_pFriendlyNameString,
// 7 g_pModelNumberString,
// 8 g_pFirmwareVersionString
r = libusb_get_string_descriptor_ascii(handle, 3, (unsigned char*)buffer1, 128);
if (r >= 0)
{
mpDeviceSerial[mDeviceCount] = CString((const char*)buffer1);
}
else
{
mpDeviceSerial[mDeviceCount] = "unavailable";
}
r = libusb_get_string_descriptor_ascii(handle, 6, (unsigned char*)buffer1, 128);
if (r >= 0)
{
mpDeviceNames[mDeviceCount] = CString((const char*)buffer1);
}
else
{
mpDeviceNames[mDeviceCount] = "unavailable";
}
r = libusb_get_string_descriptor_ascii(handle, 7, (unsigned char*)buffer1, 128);
if (r >= 0)
{
mpDeviceModel[mDeviceCount] = CString((const char*)buffer1);
}
else
{
mpDeviceModel[mDeviceCount] = "unavailable";
}
r = libusb_get_string_descriptor_ascii(handle, 8, (unsigned char*)buffer1, 128);
if (r >= 0)
{
mpDeviceVersion[mDeviceCount] = CString((const char*)buffer1);
}
else
{
mpDeviceVersion[mDeviceCount] = "unavailable";
}
libusb_close(handle);
++mDeviceCount;
}
}
}
}
libusb_free_device_list(devs, 1);
return mDeviceCount;
}
int CUSBCommunicationsInterface::ConnectToDevice( int index )
//=====================================================================
// ConnectToDevice - Attempt to open a connection to device by index
//
// Return 0 if success
// 1 if set-up failure
// 2 if device busy
//=====================================================================
{
char buffer1[128];
if(index >= mDeviceCount)
{
return 1;
}
//***************************************************************
// Search attached USB devices to find one that matches the index
//***************************************************************
libusb_device **devs;
ssize_t cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
{
return 1;
}
else if(cnt == 0)
{
libusb_free_device_list(devs, 1);
return 1;
}
libusb_device *dev;
int i = 0;
int r;
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
r = libusb_get_device_descriptor(dev, &desc);
if (r == 0)
{
if( desc.idVendor == mVID && desc.idProduct == mPID )
{
libusb_device_handle *handle;
r = libusb_open(dev, &handle);
if (r == 0)
{
int matches = 0;
r = libusb_get_string_descriptor_ascii(handle, 3, (unsigned char*)buffer1, 128);
if (r >= 0)
{
if( strcmp(mpDeviceSerial[index], buffer1) == 0 )
{
matches++;
}
}
r = libusb_get_string_descriptor_ascii(handle, 6, (unsigned char*)buffer1, 128);
if (r >= 0)
{
if( strcmp(mpDeviceNames[index], buffer1) == 0 )
{
matches++;
}
}
r = libusb_get_string_descriptor_ascii(handle, 7, (unsigned char*)buffer1, 128);
if (r >= 0)
{
if( strcmp(mpDeviceModel[index], buffer1) == 0 )
{
matches++;
}
}
r = libusb_get_string_descriptor_ascii(handle, 8, (unsigned char*)buffer1, 128);
if (r >= 0)
{
if( strcmp(mpDeviceVersion[index], buffer1) == 0 )
{
matches++;
}
}
if(matches > 0) //If anything matches, we will assume it is the correct unit
{
mDeviceIndex = index;
mHandle = handle;
}
else
{
libusb_close(handle);
}
}
}
}
}
libusb_free_device_list(devs, 1);
if(mHandle == NULL)
{
return 1;
}
//------------------------------------------------------------------
// Claim the interface
//------------------------------------------------------------------
r = libusb_claim_interface(mHandle, 0);
if( r == LIBUSB_ERROR_BUSY )
{
if(mPrintTraceMessages)
{
TRACE("Usb.ClaimInterface failed - Device Busy");
}
return 2;
}
else if( r != 0 )
{
if(mPrintTraceMessages)
{
TRACE("Usb.ClaimInterface failed. (0x%08X)\n", r);
}
return 1;
}
//------------------------------------------------------------------
// Start streaming thread on Streaming IN endpoint
//------------------------------------------------------------------
int rc = StartStream();
if( rc != 0 && mPrintTraceMessages)
{
TRACE("StartStream() failed. ErrorCode: %08Xh\n", rc);
}
if(mPrintTraceMessages)
{
TRACE("Device opened successfully!\n");
}
return 0;
}
#if defined(_WINDOWS)
static UINT StartStreamThread(void *pObj)
//=====================================================================
// StartStreamThread -- Helper function for stream thread
//=====================================================================
{
if(pObj)
{
return ((CUSBCommunicationsInterface *)pObj)->StreamThread();
}
return 0;
}
#elif defined LINUX_TARGET
void * StartStreamThread(void *pObj)
//=====================================================================
// StartStreamThread -- Helper function for starting a task
//=====================================================================
{
if(pObj)
{
((CUSBCommunicationsInterface *)pObj)->StreamThread();
}
return NULL;
}
#endif
int CUSBCommunicationsInterface::StartStream(void)
//=====================================================================
// ConnectToStream - Initialize the Stream
//
// INPUTS: none
//
// RETURNS: status code
// 0 = OK
// -1 = device not open
// 1 = error from Init
// 2 = error from Start
//=====================================================================
{
if(!mHandle)
{
return -1;
}
//----------------------------
// Is streaming already Active
//----------------------------
if(mpStreamThread != 0)
{
return -1;
}
//------------------------------------------------------------------
// Initialize the stream.
//------------------------------------------------------------------
mStreamState = 0;
//-----------------
// Reset our events
//-----------------
#if defined(_WINDOWS)
mStopStream.ResetEvent();
mStreamStartStop.ResetEvent();
#elif defined(LINUX_TARGET)
while(sem_trywait(&mStopStream) == 0);
while(sem_trywait(&mStreamStartStop) == 0);
#endif
#if defined(_WINDOWS)
//------------------------------------------------------------------
// Start the stream - WINDOWS
//------------------------------------------------------------------
mpStreamThread = AfxBeginThread(::StartStreamThread, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
if(mpStreamThread == 0) //AfxBeginThread failed
{
return 2;
}
mpStreamThread->m_bAutoDelete = TRUE; //This is the default
mpStreamThread->ResumeThread();
#elif defined LINUX_TARGET
//------------------------------------------------------------------
// Start the stream - LINUX
//------------------------------------------------------------------
int rc = pthread_create(&mpStreamThread, NULL, ::StartStreamThread, this);
if(rc != 0)
{
return 2;
}
#endif
if(mpStreamThread == 0) //StreamThread shut itself down
{
return 2;
}
return 0;
}
int CUSBCommunicationsInterface::StreamThread()
//=====================================================================
// StreamThread
//=====================================================================
{
#if defined(_WINDOWS)
DWORD dwResult;
#elif defined LINUX_TARGET
int rc;
#endif
std::map<void*, bool>::iterator map_it;
std::list<unsigned char *>::iterator list_it;
struct libusb_transfer *xfr = NULL;
struct timeval zero_tv;
zero_tv.tv_sec = 0;
zero_tv.tv_usec = 0;
mPendingIO = 0;
mPendingTransfer = 0;
mDataList.clear();
//Allocate buffers
mAvailableBuffers.clear();
for(int i=0; i<MAX_PEND_XFERS; i++)
{
unsigned char * data = (unsigned char*)malloc(MAX_XFER_SIZE);
mAvailableBuffers.push_back(data);
}
//Allocate transfers
mTransfers.clear();
for(int i=0; i<MAX_PEND_IO; i++)
{
xfr = libusb_alloc_transfer(0);
mTransfers[(void*)xfr] = false;
}
mPartialDataItem = NULL;
mPartialDataIndex = 0;
//--------------
// We are active
//--------------
mStreamState = 1;
#if defined(_WINDOWS)
mStreamStartStop.SetEvent(); //Alert caller
#elif defined LINUX_TARGET
sem_post(&mStreamStartStop);
#endif
bool stopMessageReceived;
while(1)
{
//-------------------------------------
// Check for STOP STREAM
//-------------------------------------
stopMessageReceived = FALSE;
#if defined (_WINDOWS)
dwResult = ::WaitForSingleObject(mStopStream.m_hObject, 0);
if(dwResult == WAIT_OBJECT_0)
{
stopMessageReceived = TRUE;
}
#elif defined LINUX_TARGET
while((rc=sem_trywait(&mStopStream))==-1 && errno==EINTR);
if(rc == 0)
{
stopMessageReceived = TRUE;
}
#endif
if(stopMessageReceived)
{
// Cancel any pending transfer requests:
GetDataAccess();
{
for(map_it = mTransfers.begin(); map_it != mTransfers.end(); map_it++)
{
if(map_it->second == true)
{
xfr = (struct libusb_transfer*)(map_it->first);
int err = libusb_cancel_transfer(xfr);
if(mPrintTraceMessages)
{
if(err)
{
TRACE("Cancel Transfer Error = %d\n", err);
}
else
{
TRACE("Transfer Cancelled\n");
}
}
}
}
}
ReleaseDataAccess();
}
if(libusb_handle_events_timeout_completed(NULL, &zero_tv, NULL) != LIBUSB_SUCCESS)
{
break;
}
if( (mStreamState == 1) && (mPendingIO < MAX_PEND_IO) && (mPendingTransfer < MAX_PEND_XFERS) )
{
// Submit new transfer
SubmitTransfer();
}
if( (mStreamState == 2) && (mPendingIO == 0) )
{
// Streaming Cancelled and pendingIO cancelled
break;
}
//Sleep(0);
}
// Free memory
GetDataAccess();
{
while(mDataList.size() > 0)
{
DataItem * item = mDataList.back();
free((void*)(item->data));
delete item;
mDataList.pop_back();
}
for(map_it = mTransfers.begin(); map_it != mTransfers.end(); map_it++)
{
xfr = (struct libusb_transfer*)(map_it->first);
libusb_free_transfer(xfr);
}
for(list_it = mAvailableBuffers.begin(); list_it != mAvailableBuffers.end(); list_it++)
{
free(*list_it);
}
mAvailableBuffers.clear();
}
ReleaseDataAccess();
if(mPartialDataItem != NULL)
{
free(mPartialDataItem->data);
delete mPartialDataItem;
mPartialDataItem = NULL;
}
mStreamState = 0;
mpStreamThread = 0;
#if defined(_WINDOWS)
mStreamStartStop.SetEvent();
#elif defined LINUX_TARGET
sem_post(&mStreamStartStop);
#endif
return 0;
}
void CallbackUSBTransferCompleteHelper(struct libusb_transfer *xfr)
//=====================================================================
// callbackUSBTransferCompleteHelper -- Helper function for callback
//=====================================================================
{
if(xfr)
{
((CUSBCommunicationsInterface *)(xfr->user_data))->CallbackUSBTransferComplete(xfr);
}
}
void CUSBCommunicationsInterface::SubmitTransfer(void)
//=====================================================================
// SubmitTransfer -- Submit a transfer request to libusb
//=====================================================================
{
struct libusb_transfer *xfr = NULL;
unsigned char * data = NULL;
std::map<void*, bool>::iterator it;
// Find available xfr structure & data buffer
GetDataAccess();
{
for(it = mTransfers.begin(); it != mTransfers.end(); it++)
{
if(it->second == false)
{
xfr = (struct libusb_transfer*)(it->first);
}
}
if(mAvailableBuffers.size() > 0)
{
data = mAvailableBuffers.front();
}
if( (xfr != NULL) && (data != NULL) )
{
mTransfers[(void*)xfr] = true;
mAvailableBuffers.pop_front();
}
}
ReleaseDataAccess();
// Configure transfer structure
if( (xfr != NULL) && (data != NULL) )
{
libusb_fill_bulk_transfer(xfr, mHandle, STREAM_EP_READ,
data, MAX_XFER_SIZE,
(libusb_transfer_cb_fn)(::CallbackUSBTransferCompleteHelper), this,
0);
if(libusb_submit_transfer(xfr) < 0)
{
// Error
GetDataAccess();
{
mTransfers[(void*)xfr] = false;
mAvailableBuffers.push_back(data);
}
ReleaseDataAccess();
if(mPrintTraceMessages)
{
TRACE("Transfer Submit Failed\n");
}
}
else
{
++mPendingIO;
++mPendingTransfer;
//TRACE("Transfer Submitted, pendingIO=%d, pendingTransfer=%d\n", mPendingIO, mPendingTransfer);
}
}
}
void CUSBCommunicationsInterface::CallbackUSBTransferComplete(struct libusb_transfer *xfr)
{
DataItem *newItem;
switch(xfr->status)
{
case LIBUSB_TRANSFER_COMPLETED:
// Success here, data transfered are inside xfr->buffer
// and the length is xfr->actual_length
newItem = new DataItem;
newItem->size = xfr->actual_length;
newItem->data = xfr->buffer;
GetDataAccess();
{
mDataList.push_front(newItem);
mTransfers[(void*)xfr] = false;
}
ReleaseDataAccess();
--mPendingIO;
//TRACE("Transfer Completed, length=%d, pendingIO=%d, pendingTransfer=%d\n", newItem->size, mPendingIO, mPendingTransfer);
if( (mPendingIO < MAX_PEND_IO) && (mPendingTransfer < MAX_PEND_XFERS) )
{
// Submit new transfer
SubmitTransfer();
}
break;
case LIBUSB_TRANSFER_CANCELLED:
case LIBUSB_TRANSFER_NO_DEVICE:
case LIBUSB_TRANSFER_TIMED_OUT:
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_STALL:
case LIBUSB_TRANSFER_OVERFLOW:
//libusb_free_transfer(xfr);
GetDataAccess();
{
mTransfers[(void*)xfr] = false;
mAvailableBuffers.push_back(xfr->buffer);
}
ReleaseDataAccess();
--mPendingIO;
if(mPrintTraceMessages)
{
TRACE("LIBUSB ERROR = %d, PendingIO=%d\n", xfr->status, mPendingIO);
}
break;
}
}
//****
// TODO: header
// returns 0=success
// 1=no more items
//****
int CUSBCommunicationsInterface::StreamRead(unsigned char * buffer, unsigned int length, unsigned int * transferredLength)
{
int list_size;
if(!buffer)
return FALSE;
*transferredLength = 0;
// We keep a pointer to the last buffer if it wasn't fully emptied
// Check it first
if(mPartialDataItem != NULL)
{
if(length >= (mPartialDataItem->size - mPartialDataIndex)) //Buffer to fill is larger than data remaining
{
// Copy the rest of the buffer
memcpy(buffer, &((mPartialDataItem->data)[mPartialDataIndex]), (mPartialDataItem->size - mPartialDataIndex));
*transferredLength += (mPartialDataItem->size - mPartialDataIndex);
GetDataAccess();
{
mAvailableBuffers.push_back(mPartialDataItem->data);
}
ReleaseDataAccess();
delete mPartialDataItem;
mPartialDataItem = NULL;
}
else //Can only fit some of the data in this buffer
{
// Copy some of the buffer
memcpy(buffer, &((mPartialDataItem->data)[mPartialDataIndex]), length);
mPartialDataIndex += length;
// Return
*transferredLength = length;
return 0;
}
}
GetDataAccess();
{
list_size = mDataList.size();
}
ReleaseDataAccess();
if(list_size < 1)
{
if(*transferredLength == 0)
{
return 1;
}
else
{
return 0;
}
}
//Iterate through list getting as much data as we can:
do
{
GetDataAccess();
{
mPartialDataItem = mDataList.back();
mPartialDataIndex = 0;
mDataList.pop_back();
--mPendingTransfer;
list_size = mDataList.size();
}
ReleaseDataAccess();
//TRACE("Transfer Retrieved, pendingIO=%d, pendingTransfer=%d\n", mPendingIO, mPendingTransfer);
if((length - *transferredLength) >= mPartialDataItem->size)
{
// Copy all of the buffer
memcpy(&buffer[*transferredLength], mPartialDataItem->data, mPartialDataItem->size);
*transferredLength += mPartialDataItem->size;
GetDataAccess();
{
mAvailableBuffers.push_back(mPartialDataItem->data);
}
ReleaseDataAccess();
delete mPartialDataItem;
mPartialDataItem = NULL;
}
else
{
// Copy some of the buffer
memcpy(&buffer[*transferredLength], mPartialDataItem->data, (length - *transferredLength));
mPartialDataIndex += (length - *transferredLength);
*transferredLength += (length - *transferredLength);
return 0;
}
}
while(list_size > 0);
return 0;
}
void CUSBCommunicationsInterface::StopStream(void)
//=====================================================================
// StopStream - Stop the stream and free resources.
//
//=====================================================================
{
//-------------------------
// Stop Streaming - WINDOWS
//-------------------------
#if defined _WINDOWS
if(mpStreamThread != 0)
{
if(mPrintTraceMessages)
{
TRACE("Set Stop Event\n");
}
mStreamState = 2;
mStreamStartStop.ResetEvent();
mStopStream.SetEvent();
if(!mStreamStartStop.Lock(5000))
{
if(mPrintTraceMessages)
{
TRACE("Timeout Waiting For libusb Stream to Stop\n");
}
}
}
else
{
mStopStream.SetEvent(); //Just in case thread is really active
}
#elif defined LINUX_TARGET
if(mpStreamThread != 0)
{
mStreamState = 2;
while(sem_trywait(&mStreamStartStop) == 0);
sem_post(&mStopStream);
pthread_join(mpStreamThread, NULL);
}
else
{
sem_post(&mStopStream); //Just in case thread is really active
}
#endif
}
void CUSBCommunicationsInterface::GetDataAccess()
//=====================================================================
//=====================================================================
{
#if defined(_WINDOWS)
mCS.Lock();
#elif defined(LINUX_TARGET)
pthread_mutex_lock(&mCS);
#endif
}
void CUSBCommunicationsInterface::ReleaseDataAccess()
//=====================================================================
//=====================================================================
{
#if defined(_WINDOWS)
mCS.Unlock();
#elif defined(LINUX_TARGET)
pthread_mutex_unlock(&mCS);
#endif
}
#endif
USBCommunicationsInterface.h
(text/plain, 5.4 KB)
/////////////////////////////////////////////////////////////////////////////
// USBCommunicationsInterface.h : header file
#pragma once
#if defined(_WINDOWS)
#define USE_LIBUSBK //LibusbK is Windows Only
#else
#endif
#ifdef USE_LIBUSBK
#include "mti_lib/third_party/libusbk/includes/libusbk.h"
#else
#if defined(_WINDOWS)
#include "mti_lib/third_party/libusb-1.0/include/libusb-1.0/libusb.h"
#elif defined(LINUX_TARGET)
#include "/usr/include/libusb-1.0/libusb.h"
#endif
#endif
#if defined LINUX_TARGET
#include <pthread.h>
#include <semaphore.h>
#endif
#include <list>
#include <map>
////////////////////////////////////////////////////////////////////////////
// DECLARATIONS -- USB IDs
////////////////////////////////////////////////////////////////////////////
#define MTI_VID 0x19FD
#define DACC_PID 0x0002 //Digital Accumeasure
#define HERMES_PID 0x0003 //Hermes project (digital control of 9000 card)
#define MT4_PID 0x0004 //Digital Microtrak
struct DataItem
{
unsigned int size;
unsigned char *data;
};
/////////////////////////////////////////////////////////////////////////////
// class CUSBCommunicationsInterface
/////////////////////////////////////////////////////////////////////////////
class CUSBCommunicationsInterface
{
friend void CallbackUSBTransferCompleteHelper(struct libusb_transfer *xfr);
#if defined _WINDOWS
friend UINT StartStreamThread(void *pObject);
#elif defined LINUX_TARGET
friend void* StartStreamThread(void *pObject);
#endif
public:
CUSBCommunicationsInterface(void);
~CUSBCommunicationsInterface(void);
void SetVID(int vid) {mVID = vid;}
void SetPID(int pid) {mPID = pid;}
void SetTraceOutput(BOOL onoff) {mPrintTraceMessages = onoff;}
int GetVID() const {return mVID;}
int GetPID() const {return mPID;}
int FindAllDevices(int maxDevices);
int GetDeviceIndex( CString name );
CString GetDeviceName( int index );
CString GetDeviceModelNumber( int index );
CString GetDeviceSerialNumber( int index );
CString GetDeviceSoftwareVersion( int index );
int ConnectToDevice( CString name );
int ConnectToDevice( int index );
void Disconnect(void);
bool IsConnected(void);
bool ReadyToStream(void);
int WriteCommand(const char *buffer, int bytesToWrite, int *bytesWritten);
int ReadResponse(char *buffer, int maxBytesToRead, int *bytesRead, int tmo);
int ReadStreaming(char *buffer, int minBytesToRead, int maxBytesToRead, int *bytesRead, int tmo);
int FlushCommand(void);
private:
int StartStream(void);
void StopStream(void);
int ReadCommand(char *buffer, int maxBytesToRead, int *bytesRead, int tmo);
int FlushStreaming(void);
private:
int mDeviceIndex; //Index of device we are currently connected to
//-------------------------------------
// USB Communication controls
//-------------------------------------
#ifdef USE_LIBUSBK
KUSB_DRIVER_API mKUsb; //libusbK
KLST_HANDLE mKDeviceList; //libusbK
KUSB_HANDLE mKHandle; //libusbK
KSTM_HANDLE mKStmHandle; //libusbK
KLST_DEVINFO_HANDLE *mpKDeviceList; //List of USB devices that match vid & pid (used by libusbK)
#else
libusb_device_handle *mHandle;
int mPendingIO;
int mPendingTransfer;
DataItem *mPartialDataItem; //A data item that has been partially returned via StreamRead
unsigned int mPartialDataIndex; //The index of the next unread location in the buffer
std::list<DataItem *> mDataList;
std::list<unsigned char *> mAvailableBuffers;
std::map<void*, bool> mTransfers; //true when used
void GetDataAccess();
void ReleaseDataAccess();
#if defined(_WINDOWS)
CCriticalSection mCS;
CWinThread *mpStreamThread;
CEvent mStopStream; //Request to stop the stream
CEvent mStreamStartStop; //Stream has started/stopped
#elif defined(LINUX_TARGET)
pthread_mutex_t mCS;
pthread_t mpStreamThread;
sem_t mStopStream;
sem_t mStreamStartStop;
#endif
int mStreamState; //0=Idle 1=Active 2=Terminating
int StreamThread(void);
void SubmitTransfer(void);
void CallbackUSBTransferComplete(struct libusb_transfer *xfr);
int StreamRead(unsigned char * buffer, unsigned int length, unsigned int * transferredLength);
#endif
CString *mpDeviceNames; //List of USB device names
CString *mpDeviceModel; //List of USB device models
CString *mpDeviceSerial; //List of USB device serial numbers
CString *mpDeviceVersion; //List of USB device SW versions
int mDeviceCount; //Number of USB devices found
int mVID; //Vendor ID (MTII = 0x19FD)
int mPID; //Product ID (DACC = 0x0002)
BOOL mPrintTraceMessages;
};