enumerateusbdevices.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 "xscontrollerconfig.h"
66 #include "enumerateusbdevices.h"
67 
68 #ifdef _WIN32
69  #include <windows.h>
70  #include <string.h>
71  #include <setupapi.h>
72  #include <devguid.h>
73  #include <regstr.h>
74  #include <regex>
75  #include <cfgmgr32.h>
76 #else
77  #include <stdlib.h>
78  #include <string.h>
79  #include <dirent.h>
80  #include "xslibusb.h"
81 #endif
82 
83 #ifdef _WIN32
84 /* return the device path for given windows device */
85 static std::string getDevicePath(HDEVINFO hDevInfo, SP_DEVINFO_DATA* DeviceInfoData)
86 {
87  char deviceInstanceID[MAX_DEVICE_ID_LEN];
88  SetupDiGetDeviceInstanceIdA(hDevInfo, DeviceInfoData, deviceInstanceID, MAX_DEVICE_ID_LEN, NULL);
89  return std::string(deviceInstanceID);
90 }
91 
92 
93 /* Get the first match for _regex_ within _devpath_ */
94 static inline std::string searchOne(std::string const& devpath, std::string const& regex)
95 {
96  std::smatch sm;
97  std::regex_search(devpath, sm, std::regex(regex));
98  if (sm.size() < 2)
99  return std::string();
100  return sm[1];
101 }
102 
103 /* Fetch the vendor ID from the given device path */
104 static inline uint16_t vidFromDevPath(std::string const& devpath)
105 {
106  try
107  {
108  auto t1 = searchOne(devpath, "VID_([0-9a-fA-F]{4}).*PID_.*");
109  if (t1.empty()) // prevent unnecessary exceptions
110  return 0;
111  return static_cast<uint16_t>(std::stoi(t1, nullptr, 16));
112  }
113  catch (std::invalid_argument&)
114  {
115  return 0;
116  }
117 }
118 
119 /* Fetch the product ID from the given device path */
120 static inline uint16_t pidFromDevPath(std::string const& devpath)
121 {
122  try
123  {
124  auto t1 = searchOne(devpath, "VID_.*PID_([0-9a-fA-F]{4})");
125  if (t1.empty()) // prevent unnecessary exceptions
126  return 0;
127  return static_cast<uint16_t>(std::stoi(t1, nullptr, 16));
128  }
129  catch (std::invalid_argument&)
130  {
131  return 0;
132  }
133 }
134 #endif
135 
146 {
147  XsPortInfo current;
148 #ifdef USE_WINUSB
149  BOOL bResult = FALSE;
150  ULONG length;
151  ULONG requiredLength = 0;
152 
153  // {FD51225C-700A-47e5-9999-B2D9031B88ED}
154  GUID guid = { 0xfd51225c, 0x700a, 0x47e5, { 0x99, 0x99, 0xb2, 0xd9, 0x3, 0x1b, 0x88, 0xed } };
155 
156  HDEVINFO deviceInfo;
157  SP_DEVICE_INTERFACE_DATA interfaceData;
158  PSP_DEVICE_INTERFACE_DETAIL_DATA_A detailData = NULL;
159 
160  deviceInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
161 
162  // Initialize variables.
163  interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
164  for (DWORD dwIndex = 0; true; ++dwIndex) //lint !e774 !e440 !e506
165  {
166  BOOL bRet = SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &guid, dwIndex, &interfaceData);
167  if (!bRet)
168  {
169  if (GetLastError() == ERROR_NO_MORE_ITEMS)
170  break;
171  }
172  else
173  {
174  if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL))
175  {
176  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
177  {
178  SetupDiDestroyDeviceInfoList(deviceInfo);
179  return false;
180  }
181  }
182  detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)LocalAlloc(LMEM_FIXED, requiredLength);
183  if (NULL == detailData)
184  {
185  SetupDiDestroyDeviceInfoList(deviceInfo);
186  return false;
187  }
188 
189  detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
190  length = requiredLength;
191  SP_DEVINFO_DATA DevInfoData;
192  DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
193  bResult = SetupDiGetDeviceInterfaceDetailA(deviceInfo, &interfaceData, detailData, length, &requiredLength, &DevInfoData);
194 
195  if (!bResult)
196  {
197  LocalFree(detailData);
198  SetupDiDestroyDeviceInfoList(deviceInfo);
199  return false;
200  }
201 
202  unsigned char serialNumber[256];
203  char* ptrEnd, *ptrStart = strchr(detailData->DevicePath, '#');
204  if (!ptrStart)
205  continue;
206  ptrStart = strchr(ptrStart + 1, '#');
207  if (!ptrStart)
208  continue;
209  ptrEnd = strchr(ptrStart + 1, '#');
210  if (!ptrEnd)
211  continue;
212 
213  size_t ln = (size_t)((ptrEnd - ptrStart) - 1);
214  strncpy((char*)serialNumber, ptrStart + 1, ln);
215  serialNumber[ln] = '\0';
216 
217  current.setPortName(detailData->DevicePath);
218 
219  unsigned int id = 0;
220  sscanf((const char*)serialNumber, "%X", &id);
221  current.setDeviceId((uint32_t) id);
222 
223  std::string devpath = getDevicePath(deviceInfo, &DevInfoData);
224  uint16_t vid = vidFromDevPath(devpath);
225  uint16_t pid = pidFromDevPath(devpath);
226  current.setVidPid(vid, pid);
227 
228  ports.push_back(current);
229  }
230  }
231 
232  SetupDiDestroyDeviceInfoList(deviceInfo);
233  return true;
234 #elif defined(HAVE_LIBUSB)
235  XsLibUsb libUsb;
236  libusb_context* context;
237  int result = libUsb.init(&context);
238  if (result != LIBUSB_SUCCESS)
239  return true;
240 
241  libusb_device** deviceList;
242  ssize_t deviceCount = libUsb.get_device_list(context, &deviceList);
243  for (ssize_t i = 0; i < deviceCount; i++)
244  {
245  libusb_device* device = deviceList[i];
246  libusb_device_descriptor desc;
247  result = libUsb.get_device_descriptor(device, &desc);
248  if (result != LIBUSB_SUCCESS)
249  continue;
250 
251  if (desc.idVendor != XSENS_VENDOR_ID)
252  continue;
253 
254  libusb_device_handle* handle;
255  result = libUsb.open(device, &handle);
256  if (result != LIBUSB_SUCCESS)
257  continue;
258 
259  unsigned char serialNumber[256];
260  result = libUsb.get_string_descriptor_ascii(handle, desc.iSerialNumber, serialNumber, 256);
261 
262  libusb_config_descriptor* configDesc;
263  result = libUsb.get_active_config_descriptor(device, &configDesc);
264  if (result != LIBUSB_SUCCESS)
265  {
266  libUsb.close(handle);
267  continue;
268  }
269 
270  bool kernelActive = false;
271  for (uint8_t ifCount = 0; ifCount < configDesc->bNumInterfaces; ++ifCount)
272  {
273  int res = libUsb.kernel_driver_active(handle, ifCount);
274  kernelActive |= (res == 1);
275  }
276 
277  libUsb.free_config_descriptor(configDesc);
278 
279  if (!kernelActive)
280  {
281  char name[256];
282  sprintf(name, "USB%03u:%03u", libUsb.get_bus_number(device),
283  libUsb.get_device_address(device));
284  current.setPortName(name);
285 
286  int id = 0;
287  sscanf((const char*)serialNumber, "%X", &id);
288  current.setDeviceId((uint32_t) id);
289  current.setVidPid(desc.idVendor, desc.idProduct);
290  ports.push_back(current);
291  }
292  else
293  {
294  JLDEBUGG("Kernel driver active on USB" <<
295  libUsb.get_bus_number(device) << ":" << libUsb.get_device_address(device) <<
296  " device " << serialNumber);
297 
298  }
299  libUsb.close(handle);
300  }
301  libUsb.free_device_list(deviceList, 1);
302  libUsb.exit(context);
303  return true;
304 #else
305  (void)ports;
306  return true;
307 #endif
308 }
searchOne
static std::string searchOne(std::string const &string, std::string const &regex)
Definition: idfetchhelpers.h:75
XSENS_VENDOR_ID
#define XSENS_VENDOR_ID
Definition: xsportinfo.h:75
xslibusb.h
enumerateusbdevices.h
uint32_t
unsigned int uint32_t
Definition: pstdint.h:485
XsPortInfo
Contains a descriptor for opening a communication port to an Xsens device.
Definition: xsportinfo.h:128
xsEnumerateUsbDevices
bool xsEnumerateUsbDevices(XsPortInfoArray &ports)
Enumerate Xsens USB devices.
Definition: enumerateusbdevices.cpp:145
XsPortInfoArray
A list of XsPortInfo values.
BOOL
int BOOL
Definition: xstypedefs.h:141
JLDEBUGG
#define JLDEBUGG(msg)
Definition: journaller.h:280
length
TF2SIMD_FORCE_INLINE tf2Scalar length(const Quaternion &q)
xscontrollerconfig.h


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