7bf4ca669a90137bacc9ae6e921671361e4cdc4f
[libftdi] / ftdipp / ftdi.cpp
1 /***************************************************************************
2                           ftdi.cpp  -  C++ wraper for libftdi
3                              -------------------
4     begin                : Mon Oct 13 2008
5     copyright            : (C) 2008-2017 by Marek Vavruša / libftdi developers
6     email                : opensource@intra2net.com and marek@vavrusa.com
7  ***************************************************************************/
8 /*
9 Copyright (C) 2008-2017 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(false,false,false);
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(false,!description.empty(),!serial.empty());
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(false,true,false);
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;
148
149     switch (mask & (Input | Output)) {
150     case Input:
151         ret = ftdi_usb_purge_rx_buffer(d->ftdi);
152         break;
153
154     case Output:
155         ret = ftdi_usb_purge_tx_buffer(d->ftdi);
156         break;
157
158     case Input | Output:
159         ret = ftdi_usb_purge_buffers(d->ftdi);
160         break;
161
162     default:
163         // Emulate behavior of previous version.
164         ret = 1;
165         break;
166     }
167
168     return ret;
169 }
170
171 int Context::set_interface(enum ftdi_interface interface)
172 {
173     return ftdi_set_interface(d->ftdi, interface);
174 }
175
176 void Context::set_usb_device(struct libusb_device_handle *dev)
177 {
178     ftdi_set_usbdev(d->ftdi, dev);
179     d->dev = libusb_get_device(dev);
180 }
181
182 int Context::set_baud_rate(int baudrate)
183 {
184     return ftdi_set_baudrate(d->ftdi, baudrate);
185 }
186
187 int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
188 {
189     return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
190 }
191
192 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)
193 {
194     return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
195 }
196
197 int Context::get_usb_read_timeout() const
198 {
199     return d->ftdi->usb_read_timeout;
200 }
201
202 void Context::set_usb_read_timeout(int usb_read_timeout)
203 {
204     d->ftdi->usb_read_timeout = usb_read_timeout;
205 }
206
207 int Context::get_usb_write_timeout() const
208 {
209     return d->ftdi->usb_write_timeout;
210 }
211
212 void Context::set_usb_write_timeout(int usb_write_timeout)
213 {
214     d->ftdi->usb_write_timeout = usb_write_timeout;
215 }
216
217 int Context::read(unsigned char *buf, int size)
218 {
219     return ftdi_read_data(d->ftdi, buf, size);
220 }
221
222 int Context::set_read_chunk_size(unsigned int chunksize)
223 {
224     return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
225 }
226
227 int Context::read_chunk_size()
228 {
229     unsigned chunk = -1;
230     if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
231         return -1;
232
233     return chunk;
234 }
235
236 int Context::write(const unsigned char *buf, int size)
237 {
238     return ftdi_write_data(d->ftdi, buf, size);
239 }
240
241 int Context::set_write_chunk_size(unsigned int chunksize)
242 {
243     return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
244 }
245
246 int Context::write_chunk_size()
247 {
248     unsigned chunk = -1;
249     if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
250         return -1;
251
252     return chunk;
253 }
254
255 int Context::set_flow_control(int flowctrl)
256 {
257     return ftdi_setflowctrl(d->ftdi, flowctrl);
258 }
259
260 int Context::set_modem_control(int mask)
261 {
262     int dtr = 0, rts = 0;
263
264     if (mask & Dtr)
265         dtr = 1;
266     if (mask & Rts)
267         rts = 1;
268
269     return ftdi_setdtr_rts(d->ftdi, dtr, rts);
270 }
271
272 int Context::set_dtr(bool state)
273 {
274     return ftdi_setdtr(d->ftdi, state);
275 }
276
277 int Context::set_rts(bool state)
278 {
279     return ftdi_setrts(d->ftdi, state);
280 }
281
282 int Context::set_latency(unsigned char latency)
283 {
284     return ftdi_set_latency_timer(d->ftdi, latency);
285 }
286
287 unsigned Context::latency()
288 {
289     unsigned char latency = 0;
290     ftdi_get_latency_timer(d->ftdi, &latency);
291     return latency;
292 }
293
294 unsigned short Context::poll_modem_status()
295 {
296     unsigned short status = 0;
297     ftdi_poll_modem_status(d->ftdi, &status);
298     return status;
299 }
300
301 int Context::set_event_char(unsigned char eventch, unsigned char enable)
302 {
303     return ftdi_set_event_char(d->ftdi, eventch, enable);
304 }
305
306 int Context::set_error_char(unsigned char errorch, unsigned char enable)
307 {
308     return ftdi_set_error_char(d->ftdi, errorch, enable);
309 }
310
311 int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
312 {
313     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
314 }
315
316 int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
317 {
318     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
319 }
320
321 int Context::bitbang_disable()
322 {
323     return ftdi_disable_bitbang(d->ftdi);
324 }
325
326 int Context::read_pins(unsigned char *pins)
327 {
328     return ftdi_read_pins(d->ftdi, pins);
329 }
330
331 const char* Context::error_string()
332 {
333     return ftdi_get_error_string(d->ftdi);
334 }
335
336 int Context::get_strings(bool vendor, bool description, bool serial)
337 {
338     // Prepare buffers
339     char ivendor[512], idesc[512], iserial[512];
340
341     int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor?ivendor:NULL, 512, description?idesc:NULL, 512, serial?iserial:NULL, 512);
342
343     if (ret < 0)
344         return -1;
345
346     d->vendor = ivendor;
347     d->description = idesc;
348     d->serial = iserial;
349
350     return 1;
351 }
352
353 int Context::get_strings_and_reopen(bool vendor, bool description, bool serial)
354 {
355     int ret = 0;
356
357     if(vendor || description || serial)
358     {
359         if (d->dev == 0)
360         {
361             d->dev = libusb_get_device(d->ftdi->usb_dev);
362         }
363
364         // Get device strings (closes device)
365         ret=get_strings(vendor, description, serial);
366         if (ret < 0)
367         {
368             d->open = 0;
369             return ret;
370         }
371
372         // Reattach device
373         ret = ftdi_usb_open_dev(d->ftdi, d->dev);
374         d->open = (ret >= 0);
375     }
376
377     return ret;
378 }
379
380 /*! \brief Device strings properties.
381  */
382 const std::string& Context::vendor()
383 {
384     if(d->vendor.empty())
385         get_strings_and_reopen(true,false,false);
386     return d->vendor;
387 }
388
389 /*! \brief Device strings properties.
390  */
391 const std::string& Context::description()
392 {
393     if(d->description.empty())
394         get_strings_and_reopen(false,true,false);
395     return d->description;
396 }
397
398 /*! \brief Device strings properties.
399  */
400 const std::string& Context::serial()
401 {
402     if(d->serial.empty())
403         get_strings_and_reopen(false,false,true);
404     return d->serial;
405 }
406
407 void Context::set_context(struct ftdi_context* context)
408 {
409     ftdi_free(d->ftdi);
410     d->ftdi = context;
411 }
412
413 void Context::set_usb_device(struct libusb_device *dev)
414 {
415     d->dev = dev;
416 }
417
418 struct ftdi_context* Context::context()
419 {
420     return d->ftdi;
421 }
422
423 class Eeprom::Private
424 {
425 public:
426     Private()
427             : context(0)
428     {}
429
430     struct ftdi_eeprom eeprom;
431     struct ftdi_context* context;
432 };
433
434 Eeprom::Eeprom(Context* parent)
435         : d ( new Private() )
436 {
437     d->context = parent->context();
438 }
439
440 Eeprom::~Eeprom()
441 {
442 }
443
444 int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
445 {
446     return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
447 }
448
449 int Eeprom::chip_id(unsigned int *chipid)
450 {
451     return ftdi_read_chipid(d->context, chipid);
452 }
453
454 int Eeprom::build(unsigned char *output)
455 {
456     return ftdi_eeprom_build(d->context);
457 }
458
459 int Eeprom::read(unsigned char *eeprom)
460 {
461     return ftdi_read_eeprom(d->context);
462 }
463
464 int Eeprom::write(unsigned char *eeprom)
465 {
466     return ftdi_write_eeprom(d->context);
467 }
468
469 int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
470 {
471     return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
472 }
473
474 int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
475 {
476     return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
477 }
478
479 int Eeprom::erase()
480 {
481     return ftdi_erase_eeprom(d->context);
482 }
483
484 class List::Private
485 {
486 public:
487     Private(struct ftdi_device_list* _devlist)
488             : devlist(_devlist)
489     {}
490
491     ~Private()
492     {
493         if(devlist)
494             ftdi_list_free(&devlist);
495     }
496
497     std::list<Context> list;
498     struct ftdi_device_list* devlist;
499 };
500
501 List::List(struct ftdi_device_list* devlist)
502         : d( new Private(devlist) )
503 {
504     if (devlist != 0)
505     {
506         // Iterate list
507         for (; devlist != 0; devlist = devlist->next)
508         {
509             Context c;
510             c.set_usb_device(devlist->dev);
511             c.get_strings();
512             d->list.push_back(c);
513         }
514     }
515 }
516
517 List::~List()
518 {
519 }
520
521 /**
522 * Return begin iterator for accessing the contained list elements
523 * @return Iterator
524 */
525 List::iterator List::begin()
526 {
527     return d->list.begin();
528 }
529
530 /**
531 * Return end iterator for accessing the contained list elements
532 * @return Iterator
533 */
534 List::iterator List::end()
535 {
536     return d->list.end();
537 }
538
539 /**
540 * Return begin iterator for accessing the contained list elements
541 * @return Const iterator
542 */
543 List::const_iterator List::begin() const
544 {
545     return d->list.begin();
546 }
547
548 /**
549 * Return end iterator for accessing the contained list elements
550 * @return Const iterator
551 */
552 List::const_iterator List::end() const
553 {
554     return d->list.end();
555 }
556
557 /**
558 * Return begin reverse iterator for accessing the contained list elements
559 * @return Reverse iterator
560 */
561 List::reverse_iterator List::rbegin()
562 {
563     return d->list.rbegin();
564 }
565
566 /**
567 * Return end reverse iterator for accessing the contained list elements
568 * @return Reverse iterator
569 */
570 List::reverse_iterator List::rend()
571 {
572     return d->list.rend();
573 }
574
575 /**
576 * Return begin reverse iterator for accessing the contained list elements
577 * @return Const reverse iterator
578 */
579 List::const_reverse_iterator List::rbegin() const
580 {
581     return d->list.rbegin();
582 }
583
584 /**
585 * Return end reverse iterator for accessing the contained list elements
586 * @return Const reverse iterator
587 */
588 List::const_reverse_iterator List::rend() const
589 {
590     return d->list.rend();
591
592 }
593
594 /**
595 * Get number of elements stored in the list
596 * @return Number of elements
597 */
598 List::ListType::size_type List::size() const
599 {
600     return d->list.size();
601 }
602
603 /**
604 * Check if list is empty
605 * @return True if empty, false otherwise
606 */
607 bool List::empty() const
608 {
609     return d->list.empty();
610 }
611
612 /**
613  * Removes all elements. Invalidates all iterators.
614  * Do it in a non-throwing way and also make
615  * sure we really free the allocated memory.
616  */
617 void List::clear()
618 {
619     ListType().swap(d->list);
620
621     // Free device list
622     if (d->devlist)
623     {
624         ftdi_list_free(&d->devlist);
625         d->devlist = 0;
626     }
627 }
628
629 /**
630  * Appends a copy of the element as the new last element.
631  * @param element Value to copy and append
632 */
633 void List::push_back(const Context& element)
634 {
635     d->list.push_back(element);
636 }
637
638 /**
639  * Adds a copy of the element as the new first element.
640  * @param element Value to copy and add
641 */
642 void List::push_front(const Context& element)
643 {
644     d->list.push_front(element);
645 }
646
647 /**
648  * Erase one element pointed by iterator
649  * @param pos Element to erase
650  * @return Position of the following element (or end())
651 */
652 List::iterator List::erase(iterator pos)
653 {
654     return d->list.erase(pos);
655 }
656
657 /**
658  * Erase a range of elements
659  * @param beg Begin of range
660  * @param end End of range
661  * @return Position of the element after the erased range (or end())
662 */
663 List::iterator List::erase(iterator beg, iterator end)
664 {
665     return d->list.erase(beg, end);
666 }
667
668 List* List::find_all(Context &context, int vendor, int product)
669 {
670     struct ftdi_device_list* dlist = 0;
671     ftdi_usb_find_all(context.context(), &dlist, vendor, product);
672     return new List(dlist);
673 }
674
675 }