usbinterface.cpp
Go to the documentation of this file.
1 
2 // Copyright (c) 2003-2021 Xsens Technologies B.V. or subsidiaries worldwide.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions, and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions, and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the names of the copyright holders nor the names of their contributors
16 // may be used to endorse or promote products derived from this software without
17 // specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24 // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
26 // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.THE LAWS OF THE NETHERLANDS
28 // SHALL BE EXCLUSIVELY APPLICABLE AND ANY DISPUTES SHALL BE FINALLY SETTLED UNDER THE RULES
29 // OF ARBITRATION OF THE INTERNATIONAL CHAMBER OF COMMERCE IN THE HAGUE BY ONE OR MORE
30 // ARBITRATORS APPOINTED IN ACCORDANCE WITH SAID RULES.
31 //
32 
33 
34 // Copyright (c) 2003-2021 Xsens Technologies B.V. or subsidiaries worldwide.
35 // All rights reserved.
36 //
37 // Redistribution and use in source and binary forms, with or without modification,
38 // are permitted provided that the following conditions are met:
39 //
40 // 1. Redistributions of source code must retain the above copyright notice,
41 // this list of conditions, and the following disclaimer.
42 //
43 // 2. Redistributions in binary form must reproduce the above copyright notice,
44 // this list of conditions, and the following disclaimer in the documentation
45 // and/or other materials provided with the distribution.
46 //
47 // 3. Neither the names of the copyright holders nor the names of their contributors
48 // may be used to endorse or promote products derived from this software without
49 // specific prior written permission.
50 //
51 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
52 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
53 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
54 // THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 // SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
56 // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
58 // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.THE LAWS OF THE NETHERLANDS
60 // SHALL BE EXCLUSIVELY APPLICABLE AND ANY DISPUTES SHALL BE FINALLY SETTLED UNDER THE RULES
61 // OF ARBITRATION OF THE INTERNATIONAL CHAMBER OF COMMERCE IN THE HAGUE BY ONE OR MORE
62 // ARBITRATORS APPOINTED IN ACCORDANCE WITH SAID RULES.
63 //
64 
65 #include <xstypes/xsthread.h>
66 #include <xstypes/xsportinfo.h>
67 #include "usbinterface.h"
68 #include <errno.h>
69 
70 #include "xswinusb.h"
71 #include "xslibusb.h"
72 #include "rx_tx_log.h"
73 
74 #ifndef _WIN32
75  #include <string.h> // strcpy
76 #else
77  #include <winbase.h>
78  #include <io.h>
79 #endif
80 #include <atomic>
81 
82 #ifndef _CRT_SECURE_NO_DEPRECATE
83  #define _CRT_SECURE_NO_DEPRECATE
84  #ifdef _WIN32
85  #pragma warning(disable:4996)
86  #endif
87 #endif
88 
91 {
92 public:
93 #ifdef LOG_RX_TX
94  XsFile rx_log;
95  XsFile tx_log;
96 #endif
97 
106 
109  char m_portname[256];
110 
111 #ifdef USE_WINUSB
112  XsWinUsb m_winUsb;
113  WINUSB_INTERFACE_HANDLE m_usbHandle[2];
114  uint8_t m_bulkInPipe, m_bulkOutPipe, m_interruptPipe, m_deviceSpeed;
115  uint16_t m_bulkInPipePacketSize;
117 
118  XsThreadId m_threadId;
119  XsThread m_threadHandle;
120  static const int m_oCount = MAXIMUM_WAIT_OBJECTS - 1;
121  OVERLAPPED m_overlapped[m_oCount];
122  XsByteArray m_varBuffer;
123  static const int m_fixedBufferSize = 8192;
124  uint8_t m_fixedBuffer[m_oCount][m_fixedBufferSize];
125  //int m_offset;
126  CRITICAL_SECTION m_mutex;
127  HANDLE m_quitEvent;
128  volatile std::atomic_bool m_running;
129  HANDLE m_waitEvents[m_oCount];
130  int m_readIdx;
131  XsResultValue m_threadedResult;
132 
133  void threadFunc();
134 
135 #elif defined(HAVE_LIBUSB)
136  int m_interfaceCount;
137  int m_interface;
138 
139  libusb_device_handle* m_deviceHandle;
144  class UsbContext
145  {
146  public:
149  UsbContext()
150  {
151  if (!m_claimedContexts)
152  m_libUsb.init(&m_usbContext);
153  m_claimedContexts++;
154  //libusb_set_debug(m_usbContext, 3);
155  }
156 
158  ~UsbContext()
159  {
160  m_claimedContexts--;
161  if (!m_claimedContexts)
162  m_libUsb.exit(m_usbContext);
163  }
164  static libusb_context* m_usbContext; // needed for proper use of libusb
165  XsLibUsb m_libUsb;
166  private:
167  static int m_claimedContexts;
168  };
169  UsbContext m_contextManager;
170 
176  XsResultValue libusbErrorToXrv(int libusbError, XsResultValue hint = XRV_ERROR)
177  {
178  switch (libusbError)
179  {
180  case LIBUSB_SUCCESS:
181  return XRV_OK;
182 
183  case LIBUSB_ERROR_IO:
184  return hint;
185 
186  case LIBUSB_ERROR_INVALID_PARAM:
187  return XRV_INVALIDPARAM;
188 
189  case LIBUSB_ERROR_ACCESS:
190  return hint;
191 
192  case LIBUSB_ERROR_NO_DEVICE:
194 
195  case LIBUSB_ERROR_NOT_FOUND:
196  return XRV_NOTFOUND;
197 
198  case LIBUSB_ERROR_BUSY:
199  return XRV_INVALIDOPERATION;
200 
201  case LIBUSB_ERROR_TIMEOUT:
202  return XRV_TIMEOUT;
203 
204  case LIBUSB_ERROR_OVERFLOW:
205  return hint;
206 
207  case LIBUSB_ERROR_PIPE:
208  return hint;
209 
210  case LIBUSB_ERROR_INTERRUPTED:
211  return XRV_UNEXPECTEDMSG;
212 
213  case LIBUSB_ERROR_NO_MEM:
214  return XRV_OUTOFMEMORY;
215 
216  case LIBUSB_ERROR_NOT_SUPPORTED:
217  return XRV_NOTIMPLEMENTED;
218 
219  case LIBUSB_ERROR_OTHER:
220  return hint;
221  }
222  return hint;
223  }
224 
226  const char* libusbErrorToString(int libusbError)
227  {
228  switch (libusbError)
229  {
230  case LIBUSB_SUCCESS:
231  return "LIBUSB_SUCCESS";
232 
233  case LIBUSB_ERROR_IO:
234  return "LIBUSB_ERROR_IO";
235 
236  case LIBUSB_ERROR_INVALID_PARAM:
237  return "LIBUSB_ERROR_INVALID_PARAM";
238 
239  case LIBUSB_ERROR_ACCESS:
240  return "LIBUSB_ERROR_ACCESS";
241 
242  case LIBUSB_ERROR_NO_DEVICE:
243  return "LIBUSB_ERROR_NO_DEVICE";
244 
245  case LIBUSB_ERROR_NOT_FOUND:
246  return "LIBUSB_ERROR_NOT_FOUND";
247 
248  case LIBUSB_ERROR_BUSY:
249  return "LIBUSB_ERROR_BUSY";
250 
251  case LIBUSB_ERROR_TIMEOUT:
252  return "LIBUSB_ERROR_TIMEOUT";
253 
254  case LIBUSB_ERROR_OVERFLOW:
255  return "LIBUSB_ERROR_OVERFLOW";
256 
257  case LIBUSB_ERROR_PIPE:
258  return "LIBUSB_ERROR_PIPE";
259 
260  case LIBUSB_ERROR_INTERRUPTED:
261  return "LIBUSB_ERROR_INTERRUPTED";
262 
263  case LIBUSB_ERROR_NO_MEM:
264  return "LIBUSB_ERROR_NO_MEM";
265 
266  case LIBUSB_ERROR_NOT_SUPPORTED:
267  return "LIBUSB_ERROR_NOT_SUPPORTED";
268 
269  case LIBUSB_ERROR_OTHER:
270  return "LIBUSB_ERROR_OTHER";
271  }
272  return "Unknown";
273  }
274 #else
276 #endif
277 };
278 
279 #ifdef USE_WINUSB
280 static DWORD usbReadThreadFunc(void* obj)
281 {
283  d->m_running = true;
284  xsSetThreadPriority(::GetCurrentThread(), XS_THREAD_PRIORITY_HIGHEST); // not using xsGetCurrentThreadHandle here because we can directly use GetCurrentThread(), which is simpler
285  xsNameThisThread("USB reader");
286  try
287  {
288  d->threadFunc();
289  }
290  catch (...)
291  {
292 #ifdef XSENS_DEBUG
293  assert(0);
294 #endif
295  }
296  d->m_running = false;
297  return 0;
298 }
299 
300 void UsbInterfacePrivate::threadFunc()
301 {
302  HANDLE handles[1 + m_oCount];
303  handles[0] = m_quitEvent;
304  handles[m_oCount] = m_waitEvents[m_oCount - 1];
305  //= { m_quitEvent, m_waitEvents[0], m_waitEvents[1] };
306 
307  // start first read operation
308  for (m_readIdx = 0 ; m_readIdx < (m_oCount - 1); ++m_readIdx)
309  {
310  handles[m_readIdx + 1] = m_waitEvents[m_readIdx];
311  m_overlapped[m_readIdx] = OVERLAPPED();
312  ::ResetEvent(m_waitEvents[m_readIdx]);
313  m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
314  m_winUsb.ReadPipe(m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx], (ULONG)m_fixedBufferSize, 0, &m_overlapped[m_readIdx]);
315  }
316  bool run = true;
317  while (run)
318  {
319  // start follow-up read operation
320  m_overlapped[m_readIdx] = OVERLAPPED();
321  ::ResetEvent(m_waitEvents[m_readIdx]);
322  m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx];
323  m_winUsb.ReadPipe(m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx], (ULONG)m_fixedBufferSize, 0, &m_overlapped[m_readIdx]);
324  m_readIdx = (m_readIdx + 1) % m_oCount;
325  DWORD waitResult = ::WaitForMultipleObjects(1 + m_oCount, handles, FALSE, INFINITE);
326 
327  // handle data
328  switch (waitResult)
329  {
330  case WAIT_TIMEOUT:
331  case WAIT_FAILED:
332  case WAIT_OBJECT_0:
333  run = false;
334  break;
335 
336  default:
337  if (waitResult >= WAIT_ABANDONED_0)
338  {
339  JLDEBUGG("WFMO abandoned: " << (waitResult - WAIT_OBJECT_0));
340  break;
341  }
342 
343 #ifndef XSENS_RELEASE
344  JLDEBUGG("WFMO trigger: " << (waitResult - WAIT_OBJECT_0));
345 #endif
346  {
347  // put data into buffer
348  int idx = m_readIdx;
349  DWORD dataRead = 0;
350  if (!m_winUsb.GetOverlappedResult(m_usbHandle[0], &m_overlapped[idx], &dataRead, FALSE))
351  {
352  // error
353  DWORD err = ::GetLastError();
354  switch (err)
355  {
356  case ERROR_SEM_TIMEOUT:
357  case ERROR_IO_INCOMPLETE:
358  //JLDEBUGG("m_winUsb.GetOverlappedResult resulted in acceptable windows error " << err);
359  break;
360 
361  case ERROR_GEN_FAILURE:
362  JLDEBUGG("We seem to have lost contact with the usb device");
363  m_threadedResult = XRV_UNEXPECTED_DISCONNECT;
364  run = false;
365  break;
366 
367  default:
368  JLALERTG("m_winUsb.GetOverlappedResult resulted in windows error " << err);
369  run = false;
370  break;
371  }
372  //assert (err == ERROR_IO_INCOMPLETE);
373  }
374  else
375  {
376  // append unread data to var buffer
377  JLTRACEG("m_winUsb.GetOverlappedResult resulted in " << dataRead << " bytes being read");
378  XsByteArray ref(&m_fixedBuffer[idx][0], dataRead, XSDF_None);
379  ::EnterCriticalSection(&m_mutex);
380  m_varBuffer.append(ref);
381  ::LeaveCriticalSection(&m_mutex);
382  }
383  }
384  break;
385  }
386  }
387 }
388 
389 #elif defined(HAVE_LIBUSB)
390 int UsbInterfacePrivate::UsbContext::m_claimedContexts = 0;
391 libusb_context* UsbInterfacePrivate::UsbContext::m_usbContext = NULL;
392 #endif
393 
401  : d(new UsbInterfacePrivate)
402 {
403  d->m_lastResult = XRV_OK;
404  d->m_timeout = 20;
405  d->m_endTime = 0;
406  d->m_dataInEndPoint = -1;
407  d->m_dataOutEndPoint = -1;
408  d->m_deviceHandle = 0;
409  d->m_portname[0] = 0;
410 
411 #ifdef USE_WINUSB
412  d->m_threadHandle = INVALID_HANDLE_VALUE;
413  ::InitializeCriticalSection(&d->m_mutex);
414  d->m_usbHandle[0] = 0;
415  d->m_usbHandle[1] = 0;
416  for (int i = 0; i < UsbInterfacePrivate::m_oCount; ++i)
417  {
418  d->m_waitEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
419  ::ResetEvent(d->m_waitEvents[i]);
420  }
421  d->m_quitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
422  ::ResetEvent(d->m_quitEvent);
423  d->m_readIdx = 0;
424  d->m_threadedResult = XRV_OK;
425 #endif
426 }
427 
430 {
431  try
432  {
433  closeUsb();
434 #ifdef USE_WINUSB
435  ::CloseHandle(d->m_quitEvent);
436  for (int i = 0; i < UsbInterfacePrivate::m_oCount; ++i)
437  ::CloseHandle(d->m_waitEvents[i]);
438  ::DeleteCriticalSection(&d->m_mutex);
439 #endif
440  delete d;
441  }
442  catch (...)
443  {
444  }
445 }
446 
450 {
451  return closeUsb();
452 }
453 
461 {
462 #ifdef LOG_RX_TX
463  d->rx_log.close();
464  d->tx_log.close();
465 
466 #endif
467  if (!isOpen())
468  return d->m_lastResult = XRV_NOPORTOPEN;
469 
470  d->m_lastResult = XRV_OK;
471 #ifdef USE_WINUSB
472  if (d->m_threadHandle != INVALID_HANDLE_VALUE)
473  {
474  while (d->m_running)
475  {
476  ::SetEvent(d->m_quitEvent);
477  XsTime::msleep(10);
478  }
479  ::CloseHandle(d->m_threadHandle);
480  }
481 
482  flushData();
483  if (d->m_usbHandle[0])
484  {
485  d->m_winUsb.Free(d->m_usbHandle[0]);
486  d->m_usbHandle[0] = NULL;
487  }
488  if (d->m_usbHandle[1])
489  {
490  d->m_winUsb.Free(d->m_usbHandle[1]);
491  d->m_usbHandle[1] = NULL;
492  }
493  if (d->m_deviceHandle)
494  {
495  CloseHandle(d->m_deviceHandle);
496  d->m_deviceHandle = NULL;
497  }
498 #elif defined(HAVE_LIBUSB)
499  flushData();
500  libusb_device* dev = d->m_contextManager.m_libUsb.get_device(d->m_deviceHandle);
501  for (int i = 0; i < d->m_interfaceCount; i++)
502  {
503  int result = LIBUSB_ERROR_OTHER;
504  while (result != LIBUSB_SUCCESS)
505  {
506  result = d->m_contextManager.m_libUsb.release_interface(d->m_deviceHandle, i);
507  if (result == LIBUSB_SUCCESS)
508  d->m_contextManager.m_libUsb.attach_kernel_driver(d->m_deviceHandle, i);
509  }
510  }
511 
512  d->m_contextManager.m_libUsb.close(d->m_deviceHandle);
513  d->m_deviceHandle = NULL;
514 
515  d->m_contextManager.m_libUsb.unref_device(dev);
516  d->m_interface = -1;
517  d->m_dataInEndPoint = -1;
518  d->m_dataOutEndPoint = -1;
519 #else
521 #endif
522  d->m_endTime = 0;
523 
524  return d->m_lastResult;
525 }
526 
528 // Flush all data to be transmitted / received.
530 {
531  d->m_lastResult = XRV_OK;
532 #ifdef USE_WINUSB
533  if (d->m_usbHandle[0])
534  {
535  d->m_winUsb.AbortPipe(d->m_usbHandle[0], d->m_bulkInPipe);
536  d->m_winUsb.FlushPipe(d->m_usbHandle[0], d->m_bulkInPipe);
537  d->m_winUsb.AbortPipe(d->m_usbHandle[0], d->m_bulkOutPipe);
538  d->m_winUsb.FlushPipe(d->m_usbHandle[0], d->m_bulkOutPipe);
539  }
540  if (d->m_usbHandle[1])
541  {
542  d->m_winUsb.AbortPipe(d->m_usbHandle[1], d->m_bulkInPipe);
543  d->m_winUsb.FlushPipe(d->m_usbHandle[1], d->m_bulkInPipe);
544  d->m_winUsb.AbortPipe(d->m_usbHandle[1], d->m_bulkOutPipe);
545  d->m_winUsb.FlushPipe(d->m_usbHandle[1], d->m_bulkOutPipe);
546  }
547 #elif defined(HAVE_LIBUSB)
548  unsigned char flushBuffer[256];
549  int actual;
550  for (int i = 0; i < 64; ++i)
551  {
552  if (d->m_contextManager.m_libUsb.bulk_transfer(d->m_deviceHandle, d->m_dataInEndPoint | LIBUSB_ENDPOINT_IN,
553  flushBuffer, sizeof(flushBuffer), &actual, 1) != LIBUSB_SUCCESS)
554  break;
555  if (actual == 0)
556  break;
557  }
558 #else
560 #endif
561  d->m_endTime = 0;
562  return d->m_lastResult;
563 }
564 
567 {
568  return d->m_lastResult;
569 }
570 
573 {
574  return d->m_timeout;
575 }
576 
578 bool UsbInterface::isOpen(void) const
579 {
580  return d->m_deviceHandle != NULL;
581 }
582 
585 {
586  d->m_endTime = 0;
587 
588 #ifdef USE_WINUSB
589  JLDEBUGG("Open usb port " << portInfo.portName());
590 #else
591  JLDEBUGG("Open usb port " << portInfo.usbBus() << ":" << portInfo.usbAddress());
592 #endif
593 
594  if (isOpen())
595  {
596  JLALERTG("Port " << portInfo.portName() << " already open");
597  return (d->m_lastResult = XRV_ALREADYOPEN);
598  }
599 
600 #ifdef USE_WINUSB
601  d->m_deviceHandle = CreateFileA(portInfo.portName_c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
602 
603  if (d->m_deviceHandle == INVALID_HANDLE_VALUE)
604  {
605  d->m_deviceHandle = NULL;
606  return (d->m_lastResult = XRV_PORTNOTFOUND);
607  }
608 
609  BOOL result;
610  UCHAR speed = 0;
611  ULONG length = 0;
612  USB_INTERFACE_DESCRIPTOR interfaceDescriptor = {0, 0, 0, 0, 0, 0, 0, 0, 0};
613  WINUSB_PIPE_INFORMATION pipeInfo;
614 
615  result = d->m_winUsb.Initialize(d->m_deviceHandle, &d->m_usbHandle[0]);
616  if (result)
617  result = d->m_winUsb.GetAssociatedInterface(d->m_usbHandle[0], 0, &d->m_usbHandle[1]);
618  else
619  {
620 #ifdef XSENS_DEBUG
621  DWORD err = GetLastError();
622  assert(result);
623 #endif
624  return (d->m_lastResult = XRV_ERROR);
625  }
626 
627  for (int k = 0; k < 2; k++)
628  {
629  if (result)
630  {
631  assert(d->m_usbHandle[k] != 0);
632  length = sizeof(UCHAR);
633  result = d->m_winUsb.QueryDeviceInformation(d->m_usbHandle[k], DEVICE_SPEED, &length, &speed);
634  }
635 
636  if (result)
637  {
638  d->m_deviceSpeed = speed;
639  result = d->m_winUsb.QueryInterfaceSettings(d->m_usbHandle[k], 0, &interfaceDescriptor);
640  }
641  if (result)
642  {
643  for (int i = 0; i < interfaceDescriptor.bNumEndpoints; i++)
644  {
645  result = d->m_winUsb.QueryPipe(d->m_usbHandle[k], 0, (UCHAR) i, &pipeInfo);
646 
647  if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId))
648  {
649  d->m_bulkInPipe = pipeInfo.PipeId;
650  d->m_bulkInPipePacketSize =
651  pipeInfo.MaximumPacketSize;
652  }
653  else if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId))
654  d->m_bulkOutPipe = pipeInfo.PipeId;
655  else if (pipeInfo.PipeType == UsbdPipeTypeInterrupt)
656  d->m_interruptPipe = pipeInfo.PipeId;
657  else
658  {
659  result = FALSE;
660  break;
661  }
662  }
663  }
664  }
665 
666  setTimeout(0);
667  flushData();
668 
669  sprintf(d->m_portname, "%s", portInfo.portName_c_str());
670 
671  // d->m_offset = 0;
672  ::ResetEvent(&d->m_quitEvent);
673  d->m_threadHandle = xsStartThread(usbReadThreadFunc, d, &d->m_threadId);
674  if (d->m_threadHandle == XSENS_INVALID_THREAD)
675  {
676 #ifdef XSENS_DEBUG
677  assert(0);
678 #endif
679  return (d->m_lastResult = XRV_ERROR);
680  }
681 
682 #elif defined(HAVE_LIBUSB)
683  libusb_device** deviceList;
684  ssize_t listLength = d->m_contextManager.m_libUsb.get_device_list(d->m_contextManager.m_usbContext, &deviceList);
685  if (listLength < 0)
686  return d->m_lastResult = d->libusbErrorToXrv((int)listLength);
687 
688  // "USBxxx:yyy"
689  uint8_t bus = XsPortInfo_usbBus(&portInfo);
690  uint8_t address = XsPortInfo_usbAddress(&portInfo);
691 
692  XsResultValue xrv = XRV_OK;
693  int result;
694  libusb_device* device = NULL;
695  for (int i = 0; i < listLength && device == NULL; ++i)
696  {
697  libusb_device* dev = deviceList[i];
698  if (d->m_contextManager.m_libUsb.get_bus_number(dev) != bus || d->m_contextManager.m_libUsb.get_device_address(dev) != address)
699  continue;
700 
701  libusb_device_descriptor desc;
702  result = d->m_contextManager.m_libUsb.get_device_descriptor(dev, &desc);
703  if (result != LIBUSB_SUCCESS)
704  break;
705 
706  libusb_config_descriptor* configDesc;
707  result = d->m_contextManager.m_libUsb.get_active_config_descriptor(dev, &configDesc);
708  if (result != LIBUSB_SUCCESS)
709  break;
710 
711  d->m_interface = -1;
712  d->m_interfaceCount = configDesc->bNumInterfaces;
713  // find the bulk transfer endpoints
714  for (uint8_t ifCount = 0; ifCount < configDesc->bNumInterfaces && d->m_interface == -1; ++ifCount)
715  {
716  for (uint8_t altsettingCount = 0; altsettingCount < configDesc->interface[ifCount].num_altsetting; altsettingCount++)
717  {
718  const libusb_endpoint_descriptor* endpoints = configDesc->interface[ifCount].altsetting[altsettingCount].endpoint;
719  int inEndpoint = -1, outEndpoint = -1;
720  for (uint8_t i = 0; i < configDesc->interface[ifCount].altsetting[altsettingCount].bNumEndpoints; i++)
721  {
722  if ((endpoints[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != LIBUSB_TRANSFER_TYPE_BULK)
723  continue;
724 
725  switch (endpoints[i].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
726  {
727  case LIBUSB_ENDPOINT_IN:
728  inEndpoint = endpoints[i].bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK;
729  break;
730 
731  case LIBUSB_ENDPOINT_OUT:
732  outEndpoint = endpoints[i].bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK;
733  break;
734  }
735 
736  }
737 
738  if (outEndpoint == -1 || inEndpoint == -1)
739  continue;
740 
741  d->m_interface = ifCount;
742  d->m_dataOutEndPoint = outEndpoint;
743  d->m_dataInEndPoint = inEndpoint;
744  }
745  }
746  if (d->m_interface == -1)
747  {
749  break;
750  }
751 
752  d->m_contextManager.m_libUsb.free_config_descriptor(configDesc);
753  d->m_contextManager.m_libUsb.ref_device(dev);
754  device = dev;
755  result = LIBUSB_SUCCESS;
756  }
757 
758  d->m_contextManager.m_libUsb.free_device_list(deviceList, 1);
759  if (result != LIBUSB_SUCCESS)
760  {
761  d->m_contextManager.m_libUsb.unref_device(device);
762  return d->m_lastResult = d->libusbErrorToXrv(result);
763  }
764 
765  if (xrv != XRV_OK)
766  {
767  d->m_contextManager.m_libUsb.unref_device(device);
768  return d->m_lastResult = xrv;
769  }
770 
771  libusb_device_handle* handle;
772  result = d->m_contextManager.m_libUsb.open(device, &handle);
773  if (result != LIBUSB_SUCCESS)
774  {
775  d->m_contextManager.m_libUsb.unref_device(device);
776  return d->m_lastResult = d->libusbErrorToXrv(result);
777  }
778 
779  // be rude and claim all interfaces
780  for (int i = 0; i < d->m_interfaceCount; i++)
781  {
782  result = d->m_contextManager.m_libUsb.kernel_driver_active(handle, i);
783  if (result > 0)
784  result = d->m_contextManager.m_libUsb.detach_kernel_driver(handle, i);
785  if (result == LIBUSB_SUCCESS)
786  result = d->m_contextManager.m_libUsb.claim_interface(handle, i);
787  if (result != LIBUSB_SUCCESS)
788  {
789  for (int j = 0; j < i; j++)
790  {
791  while (result != LIBUSB_SUCCESS)
792  {
793  result = d->m_contextManager.m_libUsb.release_interface(handle, j);
794  d->m_contextManager.m_libUsb.attach_kernel_driver(handle, j);
795  }
796  }
797 
798  d->m_contextManager.m_libUsb.close(handle);
799  d->m_contextManager.m_libUsb.unref_device(device);
800  return d->m_lastResult = d->libusbErrorToXrv(result);
801  }
802  }
803 
804  d->m_deviceHandle = handle;
805  sprintf(d->m_portname, "%s", portInfo.portName_c_str());
806 
807  flushData();
808 #else // HAVE_LIBUSB
809  (void)portInfo;
811 #endif
812  JLDEBUGG("USB Port opened");
813  return (d->m_lastResult = XRV_OK);
814 }
815 
825 {
826  XsFilePos length = 0;
827  data.setSize((XsSize) maxLength);
828  XsResultValue res = readData(maxLength, data.data(), &length);
829  data.pop_back((XsSize)(maxLength - length));
830  return res;
831 }
832 
843 {
844  JLTRACEG("maxLength=" << maxLength << ", data=" << JLHEXLOG(data) << ", length=" << JLHEXLOG(length));
845  XsFilePos ln;
846  if (length == NULL)
847  length = &ln;
848 
849  if (!isOpen())
850  return (d->m_lastResult = XRV_NOPORTOPEN);
851 
852 #ifdef USE_WINUSB
853  ::EnterCriticalSection(&d->m_mutex);
854  XsFilePos remaining = *length = (XsFilePos) d->m_varBuffer.size();
855  if (*length > maxLength)
856  *length = maxLength;
857  if (*length)
858  {
859  memcpy(data, (void*) d->m_varBuffer.data(), (XsSize) *length);
860  d->m_varBuffer.erase(0, (XsSize) *length);
861  remaining = (XsFilePos) d->m_varBuffer.size();
862  }
863 
864  if (d->m_threadedResult != XRV_OK)
865  return (d->m_lastResult = d->m_threadedResult);
866 
867  ::LeaveCriticalSection(&d->m_mutex);
868  JLTRACEG("returned success, read " << *length << " of " << maxLength << " bytes, first: " << JLHEXLOG(((char*)data)[0]) << ", " << remaining << " remaining in buffer");
869  (void) remaining;
870 
871 #elif defined(HAVE_LIBUSB)
872  int actual = 0;
873  JLTRACEG("starting bulk read, timeout = " << d->m_timeout);
874  int res = d->m_contextManager.m_libUsb.bulk_transfer(d->m_deviceHandle, (d->m_dataInEndPoint | LIBUSB_ENDPOINT_IN), (unsigned char*)data, maxLength, &actual, d->m_timeout);
875  JLTRACEG("bulk read returned: " << d->libusbErrorToString(res) << ". " << actual << " bytes received");
876  if ((res != LIBUSB_SUCCESS && res != LIBUSB_ERROR_TIMEOUT) || (res == LIBUSB_ERROR_TIMEOUT && actual <= 0))
877  return d->m_lastResult = d->libusbErrorToXrv(res);
878 
879  *length = actual;
880 #else
881  (void)maxLength;
882  (void)data;
883 #endif
884 
885 #ifdef LOG_RX_TX
886  if (*length > 0)
887  {
888  CHECK_STATE_RX(*length, data, d->rx_log);
889 
890  if (!d->rx_log.isOpen())
891  {
892  char fname[XS_MAX_FILENAME_LENGTH];
893  sprintf(fname, "rx_USB%03u_%03u.log", usbBus(), usbAddress());
894  d->rx_log.create(XsString(fname), true);
895  }
896  d->rx_log.write(data, 1, *length);
897 #ifdef LOG_RX_TX_FLUSH
898  d->rx_log.flush();
899 #endif
900  }
901 #endif
902 
903  return (d->m_lastResult = XRV_OK);
904 }
905 
913 {
914 #ifdef USE_WINUSB
915  JLDEBUGG("Request to set timeout to " << ms << " ms overridden, setting to 0 ms instead");
916  ms = 0; // no timeout ever
917  UCHAR enable = FALSE;
918 
919  d->m_winUsb.SetPipePolicy(d->m_usbHandle[1], d->m_bulkInPipe, IGNORE_SHORT_PACKETS, sizeof(UCHAR), &enable);
920  d->m_winUsb.SetPipePolicy(d->m_usbHandle[1], d->m_bulkInPipe, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &ms);
921 
922  d->m_timeout = ms;
923 #else
924  JLDEBUGG("Setting timeout to " << ms);
925  if (ms == 0)
926  d->m_timeout = 1;
927  else
928  d->m_timeout = ms;
929 #endif
930  return (d->m_lastResult = XRV_OK);
931 }
932 
937 void UsbInterface::setRawIo(bool enable)
938 {
939  JLDEBUGG("Setting RAWIO mode to " << enable);
940 
941 #ifdef USE_WINUSB
942  enable = false; // never use raw IO
943  UCHAR rawIo = (UCHAR)enable;
944  d->m_winUsb.SetPipePolicy(d->m_usbHandle[1], d->m_bulkInPipe, RAW_IO, sizeof(UCHAR), &rawIo);
945 #else
946  (void)enable;
947 #endif
948  d->m_lastResult = XRV_OK;
949 }
950 
956 {
957 #ifdef USE_WINUSB
958  UCHAR rawIo = 0;
959  ULONG someSize = sizeof(UCHAR);
960  d->m_winUsb.GetPipePolicy(d->m_usbHandle[1], d->m_bulkInPipe, RAW_IO, &someSize, &rawIo);
961  return (rawIo != 0);
962 #else
963  return false;
964 #endif
965 }
966 
979 {
980  JLTRACEG("timeout=" << d->m_timeout << ", data=" << data << ", length=" << length);
981  uint32_t timeout = d->m_timeout;
982 
983  char* bdata = (char*)data;
984 
985  XsFilePos ln;
986  if (length == NULL)
987  length = &ln;
988  uint32_t eTime = XsTime::getTimeOfDay() + timeout;
989  XsFilePos newLength = 0;
990 
991  *length = 0;
992  while ((*length < maxLength) && (XsTime::getTimeOfDay() <= eTime))
993  {
994  if (readData(maxLength - *length, bdata + *length, &newLength))
995  return d->m_lastResult;
996  *length += newLength;
997  }
998  JLTRACEG("read " << length[0] << " of " << maxLength << " bytes");
999 
1000  if (length[0] < maxLength)
1001  return (d->m_lastResult = XRV_TIMEOUT);
1002  else
1003  return (d->m_lastResult = XRV_OK);
1004 }
1005 
1015 {
1016  return writeData((XsFilePos) data.size(), data.data(), written);
1017 }
1018 
1028 XsResultValue UsbInterface::writeData(XsFilePos length, const void* data, XsFilePos* written)
1029 {
1030  XsFilePos bytes;
1031  if (written == NULL)
1032  written = &bytes;
1033 
1034  if (!isOpen())
1035  return (d->m_lastResult = XRV_NOPORTOPEN);
1036 
1037  *written = 0;
1038 
1039 #ifdef USE_WINUSB
1040  ULONG dataWritten;
1041  d->m_winUsb.WritePipe(d->m_usbHandle[1], d->m_bulkOutPipe, static_cast<PUCHAR>(const_cast<void*>(data)), (ULONG)length, &dataWritten, NULL);
1042 
1043  *written = dataWritten;
1044 #elif defined(HAVE_LIBUSB)
1045  *written = 0;
1046  while (*written < length)
1047  {
1048  int actual;
1049  int result = d->m_contextManager.m_libUsb.bulk_transfer(d->m_deviceHandle, (d->m_dataOutEndPoint | LIBUSB_ENDPOINT_OUT), (unsigned char*)data, length, &actual, 0);
1050  *written += actual;
1051  if (result != LIBUSB_SUCCESS)
1052  {
1053  JLALERTG("bulk write failed: " << d->libusbErrorToString(result) << ". " << actual << " bytes sent");
1054  return (d->m_lastResult = d->libusbErrorToXrv(result));
1055  }
1056  }
1057 #else
1058  (void)length;
1059  (void)data;
1060 #endif
1061 
1062 #ifdef LOG_RX_TX
1063  if (*written > 0)
1064  {
1065  CHECK_STATE_TX(*written, data, d->tx_log);
1066 
1067  if (!d->tx_log.isOpen())
1068  {
1069  char fname[XS_MAX_FILENAME_LENGTH];
1070  sprintf(fname, "tx_USB%03u_%03u.log", usbBus(), usbAddress());
1071  d->tx_log.create(XsString(fname), true);
1072  }
1073  d->tx_log.write(data, 1, *written);
1074 #ifdef LOG_RX_TX_FLUSH
1075  d->tx_log.flush();
1076 #endif
1077  }
1078 #endif
1079 
1080  return (d->m_lastResult = XRV_OK);
1081 }
1082 
1084 uint8_t UsbInterface::usbBus() const
1085 {
1086 #if defined(HAVE_LIBUSB)
1087  if (!d->m_deviceHandle)
1088  return 0;
1089 
1090  libusb_device* dev = d->m_contextManager.m_libUsb.get_device(d->m_deviceHandle);
1091  return d->m_contextManager.m_libUsb.get_bus_number(dev);
1092 #else
1093  return 0;
1094 #endif
1095 }
1096 
1099 {
1100 #if defined(HAVE_LIBUSB)
1101  if (!d->m_deviceHandle)
1102  return 0;
1103 
1104  libusb_device* dev = d->m_contextManager.m_libUsb.get_device(d->m_deviceHandle);
1105  return d->m_contextManager.m_libUsb.get_device_address(dev);
1106 #else
1107  return 0;
1108 #endif
1109 }
1110 
1113 {
1114  portname = d->m_portname;
1115 }
XRV_NOPORTOPEN
@ XRV_NOPORTOPEN
288: No serial port opened for reading/writing
Definition: xsresultvalue.h:159
XsIoHandle
int32_t XsIoHandle
The type that is used for low-level identification of an open I/O device.
Definition: xsfilepos.h:104
XsString
struct XsString XsString
Definition: xsstring.h:87
XsThreadId
pthread_t XsThreadId
Definition: xsthread.h:187
UsbInterface::~UsbInterface
~UsbInterface()
Destructor, de-initializes, frees memory allocated for buffers, etc.
Definition: usbinterface.cpp:429
XsByteArray
A list of uint8_t values.
UsbInterfacePrivate::m_deviceHandle
void * m_deviceHandle
Definition: usbinterface.cpp:275
UsbInterface::usbBus
uint8_t usbBus() const
The USB bus number this device is on (libusb/linux only)
Definition: usbinterface.cpp:1084
io.h
XRV_TIMEOUT
@ XRV_TIMEOUT
258: A timeout occurred
Definition: xsresultvalue.h:128
xsNameThisThread
void XSTYPES_DLL_API xsNameThisThread(const char *threadName)
Set the name of the current thread to threadName.
Definition: xsthread.c:140
UsbInterface::getLastResult
XsResultValue getLastResult(void) const
Return the error code of the last operation.
Definition: usbinterface.cpp:566
UsbInterface::close
XsResultValue close(void)
Close the USB communication port.
Definition: usbinterface.cpp:449
UsbInterface::waitForData
XsResultValue waitForData(XsFilePos maxLength, void *data, XsFilePos *length=NULL)
Wait for data to arrive or a timeout to occur.
Definition: usbinterface.cpp:978
UsbInterfacePrivate::m_endTime
uint32_t m_endTime
The time at which an operation will end in ms, used by several functions.
Definition: usbinterface.cpp:99
xsthread.h
xslibusb.h
JLALERTG
#define JLALERTG(msg)
Definition: journaller.h:281
xsStartThread
pthread_t XSTYPES_DLL_API xsStartThread(void *(func)(void *), void *param, void *pid)
Start a function as a thread.
Definition: xsthread.c:156
UsbInterface::writeData
XsResultValue writeData(const XsByteArray &data, XsFilePos *written=NULL) override
Write the data to the USB port.
Definition: usbinterface.cpp:1014
UsbInterfacePrivate::m_timeout
uint32_t m_timeout
Definition: usbinterface.cpp:105
UsbInterfacePrivate::m_portname
char m_portname[256]
Definition: usbinterface.cpp:109
XRV_NOTFOUND
@ XRV_NOTFOUND
262: The requested item was not found
Definition: xsresultvalue.h:132
UsbInterface::getPortName
void getPortName(XsString &portname) const
Retrieve the port name that was last successfully opened.
Definition: usbinterface.cpp:1112
XRV_ALREADYOPEN
@ XRV_ALREADYOPEN
269: An I/O device is already opened with this object
Definition: xsresultvalue.h:139
xsportinfo.h
XRV_ERROR
@ XRV_ERROR
256: A generic error occurred
Definition: xsresultvalue.h:126
UsbInterface::getRawIo
bool getRawIo(void)
Retrieves the state of the RAWIO mode of the USB interface.
Definition: usbinterface.cpp:955
data
data
XsPortInfo_usbAddress
XSTYPES_DLL_API int XsPortInfo_usbAddress(XsPortInfo const *thisPtr)
IoInterface::PortOptions
PortOptions
Options for flow control and stopbits which must be used when opening a port.
Definition: iointerface.h:130
XRV_OK
@ XRV_OK
0: Operation was performed successfully
Definition: xsresultvalue.h:85
XsThread
pthread_t XsThread
A handle for a thread.
Definition: xsthread.h:186
XsResultValue
XsResultValue
Xsens result values.
Definition: xsresultvalue.h:82
XsPortInfo_usbBus
XSTYPES_DLL_API int XsPortInfo_usbBus(XsPortInfo const *thisPtr)
UsbInterface::closeUsb
XsResultValue closeUsb(void)
Close the USB communication port.
Definition: usbinterface.cpp:460
XRV_UNEXPECTED_DISCONNECT
@ XRV_UNEXPECTED_DISCONNECT
312: Motion tracker disconnected unexpectedly
Definition: xsresultvalue.h:187
UsbInterface::usbAddress
uint8_t usbAddress() const
The address of the device (libusb/linux only)
Definition: usbinterface.cpp:1098
XRV_OUTOFMEMORY
@ XRV_OUTOFMEMORY
261: No internal memory available
Definition: xsresultvalue.h:131
uint32_t
unsigned int uint32_t
Definition: pstdint.h:485
XRV_PORTNOTFOUND
@ XRV_PORTNOTFOUND
290: A required port could not be found
Definition: xsresultvalue.h:161
XsPortInfo
Contains a descriptor for opening a communication port to an Xsens device.
Definition: xsportinfo.h:128
UsbInterfacePrivate::m_dataOutEndPoint
int m_dataOutEndPoint
Definition: usbinterface.cpp:108
UsbInterfacePrivate
Private object for UsbInterface.
Definition: usbinterface.cpp:90
usbinterface.h
UsbInterfacePrivate::m_lastResult
XsResultValue m_lastResult
The last result of an operation.
Definition: usbinterface.cpp:101
UsbInterface::getTimeout
uint32_t getTimeout(void) const
Return the current timeout value.
Definition: usbinterface.cpp:572
JLTRACEG
#define JLTRACEG(msg)
Definition: journaller.h:279
d
d
UsbInterface::flushData
XsResultValue flushData(void)
Flush all data in the buffers to and from the device.
Definition: usbinterface.cpp:529
XRV_UNEXPECTEDMSG
@ XRV_UNEXPECTEDMSG
263: Unexpected message received (e.g. no acknowledge message received)
Definition: xsresultvalue.h:133
XRV_NOTIMPLEMENTED
@ XRV_NOTIMPLEMENTED
257: Operation not implemented in this version (yet)
Definition: xsresultvalue.h:127
xsSetThreadPriority
#define xsSetThreadPriority(thrd, prio)
Definition: xsthread.h:194
XsSize
size_t XsSize
XsSize must be unsigned number!
Definition: xstypedefs.h:74
XRV_INPUTCANNOTBEOPENED
@ XRV_INPUTCANNOTBEOPENED
267: The specified i/o device can not be opened
Definition: xsresultvalue.h:137
UsbInterface::setTimeout
XsResultValue setTimeout(uint32_t ms)
Set the default timeout value to use in blocking operations.
Definition: usbinterface.cpp:912
UsbInterface::readData
XsResultValue readData(XsFilePos maxLength, XsByteArray &data) override
Read data from the USB port and put it into the data buffer.
Definition: usbinterface.cpp:824
UsbInterface::UsbInterface
UsbInterface()
Default constructor, initializes all members to their default values.
Definition: usbinterface.cpp:400
UsbInterfacePrivate::m_dataInEndPoint
int m_dataInEndPoint
Definition: usbinterface.cpp:107
XsFile
Encapsulates a file, providing a platform independent interface.
Definition: xsfile.h:131
BOOL
int BOOL
Definition: xstypedefs.h:141
JLHEXLOG
#define JLHEXLOG(d)
Definition: journaller.h:335
XSENS_INVALID_THREAD
#define XSENS_INVALID_THREAD
Definition: xsthread.h:179
XSDF_None
@ XSDF_None
No flag set.
Definition: xstypedefs.h:109
JLDEBUGG
#define JLDEBUGG(msg)
Definition: journaller.h:280
UsbInterface::setRawIo
void setRawIo(bool enable)
Sets the RAWIO mode of the USB interface.
Definition: usbinterface.cpp:937
UsbInterface::open
XsResultValue open(const XsPortInfo &portInfo, XsFilePos readBufSize=0, XsFilePos writeBufSize=0, PortOptions=PO_XsensDefaults) override
Open a communication channel to the given USB port name.
Definition: usbinterface.cpp:584
xswinusb.h
length
TF2SIMD_FORCE_INLINE tf2Scalar length(const Quaternion &q)
rx_tx_log.h
XRV_INVALIDOPERATION
@ XRV_INVALIDOPERATION
265: Operation is invalid at this point
Definition: xsresultvalue.h:135
UsbInterface::d
UsbInterfacePrivate * d
Definition: usbinterface.h:91
XsFilePos
int64_t XsFilePos
The type that is used for positioning inside a file.
Definition: xsfilepos.h:102
XsString
A 0-terminated managed string of characters.
XS_THREAD_PRIORITY_HIGHEST
@ XS_THREAD_PRIORITY_HIGHEST
Definition: xsthread.h:170
threadFunc
void threadFunc(boost::barrier *b)
XS_MAX_FILENAME_LENGTH
#define XS_MAX_FILENAME_LENGTH
Definition: xsfile.h:78
XRV_INVALIDPARAM
@ XRV_INVALIDPARAM
33: An invalid parameter is supplied
Definition: xsresultvalue.h:105
UsbInterface::isOpen
bool isOpen(void) const
Return whether the USB communication port is open or not.
Definition: usbinterface.cpp:578


xsens_mti_driver
Author(s):
autogenerated on Sun Sep 3 2023 02:43:20