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