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