Correct const-ness of write to agree with ftdi.h
[libftdi] / ftdipp / ftdi.cpp
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 /*
9 Copyright (C) 2008-2017 by Marek Vavruša / libftdi developers
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 <libusb.h>
30 #include "ftdi.hpp"
31 #include "ftdi_i.h"
32 #include "ftdi.h"
33
34 namespace Ftdi
35 {
36
37 class Context::Private
38 {
39 public:
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  */
66 Context::Context()
67         : d( new Private() )
68 {
69 }
70
71 /*! \brief Destructor.
72  */
73 Context::~Context()
74 {
75 }
76
77 bool Context::is_open()
78 {
79     return d->open;
80 }
81
82 int 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
93 int 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
112 int 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
122 int 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
133 int Context::close()
134 {
135     d->open = false;
136     d->dev = 0;
137     return ftdi_usb_close(d->ftdi);
138 }
139
140 int Context::reset()
141 {
142     return ftdi_usb_reset(d->ftdi);
143 }
144
145 int 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
157 int Context::set_interface(enum ftdi_interface interface)
158 {
159     return ftdi_set_interface(d->ftdi, interface);
160 }
161
162 void 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
168 int Context::set_baud_rate(int baudrate)
169 {
170     return ftdi_set_baudrate(d->ftdi, baudrate);
171 }
172
173 int 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
178 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)
179 {
180     return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
181 }
182
183 int Context::get_usb_read_timeout() const
184 {
185     return d->ftdi->usb_read_timeout;
186 }
187
188 void Context::set_usb_read_timeout(int usb_read_timeout)
189 {
190     d->ftdi->usb_read_timeout = usb_read_timeout;
191 }
192
193 int Context::get_usb_write_timeout() const
194 {
195     return d->ftdi->usb_write_timeout;
196 }
197
198 void Context::set_usb_write_timeout(int usb_write_timeout)
199 {
200     d->ftdi->usb_write_timeout = usb_write_timeout;
201 }
202
203 int Context::read(unsigned char *buf, int size)
204 {
205     return ftdi_read_data(d->ftdi, buf, size);
206 }
207
208 int Context::set_read_chunk_size(unsigned int chunksize)
209 {
210     return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
211 }
212
213 int 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
222 int Context::write(const unsigned char *buf, int size)
223 {
224     return ftdi_write_data(d->ftdi, buf, size);
225 }
226
227 int Context::set_write_chunk_size(unsigned int chunksize)
228 {
229     return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
230 }
231
232 int 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
241 int Context::set_flow_control(int flowctrl)
242 {
243     return ftdi_setflowctrl(d->ftdi, flowctrl);
244 }
245
246 int 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
258 int Context::set_dtr(bool state)
259 {
260     return ftdi_setdtr(d->ftdi, state);
261 }
262
263 int Context::set_rts(bool state)
264 {
265     return ftdi_setrts(d->ftdi, state);
266 }
267
268 int Context::set_latency(unsigned char latency)
269 {
270     return ftdi_set_latency_timer(d->ftdi, latency);
271 }
272
273 unsigned Context::latency()
274 {
275     unsigned char latency = 0;
276     ftdi_get_latency_timer(d->ftdi, &latency);
277     return latency;
278 }
279
280 unsigned short Context::poll_modem_status()
281 {
282     unsigned short status = 0;
283     ftdi_poll_modem_status(d->ftdi, &status);
284     return status;
285 }
286
287 int Context::set_event_char(unsigned char eventch, unsigned char enable)
288 {
289     return ftdi_set_event_char(d->ftdi, eventch, enable);
290 }
291
292 int Context::set_error_char(unsigned char errorch, unsigned char enable)
293 {
294     return ftdi_set_error_char(d->ftdi, errorch, enable);
295 }
296
297 int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
298 {
299     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
300 }
301
302 int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
303 {
304     return ftdi_set_bitmode(d->ftdi, bitmask, mode);
305 }
306
307 int Context::bitbang_disable()
308 {
309     return ftdi_disable_bitbang(d->ftdi);
310 }
311
312 int Context::read_pins(unsigned char *pins)
313 {
314     return ftdi_read_pins(d->ftdi, pins);
315 }
316
317 const char* Context::error_string()
318 {
319     return ftdi_get_error_string(d->ftdi);
320 }
321
322 int 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
339 int 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  */
368 const 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  */
377 const 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  */
386 const std::string& Context::serial()
387 {
388     if(d->serial.empty())
389         get_strings_and_reopen(false,false,true);
390     return d->serial;
391 }
392
393 void Context::set_context(struct ftdi_context* context)
394 {
395     ftdi_free(d->ftdi);
396     d->ftdi = context;
397 }
398
399 void Context::set_usb_device(struct libusb_device *dev)
400 {
401     d->dev = dev;
402 }
403
404 struct ftdi_context* Context::context()
405 {
406     return d->ftdi;
407 }
408
409 class Eeprom::Private
410 {
411 public:
412     Private()
413             : context(0)
414     {}
415
416     struct ftdi_eeprom eeprom;
417     struct ftdi_context* context;
418 };
419
420 Eeprom::Eeprom(Context* parent)
421         : d ( new Private() )
422 {
423     d->context = parent->context();
424 }
425
426 Eeprom::~Eeprom()
427 {
428 }
429
430 int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
431 {
432     return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
433 }
434
435 int Eeprom::chip_id(unsigned int *chipid)
436 {
437     return ftdi_read_chipid(d->context, chipid);
438 }
439
440 int Eeprom::build(unsigned char *output)
441 {
442     return ftdi_eeprom_build(d->context);
443 }
444
445 int Eeprom::read(unsigned char *eeprom)
446 {
447     return ftdi_read_eeprom(d->context);
448 }
449
450 int Eeprom::write(unsigned char *eeprom)
451 {
452     return ftdi_write_eeprom(d->context);
453 }
454
455 int 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
460 int 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
465 int Eeprom::erase()
466 {
467     return ftdi_erase_eeprom(d->context);
468 }
469
470 class List::Private
471 {
472 public:
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
487 List::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
503 List::~List()
504 {
505 }
506
507 /**
508 * Return begin iterator for accessing the contained list elements
509 * @return Iterator
510 */
511 List::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 */
520 List::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 */
529 List::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 */
538 List::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 */
547 List::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 */
556 List::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 */
565 List::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 */
574 List::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 */
584 List::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 */
593 bool 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  */
603 void 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 */
619 void 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 */
628 void 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 */
638 List::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 */
649 List::iterator List::erase(iterator beg, iterator end)
650 {
651     return d->list.erase(beg, end);
652 }
653
654 List* 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 }