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