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