Don't #include <libusb.h> from ftdi.h
[libftdi] / ftdipp / ftdi.cpp
1 /***************************************************************************
2                           ftdi.cpp  -  C++ wraper for libftdi
3                              -------------------
4     begin                : Mon Oct 13 2008
5     copyright            : (C) 2008-2013 by Marek Vavruša / libftdi developers
6     email                : opensource@intra2net.com and marek@vavrusa.com
7  ***************************************************************************/
8 /*
9 Copyright (C) 2008-2013 by Marek Vavruša / libftdi developers
10
11 The software in this package is distributed under the GNU General
12 Public License version 2 (with a special exception described below).
13
14 A copy of GNU General Public License (GPL) is included in this distribution,
15 in the file COPYING.GPL.
16
17 As a special exception, if other files instantiate templates or use macros
18 or inline functions from this file, or you compile this file and link it
19 with other works to produce a work based on this file, this file
20 does not by itself cause the resulting work to be covered
21 by the GNU General Public License.
22
23 However the source code for this file must still be made available
24 in accordance with section (3) of the GNU General Public License.
25
26 This exception does not invalidate any other reasons why a work based
27 on this file might be covered by the GNU General Public License.
28 */
29 #include <libusb.h>
30 #include "ftdi.hpp"
31 #include "ftdi_i.h"
32 #include "ftdi.h"
33
34 namespace Ftdi
35 {
36
37 class Context::Private
38 {
39 public:
40     Private()
41             : open(false), ftdi(0), dev(0)
42     {
43         ftdi = ftdi_new();
44     }
45
46     ~Private()
47     {
48         if (open)
49             ftdi_usb_close(ftdi);
50
51         ftdi_free(ftdi);
52     }
53
54     bool open;
55
56     struct ftdi_context* ftdi;
57     struct libusb_device* dev;
58
59     std::string vendor;
60     std::string description;
61     std::string serial;
62 };
63
64 /*! \brief Constructor.
65  */
66 Context::Context()
67         : d( new Private() )
68 {
69 }
70
71 /*! \brief Destructor.
72  */
73 Context::~Context()
74 {
75 }
76
77 bool Context::is_open()
78 {
79     return d->open;
80 }
81
82 int Context::open(int vendor, int product)
83 {
84     // Open device
85     int ret = ftdi_usb_open(d->ftdi, vendor, product);
86
87     if (ret < 0)
88        return ret;
89
90     return get_strings_and_reopen();
91 }
92
93 int Context::open(int vendor, int product, const std::string& description, const std::string& serial, unsigned int index)
94 {
95     // translate empty strings to NULL
96     // -> do not use them to find the device (vs. require an empty string to be set in the EEPROM)
97     const char* c_description=NULL;
98     const char* c_serial=NULL;
99     if (!description.empty())
100         c_description=description.c_str();
101     if (!serial.empty())
102         c_serial=serial.c_str();
103
104     int ret = ftdi_usb_open_desc_index(d->ftdi, vendor, product, c_description, c_serial, index);
105
106     if (ret < 0)
107        return ret;
108
109     return get_strings_and_reopen();
110 }
111
112 int Context::open(const std::string& description)
113 {
114     int ret = ftdi_usb_open_string(d->ftdi, description.c_str());
115
116     if (ret < 0)
117        return ret;
118
119     return get_strings_and_reopen();
120 }
121
122 int Context::open(struct libusb_device *dev)
123 {
124     if (dev != 0)
125         d->dev = dev;
126
127     if (d->dev == 0)
128         return -1;
129
130     return get_strings_and_reopen();
131 }
132
133 int Context::close()
134 {
135     d->open = false;
136     d->dev = 0;
137     return ftdi_usb_close(d->ftdi);
138 }
139
140 int Context::reset()
141 {
142     return ftdi_usb_reset(d->ftdi);
143 }
144
145 int Context::flush(int mask)
146 {
147     int ret = 1;
148
149     if (mask & Input)
150         ret &= ftdi_usb_purge_rx_buffer(d->ftdi);
151     if (mask & Output)
152         ret &= ftdi_usb_purge_tx_buffer(d->ftdi);
153
154     return ret;
155 }
156
157 int Context::set_interface(enum ftdi_interface interface)
158 {
159     return ftdi_set_interface(d->ftdi, interface);
160 }
161
162 void Context::set_usb_device(struct libusb_device_handle *dev)
163 {
164     ftdi_set_usbdev(d->ftdi, dev);
165     d->dev = libusb_get_device(dev);
166 }
167
168 int Context::set_baud_rate(int baudrate)
169 {
170     return ftdi_set_baudrate(d->ftdi, baudrate);
171 }
172
173 int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
174 {
175     return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
176 }
177
178 int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type)
179 {
180     return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
181 }
182
183 int Context::read(unsigned char *buf, int size)
184 {
185     return ftdi_read_data(d->ftdi, buf, size);
186 }
187
188 int Context::set_read_chunk_size(unsigned int chunksize)
189 {
190     return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
191 }
192
193 int Context::read_chunk_size()
194 {
195     unsigned chunk = -1;
196     if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
197         return -1;
198
199     return chunk;
200 }
201
202 int Context::write(unsigned char *buf, int size)
203 {
204     return ftdi_write_data(d->ftdi, buf, size);
205 }
206
207 int Context::set_write_chunk_size(unsigned int chunksize)
208 {
209     return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
210 }
211
212 int Context::write_chunk_size()
213 {
214     unsigned chunk = -1;
215     if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
216         return -1;
217
218     return chunk;
219 }
220
221 int Context::set_flow_control(int flowctrl)
222 {
223     return ftdi_setflowctrl(d->ftdi, flowctrl);
224 }
225
226 int Context::set_modem_control(int mask)
227 {
228     int dtr = 0, rts = 0;
229
230     if (mask & Dtr)
231         dtr = 1;
232     if (mask & Rts)
233         rts = 1;
234
235     return ftdi_setdtr_rts(d->ftdi, dtr, rts);
236 }
237
238 int Context::set_dtr(bool state)
239 {
240     return ftdi_setdtr(d->ftdi, state);
241 }
242
243 int Context::set_rts(bool state)
244 {
245     return ftdi_setrts(d->ftdi, state);
246 }
247
248 int Context::set_latency(unsigned char latency)
249 {
250     return ftdi_set_latency_timer(d->ftdi, latency);
251 }
252
253 unsigned Context::latency()
254 {
255     unsigned char latency = 0;
256     ftdi_get_latency_timer(d->ftdi, &latency);
257     return latency;
258 }
259
260 unsigned short Context::poll_modem_status()
261 {
262     unsigned short status = 0;
263     ftdi_poll_modem_status(d->ftdi, &status);
264     return status;
265 }
266
267 int Context::set_event_char(unsigned char eventch, unsigned char enable)
268 {
269     return ftdi_set_event_char(d->ftdi, eventch, enable);
270 }
271
272 int Context::set_error_char(unsigned char errorch, unsigned char enable)
273 {
274     return ftdi_set_error_char(d->ftdi, errorch, enable);
275 }
276
277 int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
278 {
279     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
280 }
281
282 int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
283 {
284     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
285 }
286
287 int Context::bitbang_disable()
288 {
289     return ftdi_disable_bitbang(d->ftdi);
290 }
291
292 int Context::read_pins(unsigned char *pins)
293 {
294     return ftdi_read_pins(d->ftdi, pins);
295 }
296
297 char* Context::error_string()
298 {
299     return ftdi_get_error_string(d->ftdi);
300 }
301
302 int Context::get_strings()
303 {
304     // Prepare buffers
305     char vendor[512], desc[512], serial[512];
306
307     int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512);
308
309     if (ret < 0)
310         return -1;
311
312     d->vendor = vendor;
313     d->description = desc;
314     d->serial = serial;
315
316     return 1;
317 }
318
319 int Context::get_strings_and_reopen()
320 {
321     if ( d->dev == 0 )
322     {
323         d->dev = libusb_get_device(d->ftdi->usb_dev);
324     }
325
326     // Get device strings (closes device)
327     int ret=get_strings();
328     if (ret < 0)
329     {
330         d->open = 0;
331         return ret;
332     }
333
334     // Reattach device
335     ret = ftdi_usb_open_dev(d->ftdi, d->dev);
336     d->open = (ret >= 0);
337
338     return ret;
339 }
340
341 /*! \brief Device strings properties.
342  */
343 const std::string& Context::vendor()
344 {
345     return d->vendor;
346 }
347
348 /*! \brief Device strings properties.
349  */
350 const std::string& Context::description()
351 {
352     return d->description;
353 }
354
355 /*! \brief Device strings properties.
356  */
357 const std::string& Context::serial()
358 {
359     return d->serial;
360 }
361
362 void Context::set_context(struct ftdi_context* context)
363 {
364     ftdi_free(d->ftdi);
365     d->ftdi = context;
366 }
367
368 void Context::set_usb_device(struct libusb_device *dev)
369 {
370     d->dev = dev;
371 }
372
373 struct ftdi_context* Context::context()
374 {
375     return d->ftdi;
376 }
377
378 class Eeprom::Private
379 {
380 public:
381     Private()
382             : context(0)
383     {}
384
385     struct ftdi_eeprom eeprom;
386     struct ftdi_context* context;
387 };
388
389 Eeprom::Eeprom(Context* parent)
390         : d ( new Private() )
391 {
392     d->context = parent->context();
393 }
394
395 Eeprom::~Eeprom()
396 {
397 }
398
399 int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
400 {
401     return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
402 }
403
404 int Eeprom::chip_id(unsigned int *chipid)
405 {
406     return ftdi_read_chipid(d->context, chipid);
407 }
408
409 int Eeprom::build(unsigned char *output)
410 {
411     return ftdi_eeprom_build(d->context);
412 }
413
414 int Eeprom::read(unsigned char *eeprom)
415 {
416     return ftdi_read_eeprom(d->context);
417 }
418
419 int Eeprom::write(unsigned char *eeprom)
420 {
421     return ftdi_write_eeprom(d->context);
422 }
423
424 int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
425 {
426     return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
427 }
428
429 int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
430 {
431     return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
432 }
433
434 int Eeprom::erase()
435 {
436     return ftdi_erase_eeprom(d->context);
437 }
438
439 class List::Private
440 {
441 public:
442     Private(struct ftdi_device_list* _devlist)
443             : devlist(_devlist)
444     {}
445
446     ~Private()
447     {
448         if(devlist)
449             ftdi_list_free(&devlist);
450     }
451
452     std::list<Context> list;
453     struct ftdi_device_list* devlist;
454 };
455
456 List::List(struct ftdi_device_list* devlist)
457         : d( new Private(devlist) )
458 {
459     if (devlist != 0)
460     {
461         // Iterate list
462         for (; devlist != 0; devlist = devlist->next)
463         {
464             Context c;
465             c.set_usb_device(devlist->dev);
466             c.get_strings();
467             d->list.push_back(c);
468         }
469     }
470 }
471
472 List::~List()
473 {
474 }
475
476 /**
477 * Return begin iterator for accessing the contained list elements
478 * @return Iterator
479 */
480 List::iterator List::begin()
481 {
482     return d->list.begin();
483 }
484
485 /**
486 * Return end iterator for accessing the contained list elements
487 * @return Iterator
488 */
489 List::iterator List::end()
490 {
491     return d->list.end();
492 }
493
494 /**
495 * Return begin iterator for accessing the contained list elements
496 * @return Const iterator
497 */
498 List::const_iterator List::begin() const
499 {
500     return d->list.begin();
501 }
502
503 /**
504 * Return end iterator for accessing the contained list elements
505 * @return Const iterator
506 */
507 List::const_iterator List::end() const
508 {
509     return d->list.end();
510 }
511
512 /**
513 * Return begin reverse iterator for accessing the contained list elements
514 * @return Reverse iterator
515 */
516 List::reverse_iterator List::rbegin()
517 {
518     return d->list.rbegin();
519 }
520
521 /**
522 * Return end reverse iterator for accessing the contained list elements
523 * @return Reverse iterator
524 */
525 List::reverse_iterator List::rend()
526 {
527     return d->list.rend();
528 }
529
530 /**
531 * Return begin reverse iterator for accessing the contained list elements
532 * @return Const reverse iterator
533 */
534 List::const_reverse_iterator List::rbegin() const
535 {
536     return d->list.rbegin();
537 }
538
539 /**
540 * Return end reverse iterator for accessing the contained list elements
541 * @return Const reverse iterator
542 */
543 List::const_reverse_iterator List::rend() const
544 {
545     return d->list.rend();
546
547 }
548
549 /**
550 * Get number of elements stored in the list
551 * @return Number of elements
552 */
553 List::ListType::size_type List::size() const
554 {
555     return d->list.size();
556 }
557
558 /**
559 * Check if list is empty
560 * @return True if empty, false otherwise
561 */
562 bool List::empty() const
563 {
564     return d->list.empty();
565 }
566
567 /**
568  * Removes all elements. Invalidates all iterators.
569  * Do it in a non-throwing way and also make
570  * sure we really free the allocated memory.
571  */
572 void List::clear()
573 {
574     ListType().swap(d->list);
575
576     // Free device list
577     if (d->devlist)
578     {
579         ftdi_list_free(&d->devlist);
580         d->devlist = 0;
581     }
582 }
583
584 /**
585  * Appends a copy of the element as the new last element.
586  * @param element Value to copy and append
587 */
588 void List::push_back(const Context& element)
589 {
590     d->list.push_back(element);
591 }
592
593 /**
594  * Adds a copy of the element as the new first element.
595  * @param element Value to copy and add
596 */
597 void List::push_front(const Context& element)
598 {
599     d->list.push_front(element);
600 }
601
602 /**
603  * Erase one element pointed by iterator
604  * @param pos Element to erase
605  * @return Position of the following element (or end())
606 */
607 List::iterator List::erase(iterator pos)
608 {
609     return d->list.erase(pos);
610 }
611
612 /**
613  * Erase a range of elements
614  * @param beg Begin of range
615  * @param end End of range
616  * @return Position of the element after the erased range (or end())
617 */
618 List::iterator List::erase(iterator beg, iterator end)
619 {
620     return d->list.erase(beg, end);
621 }
622
623 List* List::find_all(Context &context, int vendor, int product)
624 {
625     struct ftdi_device_list* dlist = 0;
626     ftdi_usb_find_all(context.context(), &dlist, vendor, product);
627     return new List(dlist);
628 }
629
630 }