C++ API: Correct the purge Direction and ModemCtl enumerations definitions
[libftdi] / ftdipp / ftdi.cpp
CommitLineData
cdf448f6
TJ
1/***************************************************************************
2 ftdi.cpp - C++ wraper for libftdi
3 -------------------
4 begin : Mon Oct 13 2008
79646368 5 copyright : (C) 2008-2017 by Marek Vavruša / libftdi developers
cdf448f6
TJ
6 email : opensource@intra2net.com and marek@vavrusa.com
7 ***************************************************************************/
3ab8f642 8/*
79646368 9Copyright (C) 2008-2017 by Marek Vavruša / libftdi developers
cdf448f6 10
3ab8f642
TJ
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.
cdf448f6 25
3ab8f642
TJ
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*/
fec55667 29#include <libusb.h>
20b1459a 30#include "ftdi.hpp"
b790d38e 31#include "ftdi_i.h"
20b1459a
TJ
32#include "ftdi.h"
33
34namespace Ftdi
35{
36
37class Context::Private
38{
cdf448f6
TJ
39public:
40 Private()
d5c91348 41 : open(false), ftdi(0), dev(0)
cdf448f6 42 {
cfceadbc
MV
43 ftdi = ftdi_new();
44 }
45
46 ~Private()
47 {
22d12cda 48 if (open)
cfceadbc
MV
49 ftdi_usb_close(ftdi);
50
51 ftdi_free(ftdi);
cdf448f6
TJ
52 }
53
54 bool open;
55
56 struct ftdi_context* ftdi;
579b006f 57 struct libusb_device* dev;
cdf448f6
TJ
58
59 std::string vendor;
60 std::string description;
61 std::string serial;
20b1459a
TJ
62};
63
64/*! \brief Constructor.
65 */
66Context::Context()
cdf448f6 67 : d( new Private() )
20b1459a 68{
20b1459a
TJ
69}
70
71/*! \brief Destructor.
72 */
73Context::~Context()
74{
20b1459a
TJ
75}
76
77bool Context::is_open()
78{
cdf448f6 79 return d->open;
20b1459a
TJ
80}
81
58cce2d4 82int Context::open(int vendor, int product)
20b1459a 83{
2f6b4bb6 84 // Open device
58cce2d4 85 int ret = ftdi_usb_open(d->ftdi, vendor, product);
20b1459a 86
2f6b4bb6
MV
87 if (ret < 0)
88 return ret;
20b1459a 89
5a7f320d 90 return get_strings_and_reopen(false,false,false);
58cce2d4 91}
2f6b4bb6 92
58cce2d4
GE
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();
20b1459a 103
58cce2d4
GE
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
5a7f320d 109 return get_strings_and_reopen(false,description.empty(),serial.empty());
58cce2d4
GE
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
5a7f320d 119 return get_strings_and_reopen(false,true,false);
20b1459a
TJ
120}
121
579b006f 122int Context::open(struct libusb_device *dev)
20b1459a 123{
cdf448f6
TJ
124 if (dev != 0)
125 d->dev = dev;
126
127 if (d->dev == 0)
128 return -1;
20b1459a 129
58cce2d4 130 return get_strings_and_reopen();
20b1459a
TJ
131}
132
133int Context::close()
134{
cdf448f6 135 d->open = false;
9330b120 136 d->dev = 0;
cdf448f6 137 return ftdi_usb_close(d->ftdi);
20b1459a
TJ
138}
139
140int Context::reset()
141{
cdf448f6 142 return ftdi_usb_reset(d->ftdi);
20b1459a
TJ
143}
144
145int Context::flush(int mask)
146{
26537a2d 147 int ret;
20b1459a 148
26537a2d
ES
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 }
cdf448f6
TJ
167
168 return ret;
20b1459a
TJ
169}
170
171int Context::set_interface(enum ftdi_interface interface)
172{
cdf448f6 173 return ftdi_set_interface(d->ftdi, interface);
20b1459a
TJ
174}
175
579b006f 176void Context::set_usb_device(struct libusb_device_handle *dev)
20b1459a 177{
cdf448f6 178 ftdi_set_usbdev(d->ftdi, dev);
579b006f 179 d->dev = libusb_get_device(dev);
20b1459a
TJ
180}
181
182int Context::set_baud_rate(int baudrate)
183{
cdf448f6 184 return ftdi_set_baudrate(d->ftdi, baudrate);
20b1459a
TJ
185}
186
187int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
188{
cdf448f6 189 return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
20b1459a
TJ
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{
cdf448f6 194 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
20b1459a
TJ
195}
196
73a71502
JS
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
20b1459a
TJ
217int Context::read(unsigned char *buf, int size)
218{
cdf448f6 219 return ftdi_read_data(d->ftdi, buf, size);
20b1459a
TJ
220}
221
222int Context::set_read_chunk_size(unsigned int chunksize)
223{
cdf448f6 224 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
225}
226
227int Context::read_chunk_size()
228{
cdf448f6
TJ
229 unsigned chunk = -1;
230 if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
231 return -1;
20b1459a 232
cdf448f6
TJ
233 return chunk;
234}
20b1459a 235
fb56d9cf 236int Context::write(const unsigned char *buf, int size)
20b1459a 237{
cdf448f6 238 return ftdi_write_data(d->ftdi, buf, size);
20b1459a
TJ
239}
240
241int Context::set_write_chunk_size(unsigned int chunksize)
242{
cdf448f6 243 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
244}
245
246int Context::write_chunk_size()
247{
cdf448f6
TJ
248 unsigned chunk = -1;
249 if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
250 return -1;
20b1459a 251
cdf448f6 252 return chunk;
20b1459a
TJ
253}
254
255int Context::set_flow_control(int flowctrl)
256{
cdf448f6 257 return ftdi_setflowctrl(d->ftdi, flowctrl);
20b1459a
TJ
258}
259
260int Context::set_modem_control(int mask)
261{
cdf448f6
TJ
262 int dtr = 0, rts = 0;
263
264 if (mask & Dtr)
265 dtr = 1;
266 if (mask & Rts)
267 rts = 1;
20b1459a 268
cdf448f6 269 return ftdi_setdtr_rts(d->ftdi, dtr, rts);
20b1459a
TJ
270}
271
272int Context::set_dtr(bool state)
273{
cdf448f6 274 return ftdi_setdtr(d->ftdi, state);
20b1459a
TJ
275}
276
277int Context::set_rts(bool state)
278{
cdf448f6 279 return ftdi_setrts(d->ftdi, state);
20b1459a
TJ
280}
281
282int Context::set_latency(unsigned char latency)
283{
cdf448f6 284 return ftdi_set_latency_timer(d->ftdi, latency);
20b1459a
TJ
285}
286
287unsigned Context::latency()
288{
cdf448f6
TJ
289 unsigned char latency = 0;
290 ftdi_get_latency_timer(d->ftdi, &latency);
291 return latency;
20b1459a
TJ
292}
293
294unsigned short Context::poll_modem_status()
295{
cdf448f6
TJ
296 unsigned short status = 0;
297 ftdi_poll_modem_status(d->ftdi, &status);
298 return status;
20b1459a
TJ
299}
300
20b1459a
TJ
301int Context::set_event_char(unsigned char eventch, unsigned char enable)
302{
cdf448f6 303 return ftdi_set_event_char(d->ftdi, eventch, enable);
20b1459a
TJ
304}
305
306int Context::set_error_char(unsigned char errorch, unsigned char enable)
307{
cdf448f6 308 return ftdi_set_error_char(d->ftdi, errorch, enable);
20b1459a
TJ
309}
310
20b1459a
TJ
311int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
312{
c2ed8c4e 313 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
58cce2d4
GE
314}
315
316int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
317{
cdf448f6 318 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
20b1459a
TJ
319}
320
2d790e37
TJ
321int Context::bitbang_disable()
322{
323 return ftdi_disable_bitbang(d->ftdi);
324}
325
20b1459a
TJ
326int Context::read_pins(unsigned char *pins)
327{
cdf448f6 328 return ftdi_read_pins(d->ftdi, pins);
20b1459a
TJ
329}
330
c45d2630 331const char* Context::error_string()
20b1459a 332{
cdf448f6 333 return ftdi_get_error_string(d->ftdi);
20b1459a
TJ
334}
335
5a7f320d 336int Context::get_strings(bool vendor, bool description, bool serial)
20b1459a 337{
cdf448f6 338 // Prepare buffers
5a7f320d 339 char ivendor[512], idesc[512], iserial[512];
cdf448f6 340
5a7f320d 341 int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor?ivendor:NULL, 512, description?idesc:NULL, 512, serial?iserial:NULL, 512);
cdf448f6
TJ
342
343 if (ret < 0)
344 return -1;
20b1459a 345
5a7f320d
MJ
346 d->vendor = ivendor;
347 d->description = idesc;
348 d->serial = iserial;
20b1459a 349
cdf448f6 350 return 1;
20b1459a
TJ
351}
352
5a7f320d 353int Context::get_strings_and_reopen(bool vendor, bool description, bool serial)
58cce2d4 354{
5a7f320d 355 int ret = 0;
d3af9b2c 356
5a7f320d 357 if(vendor || description || serial)
58cce2d4 358 {
5a7f320d
MJ
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);
58cce2d4
GE
375 }
376
58cce2d4
GE
377 return ret;
378}
379
1bbaf1ce 380/*! \brief Device strings properties.
20b1459a
TJ
381 */
382const std::string& Context::vendor()
383{
5a7f320d
MJ
384 if(d->vendor.empty())
385 get_strings_and_reopen(true,false,false);
cdf448f6 386 return d->vendor;
20b1459a
TJ
387}
388
1bbaf1ce
JP
389/*! \brief Device strings properties.
390 */
20b1459a
TJ
391const std::string& Context::description()
392{
5a7f320d
MJ
393 if(d->description.empty())
394 get_strings_and_reopen(false,true,false);
cdf448f6 395 return d->description;
20b1459a
TJ
396}
397
1bbaf1ce
JP
398/*! \brief Device strings properties.
399 */
20b1459a
TJ
400const std::string& Context::serial()
401{
5a7f320d
MJ
402 if(d->serial.empty())
403 get_strings_and_reopen(false,false,true);
cdf448f6 404 return d->serial;
20b1459a
TJ
405}
406
407void Context::set_context(struct ftdi_context* context)
408{
cdf448f6
TJ
409 ftdi_free(d->ftdi);
410 d->ftdi = context;
20b1459a
TJ
411}
412
579b006f 413void Context::set_usb_device(struct libusb_device *dev)
20b1459a 414{
cdf448f6 415 d->dev = dev;
20b1459a
TJ
416}
417
418struct ftdi_context* Context::context()
419{
cdf448f6 420 return d->ftdi;
20b1459a
TJ
421}
422
423class Eeprom::Private
424{
cdf448f6
TJ
425public:
426 Private()
427 : context(0)
428 {}
20b1459a 429
cdf448f6
TJ
430 struct ftdi_eeprom eeprom;
431 struct ftdi_context* context;
20b1459a
TJ
432};
433
434Eeprom::Eeprom(Context* parent)
cdf448f6 435 : d ( new Private() )
20b1459a 436{
cdf448f6 437 d->context = parent->context();
20b1459a
TJ
438}
439
440Eeprom::~Eeprom()
441{
20b1459a
TJ
442}
443
f14f84d3 444int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
20b1459a 445{
74e8e79d 446 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
20b1459a
TJ
447}
448
20b1459a
TJ
449int Eeprom::chip_id(unsigned int *chipid)
450{
cdf448f6 451 return ftdi_read_chipid(d->context, chipid);
20b1459a
TJ
452}
453
454int Eeprom::build(unsigned char *output)
455{
a35aa9bd 456 return ftdi_eeprom_build(d->context);
20b1459a
TJ
457}
458
459int Eeprom::read(unsigned char *eeprom)
460{
a35aa9bd 461 return ftdi_read_eeprom(d->context);
20b1459a
TJ
462}
463
464int Eeprom::write(unsigned char *eeprom)
465{
a35aa9bd 466 return ftdi_write_eeprom(d->context);
20b1459a
TJ
467}
468
449c87a9
TJ
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
20b1459a
TJ
479int Eeprom::erase()
480{
cdf448f6 481 return ftdi_erase_eeprom(d->context);
20b1459a
TJ
482}
483
484class List::Private
485{
cdf448f6 486public:
6b22a054
MV
487 Private(struct ftdi_device_list* _devlist)
488 : devlist(_devlist)
cdf448f6 489 {}
20b1459a 490
cfceadbc
MV
491 ~Private()
492 {
6b22a054
MV
493 if(devlist)
494 ftdi_list_free(&devlist);
cfceadbc
MV
495 }
496
6b22a054
MV
497 std::list<Context> list;
498 struct ftdi_device_list* devlist;
20b1459a
TJ
499};
500
501List::List(struct ftdi_device_list* devlist)
6b22a054 502 : d( new Private(devlist) )
20b1459a 503{
cdf448f6
TJ
504 if (devlist != 0)
505 {
506 // Iterate list
6b22a054 507 for (; devlist != 0; devlist = devlist->next)
cdf448f6 508 {
cfceadbc 509 Context c;
6b22a054 510 c.set_usb_device(devlist->dev);
cfceadbc 511 c.get_strings();
6b22a054 512 d->list.push_back(c);
cdf448f6 513 }
cdf448f6 514 }
20b1459a
TJ
515}
516
517List::~List()
518{
20b1459a
TJ
519}
520
a14193ac
TJ
521/**
522* Return begin iterator for accessing the contained list elements
523* @return Iterator
524*/
525List::iterator List::begin()
6b22a054 526{
a14193ac 527 return d->list.begin();
6b22a054
MV
528}
529
a14193ac
TJ
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
6b22a054 544{
a14193ac 545 return d->list.begin();
6b22a054
MV
546}
547
a14193ac
TJ
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}
6b22a054 556
a14193ac
TJ
557/**
558* Return begin reverse iterator for accessing the contained list elements
559* @return Reverse iterator
560*/
561List::reverse_iterator List::rbegin()
6b22a054 562{
a14193ac 563 return d->list.rbegin();
6b22a054
MV
564}
565
a14193ac
TJ
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 */
6b22a054
MV
617void List::clear()
618{
a14193ac 619 ListType().swap(d->list);
6b22a054
MV
620
621 // Free device list
a14193ac
TJ
622 if (d->devlist)
623 {
624 ftdi_list_free(&d->devlist);
625 d->devlist = 0;
626 }
6b22a054
MV
627}
628
a14193ac
TJ
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)
6b22a054 634{
a14193ac 635 d->list.push_back(element);
6b22a054
MV
636}
637
a14193ac
TJ
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)
6b22a054 643{
a14193ac 644 d->list.push_front(element);
6b22a054
MV
645}
646
a14193ac
TJ
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}
6b22a054 667
7c21beca 668List* List::find_all(Context &context, int vendor, int product)
20b1459a 669{
cdf448f6 670 struct ftdi_device_list* dlist = 0;
7c21beca 671 ftdi_usb_find_all(context.context(), &dlist, vendor, product);
cdf448f6 672 return new List(dlist);
20b1459a
TJ
673}
674
675}