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