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