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