1#![allow(dead_code)]
2#![allow(unused_variables)]
3
4use libftdi1_sys as ffi;
5use libusb1_sys as usb_ffi;
6use std::ffi::{CStr, CString};
7use std::ptr::null_mut;
8
9use std::error::Error;
10use std::fmt;
11
12use std::io;
13use std::io::{Read, Write};
14
15#[derive(Debug)]
16pub struct FtdiError {
17 error_string: Option<&'static CStr>,
18}
19
20impl Error for FtdiError {}
21
22impl fmt::Display for FtdiError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self.error_string {
25 Some(err) => write!(f, "libftdi error: {:?}", err),
26 None => write!(f, "libftdi error occurred, but no error text was found"),
27 }
28 }
29}
30
31pub enum Interface {
32 A,
33 B,
34 C,
35 D,
36 Any,
37}
38
39impl Into<ffi::ftdi_interface> for Interface {
40 fn into(self) -> ffi::ftdi_interface {
41 match self {
42 Interface::A => ffi::ftdi_interface::INTERFACE_A,
43 Interface::B => ffi::ftdi_interface::INTERFACE_B,
44 Interface::C => ffi::ftdi_interface::INTERFACE_C,
45 Interface::D => ffi::ftdi_interface::INTERFACE_D,
46 Interface::Any => ffi::ftdi_interface::INTERFACE_ANY,
47 }
48 }
49}
50
51pub enum BitsType {
52 Bits7,
53 Bits8,
54}
55
56impl Into<ffi::ftdi_bits_type> for BitsType {
57 fn into(self) -> ffi::ftdi_bits_type {
58 match self {
59 BitsType::Bits7 => ffi::ftdi_bits_type::BITS_7,
60 BitsType::Bits8 => ffi::ftdi_bits_type::BITS_8,
61 }
62 }
63}
64
65pub enum StopBitsType {
66 StopBit1,
67 StopBit15,
68 StopBit2,
69}
70
71impl Into<ffi::ftdi_stopbits_type> for StopBitsType {
72 fn into(self) -> ffi::ftdi_stopbits_type {
73 match self {
74 StopBitsType::StopBit1 => ffi::ftdi_stopbits_type::STOP_BIT_1,
75 StopBitsType::StopBit15 => ffi::ftdi_stopbits_type::STOP_BIT_15,
76 StopBitsType::StopBit2 => ffi::ftdi_stopbits_type::STOP_BIT_2,
77 }
78 }
79}
80
81pub enum ParityType {
82 None,
83 Odd,
84 Even,
85 Mark,
86 Space,
87}
88
89impl Into<ffi::ftdi_parity_type> for ParityType {
90 fn into(self) -> ffi::ftdi_parity_type {
91 match self {
92 ParityType::None => ffi::ftdi_parity_type::NONE,
93 ParityType::Odd => ffi::ftdi_parity_type::ODD,
94 ParityType::Even => ffi::ftdi_parity_type::EVEN,
95 ParityType::Mark => ffi::ftdi_parity_type::MARK,
96 ParityType::Space => ffi::ftdi_parity_type::SPACE,
97 }
98 }
99}
100
101pub enum BreakType {
102 Off,
103 On,
104}
105
106impl Into<ffi::ftdi_break_type> for BreakType {
107 fn into(self) -> ffi::ftdi_break_type {
108 match self {
109 BreakType::Off => ffi::ftdi_break_type::BREAK_OFF,
110 BreakType::On => ffi::ftdi_break_type::BREAK_ON,
111 }
112 }
113}
114
115pub enum ChipType {
116 Am,
117 Bm,
118 _2232C,
119 R,
120 _2232H,
121 _4232H,
122 _232H,
123 _230X,
124}
125
126impl Into<ffi::ftdi_chip_type> for ChipType {
127 fn into(self) -> ffi::ftdi_chip_type {
128 match self {
129 ChipType::Am => ffi::ftdi_chip_type::TYPE_AM,
130 ChipType::Bm => ffi::ftdi_chip_type::TYPE_BM,
131 ChipType::_2232C => ffi::ftdi_chip_type::TYPE_2232C,
132 ChipType::R => ffi::ftdi_chip_type::TYPE_R,
133 ChipType::_2232H => ffi::ftdi_chip_type::TYPE_2232H,
134 ChipType::_4232H => ffi::ftdi_chip_type::TYPE_4232H,
135 ChipType::_232H => ffi::ftdi_chip_type::TYPE_232H,
136 ChipType::_230X => ffi::ftdi_chip_type::TYPE_230X,
137 }
138 }
139}
140
141#[derive(Debug, Default)]
142pub struct MpsseMode {
143 pub bitbang: bool,
144 pub mpsse: bool,
145 pub syncbb: bool,
146 pub mcu: bool,
147 pub opto: bool,
148 pub cbus: bool,
149 pub syncff: bool,
150 pub ft1284: bool,
151}
152
153impl Into<u8> for MpsseMode {
154 fn into(self) -> u8 {
155 let mut result = ffi::ftdi_mpsse_mode::BITMODE_RESET.0 as u8;
156 if self.bitbang {
157 result |= ffi::ftdi_mpsse_mode::BITMODE_BITBANG.0 as u8
158 }
159 if self.mpsse {
160 result |= ffi::ftdi_mpsse_mode::BITMODE_MPSSE.0 as u8
161 }
162 if self.syncbb {
163 result |= ffi::ftdi_mpsse_mode::BITMODE_SYNCBB.0 as u8
164 }
165 if self.mcu {
166 result |= ffi::ftdi_mpsse_mode::BITMODE_MCU.0 as u8
167 }
168 if self.opto {
169 result |= ffi::ftdi_mpsse_mode::BITMODE_OPTO.0 as u8
170 }
171 if self.cbus {
172 result |= ffi::ftdi_mpsse_mode::BITMODE_CBUS.0 as u8
173 }
174 if self.syncff {
175 result |= ffi::ftdi_mpsse_mode::BITMODE_SYNCFF.0 as u8
176 }
177 if self.ft1284 {
178 result |= ffi::ftdi_mpsse_mode::BITMODE_FT1284.0 as u8
179 }
180
181 result
182 }
183}
184
185pub enum ModuleDetachMode {
186 AutoDetachSioModule,
187 DontDetachSioModule,
188 }
190
191impl Into<ffi::ftdi_module_detach_mode> for ModuleDetachMode {
192 fn into(self) -> ffi::ftdi_module_detach_mode {
193 match self {
194 ModuleDetachMode::AutoDetachSioModule => {
195 ffi::ftdi_module_detach_mode::AUTO_DETACH_SIO_MODULE
196 }
197 ModuleDetachMode::DontDetachSioModule => {
198 ffi::ftdi_module_detach_mode::DONT_DETACH_SIO_MODULE
199 } }
201 }
202}
203
204pub enum EepromValue {
205 VendorId,
206 ProductId,
207 SelfPowered,
208 RemoteWakeup,
209 IsNotPnp,
210 SuspendDbus7,
211 InIsIsochronous,
212 OutIsIsochronous,
213 SuspendPullDowns,
214 UseSerial,
215 UsbVersion,
216 UseUsbVersion,
217 MaxPower,
218 ChannelAType,
219 ChannelBType,
220 ChannelADriver,
221 ChannelBDriver,
222 CbusFunction0,
223 CbusFunction1,
224 CbusFunction2,
225 CbusFunction3,
226 CbusFunction4,
227 CbusFunction5,
228 CbusFunction6,
229 CbusFunction7,
230 CbusFunction8,
231 CbusFunction9,
232 HighCurrent,
233 HighCurrentA,
234 HighCurrentB,
235 Invert,
236 Group0Drive,
237 Group0Schmitt,
238 Group0Slew,
239 Group1Drive,
240 Group1Schmitt,
241 Group1Slew,
242 Group2Drive,
243 Group2Schmitt,
244 Group2Slew,
245 Group3Drive,
246 Group3Schmitt,
247 Group3Slew,
248 ChipSize,
249 ChipType,
250 PowerSave,
251 ClockPolarity,
252 DataOrder,
253 FlowControl,
254 ChannelCDriver,
255 ChannelDDriver,
256 ChannelARs485,
257 ChannelBRs485,
258 ChannelCRs485,
259 ChannelDRs485,
260 ReleaseNumber,
261}
262
263impl Into<ffi::ftdi_eeprom_value> for EepromValue {
264 fn into(self) -> ffi::ftdi_eeprom_value {
265 match self {
266 EepromValue::VendorId => ffi::ftdi_eeprom_value::VENDOR_ID,
267 EepromValue::ProductId => ffi::ftdi_eeprom_value::PRODUCT_ID,
268 EepromValue::SelfPowered => ffi::ftdi_eeprom_value::SELF_POWERED,
269 EepromValue::RemoteWakeup => ffi::ftdi_eeprom_value::REMOTE_WAKEUP,
270 EepromValue::IsNotPnp => ffi::ftdi_eeprom_value::IS_NOT_PNP,
271 EepromValue::SuspendDbus7 => ffi::ftdi_eeprom_value::SUSPEND_DBUS7,
272 EepromValue::InIsIsochronous => ffi::ftdi_eeprom_value::IN_IS_ISOCHRONOUS,
273 EepromValue::OutIsIsochronous => ffi::ftdi_eeprom_value::OUT_IS_ISOCHRONOUS,
274 EepromValue::SuspendPullDowns => ffi::ftdi_eeprom_value::SUSPEND_PULL_DOWNS,
275 EepromValue::UseSerial => ffi::ftdi_eeprom_value::USE_SERIAL,
276 EepromValue::UsbVersion => ffi::ftdi_eeprom_value::USB_VERSION,
277 EepromValue::UseUsbVersion => ffi::ftdi_eeprom_value::USE_USB_VERSION,
278 EepromValue::MaxPower => ffi::ftdi_eeprom_value::MAX_POWER,
279 EepromValue::ChannelAType => ffi::ftdi_eeprom_value::CHANNEL_A_TYPE,
280 EepromValue::ChannelBType => ffi::ftdi_eeprom_value::CHANNEL_B_TYPE,
281 EepromValue::ChannelADriver => ffi::ftdi_eeprom_value::CHANNEL_A_DRIVER,
282 EepromValue::ChannelBDriver => ffi::ftdi_eeprom_value::CHANNEL_B_DRIVER,
283 EepromValue::CbusFunction0 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_0,
284 EepromValue::CbusFunction1 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_1,
285 EepromValue::CbusFunction2 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_2,
286 EepromValue::CbusFunction3 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_3,
287 EepromValue::CbusFunction4 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_4,
288 EepromValue::CbusFunction5 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_5,
289 EepromValue::CbusFunction6 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_6,
290 EepromValue::CbusFunction7 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_7,
291 EepromValue::CbusFunction8 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_8,
292 EepromValue::CbusFunction9 => ffi::ftdi_eeprom_value::CBUS_FUNCTION_9,
293 EepromValue::HighCurrent => ffi::ftdi_eeprom_value::HIGH_CURRENT,
294 EepromValue::HighCurrentA => ffi::ftdi_eeprom_value::HIGH_CURRENT_A,
295 EepromValue::HighCurrentB => ffi::ftdi_eeprom_value::HIGH_CURRENT_B,
296 EepromValue::Invert => ffi::ftdi_eeprom_value::INVERT,
297 EepromValue::Group0Drive => ffi::ftdi_eeprom_value::GROUP0_DRIVE,
298 EepromValue::Group0Schmitt => ffi::ftdi_eeprom_value::GROUP0_SCHMITT,
299 EepromValue::Group0Slew => ffi::ftdi_eeprom_value::GROUP0_SLEW,
300 EepromValue::Group1Drive => ffi::ftdi_eeprom_value::GROUP1_DRIVE,
301 EepromValue::Group1Schmitt => ffi::ftdi_eeprom_value::GROUP1_SCHMITT,
302 EepromValue::Group1Slew => ffi::ftdi_eeprom_value::GROUP1_SLEW,
303 EepromValue::Group2Drive => ffi::ftdi_eeprom_value::GROUP2_DRIVE,
304 EepromValue::Group2Schmitt => ffi::ftdi_eeprom_value::GROUP2_SCHMITT,
305 EepromValue::Group2Slew => ffi::ftdi_eeprom_value::GROUP2_SLEW,
306 EepromValue::Group3Drive => ffi::ftdi_eeprom_value::GROUP3_DRIVE,
307 EepromValue::Group3Schmitt => ffi::ftdi_eeprom_value::GROUP3_SCHMITT,
308 EepromValue::Group3Slew => ffi::ftdi_eeprom_value::GROUP3_SLEW,
309 EepromValue::ChipSize => ffi::ftdi_eeprom_value::CHIP_SIZE,
310 EepromValue::ChipType => ffi::ftdi_eeprom_value::CHIP_TYPE,
311 EepromValue::PowerSave => ffi::ftdi_eeprom_value::POWER_SAVE,
312 EepromValue::ClockPolarity => ffi::ftdi_eeprom_value::CLOCK_POLARITY,
313 EepromValue::DataOrder => ffi::ftdi_eeprom_value::DATA_ORDER,
314 EepromValue::FlowControl => ffi::ftdi_eeprom_value::FLOW_CONTROL,
315 EepromValue::ChannelCDriver => ffi::ftdi_eeprom_value::CHANNEL_C_DRIVER,
316 EepromValue::ChannelDDriver => ffi::ftdi_eeprom_value::CHANNEL_D_DRIVER,
317 EepromValue::ChannelARs485 => ffi::ftdi_eeprom_value::CHANNEL_A_RS485,
318 EepromValue::ChannelBRs485 => ffi::ftdi_eeprom_value::CHANNEL_B_RS485,
319 EepromValue::ChannelCRs485 => ffi::ftdi_eeprom_value::CHANNEL_C_RS485,
320 EepromValue::ChannelDRs485 => ffi::ftdi_eeprom_value::CHANNEL_D_RS485,
321 EepromValue::ReleaseNumber => ffi::ftdi_eeprom_value::RELEASE_NUMBER,
322 }
323 }
324}
325
326pub enum CbusFunc {
327 TxdEn,
328 PwrEn,
329 RxLed,
330 TxLed,
331 TxRxLed,
332 Sleep,
333 Clk48,
334 Clk24,
335 Clk12,
336 Clk6,
337 IoMode,
338 BbWr,
339 BbRd,
340}
341
342impl Into<ffi::ftdi_cbus_func> for CbusFunc {
343 fn into(self) -> ffi::ftdi_cbus_func {
344 match self {
345 CbusFunc::TxdEn => ffi::ftdi_cbus_func::CBUS_TXDEN,
346 CbusFunc::PwrEn => ffi::ftdi_cbus_func::CBUS_PWREN,
347 CbusFunc::RxLed => ffi::ftdi_cbus_func::CBUS_RXLED,
348 CbusFunc::TxLed => ffi::ftdi_cbus_func::CBUS_TXLED,
349 CbusFunc::TxRxLed => ffi::ftdi_cbus_func::CBUS_TXRXLED,
350 CbusFunc::Sleep => ffi::ftdi_cbus_func::CBUS_SLEEP,
351 CbusFunc::Clk48 => ffi::ftdi_cbus_func::CBUS_CLK48,
352 CbusFunc::Clk24 => ffi::ftdi_cbus_func::CBUS_CLK24,
353 CbusFunc::Clk12 => ffi::ftdi_cbus_func::CBUS_CLK12,
354 CbusFunc::Clk6 => ffi::ftdi_cbus_func::CBUS_CLK6,
355 CbusFunc::IoMode => ffi::ftdi_cbus_func::CBUS_IOMODE,
356 CbusFunc::BbWr => ffi::ftdi_cbus_func::CBUS_BB_WR,
357 CbusFunc::BbRd => ffi::ftdi_cbus_func::CBUS_BB_RD,
358 }
359 }
360}
361
362pub enum CbusHFunc {
363 Tristate,
364 TxLed,
365 RxLed,
366 TxRxLed,
367 PwrEn,
368 Sleep,
369 Drive0,
370 Drive1,
371 IoMode,
372 Clk30,
373 Clk15,
374 Clk7p5,
375}
376
377impl Into<ffi::ftdi_cbush_func> for CbusHFunc {
378 fn into(self) -> ffi::ftdi_cbush_func {
379 match self {
380 CbusHFunc::Tristate => ffi::ftdi_cbush_func::CBUSH_TRISTATE,
381 CbusHFunc::PwrEn => ffi::ftdi_cbush_func::CBUSH_PWREN,
382 CbusHFunc::RxLed => ffi::ftdi_cbush_func::CBUSH_RXLED,
383 CbusHFunc::TxLed => ffi::ftdi_cbush_func::CBUSH_TXLED,
384 CbusHFunc::TxRxLed => ffi::ftdi_cbush_func::CBUSH_TXRXLED,
385 CbusHFunc::Sleep => ffi::ftdi_cbush_func::CBUSH_SLEEP,
386 CbusHFunc::Drive0 => ffi::ftdi_cbush_func::CBUSH_DRIVE_0,
387 CbusHFunc::Drive1 => ffi::ftdi_cbush_func::CBUSH_DRIVE1,
388 CbusHFunc::IoMode => ffi::ftdi_cbush_func::CBUSH_IOMODE,
389 CbusHFunc::Clk30 => ffi::ftdi_cbush_func::CBUSH_CLK30,
390 CbusHFunc::Clk15 => ffi::ftdi_cbush_func::CBUSH_CLK15,
391 CbusHFunc::Clk7p5 => ffi::ftdi_cbush_func::CBUSH_CLK7_5,
392 }
393 }
394}
395
396fn bytes_into_cstring(bytes: &[u8]) -> Option<CString> {
397 let first_nul = bytes.iter().position(|&b| b == 0);
398 match first_nul {
399 Some(i) => Some(
400 CStr::from_bytes_with_nul(&bytes[0..=i])
401 .expect("Data wasn't well formed")
402 .to_owned(),
403 ),
404 None => None,
405 }
406}
407
408#[derive(Debug)]
409pub struct Device {
410 context: Context,
411}
412
413impl Device {
414 fn check_for_result(&self, result_code: i32) -> Result<&Self, FtdiError> {
421 if result_code >= 0 {
422 Ok(&self)
423 } else {
424 Err(self.context.get_error())
425 }
426 }
427
428 fn panic_on_error(&self, result_code: i32) -> &Self {
429 if result_code >= 0 {
430 &self
431 } else {
432 panic!(
433 "Expected action to always be successful, but got non-zero result code: {}",
434 result_code
435 )
436 }
437 }
438
439 pub fn set_interface(&mut self, interface: Interface) -> Result<&Self, FtdiError> {
440 let result_code = unsafe { ffi::ftdi_set_interface(self.context.0, interface.into()) };
441 if result_code == 0 {
442 Ok(self)
443 } else {
444 Err(self.context.get_error())
445 }
446 }
447
448 pub fn set_baudrate(&mut self, baudrate: u32) -> Result<&Self, FtdiError> {
449 let result_code = unsafe { ffi::ftdi_set_baudrate(self.context.0, baudrate as i32) };
450
451 self.check_for_result(result_code)
452 }
453
454 pub fn set_line_property(
456 &mut self,
457 bits: BitsType,
458 stop_bits: StopBitsType,
459 parity: ParityType,
460 break_type: BreakType,
461 ) -> Result<&Self, FtdiError> {
462 let result_code = unsafe {
463 ffi::ftdi_set_line_property2(
464 self.context.0,
465 bits.into(),
466 stop_bits.into(),
467 parity.into(),
468 break_type.into(),
469 )
470 };
471 self.check_for_result(result_code)
472 }
473
474 pub fn reset(&mut self) -> Result<&Self, FtdiError> {
475 let result_code = unsafe { ffi::ftdi_usb_reset(self.context.0) };
476
477 self.check_for_result(result_code)
478 }
479
480 pub fn close(self) -> Result<Context, FtdiError> {
481 let result_code = unsafe { ffi::ftdi_usb_close(self.context.0) };
482
483 if result_code == 0 {
484 Ok(self.context)
485 } else {
486 Err(self.context.get_error())
487 }
488 }
489
490 fn input_flush(&mut self) -> Result<&Self, FtdiError> {
491 let result_code = unsafe { ffi::ftdi_usb_purge_rx_buffer(self.context.0) };
492
493 self.check_for_result(result_code)
494 }
495
496 fn output_flush(&mut self) -> Result<&Self, FtdiError> {
497 let result_code = unsafe { ffi::ftdi_usb_purge_tx_buffer(self.context.0) };
498
499 self.check_for_result(result_code)
500 }
501
502 fn io_flush(&mut self) -> Result<&Self, FtdiError> {
503 let result_code = unsafe { ffi::ftdi_usb_purge_buffers(self.context.0) };
504
505 self.check_for_result(result_code)
506 }
507
508 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, FtdiError> {
509 let result_code =
510 unsafe { ffi::ftdi_read_data(self.context.0, buf.as_mut_ptr(), buf.len() as i32) };
511
512 if result_code >= 0 {
513 Ok(result_code as usize)
514 } else {
515 Err(self.context.get_error())
516 }
517 }
518
519 pub fn set_read_chunksize(&mut self, chunksize: u32) -> &Self {
520 let result_code = unsafe { ffi::ftdi_read_data_set_chunksize(self.context.0, chunksize) };
521
522 self.panic_on_error(result_code)
523 }
524
525 pub fn get_read_chunksize(&self) -> u32 {
526 let mut chunksize: u32 = 0;
527 let result_code =
528 unsafe { ffi::ftdi_read_data_get_chunksize(self.context.0, &mut chunksize) };
529
530 self.panic_on_error(result_code);
531
532 result_code as u32
533 }
534
535 pub fn write_data(&mut self, data: &[u8]) -> Result<usize, FtdiError> {
536 let result_code =
537 unsafe { ffi::ftdi_write_data(self.context.0, data.as_ptr(), data.len() as i32) };
538
539 if result_code >= 0 {
540 Ok(result_code as usize)
541 } else {
542 Err(self.context.get_error())
543 }
544 }
545
546 pub fn set_write_chunksize(&mut self, chunksize: u32) -> &Self {
547 let result_code = unsafe { ffi::ftdi_write_data_set_chunksize(self.context.0, chunksize) };
548
549 self.panic_on_error(result_code)
550 }
551
552 pub fn get_write_chunksize(&self) -> u32 {
553 let mut chunksize: u32 = 0;
554 let result_code =
555 unsafe { ffi::ftdi_write_data_get_chunksize(self.context.0, &mut chunksize) };
556
557 self.panic_on_error(result_code);
558
559 result_code as u32
560 }
561
562 pub fn set_bitmode(&mut self, bitmask: u8, mode: MpsseMode) -> Result<&Self, FtdiError> {
564 let result_code = unsafe { ffi::ftdi_set_bitmode(self.context.0, bitmask, mode.into()) };
565
566 self.check_for_result(result_code)
567 }
568
569 pub fn disable_bitbang(&mut self) -> Result<&Self, FtdiError> {
570 let result_code = unsafe { ffi::ftdi_disable_bitbang(self.context.0) };
571
572 self.check_for_result(result_code)
573 }
574
575 pub fn read_pins(&self) -> Result<u8, FtdiError> {
577 let mut pins: u8 = 0;
578 let result_code = unsafe { ffi::ftdi_read_pins(self.context.0, &mut pins) };
579
580 if result_code == 0 {
581 Ok(pins)
582 } else {
583 Err(self.context.get_error())
584 }
585 }
586
587 pub fn set_latency_timer(&mut self, latency: u8) -> Result<&Self, FtdiError> {
588 let result_code = unsafe { ffi::ftdi_set_latency_timer(self.context.0, latency) };
589
590 self.check_for_result(result_code)
591 }
592
593 pub fn get_latency_timer(&self) -> Result<u8, FtdiError> {
594 let mut latency: u8 = 0;
595 let result_code = unsafe { ffi::ftdi_get_latency_timer(self.context.0, &mut latency) };
596
597 if result_code == 0 {
598 Ok(latency)
599 } else {
600 Err(self.context.get_error())
601 }
602 }
603
604 pub fn set_event_char(&self, character: Option<u8>) -> Result<&Self, FtdiError> {
605 let result_code = match character {
606 Some(c) => unsafe { ffi::ftdi_set_event_char(self.context.0, c, 1u8) },
607 None => unsafe { ffi::ftdi_set_event_char(self.context.0, 0, 0u8) },
608 };
609
610 self.check_for_result(result_code)
611 }
612
613 pub fn set_error_char(&self, character: Option<u8>) -> Result<&Self, FtdiError> {
614 let result_code = match character {
615 Some(c) => unsafe { ffi::ftdi_set_error_char(self.context.0, c, 1u8) },
616 None => unsafe { ffi::ftdi_set_error_char(self.context.0, 0, 0u8) },
617 };
618
619 self.check_for_result(result_code)
620 }
621
622 pub fn eeprom_erase(&self) -> Result<&Self, FtdiError> {
623 let result_code = unsafe { ffi::ftdi_erase_eeprom(self.context.0) };
624
625 self.check_for_result(result_code)
626 }
627
628 }
656
657impl Read for Device {
658 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
659 let result = self.read_data(buf);
660
661 match result {
662 Ok(bytes_read) => Ok(bytes_read),
663 Err(ftdi_error) => Err(io::Error::new(io::ErrorKind::Other, ftdi_error)),
664 }
665 }
666}
667
668impl Write for Device {
669 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
670 let result = self.write_data(buf);
671
672 match result {
673 Ok(bytes_written) => Ok(bytes_written),
674 Err(ftdi_error) => Err(io::Error::new(io::ErrorKind::Other, ftdi_error)),
675 }
676 }
677
678 fn flush(&mut self) -> io::Result<()> {
679 Ok(())
681 }
682}
683
684#[derive(Debug)]
685pub struct DiscoveredDevice(*mut usb_ffi::libusb_device);
686
687impl DiscoveredDevice {}
688
689#[derive(Debug)]
690pub struct DeviceInfo {
691 manufacturer: Option<CString>,
692 description: Option<CString>,
693 serial: Option<CString>,
694}
695
696pub struct VersionInfo(pub ffi::ftdi_version_info);
697
698pub fn version_info() -> VersionInfo {
699 let result = unsafe { ffi::ftdi_get_library_version() };
700 VersionInfo(result)
701}
702
703#[derive(Debug)]
704pub struct Context(*mut ffi::ftdi_context);
705
706impl Context {
707 pub fn new() -> Result<Self, FtdiError> {
708 let result = unsafe { ffi::ftdi_new() };
709 if result.is_null() {
710 panic!("Could not allocate FTDI Context")
711 } else {
712 Ok(Context(result))
713 }
714 }
715
716 pub fn usb_find_all(
721 &self,
722 vendor: i32,
723 product: i32,
724 ) -> Result<Vec<DiscoveredDevice>, FtdiError> {
725 let mut list = null_mut();
726 let result_code = unsafe { ffi::ftdi_usb_find_all(self.0, &mut list, vendor, product) };
727
728 if result_code < 0 {
729 return Err(self.get_error());
730 }
731
732 let mut results = Vec::<DiscoveredDevice>::with_capacity(result_code as usize);
734 let mut cur = list;
735 while !cur.is_null() {
736 results.push(DiscoveredDevice(unsafe { (*cur).dev }));
737 cur = unsafe { (*cur).next };
738 }
739 unsafe { ffi::ftdi_list_free2(list) };
740
741 Ok(results)
742 }
743
744 pub fn read_data_set_chunksize(&mut self, size: u32) -> Result<Self, FtdiError> {
745 todo!()
746 }
747
748 pub fn read_data_get_chunksize(&self, size: u32) -> Result<Self, FtdiError> {
749 todo!()
750 }
751
752 pub fn write_data_set_chunksize(&mut self, size: u32) -> Result<Self, FtdiError> {
753 todo!()
754 }
755
756 pub fn write_data_get_chunksize(&self, size: u32) -> Result<Self, FtdiError> {
757 todo!()
758 }
759
760 fn get_error(&self) -> FtdiError {
761 let error_string = unsafe { ffi::ftdi_get_error_string(self.0) };
762 if error_string.is_null() {
763 FtdiError { error_string: None }
764 } else {
765 let safe_string = unsafe { CStr::from_ptr(error_string) };
766 FtdiError {
767 error_string: Some(safe_string),
768 }
769 }
770 }
771
772 fn check_for_result(&self, result_code: i32) -> Result<&Self, FtdiError> {
779 if result_code >= 0 {
780 Ok(&self)
781 } else {
782 Err(self.get_error())
783 }
784 }
785
786 pub fn open(self, device: &DiscoveredDevice) -> Result<Device, FtdiError> {
787 let result = unsafe { ffi::ftdi_usb_open_dev(self.0, device.0) };
788
789 if result == 0 {
790 Ok(Device { context: self })
791 } else {
792 Err(self.get_error())
793 }
794 }
795
796 pub fn get_info(&self, device: &DiscoveredDevice) -> Result<DeviceInfo, FtdiError> {
797 let mut manufacturer_bytes = [0u8; 256];
798 let mut description_bytes = [0u8; 256];
799 let mut serial_bytes = [0u8; 256];
800
801 let result = unsafe {
802 ffi::ftdi_usb_get_strings(
803 self.0,
804 device.0,
805 manufacturer_bytes.as_mut_ptr() as *mut i8,
806 manufacturer_bytes.len() as i32,
807 description_bytes.as_mut_ptr() as *mut i8,
808 description_bytes.len() as i32,
809 serial_bytes.as_mut_ptr() as *mut i8,
810 serial_bytes.len() as i32,
811 )
812 };
813
814 let manufacturer: Option<CString>;
815 let description: Option<CString>;
816 let serial: Option<CString>;
817
818 if result == 0 {
819 manufacturer = bytes_into_cstring(&manufacturer_bytes);
820 description = bytes_into_cstring(&description_bytes);
821 serial = bytes_into_cstring(&serial_bytes);
822 } else if result == -9 {
823 manufacturer = bytes_into_cstring(&manufacturer_bytes);
824 description = bytes_into_cstring(&description_bytes);
825 serial = None;
826 } else if result == -8 {
827 manufacturer = bytes_into_cstring(&manufacturer_bytes);
828 description = None;
829 serial = None;
830 } else if result == -7 {
831 manufacturer = None;
832 description = None;
833 serial = None;
834 } else {
835 return Err(self.get_error());
836 }
837
838 Ok(DeviceInfo {
839 manufacturer,
840 description,
841 serial,
842 })
843 }
844
845 }
866
867impl Drop for Context {
868 fn drop(&mut self) {
869 unsafe { ffi::ftdi_free(self.0) }
870 }
871}