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