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