27 #ifndef _CRT_SECURE_NO_DEPRECATE
28 #define _CRT_SECURE_NO_DEPRECATE
30 #pragma warning(disable : 4996)
61 WINUSB_INTERFACE_HANDLE m_usbHandle[2];
62 uint8_t m_bulkInPipe, m_bulkOutPipe, m_interruptPipe, m_deviceSpeed;
68 static const int m_oCount = MAXIMUM_WAIT_OBJECTS - 1;
69 OVERLAPPED m_overlapped[m_oCount];
71 static const int m_fixedBufferSize = 8192;
72 static const int m_fastPolicyThreshold = 3;
73 uint8_t m_fixedBuffer[m_oCount][m_fixedBufferSize];
75 CRITICAL_SECTION m_mutex;
77 volatile bool m_running;
78 HANDLE m_waitEvents[m_oCount];
130 case LIBUSB_ERROR_IO:
133 case LIBUSB_ERROR_INVALID_PARAM:
136 case LIBUSB_ERROR_ACCESS:
139 case LIBUSB_ERROR_NO_DEVICE:
142 case LIBUSB_ERROR_NOT_FOUND:
145 case LIBUSB_ERROR_BUSY:
148 case LIBUSB_ERROR_TIMEOUT:
151 case LIBUSB_ERROR_OVERFLOW:
154 case LIBUSB_ERROR_PIPE:
157 case LIBUSB_ERROR_INTERRUPTED:
160 case LIBUSB_ERROR_NO_MEM:
163 case LIBUSB_ERROR_NOT_SUPPORTED:
166 case LIBUSB_ERROR_OTHER:
178 return "LIBUSB_SUCCESS";
180 case LIBUSB_ERROR_IO:
181 return "LIBUSB_ERROR_IO";
183 case LIBUSB_ERROR_INVALID_PARAM:
184 return "LIBUSB_ERROR_INVALID_PARAM";
186 case LIBUSB_ERROR_ACCESS:
187 return "LIBUSB_ERROR_ACCESS";
189 case LIBUSB_ERROR_NO_DEVICE:
190 return "LIBUSB_ERROR_NO_DEVICE";
192 case LIBUSB_ERROR_NOT_FOUND:
193 return "LIBUSB_ERROR_NOT_FOUND";
195 case LIBUSB_ERROR_BUSY:
196 return "LIBUSB_ERROR_BUSY";
198 case LIBUSB_ERROR_TIMEOUT:
199 return "LIBUSB_ERROR_TIMEOUT";
201 case LIBUSB_ERROR_OVERFLOW:
202 return "LIBUSB_ERROR_OVERFLOW";
204 case LIBUSB_ERROR_PIPE:
205 return "LIBUSB_ERROR_PIPE";
207 case LIBUSB_ERROR_INTERRUPTED:
208 return "LIBUSB_ERROR_INTERRUPTED";
210 case LIBUSB_ERROR_NO_MEM:
211 return "LIBUSB_ERROR_NO_MEM";
213 case LIBUSB_ERROR_NOT_SUPPORTED:
214 return "LIBUSB_ERROR_NOT_SUPPORTED";
216 case LIBUSB_ERROR_OTHER:
217 return "LIBUSB_ERROR_OTHER";
225 DWORD usbReadThreadFunc(
void*
obj)
235 d->m_running =
false;
240 d->m_running =
false;
246 void UsbInterfacePrivate::threadFunc()
248 HANDLE handles[1 + m_oCount];
249 handles[0] = m_quitEvent;
250 handles[m_oCount] = m_waitEvents[m_oCount - 1];
254 for (m_readIdx = 0; m_readIdx < (m_oCount - 1); ++m_readIdx)
256 handles[m_readIdx + 1] = m_waitEvents[m_readIdx];
258 m_overlapped[m_readIdx] = OVERLAPPED();
259 ::ResetEvent(m_waitEvents[m_readIdx]);
260 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
262 m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx],
263 (ULONG)m_fixedBufferSize, 0,
264 &m_overlapped[m_readIdx]);
268 bool policyFast =
false;
273 m_overlapped[m_readIdx] = OVERLAPPED();
274 ::ResetEvent(m_waitEvents[m_readIdx]);
275 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
277 m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx],
278 (ULONG)m_fixedBufferSize, 0,
279 &m_overlapped[m_readIdx]);
280 m_readIdx = (m_readIdx + 1) % m_oCount;
283 ::WaitForMultipleObjects(1 + m_oCount, handles,
FALSE, INFINITE);
286 switch (tEnd - tBegin)
289 if (++fastCount > m_fastPolicyThreshold && !policyFast)
294 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
301 if (policyFast && fastCount <= m_fastPolicyThreshold)
305 UCHAR enable =
FALSE;
306 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
316 UCHAR enable =
FALSE;
317 m_winUsb.SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR), &enable);
333 if (waitResult >= WAIT_ABANDONED_0)
337 "WFMO abandoned: " << (waitResult - WAIT_OBJECT_0));
341 #ifndef XSENS_RELEASE
343 gJournal,
"WFMO trigger: " << (waitResult - WAIT_OBJECT_0));
349 if (!m_winUsb.GetOverlappedResult(
350 m_usbHandle[0], &m_overlapped[idx], &dataRead,
354 DWORD err = ::GetLastError();
357 case ERROR_SEM_TIMEOUT:
358 case ERROR_IO_INCOMPLETE:
367 "m_winUsb.GetOverlappedResult resulted in "
380 "m_winUsb.GetOverlappedResult resulted in "
381 << dataRead <<
" bytes being read");
383 &m_fixedBuffer[idx][0], dataRead,
XSDF_None);
384 ::EnterCriticalSection(&m_mutex);
385 m_varBuffer.append(
ref);
386 ::LeaveCriticalSection(&m_mutex);
420 d->m_threadHandle = INVALID_HANDLE_VALUE;
421 ::InitializeCriticalSection(&
d->m_mutex);
422 d->m_usbHandle[0] = 0;
423 d->m_usbHandle[1] = 0;
424 for (
int i = 0; i <
d->m_oCount; ++i)
426 d->m_waitEvents[i] = ::CreateEvent(
nullptr,
TRUE,
FALSE,
nullptr);
427 ::ResetEvent(
d->m_waitEvents[i]);
429 d->m_quitEvent = ::CreateEvent(
nullptr,
TRUE,
FALSE,
nullptr);
430 ::ResetEvent(
d->m_quitEvent);
443 ::CloseHandle(
d->m_quitEvent);
444 for (
int i = 0; i <
d->m_oCount; ++i)
445 ::CloseHandle(
d->m_waitEvents[i]);
446 ::DeleteCriticalSection(&
d->m_mutex);
468 if (
d->rx_log !=
nullptr)
fclose(
d->rx_log);
469 if (
d->tx_log !=
nullptr)
fclose(
d->tx_log);
477 if (
d->m_threadHandle != INVALID_HANDLE_VALUE)
481 ::SetEvent(
d->m_quitEvent);
484 ::CloseHandle(
d->m_threadHandle);
488 if (
d->m_usbHandle[0])
490 d->m_winUsb.Free(
d->m_usbHandle[0]);
491 d->m_usbHandle[0] =
nullptr;
493 if (
d->m_usbHandle[1])
495 d->m_winUsb.Free(
d->m_usbHandle[1]);
496 d->m_usbHandle[1] =
nullptr;
510 int result = LIBUSB_ERROR_OTHER;
511 while (result != LIBUSB_SUCCESS)
515 if (result == LIBUSB_SUCCESS)
543 if (
d->m_usbHandle[0])
545 d->m_winUsb.AbortPipe(
d->m_usbHandle[0],
d->m_bulkInPipe);
546 d->m_winUsb.FlushPipe(
d->m_usbHandle[0],
d->m_bulkInPipe);
547 d->m_winUsb.AbortPipe(
d->m_usbHandle[0],
d->m_bulkOutPipe);
548 d->m_winUsb.FlushPipe(
d->m_usbHandle[0],
d->m_bulkOutPipe);
550 if (
d->m_usbHandle[1])
552 d->m_winUsb.AbortPipe(
d->m_usbHandle[1],
d->m_bulkInPipe);
553 d->m_winUsb.FlushPipe(
d->m_usbHandle[1],
d->m_bulkInPipe);
554 d->m_winUsb.AbortPipe(
d->m_usbHandle[1],
d->m_bulkOutPipe);
555 d->m_winUsb.FlushPipe(
d->m_usbHandle[1],
d->m_bulkOutPipe);
558 unsigned char flushBuffer[256];
560 for (
int i = 0; i < 64; ++i)
564 flushBuffer,
sizeof(flushBuffer), &actual, 1) != LIBUSB_SUCCESS)
566 if (actual == 0)
break;
589 JLDEBUG(gJournal,
"Open usb port " << portInfo.portName().toStdString());
592 gJournal,
"Open usb port " << portInfo.usbBus() <<
":"
593 << portInfo.usbAddress());
599 gJournal,
"Port " << portInfo.portName().toStdString()
606 portInfo.portName().c_str(), GENERIC_WRITE | GENERIC_READ,
607 FILE_SHARE_WRITE | FILE_SHARE_READ,
nullptr, OPEN_EXISTING,
608 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
nullptr);
619 USB_INTERFACE_DESCRIPTOR interfaceDescriptor = {0, 0, 0, 0, 0, 0, 0, 0, 0};
620 WINUSB_PIPE_INFORMATION pipeInfo;
625 result =
d->m_winUsb.GetAssociatedInterface(
626 d->m_usbHandle[0], 0, &
d->m_usbHandle[1]);
631 DWORD err = GetLastError();
637 for (
int k = 0; k < 2; k++)
641 assert(
d->m_usbHandle[k] != 0);
643 result =
d->m_winUsb.QueryDeviceInformation(
644 d->m_usbHandle[k], DEVICE_SPEED, &
length, &speed);
649 d->m_deviceSpeed = speed;
650 result =
d->m_winUsb.QueryInterfaceSettings(
651 d->m_usbHandle[k], 0, &interfaceDescriptor);
655 for (
int i = 0; i < interfaceDescriptor.bNumEndpoints; i++)
657 result =
d->m_winUsb.QueryPipe(
658 d->m_usbHandle[k], 0, (UCHAR)i, &pipeInfo);
660 if (pipeInfo.PipeType == UsbdPipeTypeBulk &&
661 USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId))
663 d->m_bulkInPipe = pipeInfo.PipeId;
664 d->m_bulkInPipePacketSize = pipeInfo.MaximumPacketSize;
667 pipeInfo.PipeType == UsbdPipeTypeBulk &&
668 USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId))
670 d->m_bulkOutPipe = pipeInfo.PipeId;
672 else if (pipeInfo.PipeType == UsbdPipeTypeInterrupt)
674 d->m_interruptPipe = pipeInfo.PipeId;
691 ::ResetEvent(&
d->m_quitEvent);
702 libusb_device** deviceList;
715 libusb_device* device =
nullptr;
716 for (
int i = 0; i < listLength && device ==
nullptr; ++i)
718 libusb_device* dev = deviceList[i];
725 libusb_device_descriptor desc;
728 if (result != LIBUSB_SUCCESS)
break;
730 libusb_config_descriptor* configDesc;
733 if (result != LIBUSB_SUCCESS)
break;
739 ifCount < configDesc->bNumInterfaces &&
d->
m_interface == -1;
742 for (
uint8_t altsettingCount = 0;
744 configDesc->interface[ifCount].num_altsetting;
747 const libusb_endpoint_descriptor* endpoints =
748 configDesc->interface[ifCount]
749 .altsetting[altsettingCount]
751 int inEndpoint = -1, outEndpoint = -1;
752 for (
uint8_t i = 0; i < configDesc->interface[ifCount]
753 .altsetting[altsettingCount]
757 if ((endpoints[i].bmAttributes &
758 LIBUSB_TRANSFER_TYPE_MASK) !=
759 LIBUSB_TRANSFER_TYPE_BULK)
762 switch (endpoints[i].bEndpointAddress &
763 LIBUSB_ENDPOINT_DIR_MASK)
765 case LIBUSB_ENDPOINT_IN:
766 inEndpoint = endpoints[i].bEndpointAddress &
767 LIBUSB_ENDPOINT_ADDRESS_MASK;
770 case LIBUSB_ENDPOINT_OUT:
771 outEndpoint = endpoints[i].bEndpointAddress &
772 LIBUSB_ENDPOINT_ADDRESS_MASK;
777 if (outEndpoint == -1 || inEndpoint == -1)
continue;
794 result = LIBUSB_SUCCESS;
799 if (result != LIBUSB_SUCCESS)
811 libusb_device_handle* handle;
814 if (result != LIBUSB_SUCCESS)
828 if (result == LIBUSB_SUCCESS)
831 if (result != LIBUSB_SUCCESS)
833 for (
int j = 0; j < i; j++)
835 while (result != LIBUSB_SUCCESS)
857 JLDEBUG(gJournal,
"USB Port opened");
896 <<
", length=0x" <<
length);
904 ::EnterCriticalSection(&
d->m_mutex);
905 remaining = *
length =
d->m_varBuffer.size();
910 d->m_varBuffer.erase(0, *
length);
911 remaining =
d->m_varBuffer.size();
913 ::LeaveCriticalSection(&
d->m_mutex);
915 gJournal,
"returned success, read "
917 <<
" bytes, first: " << JLHEXLOG(((
char*)
data)[0]) <<
", "
918 << remaining <<
" remaining in buffer");
927 << actual <<
" bytes received");
928 if ((
res != LIBUSB_SUCCESS &&
res != LIBUSB_ERROR_TIMEOUT) ||
929 (
res == LIBUSB_ERROR_TIMEOUT && actual <= 0))
938 if (
d->rx_log ==
nullptr)
942 d->rx_log =
fopen(fname,
"wb");
945 #ifdef LOG_RX_TX_FLUSH
965 gJournal,
"Request to set timeout to "
966 << ms <<
" ms overridden, setting to 0 ms instead");
968 UCHAR enable =
FALSE;
970 d->m_winUsb.SetPipePolicy(
971 d->m_usbHandle[1],
d->m_bulkInPipe, IGNORE_SHORT_PACKETS,
sizeof(UCHAR),
973 d->m_winUsb.SetPipePolicy(
974 d->m_usbHandle[1],
d->m_bulkInPipe, PIPE_TRANSFER_TIMEOUT,
979 JLDEBUG(gJournal,
"Setting timeout to " << ms);
994 JLDEBUG(gJournal,
"Setting RAWIO mode to " << enable);
998 UCHAR rawIo = (UCHAR)enable;
999 d->m_winUsb.SetPipePolicy(
1000 d->m_usbHandle[1],
d->m_bulkInPipe, RAW_IO,
sizeof(UCHAR),
1016 ULONG someSize =
sizeof(UCHAR);
1017 d->m_winUsb.GetPipePolicy(
1018 d->m_usbHandle[1],
d->m_bulkInPipe, RAW_IO, &someSize,
1020 return (rawIo != 0);
1047 <<
", length=" <<
length);
1050 char* bdata = (
char*)
data;
1100 if (written ==
nullptr) written = &bytes;
1108 d->m_winUsb.WritePipe(
1113 *written = dataWritten;
1116 while (*written <
length)
1124 if (result != LIBUSB_SUCCESS)
1129 << actual <<
" bytes sent");
1139 if (
d->tx_log ==
nullptr)
1143 d->tx_log =
fopen(fname,
"wb");
1145 fwrite(
data, 1, *written,
d->tx_log);
1146 #ifdef LOG_RX_TX_FLUSH
1163 libusb_device* dev =
1179 libusb_device* dev =
bool isOpen(void) const
Return whether the USB communication port is open or not.
XsResultValue close(void)
Close the USB communication 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.
virtual XsResultValue writeData(const XsByteArray &data, XsSize *written=nullptr)
Write the data to the USB 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 sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
int void fclose(FILE *f)
An OS-independent version of fclose.
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
#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_INPUTCANNOTBEOPENED
@ XRV_OK
Operation was performed successfully.
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!