Provide internal eeprom structure buffer with internal byte buffer Purge external...
[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
401int Eeprom::chip_id(unsigned int *chipid)
402{
403 return ftdi_read_chipid(d->context, chipid);
404}
405
406int Eeprom::build(unsigned char *output)
407{
408 return ftdi_eeprom_build(d->context);
409}
410
411int Eeprom::read(unsigned char *eeprom)
412{
413 return ftdi_read_eeprom(d->context);
414}
415
416int Eeprom::write(unsigned char *eeprom)
417{
418 return ftdi_write_eeprom(d->context);
419}
420
421int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
422{
423 return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
424}
425
426int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
427{
428 return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
429}
430
431int Eeprom::erase()
432{
433 return ftdi_erase_eeprom(d->context);
434}
435
436class List::Private
437{
438public:
439 Private(struct ftdi_device_list* _devlist)
440 : devlist(_devlist)
441 {}
442
443 ~Private()
444 {
445 if(devlist)
446 ftdi_list_free(&devlist);
447 }
448
449 std::list<Context> list;
450 struct ftdi_device_list* devlist;
451};
452
453List::List(struct ftdi_device_list* devlist)
454 : d( new Private(devlist) )
455{
456 if (devlist != 0)
457 {
458 // Iterate list
459 for (; devlist != 0; devlist = devlist->next)
460 {
461 Context c;
462 c.set_usb_device(devlist->dev);
463 c.get_strings();
464 d->list.push_back(c);
465 }
466 }
467}
468
469List::~List()
470{
471}
472
473/**
474* Return begin iterator for accessing the contained list elements
475* @return Iterator
476*/
477List::iterator List::begin()
478{
479 return d->list.begin();
480}
481
482/**
483* Return end iterator for accessing the contained list elements
484* @return Iterator
485*/
486List::iterator List::end()
487{
488 return d->list.end();
489}
490
491/**
492* Return begin iterator for accessing the contained list elements
493* @return Const iterator
494*/
495List::const_iterator List::begin() const
496{
497 return d->list.begin();
498}
499
500/**
501* Return end iterator for accessing the contained list elements
502* @return Const iterator
503*/
504List::const_iterator List::end() const
505{
506 return d->list.end();
507}
508
509/**
510* Return begin reverse iterator for accessing the contained list elements
511* @return Reverse iterator
512*/
513List::reverse_iterator List::rbegin()
514{
515 return d->list.rbegin();
516}
517
518/**
519* Return end reverse iterator for accessing the contained list elements
520* @return Reverse iterator
521*/
522List::reverse_iterator List::rend()
523{
524 return d->list.rend();
525}
526
527/**
528* Return begin reverse iterator for accessing the contained list elements
529* @return Const reverse iterator
530*/
531List::const_reverse_iterator List::rbegin() const
532{
533 return d->list.rbegin();
534}
535
536/**
537* Return end reverse iterator for accessing the contained list elements
538* @return Const reverse iterator
539*/
540List::const_reverse_iterator List::rend() const
541{
542 return d->list.rend();
543
544}
545
546/**
547* Get number of elements stored in the list
548* @return Number of elements
549*/
550List::ListType::size_type List::size() const
551{
552 return d->list.size();
553}
554
555/**
556* Check if list is empty
557* @return True if empty, false otherwise
558*/
559bool List::empty() const
560{
561 return d->list.empty();
562}
563
564/**
565 * Removes all elements. Invalidates all iterators.
566 * Do it in a non-throwing way and also make
567 * sure we really free the allocated memory.
568 */
569void List::clear()
570{
571 ListType().swap(d->list);
572
573 // Free device list
574 if (d->devlist)
575 {
576 ftdi_list_free(&d->devlist);
577 d->devlist = 0;
578 }
579}
580
581/**
582 * Appends a copy of the element as the new last element.
583 * @param element Value to copy and append
584*/
585void List::push_back(const Context& element)
586{
587 d->list.push_back(element);
588}
589
590/**
591 * Adds a copy of the element as the new first element.
592 * @param element Value to copy and add
593*/
594void List::push_front(const Context& element)
595{
596 d->list.push_front(element);
597}
598
599/**
600 * Erase one element pointed by iterator
601 * @param pos Element to erase
602 * @return Position of the following element (or end())
603*/
604List::iterator List::erase(iterator pos)
605{
606 return d->list.erase(pos);
607}
608
609/**
610 * Erase a range of elements
611 * @param beg Begin of range
612 * @param end End of range
613 * @return Position of the element after the erased range (or end())
614*/
615List::iterator List::erase(iterator beg, iterator end)
616{
617 return d->list.erase(beg, end);
618}
619
620List* List::find_all(int vendor, int product)
621{
622 struct ftdi_device_list* dlist = 0;
623 struct ftdi_context ftdi;
624 ftdi_init(&ftdi);
625 ftdi_usb_find_all(&ftdi, &dlist, vendor, product);
626 ftdi_deinit(&ftdi);
627 return new List(dlist);
628}
629
630}