c2000ware-core-sdk/utilities/tools/f2806x/tiusbdll/tiusbdll.cpp
2023-06-26 16:14:08 +05:30

972 lines
32 KiB
C++

//###########################################################################
//
// FILE: tiusbdll.cpp
//
// TITLE: A thin layer over WinUSB allowing device open/close/
// read and write functionality.
//
// The WinUSB code in this example is based on information provided
// in Microsoft's white paper, "How to Use WinUSB to Communicate
// with a USB Device", WinUsb_HowTo.doc, available from URL:
//
// http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-
// d599bac8184a/WinUsb_HowTo.doc
//
//###########################################################################
// $TI Release: f2806x Support Library v1.15 $
// $Release Date: December 12, 2011 $
// $Copyright:
// Copyright (C) 2009-2023 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################
//
// Included Files
//
#include "stdafx.h"
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#include <strsafe.h>
#include <initguid.h>
#include "winusb.h"
#include "usb100.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include "resource.h" // main symbols
//
// CusbdllApp
// See usbdll.cpp for the implementation of this class
//
class CtiusbdllApp : public CWinApp
{
public:
CtiusbdllApp();
//
// Overrides
//
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
//
// CtiusbdllApp
//
BEGIN_MESSAGE_MAP(CtiusbdllApp, CWinApp)
END_MESSAGE_MAP()
//
// CusbdllApp construction
//
CtiusbdllApp::CtiusbdllApp()
{
//
// TODO: add construction code here,
// Place all significant initialization in InitInstance
//
}
//
// The one and only CusbdllApp object
//
CtiusbdllApp theApp;
//
// CusbdllApp initialization
//
BOOL CtiusbdllApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
//****************************************************************************
//
// Buffer size definitions.
//
//****************************************************************************
#define MAX_DEVPATH_LENGTH 256
//****************************************************************************
//
// Flag indicating that a blocking read should be performed.
//
//****************************************************************************
#define TIUSB_WAIT_FOREVER 0xFFFFFFFF
//****************************************************************************
//
// Structure containing handles and information required to communicate with
// the USB bulk device.
//
//****************************************************************************
typedef struct
{
HANDLE deviceHandle;
WINUSB_INTERFACE_HANDLE winUSBHandle;
UCHAR deviceSpeed;
UCHAR bulkInPipe;
UCHAR bulkOutPipe;
HANDLE hReadEvent;
} tDeviceInfoWinUSB;
typedef void *TIUSB_HANDLE;
//****************************************************************************
//
// Returns the device path associated with a provided interface GUID.
//
// \param dwIndex is the zero-based index of the device whose path is to be
// found.
// \param InterfaceGuid is a pointer to the GUID for the interface that
// we are looking for. Assuming you installed the device using the sample
// INF file, this will be the GUID provided in the Dev_AddReg section.
// \param pcDevicePath is a pointer to a buffer into which will be written
// the path to the device if the function is successful.
// \param BufLen is the size of the buffer pointed to by \f pcDevicePath.
//
// Given an interface GUID, this function determines the path that is
// necessary to open a file handle on the USB device we are interested in
// talking to. It returns the path to the first device which is present in
// the system and which offers the required interface.
//
// \return Returns one of the following Windows system error codes.
// ERROR_SUCCESS if the operation completed successfully
// ERROR_DEV_NOT_EXIST if the interface is not found on the system. This
// implies that the driver for the USB device has not been installed.
// ERROR_DEVICE_NOT_CONNECTED if the interface has been installed but no
// device offering it is presently available. This typically indicates
// that the USB device is not currently connected.
// ERROR_NOT_ENOUGH_MEMORY if the function fails to allocate any required
// buffers.
// ERROR_INSUFFICIENT_BUFFER if the buffer passed is too small to hold
// the device path.
//****************************************************************************
static DWORD GetDevicePath(DWORD dwIndex, LPGUID InterfaceGuid,
PCHAR pcDevicePath,
size_t BufLen)
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
ULONG length;
ULONG requiredLength=0;
HRESULT hr;
//
// Get a handle to the device information set containing information on
// the interface GUID supplied on this PC.
//
deviceInfo = SetupDiGetClassDevs(InterfaceGuid,
NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(deviceInfo == INVALID_HANDLE_VALUE)
{
//
// No device offering the required interface is present. Has the
// interface been installed? Ask for the information set for all
// devices and not just those that are presently installed.
//
deviceInfo = SetupDiGetClassDevs(InterfaceGuid,
NULL, NULL,
DIGCF_DEVICEINTERFACE);
if(deviceInfo == INVALID_HANDLE_VALUE)
{
return(ERROR_DEV_NOT_EXIST);
}
else
{
SetupDiDestroyDeviceInfoList(deviceInfo);
return(ERROR_DEVICE_NOT_CONNECTED);
}
}
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//
// SetupDiGetClassDevs returned us a valid information set handle so we
// now query this set to find the find the first device offering the
// interface whose GUID was supplied.
//
bResult = SetupDiEnumDeviceInterfaces(deviceInfo,
NULL,
InterfaceGuid,
dwIndex,
&interfaceData);
if(bResult == FALSE)
{
//
// We failed to find the first matching device so tell the caller
// that no suitable device is connected.
//
return(ERROR_DEVICE_NOT_CONNECTED);
}
//
// Now that we have the interface information, we need to query details
// to retrieve the device path. First determine how much space we need to
// hold the detail information.
//
SetupDiGetDeviceInterfaceDetail(deviceInfo,
&interfaceData,
NULL, 0,
&requiredLength,
NULL);
//
// Allocate a buffer to hold the interface details.
//
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED,
requiredLength);
if(NULL == detailData)
{
SetupDiDestroyDeviceInfoList(deviceInfo);
return(ERROR_NOT_ENOUGH_MEMORY);
}
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
length = requiredLength;
//
// Now call once again to retrieve the actual interface detail information.
//
bResult = SetupDiGetDeviceInterfaceDetail(deviceInfo,
&interfaceData,
detailData,
length,
&requiredLength,
NULL);
if(FALSE == bResult)
{
SetupDiDestroyDeviceInfoList(deviceInfo);
LocalFree(detailData);
return(GetLastError());
}
//
// Copy the device path string from the interface details structure into
// the caller's buffer.
//
hr = StringCchCopy((LPTSTR)pcDevicePath,
BufLen,
(LPCTSTR)detailData->DevicePath);
if(FAILED(hr))
{
//
// We failed to copy the device path string!
//
SetupDiDestroyDeviceInfoList(deviceInfo);
LocalFree(detailData);
return(ERROR_INSUFFICIENT_BUFFER);
}
//
// Clean up and free locally allocated resources.
//
SetupDiDestroyDeviceInfoList(deviceInfo);
LocalFree(detailData);
return(ERROR_SUCCESS);
}
//****************************************************************************
//
// Opens a given instance of the USB device and returns a file handle.
//
// \param dwIndex is the zero-based index of the device that is to be opened.
// \param lpGUID is a pointer to the GUID of the interface that is to
// be opened.
//
// This function determines whether or not the required USB device is
// available and, if so, creates a file allowing access to it. The file
// handle is returned on success.
//
// \return Returns a valid file handle on success of INVALID_HANDLE_VALUE
// on failure. In cases of failure, GetLastError() can be called to determine
// the cause.
//
//****************************************************************************
static HANDLE OpenDeviceByIndex(DWORD dwIndex, LPGUID lpGUID)
{
HANDLE hDev = NULL;
char devicePath[MAX_DEVPATH_LENGTH];
BOOL retVal;
//
// Get the path needed to open a file handle on our USB device.
//
retVal = GetDevicePath(dwIndex, lpGUID, devicePath, sizeof(devicePath));
if(retVal != ERROR_SUCCESS)
{
SetLastError(retVal);
return(INVALID_HANDLE_VALUE);
}
//
// Open the file we will use to communicate with the device.
//
hDev = CreateFile((LPCTSTR)devicePath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
return(hDev);
}
//****************************************************************************
//
// Opens the first instance of a given USB device and returns a file handle.
//
// \param lpGUID is a pointer to the GUID of the interface that is to
// be opened.
//
// This function determines whether or not the required USB device is
// available and, if so, creates a file allowing access to it. The file
// handle is returned on success.
//
// \return Returns a valid file handle on success of INVALID_HANDLE_VALUE
// on failure. In cases of failure, GetLastError() can be called to determine
// the cause.
//
//****************************************************************************
static HANDLE OpenDevice(LPGUID lpGUID)
{
return(OpenDeviceByIndex(0, lpGUID));
}
//****************************************************************************
//
// Determines that the required USB device is present, opens it and gathers
// required information to allow us to read and write it.
//
// \param usVID is the vendor ID of the device to be initialized.
// \param usPID is the product ID of the device to be intialized.
// \param lpGUID is the GUID of the device interface that is to be opened.
// \param dwIndex is the zero-based index of the device to open.
// \param bOpenDataEndpoints is \e TRUE to open endpoints for bulk transfer
// of data to and from the host or \e FALSE to open the device without
// attempting to open any additional endpoints.
// \param pbDriverInstalled is written to \e TRUE if the device driver for the
// required class is installed or \e FALSE otherwise.
//
// This function is called to initialize the USB device and perform one-off
// setup required to allocate handles allowing the application to read and
// write the device endpoints. It offers a superset of the function provided
// by InitializeDevice(), allowing a caller to specify an index to differentiate
// between multiple devices of the same type and also offering the ability to
// open a device without opening endpoint handles for bulk data transfer.
//
// \return Returns a valid handle on success or NULL on failure. In failing
// cases, GetLastError() can be called to determine the cause.
//
//****************************************************************************
extern "C" TIUSB_HANDLE PASCAL EXPORT
InitializeDeviceByIndex(unsigned short usVID,
unsigned short usPID,
LPGUID lpGUID,
DWORD dwIndex,
BOOL bOpenDataEndpoints,
BOOL *pbDriverInstalled)
{
BOOL bResult;
WINUSB_INTERFACE_HANDLE usbHandle;
USB_INTERFACE_DESCRIPTOR ifaceDescriptor;
WINUSB_PIPE_INFORMATION pipeInfo;
UCHAR speed;
ULONG length;
DWORD dwError;
int i;
tDeviceInfoWinUSB *psDevInfo;
//
// Check for NULL pointer parameters.
//
if(!lpGUID || !pbDriverInstalled)
{
return(NULL);
}
//
// Allocate a new device info structure.
//
psDevInfo = (tDeviceInfoWinUSB *)LocalAlloc(LPTR, sizeof(tDeviceInfoWinUSB));
if(!psDevInfo)
{
return(NULL);
}
//
// Determine whether the USB device is present and, if so, generate a file
// handle to allow access to it.
//
psDevInfo->deviceHandle = OpenDeviceByIndex(dwIndex, lpGUID);
if(psDevInfo->deviceHandle == INVALID_HANDLE_VALUE)
{
//
// We were unable to access the device - is that because the device isn't
// connected or has the driver not been installed?
//
dwError = GetLastError();
*pbDriverInstalled = (dwError == ERROR_DEV_NOT_EXIST) ? FALSE : TRUE;
//
// Free our instance data.
//
LocalFree((HLOCAL)psDevInfo);
//
// Return an error to the caller.
//
return(NULL);
}
//
// The device is opened so we now initialize the WinUSB layer passing it
// the device handle.
//
bResult = WinUsb_Initialize(psDevInfo->deviceHandle, &usbHandle);
if(bResult)
{
//
// If we managed to initialize the WinUSB layer, we now query the
// device descriptor to determine the speed of the device.
//
psDevInfo->winUSBHandle = usbHandle;
length = sizeof(UCHAR);
bResult = WinUsb_QueryDeviceInformation(psDevInfo->winUSBHandle,
DEVICE_SPEED,
&length,
&speed);
}
//
// The device opened correctly. Do we need to also open pipes to allow us
// to send and receive data via the bulk endpoints?
//
if(bOpenDataEndpoints)
{
//
// Yes - we do need to open the endpoints for data transfer.
//
if(bResult)
{
//
// If all is well, now query the interface descriptor. We ask for the
// first interface only since, in the case of the generic bulk device,
// this is all that is available.
//
psDevInfo->deviceSpeed = speed;
bResult = WinUsb_QueryInterfaceSettings(psDevInfo->winUSBHandle,
0,
&ifaceDescriptor);
}
if(bResult)
{
//
// We got the interface descriptor so now we enumerate the endpoints
// to find the two we require - one bulk IN endpoint and one bulk OUT
// endpoint.
//
for(i=0;i<ifaceDescriptor.bNumEndpoints;i++)
{
bResult = WinUsb_QueryPipe(psDevInfo->winUSBHandle, 0, (UCHAR) i,
&pipeInfo);
if((pipeInfo.PipeType == UsbdPipeTypeBulk) &&
USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId))
{
psDevInfo->bulkInPipe = pipeInfo.PipeId;
}
else if((pipeInfo.PipeType == UsbdPipeTypeBulk) &&
USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId))
{
psDevInfo->bulkOutPipe = pipeInfo.PipeId;
}
else
{
//
// Hmm... we found an endpoint that we didn't expect to see
// on this interface. This tends to imply that there is a
// mismatch between the device configuration and this
// application so we will fail the call after setting an
// appropriate error code for the caller to query.
//
SetLastError(ERROR_NOT_SAME_DEVICE);
bResult = FALSE;
break;
}
}
}
//
// Did all go well so far?
//
if(bResult)
{
//
// All is well - create the signal event we need.
//
psDevInfo->hReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//
// If we created the event successfully, return a good handle.
//
if(psDevInfo->hReadEvent)
{
//
// Everything is good. Set the return code flag to indicate
// this.
//
bResult = true;
}
}
}
else
{
//
// Data transfer endpoints do not need to be opened so merely mark
// this in the device info structure.
//
psDevInfo->bulkOutPipe = 0;
psDevInfo->bulkInPipe = 0;
psDevInfo->hReadEvent = NULL;
}
//
// Did all go well?
//
if(bResult)
{
//
// All is well - return the instance data pointer as a handle to the
// caller.
//
return((TIUSB_HANDLE)psDevInfo);
}
else
{
//
// If we drop through to here, something went wrong so free the
// instance structure and return NULL.
//
LocalFree((HLOCAL)psDevInfo);
return(NULL);
}
}
//****************************************************************************
//
// Determines that the required USB device is present, opens it and gathers
// required information to allow us to read and write it.
//
// \param usVID is the vendor ID of the device to be initialized.
// \param usPID is the product ID of the device to be intialized.
// \param lpGUID is the GUID of the device interface that is to be opened.
// \param pbDriverInstalled is written to \e TRUE if the device driver for the
// required class is installed or \e FALSE otherwise.
//
// This function is called to initialize the USB device and perform one-off
// setup required to allocate handles allowing the application to read and
// write the device endpoints.
//
// InitializeDevice() always opens the first instance of a device and assumes
// that the caller will always want to open handles allowing communication via
// only IN and OUT bulk endpoints. To open an instance of a device other than
// the first or to open a device without opening handles on any endpoints other
// than the control endpoint, InitializeDeviceByIndex() may be used instead.
//
// \return Returns a valid handle on success or NULL on failure. In failing
// cases, GetLastError() can be called to determine the cause.
//
//****************************************************************************
extern "C" TIUSB_HANDLE PASCAL EXPORT
InitializeDevice(unsigned short usVID,
unsigned short usPID,
LPGUID lpGUID,
BOOL *pbDriverInstalled)
{
//
// Call our more capable cousin to open the first instance of the device
// and set up for data transfer via bulk IN and OUT endpoints.
//
return(InitializeDeviceByIndex(usVID, usPID, lpGUID, 0, true,
pbDriverInstalled));
}
//****************************************************************************
//
// Performs a control transfer on endpoint 0.
//
// \param hUSB is the device handle as returned from InitializeDevice().
// \param ucRequestType is the value to be placed in the bmRequestType field
// of the setup data as defined in table 9-2 of the USB 2.0 specification. The
// value is an ORed combination of the REQUEST_xxx flags found in tiusbdll.h.
// \param ucRequest is the specific request identifier which will be placed in
// the bRequest field of the setup data for the transaction.
// \param usValue is the request-specific value placed into the wValue field of
// the setup data for the transaction.
// \param usIndex is the value placed into the wIndex field of the setup data
// for the transaction.
// \param usLength is the number of bytes of data to transfer from or to the
// caller-supplied buffer during the transaction. This value is used to set
// the wLength field in the setup data for the transaction.
// \param pucBuffer is a pointer to a buffer containing at least usLength bytes.
// If ucRequestType contains REQUEST_TRANSFER_IN, usLength bytes of data will
// be transfered from the device and written into this buffer. If ucRequestType
// contains REQUEST_TRANSFER_OUT, usLength bytes of data will be transfered
// from this buffer to the device.
// \param pusCount will be written with the number of bytes actually written to
// or read from the device.
//
// This function performs a control transfer to the device. This transaction
// may transfer data to or from the device depending upon the value of the
// ucRequestType parameter.
//
// \return Returns \e TRUE on success or \e FALSE on failure. If \e FALSE is
// returned, GetLastError() may be called to determine the cause of the failure.
//
//****************************************************************************
extern "C" BOOL PASCAL EXPORT
Endpoint0Transfer(TIUSB_HANDLE hUSB, UCHAR ucRequestType, UCHAR ucRequest,
USHORT usValue, USHORT usIndex, USHORT usLength,
PUCHAR pucBuffer, PUSHORT pusCount)
{
tDeviceInfoWinUSB *psDevInfo = (tDeviceInfoWinUSB *)hUSB;
WINUSB_SETUP_PACKET sSetup;
ULONG ulCount;
ULONG ulError;
BOOL bRetcode;
//
// Check for invalid parameters. We require a buffer pointer if the
// transfer length is non-zero.
//
if(!hUSB || (usLength && !pucBuffer))
{
return(0);
}
//
// Fill in the setup data structure.
//
sSetup.RequestType = ucRequestType;
sSetup.Request = ucRequest;
sSetup.Value = usValue;
sSetup.Index = usIndex;
sSetup.Length = usLength;
//
// Issue the control transaction.
//
bRetcode = WinUsb_ControlTransfer(psDevInfo->winUSBHandle,
sSetup,
pucBuffer,
(ULONG)usLength,
&ulCount,
NULL);
//
// Return either the number of bytes written/read or 0 if there was an
// error.
//
if(bRetcode)
{
*pusCount = (USHORT)ulCount;
}
else
{
ulError = GetLastError();
*pusCount = 0;
}
return(bRetcode);
}
//****************************************************************************
//
// Cleans up and free resources associated with the USB device communication
// prior to exiting the application.
//
// \param hUSB is the device handle as returned from InitializeDevice().
//
// This function should be called prior to exiting the application to free
// the resources allocated during InitializeDevice().
//
// \return Returns \e TRUE on success or \e FALSE on failure.
//
//****************************************************************************
extern "C" BOOL PASCAL EXPORT TerminateDevice(TIUSB_HANDLE hUSB)
{
BOOL bRetcode;
BOOL bRetcode2;
tDeviceInfoWinUSB *psDevInfo = (tDeviceInfoWinUSB *)hUSB;
//
// Check for a bad handle.
//
if(!hUSB)
{
return(false);
}
//
// Free WinUSB and Windows resources.
//
bRetcode = WinUsb_Free(psDevInfo->winUSBHandle);
bRetcode2 = CloseHandle(psDevInfo->deviceHandle);
//
// Free the device instance structure.
//
LocalFree((HLOCAL)psDevInfo);
//
// Did all go well?
//
if(bRetcode & bRetcode2)
{
return(TRUE);
}
else
{
return(FALSE);
}
}
//****************************************************************************
//
// Writes a buffer of data to the USB device via the bulk OUT endpoint.
//
// \param hUSB is the device handle as returned from InitializeDevice().
// \param pcBuffer points to the first byte of data to send.
// \param ulSize contains the number of bytes of data to send.
// \param pulWritten is a pointer which will be written with the number of
// bytes of data actually written to the device.
//
// This function is used to send data to the USB device via its bulk OUT endpoint.
//
// \return Returns \e TRUE on success or \e FALSE on failure.
//
//****************************************************************************
extern "C" BOOL PASCAL EXPORT
WriteUSBPacket(TIUSB_HANDLE hUSB, unsigned char *pcBuffer,
unsigned long ulSize,
unsigned long *pulWritten)
{
BOOL bResult;
tDeviceInfoWinUSB *psDevInfo = (tDeviceInfoWinUSB *)hUSB;
//
// Check for bad parameters.
//
if(!hUSB || !pcBuffer || !pulWritten || !ulSize)
{
return(false);
}
//
// Ask WinUSB to write the data for us.
//
bResult = WinUsb_WritePipe(psDevInfo->winUSBHandle,
psDevInfo->bulkOutPipe,
pcBuffer,
ulSize,
pulWritten,
NULL);
return(bResult);
}
//****************************************************************************
//
// Reads data from the USB device via the bulk IN endpoint.
//
// \param hUSB is the device handle as returned from InitializeDevice().
// \param pcBuffer points to a buffer into which the data from the device will
// be written.
// \param ulSize contains the number of bytes that are requested from the
// device.
// \param pulRead is a pointer which will be written with the number of
// bytes of data actually read from the device.
// \param ulTimeoutmS is the number of milliseconds to wait for the
// data before returning an error. To block indefinitely, set this parameter
// to INFINITE.
// \param hBreak is the handle of an event that may be used to break out of
// the read operation. If this is a valid event handle and the event is
// signalled, the read operation will return immediately. Set this to
// NULL if the additional break condition is not required.
//
// This function is used to receive data from the USB device via its bulk IN
// endpoint.
//
// \return Returns \e ERROR_SUCCESS on success, WAIT_TIMEOUT if the data as
// not received within ulTimeoutmS milliseconds, WAIT_OBJECT_0 if the break
// event was signalled or other Windows system error codes on failure.
//
//****************************************************************************
extern "C" DWORD PASCAL EXPORT
ReadUSBPacket(TIUSB_HANDLE hUSB, unsigned char *pcBuffer, unsigned long ulSize,
unsigned long *pulRead, unsigned long ulTimeoutmS, HANDLE hBreak)
{
BOOL bResult;
DWORD dwError;
OVERLAPPED sOverlapped;
HANDLE phSignals[2];
tDeviceInfoWinUSB *psDevInfo = (tDeviceInfoWinUSB *)hUSB;
//
// Check for bad parameters.
//
if(!hUSB || !pcBuffer || !pulRead || !ulSize)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Tell WinUSB how to signal us when reads are completed (if blocking)
//
sOverlapped.hEvent = psDevInfo->hReadEvent;
sOverlapped.Offset = 0;
sOverlapped.OffsetHigh = 0;
//
// Perform the read.
//
bResult = WinUsb_ReadPipe(psDevInfo->winUSBHandle,
psDevInfo->bulkInPipe,
pcBuffer,
ulSize,
pulRead,
&sOverlapped);
//
// A good return code indicates success regardless of whether we performed
// a blocking or non-blocking read.
//
if(bResult)
{
dwError = ERROR_SUCCESS;
}
else
{
//
// An error occurred or the read will complete asynchronously.
// Which is it?
//
dwError = GetLastError();
//
// Check for error cases other than the one we expect.
//
if(dwError == ERROR_IO_PENDING)
{
//
// The IO is pending so wait for it to complete or for a
// timeout to occur.
//
phSignals[0] = psDevInfo->hReadEvent;
phSignals[1] = hBreak;
dwError = WaitForMultipleObjects(hBreak ? 2 : 1, phSignals, FALSE,
ulTimeoutmS);
//
// At this stage, one of three things could have occurred.
// Either we read a packet or we timed out or the break
// signal was detected. Which was it?
//
if(dwError == WAIT_OBJECT_0)
{
//
// The overlapped IO request completed so check to see how
// many bytes we got.
//
bResult = GetOverlappedResult(psDevInfo->deviceHandle,
&sOverlapped,
pulRead, FALSE);
if(bResult)
{
dwError = ERROR_SUCCESS;
}
else
{
//
// Something went wrong. Return the Windows error code.
//
dwError = GetLastError();
}
}
else
{
//
// Something went wrong - abort the transfer
//
WinUsb_AbortPipe(psDevInfo->winUSBHandle,
psDevInfo->bulkInPipe);
//
// Was the break event signalled?
//
if(dwError == (WAIT_OBJECT_0 + 1))
{
//
// The break event was signalled - abort the read and return.
//
dwError = WAIT_OBJECT_0;
}
}
}
}
//
// Pass the result back to the caller.
//
return(dwError);
}