Implement tc[io]flush methods & deprecate broken purge_buffers methods.
[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>
ed46f09c 30#define _FTDI_DISABLE_DEPRECATED
20b1459a 31#include "ftdi.hpp"
b790d38e 32#include "ftdi_i.h"
20b1459a
TJ
33#include "ftdi.h"
34
35namespace Ftdi
36{
37
38class Context::Private
39{
cdf448f6
TJ
40public:
41 Private()
d5c91348 42 : open(false), ftdi(0), dev(0)
cdf448f6 43 {
cfceadbc
MV
44 ftdi = ftdi_new();
45 }
46
47 ~Private()
48 {
22d12cda 49 if (open)
cfceadbc
MV
50 ftdi_usb_close(ftdi);
51
52 ftdi_free(ftdi);
cdf448f6
TJ
53 }
54
55 bool open;
56
57 struct ftdi_context* ftdi;
579b006f 58 struct libusb_device* dev;
cdf448f6
TJ
59
60 std::string vendor;
61 std::string description;
62 std::string serial;
20b1459a
TJ
63};
64
65/*! \brief Constructor.
66 */
67Context::Context()
cdf448f6 68 : d( new Private() )
20b1459a 69{
20b1459a
TJ
70}
71
72/*! \brief Destructor.
73 */
74Context::~Context()
75{
20b1459a
TJ
76}
77
78bool Context::is_open()
79{
cdf448f6 80 return d->open;
20b1459a
TJ
81}
82
58cce2d4 83int Context::open(int vendor, int product)
20b1459a 84{
2f6b4bb6 85 // Open device
58cce2d4 86 int ret = ftdi_usb_open(d->ftdi, vendor, product);
20b1459a 87
2f6b4bb6
MV
88 if (ret < 0)
89 return ret;
20b1459a 90
5a7f320d 91 return get_strings_and_reopen(false,false,false);
58cce2d4 92}
2f6b4bb6 93
58cce2d4
GE
94int 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();
20b1459a 104
58cce2d4
GE
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
f1b4c09a 110 return get_strings_and_reopen(false,!description.empty(),!serial.empty());
58cce2d4
GE
111}
112
113int 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
5a7f320d 120 return get_strings_and_reopen(false,true,false);
20b1459a
TJ
121}
122
579b006f 123int Context::open(struct libusb_device *dev)
20b1459a 124{
cdf448f6
TJ
125 if (dev != 0)
126 d->dev = dev;
127
128 if (d->dev == 0)
129 return -1;
20b1459a 130
58cce2d4 131 return get_strings_and_reopen();
20b1459a
TJ
132}
133
134int Context::close()
135{
cdf448f6 136 d->open = false;
9330b120 137 d->dev = 0;
cdf448f6 138 return ftdi_usb_close(d->ftdi);
20b1459a
TJ
139}
140
141int Context::reset()
142{
cdf448f6 143 return ftdi_usb_reset(d->ftdi);
20b1459a
TJ
144}
145
146int Context::flush(int mask)
147{
26537a2d 148 int ret;
20b1459a 149
26537a2d
ES
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;
ed46f09c
ES
167 }
168
169 return ret;
170}
171
172int 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;
26537a2d 193 }
cdf448f6
TJ
194
195 return ret;
20b1459a
TJ
196}
197
198int Context::set_interface(enum ftdi_interface interface)
199{
cdf448f6 200 return ftdi_set_interface(d->ftdi, interface);
20b1459a
TJ
201}
202
579b006f 203void Context::set_usb_device(struct libusb_device_handle *dev)
20b1459a 204{
cdf448f6 205 ftdi_set_usbdev(d->ftdi, dev);
579b006f 206 d->dev = libusb_get_device(dev);
20b1459a
TJ
207}
208
209int Context::set_baud_rate(int baudrate)
210{
cdf448f6 211 return ftdi_set_baudrate(d->ftdi, baudrate);
20b1459a
TJ
212}
213
214int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
215{
cdf448f6 216 return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
20b1459a
TJ
217}
218
219int 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{
cdf448f6 221 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
20b1459a
TJ
222}
223
73a71502
JS
224int Context::get_usb_read_timeout() const
225{
226 return d->ftdi->usb_read_timeout;
227}
228
229void Context::set_usb_read_timeout(int usb_read_timeout)
230{
231 d->ftdi->usb_read_timeout = usb_read_timeout;
232}
233
234int Context::get_usb_write_timeout() const
235{
236 return d->ftdi->usb_write_timeout;
237}
238
239void Context::set_usb_write_timeout(int usb_write_timeout)
240{
241 d->ftdi->usb_write_timeout = usb_write_timeout;
242}
243
20b1459a
TJ
244int Context::read(unsigned char *buf, int size)
245{
cdf448f6 246 return ftdi_read_data(d->ftdi, buf, size);
20b1459a
TJ
247}
248
249int Context::set_read_chunk_size(unsigned int chunksize)
250{
cdf448f6 251 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
252}
253
254int Context::read_chunk_size()
255{
cdf448f6
TJ
256 unsigned chunk = -1;
257 if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
258 return -1;
20b1459a 259
cdf448f6
TJ
260 return chunk;
261}
20b1459a 262
fb56d9cf 263int Context::write(const unsigned char *buf, int size)
20b1459a 264{
cdf448f6 265 return ftdi_write_data(d->ftdi, buf, size);
20b1459a
TJ
266}
267
268int Context::set_write_chunk_size(unsigned int chunksize)
269{
cdf448f6 270 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
271}
272
273int Context::write_chunk_size()
274{
cdf448f6
TJ
275 unsigned chunk = -1;
276 if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
277 return -1;
20b1459a 278
cdf448f6 279 return chunk;
20b1459a
TJ
280}
281
282int Context::set_flow_control(int flowctrl)
283{
cdf448f6 284 return ftdi_setflowctrl(d->ftdi, flowctrl);
20b1459a
TJ
285}
286
287int Context::set_modem_control(int mask)
288{
cdf448f6
TJ
289 int dtr = 0, rts = 0;
290
291 if (mask & Dtr)
292 dtr = 1;
293 if (mask & Rts)
294 rts = 1;
20b1459a 295
cdf448f6 296 return ftdi_setdtr_rts(d->ftdi, dtr, rts);
20b1459a
TJ
297}
298
299int Context::set_dtr(bool state)
300{
cdf448f6 301 return ftdi_setdtr(d->ftdi, state);
20b1459a
TJ
302}
303
304int Context::set_rts(bool state)
305{
cdf448f6 306 return ftdi_setrts(d->ftdi, state);
20b1459a
TJ
307}
308
309int Context::set_latency(unsigned char latency)
310{
cdf448f6 311 return ftdi_set_latency_timer(d->ftdi, latency);
20b1459a
TJ
312}
313
314unsigned Context::latency()
315{
cdf448f6
TJ
316 unsigned char latency = 0;
317 ftdi_get_latency_timer(d->ftdi, &latency);
318 return latency;
20b1459a
TJ
319}
320
321unsigned short Context::poll_modem_status()
322{
cdf448f6
TJ
323 unsigned short status = 0;
324 ftdi_poll_modem_status(d->ftdi, &status);
325 return status;
20b1459a
TJ
326}
327
20b1459a
TJ
328int Context::set_event_char(unsigned char eventch, unsigned char enable)
329{
cdf448f6 330 return ftdi_set_event_char(d->ftdi, eventch, enable);
20b1459a
TJ
331}
332
333int Context::set_error_char(unsigned char errorch, unsigned char enable)
334{
cdf448f6 335 return ftdi_set_error_char(d->ftdi, errorch, enable);
20b1459a
TJ
336}
337
20b1459a
TJ
338int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
339{
c2ed8c4e 340 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
58cce2d4
GE
341}
342
343int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
344{
cdf448f6 345 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
20b1459a
TJ
346}
347
2d790e37
TJ
348int Context::bitbang_disable()
349{
350 return ftdi_disable_bitbang(d->ftdi);
351}
352
20b1459a
TJ
353int Context::read_pins(unsigned char *pins)
354{
cdf448f6 355 return ftdi_read_pins(d->ftdi, pins);
20b1459a
TJ
356}
357
c45d2630 358const char* Context::error_string()
20b1459a 359{
cdf448f6 360 return ftdi_get_error_string(d->ftdi);
20b1459a
TJ
361}
362
5a7f320d 363int Context::get_strings(bool vendor, bool description, bool serial)
20b1459a 364{
cdf448f6 365 // Prepare buffers
5a7f320d 366 char ivendor[512], idesc[512], iserial[512];
cdf448f6 367
5a7f320d 368 int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor?ivendor:NULL, 512, description?idesc:NULL, 512, serial?iserial:NULL, 512);
cdf448f6
TJ
369
370 if (ret < 0)
371 return -1;
20b1459a 372
5a7f320d
MJ
373 d->vendor = ivendor;
374 d->description = idesc;
375 d->serial = iserial;
20b1459a 376
cdf448f6 377 return 1;
20b1459a
TJ
378}
379
5a7f320d 380int Context::get_strings_and_reopen(bool vendor, bool description, bool serial)
58cce2d4 381{
5a7f320d 382 int ret = 0;
d3af9b2c 383
5a7f320d 384 if(vendor || description || serial)
58cce2d4 385 {
5a7f320d
MJ
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);
58cce2d4
GE
402 }
403
58cce2d4
GE
404 return ret;
405}
406
1bbaf1ce 407/*! \brief Device strings properties.
20b1459a
TJ
408 */
409const std::string& Context::vendor()
410{
5a7f320d
MJ
411 if(d->vendor.empty())
412 get_strings_and_reopen(true,false,false);
cdf448f6 413 return d->vendor;
20b1459a
TJ
414}
415
1bbaf1ce
JP
416/*! \brief Device strings properties.
417 */
20b1459a
TJ
418const std::string& Context::description()
419{
5a7f320d
MJ
420 if(d->description.empty())
421 get_strings_and_reopen(false,true,false);
cdf448f6 422 return d->description;
20b1459a
TJ
423}
424
1bbaf1ce
JP
425/*! \brief Device strings properties.
426 */
20b1459a
TJ
427const std::string& Context::serial()
428{
5a7f320d
MJ
429 if(d->serial.empty())
430 get_strings_and_reopen(false,false,true);
cdf448f6 431 return d->serial;
20b1459a
TJ
432}
433
434void Context::set_context(struct ftdi_context* context)
435{
cdf448f6
TJ
436 ftdi_free(d->ftdi);
437 d->ftdi = context;
20b1459a
TJ
438}
439
579b006f 440void Context::set_usb_device(struct libusb_device *dev)
20b1459a 441{
cdf448f6 442 d->dev = dev;
20b1459a
TJ
443}
444
445struct ftdi_context* Context::context()
446{
cdf448f6 447 return d->ftdi;
20b1459a
TJ
448}
449
450class Eeprom::Private
451{
cdf448f6
TJ
452public:
453 Private()
454 : context(0)
455 {}
20b1459a 456
cdf448f6
TJ
457 struct ftdi_eeprom eeprom;
458 struct ftdi_context* context;
20b1459a
TJ
459};
460
461Eeprom::Eeprom(Context* parent)
cdf448f6 462 : d ( new Private() )
20b1459a 463{
cdf448f6 464 d->context = parent->context();
20b1459a
TJ
465}
466
467Eeprom::~Eeprom()
468{
20b1459a
TJ
469}
470
f14f84d3 471int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
20b1459a 472{
74e8e79d 473 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
20b1459a
TJ
474}
475
20b1459a
TJ
476int Eeprom::chip_id(unsigned int *chipid)
477{
cdf448f6 478 return ftdi_read_chipid(d->context, chipid);
20b1459a
TJ
479}
480
481int Eeprom::build(unsigned char *output)
482{
a35aa9bd 483 return ftdi_eeprom_build(d->context);
20b1459a
TJ
484}
485
486int Eeprom::read(unsigned char *eeprom)
487{
a35aa9bd 488 return ftdi_read_eeprom(d->context);
20b1459a
TJ
489}
490
491int Eeprom::write(unsigned char *eeprom)
492{
a35aa9bd 493 return ftdi_write_eeprom(d->context);
20b1459a
TJ
494}
495
449c87a9
TJ
496int 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
501int 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
20b1459a
TJ
506int Eeprom::erase()
507{
cdf448f6 508 return ftdi_erase_eeprom(d->context);
20b1459a
TJ
509}
510
511class List::Private
512{
cdf448f6 513public:
6b22a054
MV
514 Private(struct ftdi_device_list* _devlist)
515 : devlist(_devlist)
cdf448f6 516 {}
20b1459a 517
cfceadbc
MV
518 ~Private()
519 {
6b22a054
MV
520 if(devlist)
521 ftdi_list_free(&devlist);
cfceadbc
MV
522 }
523
6b22a054
MV
524 std::list<Context> list;
525 struct ftdi_device_list* devlist;
20b1459a
TJ
526};
527
528List::List(struct ftdi_device_list* devlist)
6b22a054 529 : d( new Private(devlist) )
20b1459a 530{
cdf448f6
TJ
531 if (devlist != 0)
532 {
533 // Iterate list
6b22a054 534 for (; devlist != 0; devlist = devlist->next)
cdf448f6 535 {
cfceadbc 536 Context c;
6b22a054 537 c.set_usb_device(devlist->dev);
cfceadbc 538 c.get_strings();
6b22a054 539 d->list.push_back(c);
cdf448f6 540 }
cdf448f6 541 }
20b1459a
TJ
542}
543
544List::~List()
545{
20b1459a
TJ
546}
547
a14193ac
TJ
548/**
549* Return begin iterator for accessing the contained list elements
550* @return Iterator
551*/
552List::iterator List::begin()
6b22a054 553{
a14193ac 554 return d->list.begin();
6b22a054
MV
555}
556
a14193ac
TJ
557/**
558* Return end iterator for accessing the contained list elements
559* @return Iterator
560*/
561List::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*/
570List::const_iterator List::begin() const
6b22a054 571{
a14193ac 572 return d->list.begin();
6b22a054
MV
573}
574
a14193ac
TJ
575/**
576* Return end iterator for accessing the contained list elements
577* @return Const iterator
578*/
579List::const_iterator List::end() const
580{
581 return d->list.end();
582}
6b22a054 583
a14193ac
TJ
584/**
585* Return begin reverse iterator for accessing the contained list elements
586* @return Reverse iterator
587*/
588List::reverse_iterator List::rbegin()
6b22a054 589{
a14193ac 590 return d->list.rbegin();
6b22a054
MV
591}
592
a14193ac
TJ
593/**
594* Return end reverse iterator for accessing the contained list elements
595* @return Reverse iterator
596*/
597List::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*/
606List::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*/
615List::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*/
625List::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*/
634bool 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 */
6b22a054
MV
644void List::clear()
645{
a14193ac 646 ListType().swap(d->list);
6b22a054
MV
647
648 // Free device list
a14193ac
TJ
649 if (d->devlist)
650 {
651 ftdi_list_free(&d->devlist);
652 d->devlist = 0;
653 }
6b22a054
MV
654}
655
a14193ac
TJ
656/**
657 * Appends a copy of the element as the new last element.
658 * @param element Value to copy and append
659*/
660void List::push_back(const Context& element)
6b22a054 661{
a14193ac 662 d->list.push_back(element);
6b22a054
MV
663}
664
a14193ac
TJ
665/**
666 * Adds a copy of the element as the new first element.
667 * @param element Value to copy and add
668*/
669void List::push_front(const Context& element)
6b22a054 670{
a14193ac 671 d->list.push_front(element);
6b22a054
MV
672}
673
a14193ac
TJ
674/**
675 * Erase one element pointed by iterator
676 * @param pos Element to erase
677 * @return Position of the following element (or end())
678*/
679List::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*/
690List::iterator List::erase(iterator beg, iterator end)
691{
692 return d->list.erase(beg, end);
693}
6b22a054 694
7c21beca 695List* List::find_all(Context &context, int vendor, int product)
20b1459a 696{
cdf448f6 697 struct ftdi_device_list* dlist = 0;
7c21beca 698 ftdi_usb_find_all(context.context(), &dlist, vendor, product);
cdf448f6 699 return new List(dlist);
20b1459a
TJ
700}
701
702}