follow-up on c++ open() fix. fixes logic in open() with long argument list.
[libftdi] / ftdipp / ftdi.cpp
... / ...
CommitLineData
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/*
9Copyright (C) 2008-2017 by Marek Vavruša / libftdi developers
10
11The software in this package is distributed under the GNU General
12Public License version 2 (with a special exception described below).
13
14A copy of GNU General Public License (GPL) is included in this distribution,
15in the file COPYING.GPL.
16
17As a special exception, if other files instantiate templates or use macros
18or inline functions from this file, or you compile this file and link it
19with other works to produce a work based on this file, this file
20does not by itself cause the resulting work to be covered
21by the GNU General Public License.
22
23However the source code for this file must still be made available
24in accordance with section (3) of the GNU General Public License.
25
26This exception does not invalidate any other reasons why a work based
27on 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
34namespace Ftdi
35{
36
37class Context::Private
38{
39public:
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 */
66Context::Context()
67 : d( new Private() )
68{
69}
70
71/*! \brief Destructor.
72 */
73Context::~Context()
74{
75}
76
77bool Context::is_open()
78{
79 return d->open;
80}
81
82int 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
93int 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
112int 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
122int 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
133int Context::close()
134{
135 d->open = false;
136 d->dev = 0;
137 return ftdi_usb_close(d->ftdi);
138}
139
140int Context::reset()
141{
142 return ftdi_usb_reset(d->ftdi);
143}
144
145int 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
171int Context::set_interface(enum ftdi_interface interface)
172{
173 return ftdi_set_interface(d->ftdi, interface);
174}
175
176void 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
182int Context::set_baud_rate(int baudrate)
183{
184 return ftdi_set_baudrate(d->ftdi, baudrate);
185}
186
187int 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
192int 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
197int Context::get_usb_read_timeout() const
198{
199 return d->ftdi->usb_read_timeout;
200}
201
202void Context::set_usb_read_timeout(int usb_read_timeout)
203{
204 d->ftdi->usb_read_timeout = usb_read_timeout;
205}
206
207int Context::get_usb_write_timeout() const
208{
209 return d->ftdi->usb_write_timeout;
210}
211
212void Context::set_usb_write_timeout(int usb_write_timeout)
213{
214 d->ftdi->usb_write_timeout = usb_write_timeout;
215}
216
217int Context::read(unsigned char *buf, int size)
218{
219 return ftdi_read_data(d->ftdi, buf, size);
220}
221
222int Context::set_read_chunk_size(unsigned int chunksize)
223{
224 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
225}
226
227int 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
236int Context::write(const unsigned char *buf, int size)
237{
238 return ftdi_write_data(d->ftdi, buf, size);
239}
240
241int Context::set_write_chunk_size(unsigned int chunksize)
242{
243 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
244}
245
246int 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
255int Context::set_flow_control(int flowctrl)
256{
257 return ftdi_setflowctrl(d->ftdi, flowctrl);
258}
259
260int 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
272int Context::set_dtr(bool state)
273{
274 return ftdi_setdtr(d->ftdi, state);
275}
276
277int Context::set_rts(bool state)
278{
279 return ftdi_setrts(d->ftdi, state);
280}
281
282int Context::set_latency(unsigned char latency)
283{
284 return ftdi_set_latency_timer(d->ftdi, latency);
285}
286
287unsigned Context::latency()
288{
289 unsigned char latency = 0;
290 ftdi_get_latency_timer(d->ftdi, &latency);
291 return latency;
292}
293
294unsigned short Context::poll_modem_status()
295{
296 unsigned short status = 0;
297 ftdi_poll_modem_status(d->ftdi, &status);
298 return status;
299}
300
301int Context::set_event_char(unsigned char eventch, unsigned char enable)
302{
303 return ftdi_set_event_char(d->ftdi, eventch, enable);
304}
305
306int Context::set_error_char(unsigned char errorch, unsigned char enable)
307{
308 return ftdi_set_error_char(d->ftdi, errorch, enable);
309}
310
311int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
312{
313 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
314}
315
316int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
317{
318 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
319}
320
321int Context::bitbang_disable()
322{
323 return ftdi_disable_bitbang(d->ftdi);
324}
325
326int Context::read_pins(unsigned char *pins)
327{
328 return ftdi_read_pins(d->ftdi, pins);
329}
330
331const char* Context::error_string()
332{
333 return ftdi_get_error_string(d->ftdi);
334}
335
336int 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
353int 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 */
382const 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 */
391const 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 */
400const std::string& Context::serial()
401{
402 if(d->serial.empty())
403 get_strings_and_reopen(false,false,true);
404 return d->serial;
405}
406
407void Context::set_context(struct ftdi_context* context)
408{
409 ftdi_free(d->ftdi);
410 d->ftdi = context;
411}
412
413void Context::set_usb_device(struct libusb_device *dev)
414{
415 d->dev = dev;
416}
417
418struct ftdi_context* Context::context()
419{
420 return d->ftdi;
421}
422
423class Eeprom::Private
424{
425public:
426 Private()
427 : context(0)
428 {}
429
430 struct ftdi_eeprom eeprom;
431 struct ftdi_context* context;
432};
433
434Eeprom::Eeprom(Context* parent)
435 : d ( new Private() )
436{
437 d->context = parent->context();
438}
439
440Eeprom::~Eeprom()
441{
442}
443
444int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
445{
446 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
447}
448
449int Eeprom::chip_id(unsigned int *chipid)
450{
451 return ftdi_read_chipid(d->context, chipid);
452}
453
454int Eeprom::build(unsigned char *output)
455{
456 return ftdi_eeprom_build(d->context);
457}
458
459int Eeprom::read(unsigned char *eeprom)
460{
461 return ftdi_read_eeprom(d->context);
462}
463
464int Eeprom::write(unsigned char *eeprom)
465{
466 return ftdi_write_eeprom(d->context);
467}
468
469int 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
474int 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
479int Eeprom::erase()
480{
481 return ftdi_erase_eeprom(d->context);
482}
483
484class List::Private
485{
486public:
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
501List::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
517List::~List()
518{
519}
520
521/**
522* Return begin iterator for accessing the contained list elements
523* @return Iterator
524*/
525List::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*/
534List::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*/
543List::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*/
552List::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*/
561List::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*/
570List::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*/
579List::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*/
588List::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*/
598List::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*/
607bool 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 */
617void 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*/
633void 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*/
642void 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*/
652List::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*/
663List::iterator List::erase(iterator beg, iterator end)
664{
665 return d->list.erase(beg, end);
666}
667
668List* 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}