Commit | Line | Data |
---|---|---|
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 | ***************************************************************************/ | |
8 | ||
9 | /*************************************************************************** | |
10 | * * | |
11 | * This program is free software; you can redistribute it and/or modify * | |
12 | * it under the terms of the GNU Lesser General Public License * | |
13 | * version 2.1 as published by the Free Software Foundation; * | |
14 | * * | |
15 | ***************************************************************************/ | |
16 | ||
20b1459a TJ |
17 | #include "ftdi.hpp" |
18 | #include "ftdi.h" | |
19 | ||
20 | namespace Ftdi | |
21 | { | |
22 | ||
23 | class Context::Private | |
24 | { | |
cdf448f6 TJ |
25 | public: |
26 | Private() | |
27 | : ftdi(0), dev(0), open(false) | |
28 | { | |
29 | } | |
30 | ||
31 | bool open; | |
32 | ||
33 | struct ftdi_context* ftdi; | |
34 | struct usb_device* dev; | |
35 | ||
36 | std::string vendor; | |
37 | std::string description; | |
38 | std::string serial; | |
20b1459a TJ |
39 | }; |
40 | ||
41 | /*! \brief Constructor. | |
42 | */ | |
43 | Context::Context() | |
cdf448f6 | 44 | : d( new Private() ) |
20b1459a | 45 | { |
cdf448f6 | 46 | d->ftdi = ftdi_new(); |
20b1459a TJ |
47 | } |
48 | ||
49 | /*! \brief Destructor. | |
50 | */ | |
51 | Context::~Context() | |
52 | { | |
cdf448f6 TJ |
53 | if (d->open) |
54 | close(); | |
55 | ||
56 | ftdi_free(d->ftdi); | |
57 | delete d; | |
20b1459a TJ |
58 | } |
59 | ||
60 | bool Context::is_open() | |
61 | { | |
cdf448f6 | 62 | return d->open; |
20b1459a TJ |
63 | } |
64 | ||
65 | int Context::open(int vendor, int product, const std::string& description, const std::string& serial) | |
66 | { | |
cdf448f6 TJ |
67 | int ret = 0; |
68 | ||
69 | if (description.empty() && serial.empty()) | |
70 | ret = ftdi_usb_open(d->ftdi, vendor, product); | |
71 | else | |
72 | ret = ftdi_usb_open_desc(d->ftdi, vendor, product, description.c_str(), serial.c_str()); | |
20b1459a | 73 | |
cdf448f6 | 74 | d->dev = usb_device(d->ftdi->usb_dev); |
20b1459a | 75 | |
cdf448f6 TJ |
76 | if ((ret = ftdi_usb_open_dev(d->ftdi, d->dev)) >= 0) |
77 | { | |
78 | d->open = true; | |
79 | get_strings(); | |
80 | } | |
20b1459a | 81 | |
cdf448f6 | 82 | return ret; |
20b1459a TJ |
83 | } |
84 | ||
85 | int Context::open(struct usb_device *dev) | |
86 | { | |
cdf448f6 TJ |
87 | int ret = 0; |
88 | ||
89 | if (dev != 0) | |
90 | d->dev = dev; | |
91 | ||
92 | if (d->dev == 0) | |
93 | return -1; | |
20b1459a | 94 | |
cdf448f6 TJ |
95 | if ((ret = ftdi_usb_open_dev(d->ftdi, d->dev)) >= 0) |
96 | { | |
97 | d->open = true; | |
98 | get_strings(); | |
99 | } | |
20b1459a | 100 | |
cdf448f6 | 101 | return ret; |
20b1459a TJ |
102 | } |
103 | ||
104 | int Context::close() | |
105 | { | |
cdf448f6 TJ |
106 | d->open = false; |
107 | return ftdi_usb_close(d->ftdi); | |
20b1459a TJ |
108 | } |
109 | ||
110 | int Context::reset() | |
111 | { | |
cdf448f6 | 112 | return ftdi_usb_reset(d->ftdi); |
20b1459a TJ |
113 | } |
114 | ||
115 | int Context::flush(int mask) | |
116 | { | |
cdf448f6 | 117 | int ret = 1; |
20b1459a | 118 | |
cdf448f6 TJ |
119 | if (mask & Input) |
120 | ret &= ftdi_usb_purge_rx_buffer(d->ftdi); | |
121 | if (mask & Output) | |
122 | ret &= ftdi_usb_purge_tx_buffer(d->ftdi); | |
123 | ||
124 | return ret; | |
20b1459a TJ |
125 | } |
126 | ||
127 | int Context::set_interface(enum ftdi_interface interface) | |
128 | { | |
cdf448f6 | 129 | return ftdi_set_interface(d->ftdi, interface); |
20b1459a TJ |
130 | } |
131 | ||
132 | void Context::set_usb_device(struct usb_dev_handle *dev) | |
133 | { | |
cdf448f6 TJ |
134 | ftdi_set_usbdev(d->ftdi, dev); |
135 | d->dev = usb_device(dev); | |
20b1459a TJ |
136 | } |
137 | ||
138 | int Context::set_baud_rate(int baudrate) | |
139 | { | |
cdf448f6 | 140 | return ftdi_set_baudrate(d->ftdi, baudrate); |
20b1459a TJ |
141 | } |
142 | ||
143 | int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity) | |
144 | { | |
cdf448f6 | 145 | return ftdi_set_line_property(d->ftdi, bits, sbit, parity); |
20b1459a TJ |
146 | } |
147 | ||
148 | 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) | |
149 | { | |
cdf448f6 | 150 | return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type); |
20b1459a TJ |
151 | } |
152 | ||
153 | int Context::read(unsigned char *buf, int size) | |
154 | { | |
cdf448f6 | 155 | return ftdi_read_data(d->ftdi, buf, size); |
20b1459a TJ |
156 | } |
157 | ||
158 | int Context::set_read_chunk_size(unsigned int chunksize) | |
159 | { | |
cdf448f6 | 160 | return ftdi_read_data_set_chunksize(d->ftdi, chunksize); |
20b1459a TJ |
161 | } |
162 | ||
163 | int Context::read_chunk_size() | |
164 | { | |
cdf448f6 TJ |
165 | unsigned chunk = -1; |
166 | if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0) | |
167 | return -1; | |
20b1459a | 168 | |
cdf448f6 TJ |
169 | return chunk; |
170 | } | |
20b1459a TJ |
171 | |
172 | int Context::write(unsigned char *buf, int size) | |
173 | { | |
cdf448f6 | 174 | return ftdi_write_data(d->ftdi, buf, size); |
20b1459a TJ |
175 | } |
176 | ||
177 | int Context::set_write_chunk_size(unsigned int chunksize) | |
178 | { | |
cdf448f6 | 179 | return ftdi_write_data_set_chunksize(d->ftdi, chunksize); |
20b1459a TJ |
180 | } |
181 | ||
182 | int Context::write_chunk_size() | |
183 | { | |
cdf448f6 TJ |
184 | unsigned chunk = -1; |
185 | if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0) | |
186 | return -1; | |
20b1459a | 187 | |
cdf448f6 | 188 | return chunk; |
20b1459a TJ |
189 | } |
190 | ||
191 | int Context::set_flow_control(int flowctrl) | |
192 | { | |
cdf448f6 | 193 | return ftdi_setflowctrl(d->ftdi, flowctrl); |
20b1459a TJ |
194 | } |
195 | ||
196 | int Context::set_modem_control(int mask) | |
197 | { | |
cdf448f6 TJ |
198 | int dtr = 0, rts = 0; |
199 | ||
200 | if (mask & Dtr) | |
201 | dtr = 1; | |
202 | if (mask & Rts) | |
203 | rts = 1; | |
20b1459a | 204 | |
cdf448f6 | 205 | return ftdi_setdtr_rts(d->ftdi, dtr, rts); |
20b1459a TJ |
206 | } |
207 | ||
208 | int Context::set_dtr(bool state) | |
209 | { | |
cdf448f6 | 210 | return ftdi_setdtr(d->ftdi, state); |
20b1459a TJ |
211 | } |
212 | ||
213 | int Context::set_rts(bool state) | |
214 | { | |
cdf448f6 | 215 | return ftdi_setrts(d->ftdi, state); |
20b1459a TJ |
216 | } |
217 | ||
218 | int Context::set_latency(unsigned char latency) | |
219 | { | |
cdf448f6 | 220 | return ftdi_set_latency_timer(d->ftdi, latency); |
20b1459a TJ |
221 | } |
222 | ||
223 | unsigned Context::latency() | |
224 | { | |
cdf448f6 TJ |
225 | unsigned char latency = 0; |
226 | ftdi_get_latency_timer(d->ftdi, &latency); | |
227 | return latency; | |
20b1459a TJ |
228 | } |
229 | ||
230 | unsigned short Context::poll_modem_status() | |
231 | { | |
cdf448f6 TJ |
232 | unsigned short status = 0; |
233 | ftdi_poll_modem_status(d->ftdi, &status); | |
234 | return status; | |
20b1459a TJ |
235 | } |
236 | ||
20b1459a TJ |
237 | int Context::set_event_char(unsigned char eventch, unsigned char enable) |
238 | { | |
cdf448f6 | 239 | return ftdi_set_event_char(d->ftdi, eventch, enable); |
20b1459a TJ |
240 | } |
241 | ||
242 | int Context::set_error_char(unsigned char errorch, unsigned char enable) | |
243 | { | |
cdf448f6 | 244 | return ftdi_set_error_char(d->ftdi, errorch, enable); |
20b1459a TJ |
245 | } |
246 | ||
247 | int Context::bitbang_enable(unsigned char bitmask) | |
248 | { | |
cdf448f6 | 249 | return ftdi_enable_bitbang(d->ftdi, bitmask); |
20b1459a TJ |
250 | } |
251 | ||
252 | int Context::bitbang_disable() | |
253 | { | |
cdf448f6 | 254 | return ftdi_disable_bitbang(d->ftdi); |
20b1459a TJ |
255 | } |
256 | ||
257 | int Context::set_bitmode(unsigned char bitmask, unsigned char mode) | |
258 | { | |
cdf448f6 | 259 | return ftdi_set_bitmode(d->ftdi, bitmask, mode); |
20b1459a TJ |
260 | } |
261 | ||
262 | int Context::read_pins(unsigned char *pins) | |
263 | { | |
cdf448f6 | 264 | return ftdi_read_pins(d->ftdi, pins); |
20b1459a TJ |
265 | } |
266 | ||
267 | char* Context::error_string() | |
268 | { | |
cdf448f6 | 269 | return ftdi_get_error_string(d->ftdi); |
20b1459a TJ |
270 | } |
271 | ||
272 | int Context::get_strings() | |
273 | { | |
cdf448f6 TJ |
274 | // Prepare buffers |
275 | char vendor[512], desc[512], serial[512]; | |
276 | ||
277 | int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512); | |
278 | ||
279 | if (ret < 0) | |
280 | return -1; | |
20b1459a | 281 | |
cdf448f6 TJ |
282 | d->vendor = vendor; |
283 | d->description = desc; | |
284 | d->serial = serial; | |
20b1459a | 285 | |
cdf448f6 | 286 | return 1; |
20b1459a TJ |
287 | } |
288 | ||
289 | /*! \fn vendor | |
290 | * \fn description | |
291 | * \fn serial | |
292 | * \brief Device strings properties. | |
293 | */ | |
294 | const std::string& Context::vendor() | |
295 | { | |
cdf448f6 | 296 | return d->vendor; |
20b1459a TJ |
297 | } |
298 | ||
299 | const std::string& Context::description() | |
300 | { | |
cdf448f6 | 301 | return d->description; |
20b1459a TJ |
302 | } |
303 | ||
304 | const std::string& Context::serial() | |
305 | { | |
cdf448f6 | 306 | return d->serial; |
20b1459a TJ |
307 | } |
308 | ||
309 | void Context::set_context(struct ftdi_context* context) | |
310 | { | |
cdf448f6 TJ |
311 | ftdi_free(d->ftdi); |
312 | d->ftdi = context; | |
20b1459a TJ |
313 | } |
314 | ||
315 | void Context::set_usb_device(struct usb_device *dev) | |
316 | { | |
cdf448f6 | 317 | d->dev = dev; |
20b1459a TJ |
318 | } |
319 | ||
320 | struct ftdi_context* Context::context() | |
321 | { | |
cdf448f6 | 322 | return d->ftdi; |
20b1459a TJ |
323 | } |
324 | ||
325 | class Eeprom::Private | |
326 | { | |
cdf448f6 TJ |
327 | public: |
328 | Private() | |
329 | : context(0) | |
330 | {} | |
20b1459a | 331 | |
cdf448f6 TJ |
332 | struct ftdi_eeprom eeprom; |
333 | struct ftdi_context* context; | |
20b1459a TJ |
334 | }; |
335 | ||
336 | Eeprom::Eeprom(Context* parent) | |
cdf448f6 | 337 | : d ( new Private() ) |
20b1459a | 338 | { |
cdf448f6 | 339 | d->context = parent->context(); |
20b1459a TJ |
340 | } |
341 | ||
342 | Eeprom::~Eeprom() | |
343 | { | |
cdf448f6 | 344 | delete d; |
20b1459a TJ |
345 | } |
346 | ||
347 | void Eeprom::init_defaults() | |
348 | { | |
cdf448f6 | 349 | return ftdi_eeprom_initdefaults(&d->eeprom); |
20b1459a TJ |
350 | } |
351 | ||
352 | void Eeprom::set_size(int size) | |
353 | { | |
cdf448f6 | 354 | return ftdi_eeprom_setsize(d->context, &d->eeprom, size); |
20b1459a TJ |
355 | } |
356 | ||
357 | int Eeprom::size(unsigned char *eeprom, int maxsize) | |
358 | { | |
cdf448f6 | 359 | return ftdi_read_eeprom_getsize(d->context, eeprom, maxsize); |
20b1459a TJ |
360 | } |
361 | ||
362 | int Eeprom::chip_id(unsigned int *chipid) | |
363 | { | |
cdf448f6 | 364 | return ftdi_read_chipid(d->context, chipid); |
20b1459a TJ |
365 | } |
366 | ||
367 | int Eeprom::build(unsigned char *output) | |
368 | { | |
cdf448f6 | 369 | return ftdi_eeprom_build(&d->eeprom, output); |
20b1459a TJ |
370 | } |
371 | ||
372 | int Eeprom::read(unsigned char *eeprom) | |
373 | { | |
cdf448f6 | 374 | return ftdi_read_eeprom(d->context, eeprom); |
20b1459a TJ |
375 | } |
376 | ||
377 | int Eeprom::write(unsigned char *eeprom) | |
378 | { | |
cdf448f6 | 379 | return ftdi_write_eeprom(d->context, eeprom); |
20b1459a TJ |
380 | } |
381 | ||
382 | int Eeprom::erase() | |
383 | { | |
cdf448f6 | 384 | return ftdi_erase_eeprom(d->context); |
20b1459a TJ |
385 | } |
386 | ||
387 | class List::Private | |
388 | { | |
cdf448f6 TJ |
389 | public: |
390 | Private() | |
391 | : list(0) | |
392 | {} | |
20b1459a | 393 | |
cdf448f6 | 394 | struct ftdi_device_list* list; |
20b1459a TJ |
395 | }; |
396 | ||
397 | List::List(struct ftdi_device_list* devlist) | |
cdf448f6 | 398 | : ListBase(), d( new Private() ) |
20b1459a | 399 | { |
cdf448f6 TJ |
400 | if (devlist != 0) |
401 | { | |
402 | // Iterate list | |
403 | Context* c = 0; | |
404 | for (d->list = devlist; d->list != 0; d->list = d->list->next) | |
405 | { | |
406 | c = new Context(); | |
407 | c->set_usb_device(d->list->dev); | |
408 | push_back(c); | |
409 | } | |
20b1459a | 410 | |
cdf448f6 TJ |
411 | // Store pointer |
412 | d->list = devlist; | |
413 | } | |
20b1459a TJ |
414 | } |
415 | ||
416 | List::~List() | |
417 | { | |
cdf448f6 TJ |
418 | // Deallocate instances |
419 | for (iterator it = begin(); it != end(); it++) | |
420 | delete *it; | |
20b1459a | 421 | |
cdf448f6 TJ |
422 | // Clear list |
423 | clear(); | |
424 | ftdi_list_free(&d->list); | |
20b1459a | 425 | |
cdf448f6 TJ |
426 | // Delete d-ptr |
427 | delete d; | |
20b1459a TJ |
428 | } |
429 | ||
430 | List* List::find_all(int vendor, int product) | |
431 | { | |
cdf448f6 TJ |
432 | struct ftdi_device_list* dlist = 0; |
433 | struct ftdi_context ftdi; | |
434 | ftdi_init(&ftdi); | |
435 | ftdi_usb_find_all(&ftdi, &dlist, vendor, product); | |
436 | ftdi_deinit(&ftdi); | |
437 | return new List(dlist); | |
20b1459a TJ |
438 | } |
439 | ||
440 | } |