Fixes the three open methods of the cpp wrapper that do not get an usb-device paramet...
[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             :  ftdi(0), dev(0), open(false)
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 usb_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     d->dev = usb_device(d->ftdi->usb_dev);
89
90     return get_strings_and_reopen();
91 }
92
93 int 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     d->dev = usb_device(d->ftdi->usb_dev);
110
111     return get_strings_and_reopen();
112 }
113
114 int Context::open(const std::string& description)
115 {
116     int ret = ftdi_usb_open_string(d->ftdi, description.c_str());
117
118     if (ret < 0)
119        return ret;
120
121     d->dev = usb_device(d->ftdi->usb_dev);
122
123     return get_strings_and_reopen();
124 }
125
126 int Context::open(struct usb_device *dev)
127 {
128     if (dev != 0)
129         d->dev = dev;
130
131     if (d->dev == 0)
132         return -1;
133
134     return get_strings_and_reopen();
135 }
136
137 int Context::close()
138 {
139     d->open = false;
140     return ftdi_usb_close(d->ftdi);
141 }
142
143 int Context::reset()
144 {
145     return ftdi_usb_reset(d->ftdi);
146 }
147
148 int Context::flush(int mask)
149 {
150     int ret = 1;
151
152     if (mask & Input)
153         ret &= ftdi_usb_purge_rx_buffer(d->ftdi);
154     if (mask & Output)
155         ret &= ftdi_usb_purge_tx_buffer(d->ftdi);
156
157     return ret;
158 }
159
160 int Context::set_interface(enum ftdi_interface interface)
161 {
162     return ftdi_set_interface(d->ftdi, interface);
163 }
164
165 void Context::set_usb_device(struct usb_dev_handle *dev)
166 {
167     ftdi_set_usbdev(d->ftdi, dev);
168     d->dev = usb_device(dev);
169 }
170
171 int Context::set_baud_rate(int baudrate)
172 {
173     return ftdi_set_baudrate(d->ftdi, baudrate);
174 }
175
176 int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
177 {
178     return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
179 }
180
181 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)
182 {
183     return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
184 }
185
186 int Context::read(unsigned char *buf, int size)
187 {
188     return ftdi_read_data(d->ftdi, buf, size);
189 }
190
191 int Context::set_read_chunk_size(unsigned int chunksize)
192 {
193     return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
194 }
195
196 int Context::read_chunk_size()
197 {
198     unsigned chunk = -1;
199     if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
200         return -1;
201
202     return chunk;
203 }
204
205 int Context::write(unsigned char *buf, int size)
206 {
207     return ftdi_write_data(d->ftdi, buf, size);
208 }
209
210 int Context::set_write_chunk_size(unsigned int chunksize)
211 {
212     return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
213 }
214
215 int Context::write_chunk_size()
216 {
217     unsigned chunk = -1;
218     if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
219         return -1;
220
221     return chunk;
222 }
223
224 int Context::set_flow_control(int flowctrl)
225 {
226     return ftdi_setflowctrl(d->ftdi, flowctrl);
227 }
228
229 int Context::set_modem_control(int mask)
230 {
231     int dtr = 0, rts = 0;
232
233     if (mask & Dtr)
234         dtr = 1;
235     if (mask & Rts)
236         rts = 1;
237
238     return ftdi_setdtr_rts(d->ftdi, dtr, rts);
239 }
240
241 int Context::set_dtr(bool state)
242 {
243     return ftdi_setdtr(d->ftdi, state);
244 }
245
246 int Context::set_rts(bool state)
247 {
248     return ftdi_setrts(d->ftdi, state);
249 }
250
251 int Context::set_latency(unsigned char latency)
252 {
253     return ftdi_set_latency_timer(d->ftdi, latency);
254 }
255
256 unsigned Context::latency()
257 {
258     unsigned char latency = 0;
259     ftdi_get_latency_timer(d->ftdi, &latency);
260     return latency;
261 }
262
263 unsigned short Context::poll_modem_status()
264 {
265     unsigned short status = 0;
266     ftdi_poll_modem_status(d->ftdi, &status);
267     return status;
268 }
269
270 int Context::set_event_char(unsigned char eventch, unsigned char enable)
271 {
272     return ftdi_set_event_char(d->ftdi, eventch, enable);
273 }
274
275 int Context::set_error_char(unsigned char errorch, unsigned char enable)
276 {
277     return ftdi_set_error_char(d->ftdi, errorch, enable);
278 }
279
280 int Context::bitbang_enable(unsigned char bitmask)
281 {
282     return ftdi_set_bitmode(d->ftdi, bitmask, BITMODE_BITBANG);
283 }
284
285 int Context::bitbang_disable()
286 {
287     return ftdi_disable_bitbang(d->ftdi);
288 }
289
290 int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
291 {
292     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
293 }
294
295 int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
296 {
297     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
298 }
299
300 int Context::read_pins(unsigned char *pins)
301 {
302     return ftdi_read_pins(d->ftdi, pins);
303 }
304
305 char* Context::error_string()
306 {
307     return ftdi_get_error_string(d->ftdi);
308 }
309
310 int Context::get_strings()
311 {
312     // Prepare buffers
313     char vendor[512], desc[512], serial[512];
314
315     int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512);
316
317     if (ret < 0)
318         return -1;
319
320     d->vendor = vendor;
321     d->description = desc;
322     d->serial = serial;
323
324     return 1;
325 }
326
327 int Context::get_strings_and_reopen()
328 {
329     // Get device strings (closes device)
330     int ret=get_strings();
331     if (ret < 0)
332     {
333         d->open = 0;
334         return ret;
335     }
336
337     // Reattach device
338     ret = ftdi_usb_open_dev(d->ftdi, d->dev);
339     d->open = (ret >= 0);
340
341     return ret;
342 }
343
344 /*! \brief Device strings properties.
345  */
346 const std::string& Context::vendor()
347 {
348     return d->vendor;
349 }
350
351 /*! \brief Device strings properties.
352  */
353 const std::string& Context::description()
354 {
355     return d->description;
356 }
357
358 /*! \brief Device strings properties.
359  */
360 const std::string& Context::serial()
361 {
362     return d->serial;
363 }
364
365 void Context::set_context(struct ftdi_context* context)
366 {
367     ftdi_free(d->ftdi);
368     d->ftdi = context;
369 }
370
371 void Context::set_usb_device(struct usb_device *dev)
372 {
373     d->dev = dev;
374 }
375
376 struct ftdi_context* Context::context()
377 {
378     return d->ftdi;
379 }
380
381 class Eeprom::Private
382 {
383 public:
384     Private()
385             : context(0)
386     {}
387
388     struct ftdi_eeprom eeprom;
389     struct ftdi_context* context;
390 };
391
392 Eeprom::Eeprom(Context* parent)
393         : d ( new Private() )
394 {
395     d->context = parent->context();
396 }
397
398 Eeprom::~Eeprom()
399 {
400 }
401
402 void Eeprom::init_defaults()
403 {
404     return ftdi_eeprom_initdefaults(&d->eeprom);
405 }
406
407 void Eeprom::set_size(int size)
408 {
409     return ftdi_eeprom_setsize(d->context, &d->eeprom, size);
410 }
411
412 int Eeprom::size(unsigned char *eeprom, int maxsize)
413 {
414     return ftdi_read_eeprom_getsize(d->context, eeprom, maxsize);
415 }
416
417 int Eeprom::chip_id(unsigned int *chipid)
418 {
419     return ftdi_read_chipid(d->context, chipid);
420 }
421
422 int Eeprom::build(unsigned char *output)
423 {
424     return ftdi_eeprom_build(&d->eeprom, output);
425 }
426
427 int Eeprom::read(unsigned char *eeprom)
428 {
429     return ftdi_read_eeprom(d->context, eeprom);
430 }
431
432 int Eeprom::write(unsigned char *eeprom)
433 {
434     return ftdi_write_eeprom(d->context, eeprom);
435 }
436
437 int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
438 {
439     return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
440 }
441
442 int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
443 {
444     return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
445 }
446
447 int Eeprom::erase()
448 {
449     return ftdi_erase_eeprom(d->context);
450 }
451
452 class List::Private
453 {
454 public:
455     Private(struct ftdi_device_list* _devlist)
456             : devlist(_devlist)
457     {}
458
459     ~Private()
460     {
461         if(devlist)
462             ftdi_list_free(&devlist);
463     }
464
465     std::list<Context> list;
466     struct ftdi_device_list* devlist;
467 };
468
469 List::List(struct ftdi_device_list* devlist)
470         : d( new Private(devlist) )
471 {
472     if (devlist != 0)
473     {
474         // Iterate list
475         for (; devlist != 0; devlist = devlist->next)
476         {
477             Context c;
478             c.set_usb_device(devlist->dev);
479             c.get_strings();
480             d->list.push_back(c);
481         }
482     }
483 }
484
485 List::~List()
486 {
487 }
488
489 /**
490 * Return begin iterator for accessing the contained list elements
491 * @return Iterator
492 */
493 List::iterator List::begin()
494 {
495     return d->list.begin();
496 }
497
498 /**
499 * Return end iterator for accessing the contained list elements
500 * @return Iterator
501 */
502 List::iterator List::end()
503 {
504     return d->list.end();
505 }
506
507 /**
508 * Return begin iterator for accessing the contained list elements
509 * @return Const iterator
510 */
511 List::const_iterator List::begin() const
512 {
513     return d->list.begin();
514 }
515
516 /**
517 * Return end iterator for accessing the contained list elements
518 * @return Const iterator
519 */
520 List::const_iterator List::end() const
521 {
522     return d->list.end();
523 }
524
525 /**
526 * Return begin reverse iterator for accessing the contained list elements
527 * @return Reverse iterator
528 */
529 List::reverse_iterator List::rbegin()
530 {
531     return d->list.rbegin();
532 }
533
534 /**
535 * Return end reverse iterator for accessing the contained list elements
536 * @return Reverse iterator
537 */
538 List::reverse_iterator List::rend()
539 {
540     return d->list.rend();
541 }
542
543 /**
544 * Return begin reverse iterator for accessing the contained list elements
545 * @return Const reverse iterator
546 */
547 List::const_reverse_iterator List::rbegin() const
548 {
549     return d->list.rbegin();
550 }
551
552 /**
553 * Return end reverse iterator for accessing the contained list elements
554 * @return Const reverse iterator
555 */
556 List::const_reverse_iterator List::rend() const
557 {
558     return d->list.rend();
559
560 }
561
562 /**
563 * Get number of elements stored in the list
564 * @return Number of elements
565 */
566 List::ListType::size_type List::size() const
567 {
568     return d->list.size();
569 }
570
571 /**
572 * Check if list is empty
573 * @return True if empty, false otherwise
574 */
575 bool List::empty() const
576 {
577     return d->list.empty();
578 }
579
580 /**
581  * Removes all elements. Invalidates all iterators.
582  * Do it in a non-throwing way and also make
583  * sure we really free the allocated memory.
584  */
585 void List::clear()
586 {
587     ListType().swap(d->list);
588
589     // Free device list
590     if (d->devlist)
591     {
592         ftdi_list_free(&d->devlist);
593         d->devlist = 0;
594     }
595 }
596
597 /**
598  * Appends a copy of the element as the new last element.
599  * @param element Value to copy and append
600 */
601 void List::push_back(const Context& element)
602 {
603     d->list.push_back(element);
604 }
605
606 /**
607  * Adds a copy of the element as the new first element.
608  * @param element Value to copy and add
609 */
610 void List::push_front(const Context& element)
611 {
612     d->list.push_front(element);
613 }
614
615 /**
616  * Erase one element pointed by iterator
617  * @param pos Element to erase
618  * @return Position of the following element (or end())
619 */
620 List::iterator List::erase(iterator pos)
621 {
622     return d->list.erase(pos);
623 }
624
625 /**
626  * Erase a range of elements
627  * @param beg Begin of range
628  * @param end End of range
629  * @return Position of the element after the erased range (or end())
630 */
631 List::iterator List::erase(iterator beg, iterator end)
632 {
633     return d->list.erase(beg, end);
634 }
635
636 List* List::find_all(int vendor, int product)
637 {
638     struct ftdi_device_list* dlist = 0;
639     struct ftdi_context ftdi;
640     ftdi_init(&ftdi);
641     ftdi_usb_find_all(&ftdi, &dlist, vendor, product);
642     ftdi_deinit(&ftdi);
643     return new List(dlist);
644 }
645
646 }