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