Increase copyright year to 2014
[libftdi] / ftdipp / ftdi.cpp
CommitLineData
cdf448f6
TJ
1/***************************************************************************
2 ftdi.cpp - C++ wraper for libftdi
3 -------------------
4 begin : Mon Oct 13 2008
dcd7e8a3 5 copyright : (C) 2008-2014 by Marek Vavruša / libftdi developers
cdf448f6
TJ
6 email : opensource@intra2net.com and marek@vavrusa.com
7 ***************************************************************************/
3ab8f642 8/*
dcd7e8a3 9Copyright (C) 2008-2014 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
58cce2d4
GE
90 return get_strings_and_reopen();
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
109 return get_strings_and_reopen();
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();
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{
cdf448f6 147 int ret = 1;
20b1459a 148
cdf448f6
TJ
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;
20b1459a
TJ
155}
156
157int Context::set_interface(enum ftdi_interface interface)
158{
cdf448f6 159 return ftdi_set_interface(d->ftdi, interface);
20b1459a
TJ
160}
161
579b006f 162void Context::set_usb_device(struct libusb_device_handle *dev)
20b1459a 163{
cdf448f6 164 ftdi_set_usbdev(d->ftdi, dev);
579b006f 165 d->dev = libusb_get_device(dev);
20b1459a
TJ
166}
167
168int Context::set_baud_rate(int baudrate)
169{
cdf448f6 170 return ftdi_set_baudrate(d->ftdi, baudrate);
20b1459a
TJ
171}
172
173int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
174{
cdf448f6 175 return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
20b1459a
TJ
176}
177
178int 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{
cdf448f6 180 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
20b1459a
TJ
181}
182
73a71502
JS
183int Context::get_usb_read_timeout() const
184{
185 return d->ftdi->usb_read_timeout;
186}
187
188void Context::set_usb_read_timeout(int usb_read_timeout)
189{
190 d->ftdi->usb_read_timeout = usb_read_timeout;
191}
192
193int Context::get_usb_write_timeout() const
194{
195 return d->ftdi->usb_write_timeout;
196}
197
198void Context::set_usb_write_timeout(int usb_write_timeout)
199{
200 d->ftdi->usb_write_timeout = usb_write_timeout;
201}
202
20b1459a
TJ
203int Context::read(unsigned char *buf, int size)
204{
cdf448f6 205 return ftdi_read_data(d->ftdi, buf, size);
20b1459a
TJ
206}
207
208int Context::set_read_chunk_size(unsigned int chunksize)
209{
cdf448f6 210 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
211}
212
213int Context::read_chunk_size()
214{
cdf448f6
TJ
215 unsigned chunk = -1;
216 if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
217 return -1;
20b1459a 218
cdf448f6
TJ
219 return chunk;
220}
20b1459a
TJ
221
222int Context::write(unsigned char *buf, int size)
223{
cdf448f6 224 return ftdi_write_data(d->ftdi, buf, size);
20b1459a
TJ
225}
226
227int Context::set_write_chunk_size(unsigned int chunksize)
228{
cdf448f6 229 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
230}
231
232int Context::write_chunk_size()
233{
cdf448f6
TJ
234 unsigned chunk = -1;
235 if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
236 return -1;
20b1459a 237
cdf448f6 238 return chunk;
20b1459a
TJ
239}
240
241int Context::set_flow_control(int flowctrl)
242{
cdf448f6 243 return ftdi_setflowctrl(d->ftdi, flowctrl);
20b1459a
TJ
244}
245
246int Context::set_modem_control(int mask)
247{
cdf448f6
TJ
248 int dtr = 0, rts = 0;
249
250 if (mask & Dtr)
251 dtr = 1;
252 if (mask & Rts)
253 rts = 1;
20b1459a 254
cdf448f6 255 return ftdi_setdtr_rts(d->ftdi, dtr, rts);
20b1459a
TJ
256}
257
258int Context::set_dtr(bool state)
259{
cdf448f6 260 return ftdi_setdtr(d->ftdi, state);
20b1459a
TJ
261}
262
263int Context::set_rts(bool state)
264{
cdf448f6 265 return ftdi_setrts(d->ftdi, state);
20b1459a
TJ
266}
267
268int Context::set_latency(unsigned char latency)
269{
cdf448f6 270 return ftdi_set_latency_timer(d->ftdi, latency);
20b1459a
TJ
271}
272
273unsigned Context::latency()
274{
cdf448f6
TJ
275 unsigned char latency = 0;
276 ftdi_get_latency_timer(d->ftdi, &latency);
277 return latency;
20b1459a
TJ
278}
279
280unsigned short Context::poll_modem_status()
281{
cdf448f6
TJ
282 unsigned short status = 0;
283 ftdi_poll_modem_status(d->ftdi, &status);
284 return status;
20b1459a
TJ
285}
286
20b1459a
TJ
287int Context::set_event_char(unsigned char eventch, unsigned char enable)
288{
cdf448f6 289 return ftdi_set_event_char(d->ftdi, eventch, enable);
20b1459a
TJ
290}
291
292int Context::set_error_char(unsigned char errorch, unsigned char enable)
293{
cdf448f6 294 return ftdi_set_error_char(d->ftdi, errorch, enable);
20b1459a
TJ
295}
296
20b1459a
TJ
297int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
298{
c2ed8c4e 299 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
58cce2d4
GE
300}
301
302int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
303{
cdf448f6 304 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
20b1459a
TJ
305}
306
2d790e37
TJ
307int Context::bitbang_disable()
308{
309 return ftdi_disable_bitbang(d->ftdi);
310}
311
20b1459a
TJ
312int Context::read_pins(unsigned char *pins)
313{
cdf448f6 314 return ftdi_read_pins(d->ftdi, pins);
20b1459a
TJ
315}
316
317char* Context::error_string()
318{
cdf448f6 319 return ftdi_get_error_string(d->ftdi);
20b1459a
TJ
320}
321
322int Context::get_strings()
323{
cdf448f6
TJ
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;
20b1459a 331
cdf448f6
TJ
332 d->vendor = vendor;
333 d->description = desc;
334 d->serial = serial;
20b1459a 335
cdf448f6 336 return 1;
20b1459a
TJ
337}
338
58cce2d4
GE
339int Context::get_strings_and_reopen()
340{
d3af9b2c
PS
341 if ( d->dev == 0 )
342 {
343 d->dev = libusb_get_device(d->ftdi->usb_dev);
344 }
345
58cce2d4
GE
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
1bbaf1ce 361/*! \brief Device strings properties.
20b1459a
TJ
362 */
363const std::string& Context::vendor()
364{
cdf448f6 365 return d->vendor;
20b1459a
TJ
366}
367
1bbaf1ce
JP
368/*! \brief Device strings properties.
369 */
20b1459a
TJ
370const std::string& Context::description()
371{
cdf448f6 372 return d->description;
20b1459a
TJ
373}
374
1bbaf1ce
JP
375/*! \brief Device strings properties.
376 */
20b1459a
TJ
377const std::string& Context::serial()
378{
cdf448f6 379 return d->serial;
20b1459a
TJ
380}
381
382void Context::set_context(struct ftdi_context* context)
383{
cdf448f6
TJ
384 ftdi_free(d->ftdi);
385 d->ftdi = context;
20b1459a
TJ
386}
387
579b006f 388void Context::set_usb_device(struct libusb_device *dev)
20b1459a 389{
cdf448f6 390 d->dev = dev;
20b1459a
TJ
391}
392
393struct ftdi_context* Context::context()
394{
cdf448f6 395 return d->ftdi;
20b1459a
TJ
396}
397
398class Eeprom::Private
399{
cdf448f6
TJ
400public:
401 Private()
402 : context(0)
403 {}
20b1459a 404
cdf448f6
TJ
405 struct ftdi_eeprom eeprom;
406 struct ftdi_context* context;
20b1459a
TJ
407};
408
409Eeprom::Eeprom(Context* parent)
cdf448f6 410 : d ( new Private() )
20b1459a 411{
cdf448f6 412 d->context = parent->context();
20b1459a
TJ
413}
414
415Eeprom::~Eeprom()
416{
20b1459a
TJ
417}
418
f14f84d3 419int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
20b1459a 420{
74e8e79d 421 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
20b1459a
TJ
422}
423
20b1459a
TJ
424int Eeprom::chip_id(unsigned int *chipid)
425{
cdf448f6 426 return ftdi_read_chipid(d->context, chipid);
20b1459a
TJ
427}
428
429int Eeprom::build(unsigned char *output)
430{
a35aa9bd 431 return ftdi_eeprom_build(d->context);
20b1459a
TJ
432}
433
434int Eeprom::read(unsigned char *eeprom)
435{
a35aa9bd 436 return ftdi_read_eeprom(d->context);
20b1459a
TJ
437}
438
439int Eeprom::write(unsigned char *eeprom)
440{
a35aa9bd 441 return ftdi_write_eeprom(d->context);
20b1459a
TJ
442}
443
449c87a9
TJ
444int 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
449int 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
20b1459a
TJ
454int Eeprom::erase()
455{
cdf448f6 456 return ftdi_erase_eeprom(d->context);
20b1459a
TJ
457}
458
459class List::Private
460{
cdf448f6 461public:
6b22a054
MV
462 Private(struct ftdi_device_list* _devlist)
463 : devlist(_devlist)
cdf448f6 464 {}
20b1459a 465
cfceadbc
MV
466 ~Private()
467 {
6b22a054
MV
468 if(devlist)
469 ftdi_list_free(&devlist);
cfceadbc
MV
470 }
471
6b22a054
MV
472 std::list<Context> list;
473 struct ftdi_device_list* devlist;
20b1459a
TJ
474};
475
476List::List(struct ftdi_device_list* devlist)
6b22a054 477 : d( new Private(devlist) )
20b1459a 478{
cdf448f6
TJ
479 if (devlist != 0)
480 {
481 // Iterate list
6b22a054 482 for (; devlist != 0; devlist = devlist->next)
cdf448f6 483 {
cfceadbc 484 Context c;
6b22a054 485 c.set_usb_device(devlist->dev);
cfceadbc 486 c.get_strings();
6b22a054 487 d->list.push_back(c);
cdf448f6 488 }
cdf448f6 489 }
20b1459a
TJ
490}
491
492List::~List()
493{
20b1459a
TJ
494}
495
a14193ac
TJ
496/**
497* Return begin iterator for accessing the contained list elements
498* @return Iterator
499*/
500List::iterator List::begin()
6b22a054 501{
a14193ac 502 return d->list.begin();
6b22a054
MV
503}
504
a14193ac
TJ
505/**
506* Return end iterator for accessing the contained list elements
507* @return Iterator
508*/
509List::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*/
518List::const_iterator List::begin() const
6b22a054 519{
a14193ac 520 return d->list.begin();
6b22a054
MV
521}
522
a14193ac
TJ
523/**
524* Return end iterator for accessing the contained list elements
525* @return Const iterator
526*/
527List::const_iterator List::end() const
528{
529 return d->list.end();
530}
6b22a054 531
a14193ac
TJ
532/**
533* Return begin reverse iterator for accessing the contained list elements
534* @return Reverse iterator
535*/
536List::reverse_iterator List::rbegin()
6b22a054 537{
a14193ac 538 return d->list.rbegin();
6b22a054
MV
539}
540
a14193ac
TJ
541/**
542* Return end reverse iterator for accessing the contained list elements
543* @return Reverse iterator
544*/
545List::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*/
554List::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*/
563List::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*/
573List::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*/
582bool 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 */
6b22a054
MV
592void List::clear()
593{
a14193ac 594 ListType().swap(d->list);
6b22a054
MV
595
596 // Free device list
a14193ac
TJ
597 if (d->devlist)
598 {
599 ftdi_list_free(&d->devlist);
600 d->devlist = 0;
601 }
6b22a054
MV
602}
603
a14193ac
TJ
604/**
605 * Appends a copy of the element as the new last element.
606 * @param element Value to copy and append
607*/
608void List::push_back(const Context& element)
6b22a054 609{
a14193ac 610 d->list.push_back(element);
6b22a054
MV
611}
612
a14193ac
TJ
613/**
614 * Adds a copy of the element as the new first element.
615 * @param element Value to copy and add
616*/
617void List::push_front(const Context& element)
6b22a054 618{
a14193ac 619 d->list.push_front(element);
6b22a054
MV
620}
621
a14193ac
TJ
622/**
623 * Erase one element pointed by iterator
624 * @param pos Element to erase
625 * @return Position of the following element (or end())
626*/
627List::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*/
638List::iterator List::erase(iterator beg, iterator end)
639{
640 return d->list.erase(beg, end);
641}
6b22a054 642
7c21beca 643List* List::find_all(Context &context, int vendor, int product)
20b1459a 644{
cdf448f6 645 struct ftdi_device_list* dlist = 0;
7c21beca 646 ftdi_usb_find_all(context.context(), &dlist, vendor, product);
cdf448f6 647 return new List(dlist);
20b1459a
TJ
648}
649
650}