UsbDevice.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2014-2020, Dataspeed Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Dataspeed Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "lusb/UsbDevice.h"
36 #include <libusb-1.0/libusb.h>
37 
38 using namespace std;
39 
40 namespace lusb
41 {
42 
43 static inline UsbDevice::Location locationFromLibUsbDevice(libusb_device *dev, const libusb_device_descriptor desc) {
44  return UsbDevice::Location(libusb_get_bus_number(dev),
45  libusb_get_port_number(dev),
46  libusb_get_device_address(dev),
47  desc.idVendor,
48  desc.idProduct);
49 }
50 
51 bool UsbDevice::handleError(int err)
52 {
53  bool success;
54  switch ((libusb_error)err) {
55  case LIBUSB_SUCCESS:
56  success = true;
57  break;
58  case LIBUSB_ERROR_TIMEOUT:
59  success = false;
60  break;
61  case LIBUSB_ERROR_BUSY:
62  case LIBUSB_ERROR_OVERFLOW:
63  case LIBUSB_ERROR_INVALID_PARAM:
64  case LIBUSB_ERROR_INTERRUPTED:
65  case LIBUSB_ERROR_NO_MEM:
66  case LIBUSB_ERROR_PIPE:
67  throwError(err);
68  success = false;
69  break;
70  case LIBUSB_ERROR_IO:
71  case LIBUSB_ERROR_ACCESS:
72  case LIBUSB_ERROR_NO_DEVICE:
73  case LIBUSB_ERROR_NOT_FOUND:
74  case LIBUSB_ERROR_NOT_SUPPORTED:
75  case LIBUSB_ERROR_OTHER:
76  default:
77  closeDevice();
78  throwError(err);
79  success = false;
80  break;
81  }
82  return success;
83 }
84 void UsbDevice::throwError(int err)
85 {
86  error_code_ = (libusb_error)err;
87  error_str_ = libusb_error_name(err);
88  if (throw_errors_) {
89  throw lusb::UsbDeviceException((libusb_error)err, error_str_.c_str());
90  }
91 }
92 int UsbDevice::getLastError(std::string &str) const
93 {
94  str = error_str_;
95  return error_code_;
96 }
97 void UsbDevice::setDebugLevel(uint8_t level)
98 {
99  if (level > LIBUSB_LOG_LEVEL_DEBUG) {
100  level = LIBUSB_LOG_LEVEL_DEBUG;
101  }
102 #if LIBUSB_API_VERSION >= 0x01000107
103  libusb_set_option(ctx_, LIBUSB_OPTION_LOG_LEVEL, level);
104 #else
105  libusb_set_debug(ctx_, level);
106 #endif
107 }
108 
109 void UsbDevice::init()
110 {
111  open_ = false;
112  location_ = Location();
113  libusb_handle_ = NULL;
114  throw_errors_ = false;
115  memset(bulk_threads_enable_, 0x00, sizeof(bulk_threads_enable_));
116  memset(interrupt_threads_enable_, 0x00, sizeof(interrupt_threads_enable_));
117  ctx_ = NULL;
118  libusb_init(&ctx_);
119 #if LIBUSB_API_VERSION >= 0x01000107
120  libusb_set_option(ctx_, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
121 #else
122  libusb_set_debug(ctx_, LIBUSB_LOG_LEVEL_NONE);
123 #endif
124 }
125 
126 UsbDevice::UsbDevice(uint16_t vid, uint16_t pid, uint8_t mi)
127 {
128  init();
129  setDevceIds(vid, pid, mi);
130 }
131 UsbDevice::UsbDevice(uint16_t vid, uint16_t pid)
132 {
133  init();
134  setDevceIds(vid, pid, 0x00);
135 }
136 UsbDevice::UsbDevice()
137 {
138  init();
139  setDevceIds(0x0000, 0x0000, 0x00);
140 }
141 UsbDevice::~UsbDevice()
142 {
143  close();
144  if (ctx_) {
145  libusb_exit(ctx_);
146  ctx_ = NULL;
147  }
148 }
149 
150 void UsbDevice::setDevceIds(uint16_t vid, uint16_t pid, uint8_t mi)
151 {
152  pid_ = pid;
153  vid_ = vid;
154  mi_ = mi;
155 }
156 
157 void UsbDevice::listDevices(uint16_t vid, uint16_t pid, std::vector<Location> &vec)
158 {
159  const std::vector<UsbIds> ids(1, UsbIds(vid, pid));
160  listDevices(ids, vec);
161 }
162 
163 void UsbDevice::listDevices(const std::vector<UsbIds> &ids, std::vector<Location> &vec)
164 {
165  vec.clear();
166 
167  libusb_context *ctx = NULL;
168  libusb_init(&ctx);
169 #if LIBUSB_API_VERSION >= 0x01000107
170  libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
171 #else
172  libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_NONE);
173 #endif
174 
175  libusb_device **list;
176  ssize_t cnt = libusb_get_device_list(ctx, &list);
177  if (cnt > 0) {
178  for (ssize_t i = 0; i < cnt; i++) {
179  libusb_device *device = list[i];
180  struct libusb_device_descriptor desc;
181  if (libusb_get_device_descriptor(device, &desc) == LIBUSB_SUCCESS) {
182  for (size_t i = 0; i < ids.size(); i++) {
183  if ((!ids[i].vid || ids[i].vid == desc.idVendor) && (!ids[i].pid || ids[i].pid == desc.idProduct)) {
184  vec.push_back(locationFromLibUsbDevice(device, desc));
185  break;
186  }
187  }
188  }
189  }
190  }
191  libusb_free_device_list(list, 1);
192 
193  libusb_exit(ctx);
194 }
195 
196 void UsbDevice::listDevices(std::vector<Location> &vec) const
197 {
198  listDevices(vid_, pid_, vec);
199 }
200 
201 bool UsbDevice::open(const Location &location)
202 {
203  closeDevice();
204 
205  libusb_device **list;
206  ssize_t cnt = libusb_get_device_list(ctx_, &list);
207  ssize_t i = 0;
208  if (cnt > 0) {
209  for (i = 0; i < cnt; i++) {
210  libusb_device *device = list[i];
211  struct libusb_device_descriptor desc;
212  if (libusb_get_device_descriptor(device, &desc) == LIBUSB_SUCCESS) {
213  if ((!vid_ || vid_ == desc.idVendor) && (!pid_ || pid_ == desc.idProduct)) {
214  Location loc = locationFromLibUsbDevice(device, desc);
215  if (location.match(loc)) {
216  libusb_device_handle *handle;
217  if (libusb_open(device, &handle) == LIBUSB_SUCCESS) {
218  if (libusb_kernel_driver_active(handle, mi_) == 1) {
219  libusb_detach_kernel_driver(handle, mi_);
220  }
221  if (libusb_claim_interface(handle, mi_) == LIBUSB_SUCCESS) {
222  location_ = loc;
223  libusb_handle_ = handle;
224  open_ = true;
225  break;
226  }
227  libusb_close(handle);
228  }
229  }
230  }
231  }
232  }
233  }
234 
235  libusb_free_device_list(list, 1);
236  return open_;
237 }
238 
239 void UsbDevice::close()
240 {
241  for (int i = 0; i < 128; i++) {
242  bulk_threads_enable_[i] = false;
243  interrupt_threads_enable_[i] = false;
244  }
245  closeDevice();
246 }
247 
248 void UsbDevice::closeDevice()
249 {
250  if (open_) {
251  open_ = false;
252  if (libusb_handle_) {
253  libusb_release_interface(libusb_handle_, 0);
254  libusb_close(libusb_handle_);
255  }
256  }
257  libusb_handle_ = NULL;
258 }
259 
260 bool UsbDevice::bulkWrite(const void * data, int size, unsigned char endpoint, int timeout)
261 {
262  if ((libusb_handle_ == NULL) || !open_) {
263  return false;
264  }
265  int actual = 0;
266  int err = libusb_bulk_transfer(libusb_handle_, endpoint & ~LIBUSB_ENDPOINT_IN, (unsigned char *)data, size, &actual,
267  timeout);
268  bool success;
269  success = handleError(err);
270  success &= size == actual;
271  return success;
272 }
273 int UsbDevice::bulkRead(void * data, int size, unsigned char endpoint, int timeout)
274 {
275  if ((libusb_handle_ == NULL) || !open_) {
276  return -1;
277  }
278  int actual = 0;
279  int err = libusb_bulk_transfer(libusb_handle_, endpoint | LIBUSB_ENDPOINT_IN, (unsigned char *)data, size, &actual,
280  timeout);
281  return handleError(err) ? actual : -1;
282 }
283 bool UsbDevice::interruptWrite(const void * data, int size, unsigned char endpoint, int timeout)
284 {
285  if ((libusb_handle_ == NULL) || !open_) {
286  return false;
287  }
288  int actual = 0;
289  int err = libusb_interrupt_transfer(libusb_handle_, endpoint & ~LIBUSB_ENDPOINT_IN, (unsigned char *)data, size,
290  &actual, timeout);
291  bool success;
292  success = handleError(err);
293  success &= size == actual;
294  return success;
295 }
296 int UsbDevice::interruptRead(void * data, int size, unsigned char endpoint, int timeout)
297 {
298  if ((libusb_handle_ == NULL) || !open_) {
299  return -1;
300  }
301  int actual = 0;
302  int err = libusb_interrupt_transfer(libusb_handle_, endpoint | LIBUSB_ENDPOINT_IN, (unsigned char *)data, size,
303  &actual, timeout);
304  return handleError(err) ? actual : -1;
305 }
306 
307 void UsbDevice::bulkReadThread(Callback callback, unsigned char endpoint)
308 {
309  endpoint &= 0x7F;
310  int size;
311  char data[1024];
312  while (bulk_threads_enable_[endpoint]) {
313  if (open_) {
314  size = bulkRead(data, sizeof(data), endpoint, 100);
315  if (size > 0) {
316  callback(data, size);
317  }
318  } else {
319  bulk_threads_enable_[endpoint] = 0;
320  return;
321  }
322  }
323 }
324 void UsbDevice::interruptReadThread(Callback callback, unsigned char endpoint)
325 {
326  endpoint &= 0x7F;
327  int size;
328  char data[1024];
329  while (interrupt_threads_enable_[endpoint]) {
330  if (open_) {
331  size = interruptRead(data, sizeof(data), endpoint, 100);
332  if (size > 0) {
333  callback(data, size);
334  }
335  } else {
336  interrupt_threads_enable_[endpoint] = false;
337  return;
338  }
339  }
340 }
341 
342 void UsbDevice::stopBulkReadThread(unsigned char endpoint)
343 {
344  endpoint &= 0x7F;
345  bulk_threads_enable_[endpoint] = false;
346  if (bulk_threads_[endpoint].joinable()) {
347  bulk_threads_[endpoint].join();
348  }
349 }
350 void UsbDevice::startBulkReadThread(Callback callback, unsigned char endpoint)
351 {
352  endpoint &= 0x7F;
353  stopBulkReadThread(endpoint);
354  bulk_threads_enable_[endpoint] = true;
355  bulk_threads_[endpoint] = boost::thread(&UsbDevice::bulkReadThread, this, callback, endpoint);
356 }
357 void UsbDevice::stopInterruptReadThread(unsigned char endpoint)
358 {
359 
360  endpoint &= 0x7F;
361  interrupt_threads_enable_[endpoint] = false;
362  if (interrupt_threads_[endpoint].joinable()) {
363  interrupt_threads_[endpoint].join();
364  }
365 }
366 void UsbDevice::startInterruptReadThread(Callback callback, unsigned char endpoint)
367 {
368  endpoint &= 0x7F;
369  stopBulkReadThread(endpoint);
370  interrupt_threads_enable_[endpoint] = true;
371  interrupt_threads_[endpoint] = boost::thread(&UsbDevice::interruptReadThread, this, callback, endpoint);
372 }
373 
374 } //namespace lusb
Definition: UsbDevice.h:46
static bool match(const Location &a, const Location &b)
Definition: UsbDevice.h:82
static UsbDevice::Location locationFromLibUsbDevice(libusb_device *dev, const libusb_device_descriptor desc)
Definition: UsbDevice.cpp:43
boost::function< void(const void *data, int size)> Callback
Definition: UsbDevice.h:137


lusb
Author(s): Kevin Hallenbeck
autogenerated on Fri Dec 11 2020 03:47:26