Fix initialization order (found by -Wall)
[libftdi] / ftdipp / ftdi.cpp
1 /***************************************************************************
2                           ftdi.cpp  -  C++ wraper for libftdi
3                              -------------------
4     begin                : Mon Oct 13 2008
5     copyright            : (C) 2008 by Marek Vavruša
6     email                : opensource@intra2net.com and marek@vavrusa.com
7  ***************************************************************************/
8 /*
9 Copyright (C) 2008 by Marek Vavruša
10
11 The software in this package is distributed under the GNU General
12 Public License version 2 (with a special exception described below).
13
14 A copy of GNU General Public License (GPL) is included in this distribution,
15 in the file COPYING.GPL.
16
17 As a special exception, if other files instantiate templates or use macros
18 or inline functions from this file, or you compile this file and link it
19 with other works to produce a work based on this file, this file
20 does not by itself cause the resulting work to be covered
21 by the GNU General Public License.
22
23 However the source code for this file must still be made available
24 in accordance with section (3) of the GNU General Public License.
25
26 This exception does not invalidate any other reasons why a work based
27 on this file might be covered by the GNU General Public License.
28 */
29 #include "ftdi.hpp"
30 #include "ftdi.h"
31
32 namespace Ftdi
33 {
34
35 class Context::Private
36 {
37 public:
38     Private()
39             : open(false), ftdi(0), dev(0)
40     {
41         ftdi = ftdi_new();
42     }
43
44     ~Private()
45     {
46         if (open)
47             ftdi_usb_close(ftdi);
48
49         ftdi_free(ftdi);
50     }
51
52     bool open;
53
54     struct ftdi_context* ftdi;
55     struct libusb_device* dev;
56
57     std::string vendor;
58     std::string description;
59     std::string serial;
60 };
61
62 /*! \brief Constructor.
63  */
64 Context::Context()
65         : d( new Private() )
66 {
67 }
68
69 /*! \brief Destructor.
70  */
71 Context::~Context()
72 {
73 }
74
75 bool Context::is_open()
76 {
77     return d->open;
78 }
79
80 int Context::open(int vendor, int product)
81 {
82     // Open device
83     int ret = ftdi_usb_open(d->ftdi, vendor, product);
84
85     if (ret < 0)
86        return ret;
87
88     return get_strings_and_reopen();
89 }
90
91 int Context::open(int vendor, int product, const std::string& description, const std::string& serial, unsigned int index)
92 {
93     // translate empty strings to NULL
94     // -> do not use them to find the device (vs. require an empty string to be set in the EEPROM)
95     const char* c_description=NULL;
96     const char* c_serial=NULL;
97     if (!description.empty())
98         c_description=description.c_str();
99     if (!serial.empty())
100         c_serial=serial.c_str();
101
102     int ret = ftdi_usb_open_desc_index(d->ftdi, vendor, product, c_description, c_serial, index);
103
104     if (ret < 0)
105        return ret;
106
107     return get_strings_and_reopen();
108 }
109
110 int Context::open(const std::string& description)
111 {
112     int ret = ftdi_usb_open_string(d->ftdi, description.c_str());
113
114     if (ret < 0)
115        return ret;
116
117     return get_strings_and_reopen();
118 }
119
120 int Context::open(struct libusb_device *dev)
121 {
122     if (dev != 0)
123         d->dev = dev;
124
125     if (d->dev == 0)
126         return -1;
127
128     return get_strings_and_reopen();
129 }
130
131 int Context::close()
132 {
133     d->open = false;
134     return ftdi_usb_close(d->ftdi);
135 }
136
137 int Context::reset()
138 {
139     return ftdi_usb_reset(d->ftdi);
140 }
141
142 int Context::flush(int mask)
143 {
144     int ret = 1;
145
146     if (mask & Input)
147         ret &= ftdi_usb_purge_rx_buffer(d->ftdi);
148     if (mask & Output)
149         ret &= ftdi_usb_purge_tx_buffer(d->ftdi);
150
151     return ret;
152 }
153
154 int Context::set_interface(enum ftdi_interface interface)
155 {
156     return ftdi_set_interface(d->ftdi, interface);
157 }
158
159 void Context::set_usb_device(struct libusb_device_handle *dev)
160 {
161     ftdi_set_usbdev(d->ftdi, dev);
162     d->dev = libusb_get_device(dev);
163 }
164
165 int Context::set_baud_rate(int baudrate)
166 {
167     return ftdi_set_baudrate(d->ftdi, baudrate);
168 }
169
170 int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
171 {
172     return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
173 }
174
175 int 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)
176 {
177     return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
178 }
179
180 int Context::read(unsigned char *buf, int size)
181 {
182     return ftdi_read_data(d->ftdi, buf, size);
183 }
184
185 int Context::set_read_chunk_size(unsigned int chunksize)
186 {
187     return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
188 }
189
190 int Context::read_chunk_size()
191 {
192     unsigned chunk = -1;
193     if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
194         return -1;
195
196     return chunk;
197 }
198
199 int Context::write(unsigned char *buf, int size)
200 {
201     return ftdi_write_data(d->ftdi, buf, size);
202 }
203
204 int Context::set_write_chunk_size(unsigned int chunksize)
205 {
206     return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
207 }
208
209 int Context::write_chunk_size()
210 {
211     unsigned chunk = -1;
212     if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
213         return -1;
214
215     return chunk;
216 }
217
218 int Context::set_flow_control(int flowctrl)
219 {
220     return ftdi_setflowctrl(d->ftdi, flowctrl);
221 }
222
223 int Context::set_modem_control(int mask)
224 {
225     int dtr = 0, rts = 0;
226
227     if (mask & Dtr)
228         dtr = 1;
229     if (mask & Rts)
230         rts = 1;
231
232     return ftdi_setdtr_rts(d->ftdi, dtr, rts);
233 }
234
235 int Context::set_dtr(bool state)
236 {
237     return ftdi_setdtr(d->ftdi, state);
238 }
239
240 int Context::set_rts(bool state)
241 {
242     return ftdi_setrts(d->ftdi, state);
243 }
244
245 int Context::set_latency(unsigned char latency)
246 {
247     return ftdi_set_latency_timer(d->ftdi, latency);
248 }
249
250 unsigned Context::latency()
251 {
252     unsigned char latency = 0;
253     ftdi_get_latency_timer(d->ftdi, &latency);
254     return latency;
255 }
256
257 unsigned short Context::poll_modem_status()
258 {
259     unsigned short status = 0;
260     ftdi_poll_modem_status(d->ftdi, &status);
261     return status;
262 }
263
264 int Context::set_event_char(unsigned char eventch, unsigned char enable)
265 {
266     return ftdi_set_event_char(d->ftdi, eventch, enable);
267 }
268
269 int Context::set_error_char(unsigned char errorch, unsigned char enable)
270 {
271     return ftdi_set_error_char(d->ftdi, errorch, enable);
272 }
273
274 int Context::bitbang_enable(unsigned char bitmask)
275 {
276     return ftdi_set_bitmode(d->ftdi, bitmask, BITMODE_BITBANG);
277 }
278
279 int Context::bitbang_disable()
280 {
281     return ftdi_disable_bitbang(d->ftdi);
282 }
283
284 int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
285 {
286     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
287 }
288
289 int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
290 {
291     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
292 }
293
294 int Context::read_pins(unsigned char *pins)
295 {
296     return ftdi_read_pins(d->ftdi, pins);
297 }
298
299 char* Context::error_string()
300 {
301     return ftdi_get_error_string(d->ftdi);
302 }
303
304 int Context::get_strings()
305 {
306     // Prepare buffers
307     char vendor[512], desc[512], serial[512];
308
309     int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512);
310
311     if (ret < 0)
312         return -1;
313
314     d->vendor = vendor;
315     d->description = desc;
316     d->serial = serial;
317
318     return 1;
319 }
320
321 int Context::get_strings_and_reopen()
322 {
323     // Get device strings (closes device)
324     int ret=get_strings();
325     if (ret < 0)
326     {
327         d->open = 0;
328         return ret;
329     }
330
331     // Reattach device
332     ret = ftdi_usb_open_dev(d->ftdi, d->dev);
333     d->open = (ret >= 0);
334
335     return ret;
336 }
337
338 /*! \brief Device strings properties.
339  */
340 const std::string& Context::vendor()
341 {
342     return d->vendor;
343 }
344
345 /*! \brief Device strings properties.
346  */
347 const std::string& Context::description()
348 {
349     return d->description;
350 }
351
352 /*! \brief Device strings properties.
353  */
354 const std::string& Context::serial()
355 {
356     return d->serial;
357 }
358
359 void Context::set_context(struct ftdi_context* context)
360 {
361     ftdi_free(d->ftdi);
362     d->ftdi = context;
363 }
364
365 void Context::set_usb_device(struct libusb_device *dev)
366 {
367     d->dev = dev;
368 }
369
370 struct ftdi_context* Context::context()
371 {
372     return d->ftdi;
373 }
374
375 class Eeprom::Private
376 {
377 public:
378     Private()
379             : context(0)
380     {}
381
382     struct ftdi_eeprom eeprom;
383     struct ftdi_context* context;
384 };
385
386 Eeprom::Eeprom(Context* parent)
387         : d ( new Private() )
388 {
389     d->context = parent->context();
390 }
391
392 Eeprom::~Eeprom()
393 {
394 }
395
396 void Eeprom::init_defaults()
397 {
398     return ftdi_eeprom_initdefaults(&d->eeprom);
399 }
400
401 void Eeprom::set_size(int size)
402 {
403     return ftdi_eeprom_setsize(d->context, &d->eeprom, size);
404 }
405
406 int Eeprom::size(unsigned char *eeprom, int maxsize)
407 {
408     return ftdi_read_eeprom_getsize(d->context, eeprom, maxsize);
409 }
410
411 int Eeprom::chip_id(unsigned int *chipid)
412 {
413     return ftdi_read_chipid(d->context, chipid);
414 }
415
416 int Eeprom::build(unsigned char *output)
417 {
418     return ftdi_eeprom_build(&d->eeprom, output);
419 }
420
421 int Eeprom::read(unsigned char *eeprom)
422 {
423     return ftdi_read_eeprom(d->context, eeprom);
424 }
425
426 int Eeprom::write(unsigned char *eeprom)
427 {
428     return ftdi_write_eeprom(d->context, eeprom);
429 }
430
431 int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
432 {
433     return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
434 }
435
436 int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
437 {
438     return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
439 }
440
441 int Eeprom::erase()
442 {
443     return ftdi_erase_eeprom(d->context);
444 }
445
446 class List::Private
447 {
448 public:
449     Private(struct ftdi_device_list* _devlist)
450             : devlist(_devlist)
451     {}
452
453     ~Private()
454     {
455         if(devlist)
456             ftdi_list_free(&devlist);
457     }
458
459     std::list<Context> list;
460     struct ftdi_device_list* devlist;
461 };
462
463 List::List(struct ftdi_device_list* devlist)
464         : d( new Private(devlist) )
465 {
466     if (devlist != 0)
467     {
468         // Iterate list
469         for (; devlist != 0; devlist = devlist->next)
470         {
471             Context c;
472             c.set_usb_device(devlist->dev);
473             c.get_strings();
474             d->list.push_back(c);
475         }
476     }
477 }
478
479 List::~List()
480 {
481 }
482
483 /**
484 * Return begin iterator for accessing the contained list elements
485 * @return Iterator
486 */
487 List::iterator List::begin()
488 {
489     return d->list.begin();
490 }
491
492 /**
493 * Return end iterator for accessing the contained list elements
494 * @return Iterator
495 */
496 List::iterator List::end()
497 {
498     return d->list.end();
499 }
500
501 /**
502 * Return begin iterator for accessing the contained list elements
503 * @return Const iterator
504 */
505 List::const_iterator List::begin() const
506 {
507     return d->list.begin();
508 }
509
510 /**
511 * Return end iterator for accessing the contained list elements
512 * @return Const iterator
513 */
514 List::const_iterator List::end() const
515 {
516     return d->list.end();
517 }
518
519 /**
520 * Return begin reverse iterator for accessing the contained list elements
521 * @return Reverse iterator
522 */
523 List::reverse_iterator List::rbegin()
524 {
525     return d->list.rbegin();
526 }
527
528 /**
529 * Return end reverse iterator for accessing the contained list elements
530 * @return Reverse iterator
531 */
532 List::reverse_iterator List::rend()
533 {
534     return d->list.rend();
535 }
536
537 /**
538 * Return begin reverse iterator for accessing the contained list elements
539 * @return Const reverse iterator
540 */
541 List::const_reverse_iterator List::rbegin() const
542 {
543     return d->list.rbegin();
544 }
545
546 /**
547 * Return end reverse iterator for accessing the contained list elements
548 * @return Const reverse iterator
549 */
550 List::const_reverse_iterator List::rend() const
551 {
552     return d->list.rend();
553
554 }
555
556 /**
557 * Get number of elements stored in the list
558 * @return Number of elements
559 */
560 List::ListType::size_type List::size() const
561 {
562     return d->list.size();
563 }
564
565 /**
566 * Check if list is empty
567 * @return True if empty, false otherwise
568 */
569 bool List::empty() const
570 {
571     return d->list.empty();
572 }
573
574 /**
575  * Removes all elements. Invalidates all iterators.
576  * Do it in a non-throwing way and also make
577  * sure we really free the allocated memory.
578  */
579 void List::clear()
580 {
581     ListType().swap(d->list);
582
583     // Free device list
584     if (d->devlist)
585     {
586         ftdi_list_free(&d->devlist);
587         d->devlist = 0;
588     }
589 }
590
591 /**
592  * Appends a copy of the element as the new last element.
593  * @param element Value to copy and append
594 */
595 void List::push_back(const Context& element)
596 {
597     d->list.push_back(element);
598 }
599
600 /**
601  * Adds a copy of the element as the new first element.
602  * @param element Value to copy and add
603 */
604 void List::push_front(const Context& element)
605 {
606     d->list.push_front(element);
607 }
608
609 /**
610  * Erase one element pointed by iterator
611  * @param pos Element to erase
612  * @return Position of the following element (or end())
613 */
614 List::iterator List::erase(iterator pos)
615 {
616     return d->list.erase(pos);
617 }
618
619 /**
620  * Erase a range of elements
621  * @param beg Begin of range
622  * @param end End of range
623  * @return Position of the element after the erased range (or end())
624 */
625 List::iterator List::erase(iterator beg, iterator end)
626 {
627     return d->list.erase(beg, end);
628 }
629
630 List* List::find_all(int vendor, int product)
631 {
632     struct ftdi_device_list* dlist = 0;
633     struct ftdi_context ftdi;
634     ftdi_init(&ftdi);
635     ftdi_usb_find_all(&ftdi, &dlist, vendor, product);
636     ftdi_deinit(&ftdi);
637     return new List(dlist);
638 }
639
640 }