Main MRPT website > C++ reference for MRPT 1.9.9
CInterfaceFTDI_LIN.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include <mrpt/config.h>
11 
12 #include <mrpt/utils/utils_defs.h>
13 #include <cstring>
14 
15 using namespace mrpt;
16 using namespace mrpt::utils;
17 
18 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
19 
20 #if MRPT_HAS_FTDI
21 #include <ftdi.h>
22 #if MRPT_FTDI_VERSION >= 0x120
23 #include <libusb-1.0/libusb.h>
24 #else
25 #include <usb.h>
26 #endif
27 #endif
28 
30 
31 #include <iostream>
32 
33 using namespace mrpt::comms;
34 using namespace std;
35 
36 /*-------------------------------------------------------------
37  CInterfaceFTDI
38 -------------------------------------------------------------*/
39 CInterfaceFTDI::CInterfaceFTDI() : m_readBuffer(4096)
40 {
42 
43 #if MRPT_HAS_FTDI
44  // Alloc mem:
45  ftdi_context* newCtx = new ftdi_context[1];
46  ASSERT_(newCtx);
47 
48  // Init:
49  int ret = ftdi_init(newCtx);
50  if (ret) THROW_EXCEPTION("There was a problem initializing ftdi_context.");
51 
52  // Save in member:
53  m_ftdi_context = static_cast<void*>(newCtx);
54 #else
56  "MRPT has been compiled without FTDI support. Please, reconfigure and "
57  "recompile MRPT.")
58 #endif
59 
60 #if MRPT_FTDI_VERSION >= 0x120
61  libusb_init(nullptr);
62 #endif
64 }
65 
66 /*-------------------------------------------------------------
67  ~CInterfaceFTDI
68 -------------------------------------------------------------*/
70 {
71 #if MRPT_HAS_FTDI
72  // Close USB:
73  if (isOpen()) Close();
74  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
75 
76  // Close context:
77  ftdi_deinit(ctx);
78 
79  // Free mem:
80  delete[] ctx;
81  ctx = nullptr;
82 #endif
83 #if MRPT_FTDI_VERSION >= 0x120
84  libusb_exit(nullptr);
85 #endif
86 }
87 
88 /** This object cannot be copied */
89 CInterfaceFTDI::CInterfaceFTDI(const CInterfaceFTDI&) : m_readBuffer(4096)
90 {
92  THROW_EXCEPTION("This object cannot be copied");
94 }
96 {
98  THROW_EXCEPTION("This object cannot be copied");
100 }
101 
102 /*-------------------------------------------------------------
103  OpenBySerialNumber
104 -------------------------------------------------------------*/
105 void CInterfaceFTDI::OpenBySerialNumber(const std::string& serialNumber)
106 {
107 #if MRPT_HAS_FTDI
109 
111 
112  // Close previous connection:
113  Close();
114 
115  // ftdi_usb_open_desc ...
116 
117  // Create a list of all the devices:
118  TFTDIDeviceList lstDevs;
119  ListAllDevices(lstDevs);
120 
121  // Look for the one we want:
122  void* myDev = nullptr;
123 
124  for (TFTDIDeviceList::iterator it = lstDevs.begin(); it != lstDevs.end();
125  ++it)
126  {
127  if (it->ftdi_serial == serialNumber)
128  {
129  myDev = it->usb_device_struct;
130  break;
131  }
132  }
133 
134  if (!myDev)
136  "USB device with serial number '%s' not found.",
137  serialNumber.c_str());
138 
139  // Open it:
140  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
141 
142  int ret = ftdi_usb_open_dev(
143  ctx,
144 #if MRPT_FTDI_VERSION >= 0x120
145  (struct libusb_device*)myDev
146 #else
147  (struct usb_device*)myDev
148 #endif
149  );
150 
151  if (ret) THROW_EXCEPTION(string(ftdi_get_error_string(ctx)));
152 
154 #else
155  MRPT_UNUSED_PARAM(serialNumber);
156 #endif
157 }
158 
159 /*-------------------------------------------------------------
160  ListAllDevices
161 -------------------------------------------------------------*/
163 {
165 #if MRPT_HAS_FTDI
166 
167  outList.clear();
168 
169 #if MRPT_FTDI_VERSION >= 0x120
170  // For new libftdi1-dev
171  // Use libusb-1.0
172 
173  libusb_device** list;
174  ssize_t nDevices = libusb_get_device_list(nullptr, &list);
175 
176  for (unsigned int i = 0; i < nDevices; i++)
177  {
178  libusb_device* device = list[i];
179  struct libusb_device_descriptor desc;
180  if (0 != libusb_get_device_descriptor(device, &desc)) continue;
181  if (!desc.idVendor) continue;
182 
183  TFTDIDevice newEntry;
184  newEntry.usb_device_struct = (void*)device;
185  newEntry.usb_idProduct = desc.idProduct;
186  newEntry.usb_idVendor = desc.idVendor;
187  newEntry.usb_serialNumber = desc.iSerialNumber;
188 
189  // Open the device temporally so we can get more info:
190  libusb_device_handle* handle;
191  if (0 != libusb_open(device, &handle)) continue;
192 
193  char buf[1024];
194  int ret;
195  // manufacturer
196  ret = libusb_get_string_descriptor_ascii(
197  handle, desc.iManufacturer, (unsigned char*)buf, sizeof(buf) - 1);
198  if (ret < 0) continue;
199  buf[ret] = '\0';
200  newEntry.ftdi_manufacturer = buf;
201 
202  // description
203  ret = libusb_get_string_descriptor_ascii(
204  handle, desc.iProduct, (unsigned char*)buf, sizeof(buf) - 1);
205  if (ret < 0) continue;
206  buf[ret] = '\0';
207  newEntry.ftdi_description = buf;
208 
209  // serial
210  ret = libusb_get_string_descriptor_ascii(
211  handle, desc.iSerialNumber, (unsigned char*)buf, sizeof(buf) - 1);
212  if (ret < 0) continue;
213  buf[ret] = '\0';
214  newEntry.ftdi_serial = buf;
215 
216  outList.push_back(newEntry);
217  }
218 
219 #else
220  // For old libftdi-dev
221  // Use old usb.h interface
222  struct usb_bus* bus;
223  struct usb_device* dev;
224 
225  usb_init();
226  if (usb_find_busses() < 0) THROW_EXCEPTION("usb_find_busses() failed");
227  if (usb_find_devices() < 0) THROW_EXCEPTION("usb_find_devices() failed");
228 
229  for (bus = usb_busses; bus; bus = bus->next)
230  for (dev = bus->devices; dev; dev = dev->next)
232  dev, outList); // Process this node and its children:
233 
234 #endif
235  if (getenv("VERBOSE") != nullptr)
236  {
237  printf("[CInterfaceFTDI::ListAllDevices] List: \n");
238  for (std::deque<TFTDIDevice>::const_iterator i = outList.begin();
239  i != outList.end(); ++i)
240  printf(
241  "USB DEV: V=%04X P=%04X S=%s\n", i->usb_idVendor,
242  i->usb_idProduct, i->ftdi_serial.c_str());
243  }
244 
245 #else
246  MRPT_UNUSED_PARAM(outList);
247 #endif
249 }
250 
252  void* usb_device_structure, TFTDIDeviceList& outList)
253 {
254 #if MRPT_HAS_FTDI
255 #if MRPT_FTDI_VERSION >= 0x120
256  // For new libftdi1-dev
257  throw std::runtime_error("Should not have got to this function!");
258 #else
259  // For old libftdi-dev
260  struct usb_device* dev = (struct usb_device*)usb_device_structure;
261 
262  if (dev->descriptor.idProduct && dev->descriptor.idVendor)
263  {
264  TFTDIDevice newEntry;
265  newEntry.usb_idProduct = dev->descriptor.idProduct;
266  newEntry.usb_idVendor = dev->descriptor.idVendor;
267  newEntry.usb_device_struct = (void*)dev;
268 
269  int strLen;
270 
271  // Open the device temporally so we can get more info:
272  usb_dev_handle* hUSB = usb_open(dev);
273 
274  if (hUSB)
275  {
276  char manufacturer[3000];
277  if ((strLen = usb_get_string_simple(
278  hUSB, dev->descriptor.iManufacturer, manufacturer,
279  sizeof(manufacturer))) <= 0)
280  {
281  cerr << "Couldn't open " << (int)dev->descriptor.iManufacturer
282  << endl;
283  // usb_close(hUSB); hUSB=nullptr;
284  }
285  else
286  {
287  manufacturer[strLen] = '\0';
288  // cout << "Manuf: " << manufacturer << endl;
289  newEntry.ftdi_manufacturer = manufacturer;
290  }
291  }
292 
293  if (hUSB)
294  {
295  char description[3000];
296  if ((strLen = usb_get_string_simple(
297  hUSB, dev->descriptor.iProduct, description,
298  sizeof(description))) <= 0)
299  {
300  // usb_close(hUSB); hUSB=nullptr;
301  }
302  else
303  {
304  description[strLen] = '\0';
305  newEntry.ftdi_description = description;
306  }
307  }
308 
309  if (hUSB)
310  {
311  char serial[300];
312  if ((strLen = usb_get_string_simple(
313  hUSB, dev->descriptor.iSerialNumber, serial,
314  sizeof(serial))) <= 0)
315  {
316  // usb_close(hUSB); hUSB=nullptr;
317  }
318  else
319  {
320  serial[strLen] = '\0';
321  newEntry.ftdi_serial = serial;
322  }
323  }
324 
325  if (hUSB)
326  {
327  outList.push_back(newEntry);
328  usb_close(hUSB);
329  }
330 
331  // And now its children:
332  // -----------------------------------
333  for (unsigned char j = 0; j < dev->num_children; j++)
334  recursive_fill_list_devices((void*)dev->children[j], outList);
335  }
336 #endif
337 #else
338  MRPT_UNUSED_PARAM(usb_device_structure);
339  MRPT_UNUSED_PARAM(outList);
340 #endif
341 }
342 
343 /*-------------------------------------------------------------
344  ftdi_read
345 -------------------------------------------------------------*/
347  void* lpvBuffer, unsigned long dwBuffSize, unsigned long* lpdwBytesRead)
348 {
349 #if MRPT_HAS_FTDI
351  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
352 
353  int ret = ftdi_read_data(ctx, (unsigned char*)lpvBuffer, dwBuffSize);
354  if (ret >= 0)
355  *lpdwBytesRead = ret;
356  else
357  {
358  if (!strcmp("usb bulk read failed", ctx->error_str))
359  {
360  *lpdwBytesRead = 0;
361  return;
362  }
363  THROW_EXCEPTION(string(ftdi_get_error_string(ctx)));
364  }
365 
367 #else
368  MRPT_UNUSED_PARAM(lpvBuffer);
369  MRPT_UNUSED_PARAM(dwBuffSize);
370  MRPT_UNUSED_PARAM(lpdwBytesRead);
371 #endif
372 }
373 
374 /*-------------------------------------------------------------
375  ftdi_write
376 -------------------------------------------------------------*/
378  const void* lpvBuffer, unsigned long dwBuffSize, unsigned long* lpdwBytes)
379 {
380 #if MRPT_HAS_FTDI
382  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
383 
384  int ret = ftdi_write_data(ctx, (unsigned char*)lpvBuffer, dwBuffSize);
385  if (ret >= 0)
386  *lpdwBytes = ret;
387  else
388  THROW_EXCEPTION(string(ftdi_get_error_string(ctx)));
389 
391 #else
392  MRPT_UNUSED_PARAM(lpvBuffer);
393  MRPT_UNUSED_PARAM(dwBuffSize);
394  MRPT_UNUSED_PARAM(lpdwBytes);
395 #endif
396 }
397 
398 /*-------------------------------------------------------------
399  isOpen
400 -------------------------------------------------------------*/
402 {
403 #if MRPT_HAS_FTDI
404  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
405  return ctx->usb_dev != nullptr;
406 #else
407  return false;
408 #endif
409 }
410 
411 /*-------------------------------------------------------------
412  Close
413 -------------------------------------------------------------*/
415 {
416 #if MRPT_HAS_FTDI
417  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
418  if (ctx->usb_dev)
419  {
420  ftdi_usb_close(ctx);
421  ctx->usb_dev = nullptr;
422  }
423 
424  // To assure this is as a "reset", re-init the ftdi context again:
425  ftdi_deinit(ctx);
426  ftdi_init(ctx);
427 
429 #endif
430 }
431 
432 /*-------------------------------------------------------------
433  ResetDevice
434 -------------------------------------------------------------*/
436 {
437 #if MRPT_HAS_FTDI
438  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
439  ASSERT_(ctx->usb_dev);
440 
441  if (ftdi_usb_reset(ctx) < 0) THROW_EXCEPTION("Error resetting device");
442 
444 #endif
445 }
446 
447 /*-------------------------------------------------------------
448  Purge
449 -------------------------------------------------------------*/
451 {
452 #if MRPT_HAS_FTDI
453  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
454  ASSERT_(ctx->usb_dev);
455 
456  if (ftdi_usb_purge_buffers(ctx) < 0)
457  THROW_EXCEPTION("Error purging device buffers");
458 
460 #endif
461 }
462 
463 /*-------------------------------------------------------------
464  SetLatencyTimer
465 -------------------------------------------------------------*/
466 void CInterfaceFTDI::SetLatencyTimer(unsigned char latency_ms)
467 {
468 #if MRPT_HAS_FTDI
469  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
470  ASSERT_(ctx->usb_dev);
471 
472  if (ftdi_set_latency_timer(ctx, latency_ms) < 0)
473  THROW_EXCEPTION("Error setting latency timer");
474 #else
475  MRPT_UNUSED_PARAM(latency_ms);
476 #endif
477 }
478 
479 /*-------------------------------------------------------------
480  SetTimeouts
481 -------------------------------------------------------------*/
483  unsigned long dwReadTimeout_ms, unsigned long dwWriteTimeout_ms)
484 {
485 #if MRPT_HAS_FTDI
486  ftdi_context* ctx = static_cast<ftdi_context*>(m_ftdi_context);
487  ASSERT_(ctx->usb_dev);
488 
489 // JL: It seems it works worse with timeouts...
490 // ctx->usb_read_timeout = dwReadTimeout_ms;
491 // ctx->usb_write_timeout = dwWriteTimeout_ms;
492 #else
493  MRPT_UNUSED_PARAM(dwReadTimeout_ms);
494  MRPT_UNUSED_PARAM(dwWriteTimeout_ms);
495 #endif
496 }
497 
498 /*-------------------------------------------------------------
499  OpenByDescription
500 -------------------------------------------------------------*/
501 std::ostream& mrpt::comms::operator<<(std::ostream& o, const TFTDIDevice& d)
502 {
503  o << "Manufacturer : " << d.ftdi_manufacturer << endl
504  << "Description : " << d.ftdi_description << endl
505  << "FTDI serial : " << d.ftdi_serial << endl
506  << "USB ID (Vendor/Product) : "
507  << format("%04X / %04X", d.usb_idVendor, d.usb_idProduct) << endl
508  << "USB serial : " << d.usb_serialNumber << endl;
509 
510  return o;
511 }
512 
513 #endif
bool isOpen()
Checks whether the chip has been successfully open.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
void ResetDevice()
Reset the USB device.
void clear()
Delete all the stored data, if any.
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Scalar * iterator
Definition: eigen_plugins.h:26
void OpenBySerialNumber(const std::string &serialNumber)
Open by device serial number.
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
void recursive_fill_list_devices(void *usb_device_structure, TFTDIDeviceList &outList)
Process recursively a USB device and its children:
void Close()
Close the USB device.
mrpt::utils::circular_buffer< uint8_t > m_readBuffer
Used in Read.
#define MRPT_TRY_END
void SetTimeouts(unsigned long dwReadTimeout_ms, unsigned long dwWriteTimeout_ms)
Change read & write timeouts, in milliseconds.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
void ListAllDevices(TFTDIDeviceList &outList)
Generates a list with all FTDI devices connected right now.
GLsizei const GLchar ** string
Definition: glext.h:4101
std::deque< TFTDIDevice > TFTDIDeviceList
Used in CInterfaceFTDI::ListAllDevices.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
CInterfaceFTDI & operator=(const CInterfaceFTDI &o)
This object cannot be copied.
std::ostream & operator<<(std::ostream &o, const TFTDIDevice &d)
Print out all the information of a FTDI device in textual form.
A definition of a CStream actually representing a USB connection to a FTDI chip.
CInterfaceFTDI()
Constructor, which loads driver interface (the DLL under Windows).
#define MRPT_TRY_START
#define ASSERT_(f)
void ftdi_read(void *lpvBuffer, unsigned long dwBuffSize, unsigned long *lpdwBytesRead)
void Purge()
Purge the I/O buffers.
void ftdi_write(const void *lpvBuffer, unsigned long dwBuffSize, unsigned long *lpdwBytes)
Serial and networking devices and utilities.
virtual ~CInterfaceFTDI()
Destructor, which closes the connection with the chip and unloads the driver interface.
void SetLatencyTimer(unsigned char latency_ms)
Change the latency timer (in milliseconds) implemented on the FTDI chip: for a few ms...
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
Definition: CStream.cpp:597
A list of FTDI devices and their descriptors.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019