Use allocated ftdi structure
[libftdi] / ftdipp / ftdi.cpp
CommitLineData
cdf448f6
TJ
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 ***************************************************************************/
3ab8f642
TJ
8/*
9Copyright (C) 2008 by Marek Vavruša
cdf448f6 10
3ab8f642
TJ
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.
cdf448f6 25
3ab8f642
TJ
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*/
20b1459a
TJ
29#include "ftdi.hpp"
30#include "ftdi.h"
31
32namespace Ftdi
33{
34
35class Context::Private
36{
cdf448f6
TJ
37public:
38 Private()
d5c91348 39 : open(false), ftdi(0), dev(0)
cdf448f6 40 {
cfceadbc
MV
41 ftdi = ftdi_new();
42 }
43
44 ~Private()
45 {
22d12cda 46 if (open)
cfceadbc
MV
47 ftdi_usb_close(ftdi);
48
49 ftdi_free(ftdi);
cdf448f6
TJ
50 }
51
52 bool open;
53
54 struct ftdi_context* ftdi;
579b006f 55 struct libusb_device* dev;
cdf448f6
TJ
56
57 std::string vendor;
58 std::string description;
59 std::string serial;
20b1459a
TJ
60};
61
62/*! \brief Constructor.
63 */
64Context::Context()
cdf448f6 65 : d( new Private() )
20b1459a 66{
20b1459a
TJ
67}
68
69/*! \brief Destructor.
70 */
71Context::~Context()
72{
20b1459a
TJ
73}
74
75bool Context::is_open()
76{
cdf448f6 77 return d->open;
20b1459a
TJ
78}
79
58cce2d4 80int Context::open(int vendor, int product)
20b1459a 81{
2f6b4bb6 82 // Open device
58cce2d4 83 int ret = ftdi_usb_open(d->ftdi, vendor, product);
20b1459a 84
2f6b4bb6
MV
85 if (ret < 0)
86 return ret;
20b1459a 87
58cce2d4
GE
88 return get_strings_and_reopen();
89}
2f6b4bb6 90
58cce2d4
GE
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();
20b1459a 101
58cce2d4
GE
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();
20b1459a
TJ
118}
119
579b006f 120int Context::open(struct libusb_device *dev)
20b1459a 121{
cdf448f6
TJ
122 if (dev != 0)
123 d->dev = dev;
124
125 if (d->dev == 0)
126 return -1;
20b1459a 127
58cce2d4 128 return get_strings_and_reopen();
20b1459a
TJ
129}
130
131int Context::close()
132{
cdf448f6
TJ
133 d->open = false;
134 return ftdi_usb_close(d->ftdi);
20b1459a
TJ
135}
136
137int Context::reset()
138{
cdf448f6 139 return ftdi_usb_reset(d->ftdi);
20b1459a
TJ
140}
141
142int Context::flush(int mask)
143{
cdf448f6 144 int ret = 1;
20b1459a 145
cdf448f6
TJ
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;
20b1459a
TJ
152}
153
154int Context::set_interface(enum ftdi_interface interface)
155{
cdf448f6 156 return ftdi_set_interface(d->ftdi, interface);
20b1459a
TJ
157}
158
579b006f 159void Context::set_usb_device(struct libusb_device_handle *dev)
20b1459a 160{
cdf448f6 161 ftdi_set_usbdev(d->ftdi, dev);
579b006f 162 d->dev = libusb_get_device(dev);
20b1459a
TJ
163}
164
165int Context::set_baud_rate(int baudrate)
166{
cdf448f6 167 return ftdi_set_baudrate(d->ftdi, baudrate);
20b1459a
TJ
168}
169
170int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
171{
cdf448f6 172 return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
20b1459a
TJ
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{
cdf448f6 177 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
20b1459a
TJ
178}
179
180int Context::read(unsigned char *buf, int size)
181{
cdf448f6 182 return ftdi_read_data(d->ftdi, buf, size);
20b1459a
TJ
183}
184
185int Context::set_read_chunk_size(unsigned int chunksize)
186{
cdf448f6 187 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
188}
189
190int Context::read_chunk_size()
191{
cdf448f6
TJ
192 unsigned chunk = -1;
193 if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
194 return -1;
20b1459a 195
cdf448f6
TJ
196 return chunk;
197}
20b1459a
TJ
198
199int Context::write(unsigned char *buf, int size)
200{
cdf448f6 201 return ftdi_write_data(d->ftdi, buf, size);
20b1459a
TJ
202}
203
204int Context::set_write_chunk_size(unsigned int chunksize)
205{
cdf448f6 206 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
207}
208
209int Context::write_chunk_size()
210{
cdf448f6
TJ
211 unsigned chunk = -1;
212 if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
213 return -1;
20b1459a 214
cdf448f6 215 return chunk;
20b1459a
TJ
216}
217
218int Context::set_flow_control(int flowctrl)
219{
cdf448f6 220 return ftdi_setflowctrl(d->ftdi, flowctrl);
20b1459a
TJ
221}
222
223int Context::set_modem_control(int mask)
224{
cdf448f6
TJ
225 int dtr = 0, rts = 0;
226
227 if (mask & Dtr)
228 dtr = 1;
229 if (mask & Rts)
230 rts = 1;
20b1459a 231
cdf448f6 232 return ftdi_setdtr_rts(d->ftdi, dtr, rts);
20b1459a
TJ
233}
234
235int Context::set_dtr(bool state)
236{
cdf448f6 237 return ftdi_setdtr(d->ftdi, state);
20b1459a
TJ
238}
239
240int Context::set_rts(bool state)
241{
cdf448f6 242 return ftdi_setrts(d->ftdi, state);
20b1459a
TJ
243}
244
245int Context::set_latency(unsigned char latency)
246{
cdf448f6 247 return ftdi_set_latency_timer(d->ftdi, latency);
20b1459a
TJ
248}
249
250unsigned Context::latency()
251{
cdf448f6
TJ
252 unsigned char latency = 0;
253 ftdi_get_latency_timer(d->ftdi, &latency);
254 return latency;
20b1459a
TJ
255}
256
257unsigned short Context::poll_modem_status()
258{
cdf448f6
TJ
259 unsigned short status = 0;
260 ftdi_poll_modem_status(d->ftdi, &status);
261 return status;
20b1459a
TJ
262}
263
20b1459a
TJ
264int Context::set_event_char(unsigned char eventch, unsigned char enable)
265{
cdf448f6 266 return ftdi_set_event_char(d->ftdi, eventch, enable);
20b1459a
TJ
267}
268
269int Context::set_error_char(unsigned char errorch, unsigned char enable)
270{
cdf448f6 271 return ftdi_set_error_char(d->ftdi, errorch, enable);
20b1459a
TJ
272}
273
274int Context::bitbang_enable(unsigned char bitmask)
275{
58cce2d4 276 return ftdi_set_bitmode(d->ftdi, bitmask, BITMODE_BITBANG);
20b1459a
TJ
277}
278
279int Context::bitbang_disable()
280{
cdf448f6 281 return ftdi_disable_bitbang(d->ftdi);
20b1459a
TJ
282}
283
284int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
285{
c2ed8c4e 286 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
58cce2d4
GE
287}
288
289int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
290{
cdf448f6 291 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
20b1459a
TJ
292}
293
294int Context::read_pins(unsigned char *pins)
295{
cdf448f6 296 return ftdi_read_pins(d->ftdi, pins);
20b1459a
TJ
297}
298
299char* Context::error_string()
300{
cdf448f6 301 return ftdi_get_error_string(d->ftdi);
20b1459a
TJ
302}
303
304int Context::get_strings()
305{
cdf448f6
TJ
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;
20b1459a 313
cdf448f6
TJ
314 d->vendor = vendor;
315 d->description = desc;
316 d->serial = serial;
20b1459a 317
cdf448f6 318 return 1;
20b1459a
TJ
319}
320
58cce2d4
GE
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
1bbaf1ce 338/*! \brief Device strings properties.
20b1459a
TJ
339 */
340const std::string& Context::vendor()
341{
cdf448f6 342 return d->vendor;
20b1459a
TJ
343}
344
1bbaf1ce
JP
345/*! \brief Device strings properties.
346 */
20b1459a
TJ
347const std::string& Context::description()
348{
cdf448f6 349 return d->description;
20b1459a
TJ
350}
351
1bbaf1ce
JP
352/*! \brief Device strings properties.
353 */
20b1459a
TJ
354const std::string& Context::serial()
355{
cdf448f6 356 return d->serial;
20b1459a
TJ
357}
358
359void Context::set_context(struct ftdi_context* context)
360{
cdf448f6
TJ
361 ftdi_free(d->ftdi);
362 d->ftdi = context;
20b1459a
TJ
363}
364
579b006f 365void Context::set_usb_device(struct libusb_device *dev)
20b1459a 366{
cdf448f6 367 d->dev = dev;
20b1459a
TJ
368}
369
370struct ftdi_context* Context::context()
371{
cdf448f6 372 return d->ftdi;
20b1459a
TJ
373}
374
375class Eeprom::Private
376{
cdf448f6
TJ
377public:
378 Private()
379 : context(0)
380 {}
20b1459a 381
cdf448f6
TJ
382 struct ftdi_eeprom eeprom;
383 struct ftdi_context* context;
20b1459a
TJ
384};
385
386Eeprom::Eeprom(Context* parent)
cdf448f6 387 : d ( new Private() )
20b1459a 388{
cdf448f6 389 d->context = parent->context();
20b1459a
TJ
390}
391
392Eeprom::~Eeprom()
393{
20b1459a
TJ
394}
395
396void Eeprom::init_defaults()
397{
c0a96aed 398 return ftdi_eeprom_initdefaults(d->context);
20b1459a
TJ
399}
400
401void Eeprom::set_size(int size)
402{
cdf448f6 403 return ftdi_eeprom_setsize(d->context, &d->eeprom, size);
20b1459a
TJ
404}
405
20b1459a
TJ
406int Eeprom::chip_id(unsigned int *chipid)
407{
cdf448f6 408 return ftdi_read_chipid(d->context, chipid);
20b1459a
TJ
409}
410
411int Eeprom::build(unsigned char *output)
412{
c0a96aed 413 return ftdi_eeprom_build(d->context, output);
20b1459a
TJ
414}
415
416int Eeprom::read(unsigned char *eeprom)
417{
cdf448f6 418 return ftdi_read_eeprom(d->context, eeprom);
20b1459a
TJ
419}
420
421int Eeprom::write(unsigned char *eeprom)
422{
cdf448f6 423 return ftdi_write_eeprom(d->context, eeprom);
20b1459a
TJ
424}
425
449c87a9
TJ
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
20b1459a
TJ
436int Eeprom::erase()
437{
cdf448f6 438 return ftdi_erase_eeprom(d->context);
20b1459a
TJ
439}
440
441class List::Private
442{
cdf448f6 443public:
6b22a054
MV
444 Private(struct ftdi_device_list* _devlist)
445 : devlist(_devlist)
cdf448f6 446 {}
20b1459a 447
cfceadbc
MV
448 ~Private()
449 {
6b22a054
MV
450 if(devlist)
451 ftdi_list_free(&devlist);
cfceadbc
MV
452 }
453
6b22a054
MV
454 std::list<Context> list;
455 struct ftdi_device_list* devlist;
20b1459a
TJ
456};
457
458List::List(struct ftdi_device_list* devlist)
6b22a054 459 : d( new Private(devlist) )
20b1459a 460{
cdf448f6
TJ
461 if (devlist != 0)
462 {
463 // Iterate list
6b22a054 464 for (; devlist != 0; devlist = devlist->next)
cdf448f6 465 {
cfceadbc 466 Context c;
6b22a054 467 c.set_usb_device(devlist->dev);
cfceadbc 468 c.get_strings();
6b22a054 469 d->list.push_back(c);
cdf448f6 470 }
cdf448f6 471 }
20b1459a
TJ
472}
473
474List::~List()
475{
20b1459a
TJ
476}
477
a14193ac
TJ
478/**
479* Return begin iterator for accessing the contained list elements
480* @return Iterator
481*/
482List::iterator List::begin()
6b22a054 483{
a14193ac 484 return d->list.begin();
6b22a054
MV
485}
486
a14193ac
TJ
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
6b22a054 501{
a14193ac 502 return d->list.begin();
6b22a054
MV
503}
504
a14193ac
TJ
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}
6b22a054 513
a14193ac
TJ
514/**
515* Return begin reverse iterator for accessing the contained list elements
516* @return Reverse iterator
517*/
518List::reverse_iterator List::rbegin()
6b22a054 519{
a14193ac 520 return d->list.rbegin();
6b22a054
MV
521}
522
a14193ac
TJ
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 */
6b22a054
MV
574void List::clear()
575{
a14193ac 576 ListType().swap(d->list);
6b22a054
MV
577
578 // Free device list
a14193ac
TJ
579 if (d->devlist)
580 {
581 ftdi_list_free(&d->devlist);
582 d->devlist = 0;
583 }
6b22a054
MV
584}
585
a14193ac
TJ
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)
6b22a054 591{
a14193ac 592 d->list.push_back(element);
6b22a054
MV
593}
594
a14193ac
TJ
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)
6b22a054 600{
a14193ac 601 d->list.push_front(element);
6b22a054
MV
602}
603
a14193ac
TJ
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}
6b22a054 624
20b1459a
TJ
625List* List::find_all(int vendor, int product)
626{
cdf448f6
TJ
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);
20b1459a
TJ
633}
634
635}