15 # include "xswinusb.h"
27 #ifndef _CRT_SECURE_NO_DEPRECATE
28 # define _CRT_SECURE_NO_DEPRECATE
30 # pragma warning(disable:4996)
60 WINUSB_INTERFACE_HANDLE m_usbHandle[2];
61 uint8_t m_bulkInPipe, m_bulkOutPipe, m_interruptPipe, m_deviceSpeed;
67 static const int m_oCount = MAXIMUM_WAIT_OBJECTS-1;
68 OVERLAPPED m_overlapped[m_oCount];
70 static const int m_fixedBufferSize = 8192;
71 static const int m_fastPolicyThreshold = 3;
72 uint8_t m_fixedBuffer[m_oCount][m_fixedBufferSize];
74 CRITICAL_SECTION m_mutex;
76 volatile bool m_running;
77 HANDLE m_waitEvents[m_oCount];
123 switch (libusbError) {
127 case LIBUSB_ERROR_IO:
130 case LIBUSB_ERROR_INVALID_PARAM:
133 case LIBUSB_ERROR_ACCESS:
136 case LIBUSB_ERROR_NO_DEVICE:
139 case LIBUSB_ERROR_NOT_FOUND:
142 case LIBUSB_ERROR_BUSY:
145 case LIBUSB_ERROR_TIMEOUT:
148 case LIBUSB_ERROR_OVERFLOW:
151 case LIBUSB_ERROR_PIPE:
154 case LIBUSB_ERROR_INTERRUPTED:
157 case LIBUSB_ERROR_NO_MEM:
160 case LIBUSB_ERROR_NOT_SUPPORTED:
163 case LIBUSB_ERROR_OTHER:
172 switch (libusbError) {
174 return "LIBUSB_SUCCESS";
176 case LIBUSB_ERROR_IO:
177 return "LIBUSB_ERROR_IO";
179 case LIBUSB_ERROR_INVALID_PARAM:
180 return "LIBUSB_ERROR_INVALID_PARAM";
182 case LIBUSB_ERROR_ACCESS:
183 return "LIBUSB_ERROR_ACCESS";
185 case LIBUSB_ERROR_NO_DEVICE:
186 return "LIBUSB_ERROR_NO_DEVICE";
188 case LIBUSB_ERROR_NOT_FOUND:
189 return "LIBUSB_ERROR_NOT_FOUND";
191 case LIBUSB_ERROR_BUSY:
192 return "LIBUSB_ERROR_BUSY";
194 case LIBUSB_ERROR_TIMEOUT:
195 return "LIBUSB_ERROR_TIMEOUT";
197 case LIBUSB_ERROR_OVERFLOW:
198 return "LIBUSB_ERROR_OVERFLOW";
200 case LIBUSB_ERROR_PIPE:
201 return "LIBUSB_ERROR_PIPE";
203 case LIBUSB_ERROR_INTERRUPTED:
204 return "LIBUSB_ERROR_INTERRUPTED";
206 case LIBUSB_ERROR_NO_MEM:
207 return "LIBUSB_ERROR_NO_MEM";
209 case LIBUSB_ERROR_NOT_SUPPORTED:
210 return "LIBUSB_ERROR_NOT_SUPPORTED";
212 case LIBUSB_ERROR_OTHER:
213 return "LIBUSB_ERROR_OTHER";
221 DWORD usbReadThreadFunc(
void*
obj)
229 d->m_running =
false;
233 d->m_running =
false;
239 void UsbInterfacePrivate::threadFunc()
241 HANDLE handles[1+m_oCount];
242 handles[0] = m_quitEvent;
243 handles[m_oCount] = m_waitEvents[m_oCount-1];
247 for (m_readIdx = 0 ; m_readIdx < (m_oCount-1); ++m_readIdx)
249 handles[m_readIdx+1] = m_waitEvents[m_readIdx];
251 m_overlapped[m_readIdx] = OVERLAPPED();
252 ::ResetEvent(m_waitEvents[m_readIdx]);
253 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
254 m_winUsb.ReadPipe(m_usbHandle[1],
256 m_fixedBuffer[m_readIdx],
257 (ULONG)m_fixedBufferSize,
259 &m_overlapped[m_readIdx]);
263 bool policyFast =
false;
268 m_overlapped[m_readIdx] = OVERLAPPED();
269 ::ResetEvent(m_waitEvents[m_readIdx]);
270 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
271 m_winUsb.ReadPipe(m_usbHandle[1],
273 m_fixedBuffer[m_readIdx],
274 (ULONG)m_fixedBufferSize,
276 &m_overlapped[m_readIdx]);
277 m_readIdx = (m_readIdx + 1) % m_oCount;
279 DWORD waitResult = ::WaitForMultipleObjects(1+m_oCount, handles,
FALSE, INFINITE);
282 switch (tEnd - tBegin)
285 if (++fastCount > m_fastPolicyThreshold && !policyFast)
290 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
297 if (policyFast && fastCount <= m_fastPolicyThreshold)
301 UCHAR enable =
FALSE;
302 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
312 UCHAR enable =
FALSE;
313 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
329 if (waitResult >= WAIT_ABANDONED_0)
331 JLDEBUG(gJournal,
"WFMO abandoned: " << (waitResult - WAIT_OBJECT_0));
335 #ifndef XSENS_RELEASE
336 JLDEBUG(gJournal,
"WFMO trigger: " << (waitResult - WAIT_OBJECT_0));
342 if (!m_winUsb.GetOverlappedResult(m_usbHandle[0], &m_overlapped[idx], &dataRead,
FALSE))
345 DWORD err = ::GetLastError();
348 case ERROR_SEM_TIMEOUT:
349 case ERROR_IO_INCOMPLETE:
354 JLALERT(gJournal,
"m_winUsb.GetOverlappedResult resulted in windows error " << err);
363 JLTRACE(gJournal,
"m_winUsb.GetOverlappedResult resulted in " << dataRead <<
" bytes being read");
365 ::EnterCriticalSection(&m_mutex);
366 m_varBuffer.append(
ref);
367 ::LeaveCriticalSection(&m_mutex);
400 d->m_threadHandle = INVALID_HANDLE_VALUE;
401 ::InitializeCriticalSection(&
d->m_mutex);
402 d->m_usbHandle[0] = 0;
403 d->m_usbHandle[1] = 0;
404 for (
int i = 0; i <
d->m_oCount; ++i)
406 d->m_waitEvents[i] = ::CreateEvent(NULL,
TRUE,
FALSE, NULL);
407 ::ResetEvent(
d->m_waitEvents[i]);
409 d->m_quitEvent = ::CreateEvent(NULL,
TRUE,
FALSE, NULL);
410 ::ResetEvent(
d->m_quitEvent);
422 ::CloseHandle(
d->m_quitEvent);
423 for (
int i = 0; i <
d->m_oCount; ++i)
424 ::CloseHandle(
d->m_waitEvents[i]);
425 ::DeleteCriticalSection(&
d->m_mutex);
449 if (
d->rx_log != NULL)
451 if (
d->tx_log != NULL)
461 if (
d->m_threadHandle != INVALID_HANDLE_VALUE)
465 ::SetEvent(
d->m_quitEvent);
468 ::CloseHandle(
d->m_threadHandle);
472 if(
d->m_usbHandle[0]) {
473 d->m_winUsb.Free(
d->m_usbHandle[0]);
474 d->m_usbHandle[0] = NULL;
476 if(
d->m_usbHandle[1]) {
477 d->m_winUsb.Free(
d->m_usbHandle[1]);
478 d->m_usbHandle[1] = NULL;
488 int result = LIBUSB_ERROR_OTHER;
489 while (result != LIBUSB_SUCCESS) {
491 if (result == LIBUSB_SUCCESS) {
517 if(
d->m_usbHandle[0]) {
518 d->m_winUsb.AbortPipe(
d->m_usbHandle[0],
d->m_bulkInPipe);
519 d->m_winUsb.FlushPipe(
d->m_usbHandle[0],
d->m_bulkInPipe);
520 d->m_winUsb.AbortPipe(
d->m_usbHandle[0],
d->m_bulkOutPipe);
521 d->m_winUsb.FlushPipe(
d->m_usbHandle[0],
d->m_bulkOutPipe);
523 if(
d->m_usbHandle[1]) {
524 d->m_winUsb.AbortPipe(
d->m_usbHandle[1],
d->m_bulkInPipe);
525 d->m_winUsb.FlushPipe(
d->m_usbHandle[1],
d->m_bulkInPipe);
526 d->m_winUsb.AbortPipe(
d->m_usbHandle[1],
d->m_bulkOutPipe);
527 d->m_winUsb.FlushPipe(
d->m_usbHandle[1],
d->m_bulkOutPipe);
530 unsigned char flushBuffer[256];
532 for (
int i = 0; i < 64; ++i) {
534 flushBuffer,
sizeof(flushBuffer), &actual, 1) != LIBUSB_SUCCESS)
568 JLDEBUG(gJournal,
"Open usb port " << portInfo.portName().toStdString());
570 JLDEBUG(gJournal,
"Open usb port " << portInfo.usbBus() <<
":" << portInfo.usbAddress());
575 JLALERT(gJournal,
"Port " << portInfo.portName().toStdString() <<
" already open");
581 GENERIC_WRITE | GENERIC_READ,
582 FILE_SHARE_WRITE | FILE_SHARE_READ,
585 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
597 USB_INTERFACE_DESCRIPTOR interfaceDescriptor = {0,0,0,0,0,0,0,0,0};
598 WINUSB_PIPE_INFORMATION pipeInfo;
603 result =
d->m_winUsb.GetAssociatedInterface(
d->m_usbHandle[0],0,&
d->m_usbHandle[1]);
608 DWORD err = GetLastError();
614 for (
int k = 0; k<2;k++)
618 assert(
d->m_usbHandle[k] != 0);
620 result =
d->m_winUsb.QueryDeviceInformation(
d->m_usbHandle[k],
628 d->m_deviceSpeed = speed;
629 result =
d->m_winUsb.QueryInterfaceSettings(
d->m_usbHandle[k],
631 &interfaceDescriptor);
635 for(
int i=0;i<interfaceDescriptor.bNumEndpoints;i++)
637 result =
d->m_winUsb.QueryPipe(
d->m_usbHandle[k],
642 if(pipeInfo.PipeType == UsbdPipeTypeBulk &&
643 USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId))
645 d->m_bulkInPipe = pipeInfo.PipeId;
646 d->m_bulkInPipePacketSize =
647 pipeInfo.MaximumPacketSize;
649 else if(pipeInfo.PipeType == UsbdPipeTypeBulk &&
650 USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId))
652 d->m_bulkOutPipe = pipeInfo.PipeId;
654 else if(pipeInfo.PipeType == UsbdPipeTypeInterrupt)
656 d->m_interruptPipe = pipeInfo.PipeId;
673 ::ResetEvent(&
d->m_quitEvent);
684 libusb_device **deviceList;
695 libusb_device *device = NULL;
696 for (
int i = 0; i < listLength && device == NULL; ++i) {
697 libusb_device *dev = deviceList[i];
701 libusb_device_descriptor desc;
703 if (result != LIBUSB_SUCCESS)
706 libusb_config_descriptor *configDesc;
708 if (result != LIBUSB_SUCCESS)
714 for (
uint8_t ifCount = 0; ifCount < configDesc->bNumInterfaces &&
d->
m_interface == -1; ++ifCount) {
715 for (
uint8_t altsettingCount = 0; altsettingCount < configDesc->interface[ifCount].num_altsetting; altsettingCount++) {
716 const libusb_endpoint_descriptor *endpoints = configDesc->interface[ifCount].altsetting[altsettingCount].endpoint;
717 int inEndpoint = -1, outEndpoint = -1;
718 for (
uint8_t i = 0; i < configDesc->interface[ifCount].altsetting[altsettingCount].bNumEndpoints; i++) {
719 if ((endpoints[i].bmAttributes&LIBUSB_TRANSFER_TYPE_MASK) != LIBUSB_TRANSFER_TYPE_BULK)
722 switch (endpoints[i].bEndpointAddress&LIBUSB_ENDPOINT_DIR_MASK) {
723 case LIBUSB_ENDPOINT_IN:
724 inEndpoint = endpoints[i].bEndpointAddress&LIBUSB_ENDPOINT_ADDRESS_MASK;
727 case LIBUSB_ENDPOINT_OUT:
728 outEndpoint = endpoints[i].bEndpointAddress&LIBUSB_ENDPOINT_ADDRESS_MASK;
734 if (outEndpoint == -1 || inEndpoint == -1)
750 result = LIBUSB_SUCCESS;
754 if (result != LIBUSB_SUCCESS) {
764 libusb_device_handle *handle;
766 if (result != LIBUSB_SUCCESS) {
776 if (result == LIBUSB_SUCCESS)
778 if (result != LIBUSB_SUCCESS) {
779 for (
int j = 0; j < i; j++) {
780 while (result != LIBUSB_SUCCESS) {
798 JLDEBUG(gJournal,
"USB Port opened");
840 ::EnterCriticalSection(&
d->m_mutex);
841 remaining = *
length =
d->m_varBuffer.size();
847 d->m_varBuffer.erase(0, *
length);
848 remaining =
d->m_varBuffer.size();
850 ::LeaveCriticalSection(&
d->m_mutex);
851 JLTRACE(gJournal,
"returned success, read " << *
length <<
" of " <<
maxLength <<
" bytes, first: " << JLHEXLOG(((
char*)
data)[0]) <<
", " << remaining <<
" remaining in buffer");
857 if ((
res != LIBUSB_SUCCESS &&
res != LIBUSB_ERROR_TIMEOUT) || (
res == LIBUSB_ERROR_TIMEOUT && actual <= 0))
866 if (
d->rx_log == NULL)
870 d->rx_log =
fopen(fname,
"wb");
873 #ifdef LOG_RX_TX_FLUSH
891 JLDEBUG(gJournal,
"Request to set timeout to " << ms <<
" ms overridden, setting to 0 ms instead");
893 UCHAR enable =
FALSE;
895 d->m_winUsb.SetPipePolicy(
d->m_usbHandle[1],
d->m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
896 d->m_winUsb.SetPipePolicy(
d->m_usbHandle[1],
d->m_bulkInPipe, PIPE_TRANSFER_TIMEOUT,
sizeof(ULONG), &ms);
900 JLDEBUG(gJournal,
"Setting timeout to " << ms);
915 JLDEBUG(gJournal,
"Setting RAWIO mode to " << enable);
919 UCHAR rawIo = (UCHAR)enable;
920 d->m_winUsb.SetPipePolicy(
d->m_usbHandle[1],
d->m_bulkInPipe, RAW_IO,
sizeof(UCHAR), &rawIo);
935 ULONG someSize =
sizeof(UCHAR);
936 d->m_winUsb.GetPipePolicy(
d->m_usbHandle[1],
d->m_bulkInPipe, RAW_IO, &someSize, &rawIo);
959 char *bdata = (
char *)
data;
1007 if (written == NULL)
1017 d->m_winUsb.WritePipe(
d->m_usbHandle[1],
1024 *written = dataWritten;
1027 while (*written <
length)
1032 if (result != LIBUSB_SUCCESS)
1044 if (
d->tx_log == NULL)
1048 d->tx_log =
fopen(fname,
"wb");
1050 fwrite(
data,1,*written,
d->tx_log);
1051 #ifdef LOG_RX_TX_FLUSH
bool isOpen(void) const
Return whether the USB communication port is open or not.
XsResultValue close(void)
Close the USB communication port.
virtual XsResultValue writeData(const XsByteArray &data, XsSize *written=NULL)
Write the data to the USB port.
uint32_t getTimeout(void) const
Return the current timeout value.
uint8_t usbBus() const
The USB bus number this device is on (libusb/linux only)
XsResultValue open(const XsPortInfo &portInfo, uint32_t readBufSize=0, uint32_t writeBufSize=0)
Open a communication channel to the given USB port name.
virtual XsResultValue readData(XsSize maxLength, XsByteArray &data)
Read data from the USB port and put it into the data buffer.
XsResultValue setTimeout(uint32_t ms)
Set the default timeout value to use in blocking operations.
XsResultValue closeUsb(void)
Close the USB communication port.
void getPortName(XsString &portname) const
Retrieve the port name that was last successfully opened.
virtual XsResultValue waitForData(XsSize maxLength, XsByteArray &data)
Wait for data to arrive or a timeout to occur.
void setRawIo(bool enable)
Sets the RAWIO mode of the USB interface.
XsResultValue flushData(void)
Flush all data in the buffers to and from the device.
UsbInterface()
Default constructor, initializes all members to their default values.
~UsbInterface()
Destructor, de-initializes, frees memory allocated for buffers, etc.
XsResultValue getLastResult(void) const
Return the error code of the last operation.
uint8_t usbAddress() const
The address of the device (libusb/linux only)
bool getRawIo(void)
Retrieves the state of the RAWIO mode of the USB interface.
A context manager for libusb.
libusb_context * m_usbContext
UsbContext()
Create the USB context.
~UsbContext()
Destroy the USB context.
Private object for UsbInterface.
uint32_t m_endTime
The time at which an operation will end in ms, used by several functions.
XsResultValue m_lastResult
The last result of an operation.
static UsbContext & getContextManager()
libusb_device_handle * m_deviceHandle
const char * libusbErrorToString(int libusbError)
Convert a libusb error to a human-readable string.
XsResultValue libusbErrorToXrv(int libusbError, XsResultValue hint=XRV_ERROR)
Map a libusb_error to XsResultValue.
libUSB_free_config_descriptor free_config_descriptor
libUSB_kernel_driver_active kernel_driver_active
libUSB_get_device_list get_device_list
libUSB_unref_device unref_device
libUSB_release_interface release_interface
libUSB_get_device get_device
libUSB_detach_kernel_driver detach_kernel_driver
libUSB_get_device_address get_device_address
libUSB_get_bus_number get_bus_number
libUSB_get_device_descriptor get_device_descriptor
libUSB_bulk_transfer bulk_transfer
libUSB_claim_interface claim_interface
libUSB_get_active_config_descriptor get_active_config_descriptor
libUSB_free_device_list free_device_list
libUSB_ref_device ref_device
libUSB_attach_kernel_driver attach_kernel_driver
Class for dynamic loading of winusb.
GLsizei GLsizei GLuint * obj
GLsizei GLsizei GLenum GLenum const GLvoid * data
GLuint GLsizei GLsizei * length
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
XsResultValue
Xsens result values.
@ XS_THREAD_PRIORITY_HIGHEST
int BASE_IMPEXP sprintf(char *buf, size_t bufSize, const char *format,...) MRPT_NO_THROWS MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
void BASE_IMPEXP memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) MRPT_NO_THROWS
An OS and compiler independent version of "memcpy".
FILE BASE_IMPEXP * fopen(const char *fileName, const char *mode) MRPT_NO_THROWS
An OS-independent version of fopen.
int BASE_IMPEXP void BASE_IMPEXP fclose(FILE *f)
An OS-independent version of fclose.
#define XS_MAX_FILENAME_LENGTH
uint32_t getTimeOfDay(tm *date_, time_t *secs_)
A platform-independent clock.
void msleep(uint32_t ms)
A platform-independent sleep routine.
unsigned __int16 uint16_t
unsigned __int32 uint32_t
struct XsByteArray XsByteArray
@ XRV_PORTNOTFOUND
A required port could not be found.
@ XRV_ALREADYOPEN
An I/O device is already opened with this object.
@ XRV_INPUTCANNOTBEOPENED
The specified i/o device can not be opened.
@ XRV_NOPORTOPEN
No serial port opened for reading/writing.
@ XRV_NOTFOUND
The requested item was not found.
@ XRV_INVALIDOPERATION
Operation is invalid at this point.
@ XRV_ERROR
A generic error occurred.
@ XRV_OUTOFMEMORY
No internal memory available.
@ XRV_TIMEOUT
A timeout occurred.
@ XRV_OK
Operation was performed successfully.
@ XRV_INVALIDPARAM
An invalid parameter is supplied.
@ XRV_NOTIMPLEMENTED
Operation not implemented in this version (yet)
@ XRV_UNEXPECTEDMSG
Unexpected message received (e.g. no acknowledge message received)
XSTYPES_DLL_API int XsPortInfo_usbBus(XsPortInfo const *thisPtr)
XSTYPES_DLL_API int XsPortInfo_usbAddress(XsPortInfo const *thisPtr)
#define xsStartThread(func, param, pid)
Start a function as a thread.
#define xsSetThreadPriority(thrd, prio)
XSTYPES_DLL_API void xsNameThisThread(const char *threadName)
HANDLE XsThread
A handle for a thread.
#define xsGetCurrentThreadHandle()
#define XSENS_INVALID_THREAD
XSTYPES_DLL_API int64_t XsTime_timeStampNow(XsTimeStamp *now)
size_t XsSize
XsSize must be unsigned number!