Implement tc[io]flush methods & deprecate broken purge_buffers methods.
[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#define _FTDI_DISABLE_DEPRECATED
31#include "ftdi.hpp"
32#include "ftdi_i.h"
33#include "ftdi.h"
34
35namespace Ftdi
36{
37
38class Context::Private
39{
40public:
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 */
67Context::Context()
68 : d( new Private() )
69{
70}
71
72/*! \brief Destructor.
73 */
74Context::~Context()
75{
76}
77
78bool Context::is_open()
79{
80 return d->open;
81}
82
83int 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
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();
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
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
120 return get_strings_and_reopen(false,true,false);
121}
122
123int 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
134int Context::close()
135{
136 d->open = false;
137 d->dev = 0;
138 return ftdi_usb_close(d->ftdi);
139}
140
141int Context::reset()
142{
143 return ftdi_usb_reset(d->ftdi);
144}
145
146int 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
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;
193 }
194
195 return ret;
196}
197
198int Context::set_interface(enum ftdi_interface interface)
199{
200 return ftdi_set_interface(d->ftdi, interface);
201}
202
203void 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
209int Context::set_baud_rate(int baudrate)
210{
211 return ftdi_set_baudrate(d->ftdi, baudrate);
212}
213
214int 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
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{
221 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
222}
223
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
244int Context::read(unsigned char *buf, int size)
245{
246 return ftdi_read_data(d->ftdi, buf, size);
247}
248
249int Context::set_read_chunk_size(unsigned int chunksize)
250{
251 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
252}
253
254int 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
263int Context::write(const unsigned char *buf, int size)
264{
265 return ftdi_write_data(d->ftdi, buf, size);
266}
267
268int Context::set_write_chunk_size(unsigned int chunksize)
269{
270 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
271}
272
273int 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
282int Context::set_flow_control(int flowctrl)
283{
284 return ftdi_setflowctrl(d->ftdi, flowctrl);
285}
286
287int 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
299int Context::set_dtr(bool state)
300{
301 return ftdi_setdtr(d->ftdi, state);
302}
303
304int Context::set_rts(bool state)
305{
306 return ftdi_setrts(d->ftdi, state);
307}
308
309int Context::set_latency(unsigned char latency)
310{
311 return ftdi_set_latency_timer(d->ftdi, latency);
312}
313
314unsigned Context::latency()
315{
316 unsigned char latency = 0;
317 ftdi_get_latency_timer(d->ftdi, &latency);
318 return latency;
319}
320
321unsigned short Context::poll_modem_status()
322{
323 unsigned short status = 0;
324 ftdi_poll_modem_status(d->ftdi, &status);
325 return status;
326}
327
328int Context::set_event_char(unsigned char eventch, unsigned char enable)
329{
330 return ftdi_set_event_char(d->ftdi, eventch, enable);
331}
332
333int Context::set_error_char(unsigned char errorch, unsigned char enable)
334{
335 return ftdi_set_error_char(d->ftdi, errorch, enable);
336}
337
338int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
339{
340 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
341}
342
343int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
344{
345 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
346}
347
348int Context::bitbang_disable()
349{
350 return ftdi_disable_bitbang(d->ftdi);
351}
352
353int Context::read_pins(unsigned char *pins)
354{
355 return ftdi_read_pins(d->ftdi, pins);
356}
357
358const char* Context::error_string()
359{
360 return ftdi_get_error_string(d->ftdi);
361}
362
363int 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
380int 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 */
409const 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 */
418const 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 */
427const std::string& Context::serial()
428{
429 if(d->serial.empty())
430 get_strings_and_reopen(false,false,true);
431 return d->serial;
432}
433
434void Context::set_context(struct ftdi_context* context)
435{
436 ftdi_free(d->ftdi);
437 d->ftdi = context;
438}
439
440void Context::set_usb_device(struct libusb_device *dev)
441{
442 d->dev = dev;
443}
444
445struct ftdi_context* Context::context()
446{
447 return d->ftdi;
448}
449
450class Eeprom::Private
451{
452public:
453 Private()
454 : context(0)
455 {}
456
457 struct ftdi_eeprom eeprom;
458 struct ftdi_context* context;
459};
460
461Eeprom::Eeprom(Context* parent)
462 : d ( new Private() )
463{
464 d->context = parent->context();
465}
466
467Eeprom::~Eeprom()
468{
469}
470
471int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
472{
473 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
474}
475
476int Eeprom::chip_id(unsigned int *chipid)
477{
478 return ftdi_read_chipid(d->context, chipid);
479}
480
481int Eeprom::build(unsigned char *output)
482{
483 return ftdi_eeprom_build(d->context);
484}
485
486int Eeprom::read(unsigned char *eeprom)
487{
488 return ftdi_read_eeprom(d->context);
489}
490
491int Eeprom::write(unsigned char *eeprom)
492{
493 return ftdi_write_eeprom(d->context);
494}
495
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
506int Eeprom::erase()
507{
508 return ftdi_erase_eeprom(d->context);
509}
510
511class List::Private
512{
513public:
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
528List::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
544List::~List()
545{
546}
547
548/**
549* Return begin iterator for accessing the contained list elements
550* @return Iterator
551*/
552List::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*/
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
571{
572 return d->list.begin();
573}
574
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}
583
584/**
585* Return begin reverse iterator for accessing the contained list elements
586* @return Reverse iterator
587*/
588List::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*/
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 */
644void 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*/
660void 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*/
669void 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*/
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}
694
695List* 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}