ftdi_embedded_hal/lib.rs
1//! This is an [embedded-hal] implementation for the FTDI chips
2//! that can use various drivers including [libftd2xx] and [ftdi-rs].
3//!
4//! This enables development of embedded device drivers without the use of
5//! a microcontroller. The FTDI devices interface with PC via USB, and
6//! provide a multi-protocol synchronous serial engine to interface
7//! with most GPIO, SPI, I2C embedded devices.
8//!
9//! **Note:**
10//! This is strictly a development tool.
11//! The crate contains runtime borrow checks and explicit panics to adapt the
12//! FTDI device into the [embedded-hal] traits.
13//!
14//! # Quickstart
15//!
16//! * Enable the "libftd2xx-static" feature flag to use static linking with libftd2xx driver.
17//! * Linux users only: Add [udev rules].
18//!
19//! ```toml
20//! [dependencies.ftdi-embedded-hal]
21//! version = "0.23.0"
22//! features = ["libftd2xx", "libftd2xx-static"]
23//! ```
24//!
25//! # Limitations
26//!
27//! * Limited trait support: SPI, I2C, Delay, InputPin, and OutputPin traits are implemented.
28//! * Limited device support: FT232H, FT2232H, FT4232H.
29//! * Limited SPI modes support: MODE0, MODE2.
30//!
31//! # Examples
32//!
33//! ## SPI
34//!
35//! Pin setup:
36//!
37//! * D0 - SCK
38//! * D1 - SDO (MOSI)
39//! * D2 - SDI (MISO)
40//! * D3..D7 - Available for CS
41//!
42//! Communicate with SPI devices using [ftdi-rs] driver:
43//! ```no_run
44//! use ftdi_embedded_hal as hal;
45//!
46//! # #[cfg(feature = "ftdi")]
47//! # {
48//! let device = ftdi::find_by_vid_pid(0x0403, 0x6010)
49//! .interface(ftdi::Interface::A)
50//! .open()?;
51//!
52//! let hal = hal::FtHal::init_freq(device, 3_000_000)?;
53//! let spi = hal.spi()?;
54//! # }
55//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
56//! ```
57//!
58//! Communicate with SPI devices using [libftd2xx] driver:
59//! ```no_run
60//! use ftdi_embedded_hal as hal;
61//!
62//! # #[cfg(feature = "libftd2xx")]
63//! # {
64//! let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
65//!
66//! let hal = hal::FtHal::init_freq(device, 3_000_000)?;
67//! let spi = hal.spi()?;
68//! # }
69//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
70//! ```
71//!
72//! ## I2C
73//!
74//! Communicate with I2C devices using [ftdi-rs] driver:
75//! ```no_run
76//! use ftdi_embedded_hal as hal;
77//!
78//! # #[cfg(feature = "ftdi")]
79//! # {
80//! let device = ftdi::find_by_vid_pid(0x0403, 0x6010)
81//! .interface(ftdi::Interface::A)
82//! .open()?;
83//!
84//! let hal = hal::FtHal::init_freq(device, 400_000)?;
85//! let i2c = hal.i2c()?;
86//! # }
87//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
88//! ```
89//!
90//! Communicate with I2C devices using [libftd2xx] driver:
91//! ```no_run
92//! use ftdi_embedded_hal as hal;
93//!
94//! # #[cfg(feature = "libftd2xx")]
95//! # {
96//! let device = libftd2xx::Ft232h::with_description("Single RS232-HS")?;
97//!
98//! let hal = hal::FtHal::init_freq(device, 400_000)?;
99//! let i2c = hal.i2c()?;
100//! # }
101//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
102//! ```
103//!
104//! ## GPIO
105//!
106//! Control GPIO pins using [libftd2xx] driver:
107//! ```no_run
108//! use ftdi_embedded_hal as hal;
109//!
110//! # #[cfg(feature = "libftd2xx")]
111//! # {
112//! let device = libftd2xx::Ft232h::with_description("Single RS232-HS")?;
113//!
114//! let hal = hal::FtHal::init_default(device)?;
115//! let gpio = hal.ad6();
116//! # }
117//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
118//! ```
119//!
120//! Control GPIO pins using [ftdi-rs] driver:
121//! ```no_run
122//! use ftdi_embedded_hal as hal;
123//!
124//! # #[cfg(feature = "ftdi")]
125//! # {
126//! let device = ftdi::find_by_vid_pid(0x0403, 0x6010)
127//! .interface(ftdi::Interface::A)
128//! .open()?;
129//!
130//! let hal = hal::FtHal::init_default(device)?;
131//! let gpio = hal.ad6();
132//! # }
133//! # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
134//! ```
135//!
136//! ## More examples
137//!
138//! * [newAM/eeprom25aa02e48-rs]: read data from Microchip 25AA02E48 SPI EEPROM
139//! * [newAM/bme280-rs]: read samples from Bosch BME280 sensor via I2C protocol
140//!
141//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
142//! [ftdi-rs]: https://github.com/tanriol/ftdi-rs
143//! [libftd2xx crate]: https://github.com/ftdi-rs/libftd2xx-rs/
144//! [libftd2xx]: https://github.com/ftdi-rs/libftd2xx-rs
145//! [newAM/eeprom25aa02e48-rs]: https://github.com/newAM/eeprom25aa02e48-rs/blob/main/examples/ftdi.rs
146//! [newAM/bme280-rs]: https://github.com/newAM/bme280-rs/blob/main/examples/ftdi-i2c.rs
147//! [udev rules]: https://github.com/ftdi-rs/libftd2xx-rs/#udev-rules
148//! [setup executable]: https://www.ftdichip.com/Drivers/CDM/CDM21228_Setup.zip
149#![forbid(missing_docs)]
150#![forbid(unsafe_code)]
151
152pub use eh0;
153pub use eh1;
154pub use ftdi_mpsse;
155
156#[cfg(feature = "ftdi")]
157pub use ftdi;
158
159#[cfg(feature = "libftd2xx")]
160pub use libftd2xx;
161
162mod delay;
163mod error;
164mod gpio;
165mod i2c;
166mod spi;
167
168pub use crate::error::{Error, ErrorKind};
169pub use delay::Delay;
170pub use gpio::{InputPin, OutputPin};
171pub use i2c::I2c;
172pub use spi::{Spi, SpiDevice};
173
174use gpio::Pin;
175
176use ftdi_mpsse::{MpsseCmdExecutor, MpsseSettings};
177use std::sync::{Arc, Mutex};
178
179/// State tracker for each pin on the FTDI chip.
180#[derive(Debug, Clone, Copy)]
181enum PinUse {
182 I2c,
183 Spi,
184 Output,
185 Input,
186}
187
188impl std::fmt::Display for PinUse {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 match self {
191 PinUse::I2c => write!(f, "I2C"),
192 PinUse::Spi => write!(f, "SPI"),
193 PinUse::Output => write!(f, "OUTPUT"),
194 PinUse::Input => write!(f, "INPUT"),
195 }
196 }
197}
198
199#[derive(Debug, Default)]
200struct GpioByte {
201 /// GPIO direction.
202 direction: u8,
203 /// GPIO value.
204 value: u8,
205 /// Pin allocation.
206 pins: [Option<PinUse>; 8],
207}
208
209#[derive(Debug)]
210struct FtInner<Device: MpsseCmdExecutor> {
211 /// FTDI device.
212 ft: Device,
213 lower: GpioByte,
214 upper: GpioByte,
215}
216
217// FtInner deref's into .lower because SPI and I2C code were not adjusted yet to handle the split;
218// once those are updated, the Deref implementation can go away again
219
220impl<Device: MpsseCmdExecutor> core::ops::Deref for FtInner<Device> {
221 type Target = GpioByte;
222 fn deref(&self) -> &GpioByte {
223 &self.lower
224 }
225}
226
227impl<Device: MpsseCmdExecutor> core::ops::DerefMut for FtInner<Device> {
228 fn deref_mut(&mut self) -> &mut GpioByte {
229 &mut self.lower
230 }
231}
232
233impl<Device: MpsseCmdExecutor> FtInner<Device> {
234 /// Allocate a pin in the lower byte for a specific use.
235 pub fn allocate_pin(&mut self, idx: u8, purpose: PinUse) {
236 assert!(idx < 8, "Pin index {idx} is out of range 0 - 7");
237
238 if let Some(current) = self.lower.pins[usize::from(idx)] {
239 panic!(
240 "Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
241 );
242 } else {
243 self.lower.pins[usize::from(idx)] = Some(purpose)
244 }
245 }
246
247 /// Allocate a pin for a specific use.
248 pub fn allocate_pin_any(&mut self, pin: Pin, purpose: PinUse) {
249 let (byte, idx) = match pin {
250 Pin::Lower(idx) => (&mut self.lower, idx),
251 Pin::Upper(idx) => (&mut self.upper, idx),
252 };
253 assert!(idx < 8, "Pin index {idx} is out of range 0 - 7");
254
255 if let Some(current) = byte.pins[usize::from(idx)] {
256 panic!(
257 "Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
258 );
259 } else {
260 byte.pins[usize::from(idx)] = Some(purpose)
261 }
262 }
263}
264
265impl<Device: MpsseCmdExecutor> From<Device> for FtInner<Device> {
266 fn from(ft: Device) -> Self {
267 FtInner {
268 ft,
269 lower: Default::default(),
270 upper: Default::default(),
271 }
272 }
273}
274
275/// FTxxx device.
276#[derive(Debug)]
277pub struct FtHal<Device: MpsseCmdExecutor> {
278 mtx: Arc<Mutex<FtInner<Device>>>,
279}
280
281impl<Device, E> FtHal<Device>
282where
283 Device: MpsseCmdExecutor<Error = E>,
284 E: std::error::Error,
285 Error<E>: From<E>,
286{
287 /// Initialize the FTDI MPSSE with sane defaults.
288 ///
289 /// Default values:
290 ///
291 /// * Reset the FTDI device.
292 /// * 4k USB transfer size.
293 /// * 1s USB read timeout.
294 /// * 1s USB write timeout.
295 /// * 16ms latency timer.
296 /// * 100kHz clock frequency.
297 ///
298 /// # Example
299 ///
300 /// ```no_run
301 /// use ftdi_embedded_hal as hal;
302 ///
303 /// # #[cfg(feature = "libftd2xx")]
304 /// # {
305 /// let device = libftd2xx::Ft232h::with_description("Single RS232-HS")?;
306 /// let hal = hal::FtHal::init_default(device)?;
307 /// # }
308 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
309 /// ```
310 pub fn init_default(device: Device) -> Result<FtHal<Device>, Error<E>> {
311 let settings: MpsseSettings = MpsseSettings {
312 clock_frequency: Some(100_000),
313 ..Default::default()
314 };
315
316 Ok(FtHal::init(device, &settings)?)
317 }
318
319 /// Initialize the FTDI MPSSE with sane defaults and custom frequency
320 ///
321 /// # Example
322 ///
323 /// ```no_run
324 /// use ftdi_embedded_hal as hal;
325 ///
326 /// # #[cfg(feature = "libftd2xx")]
327 /// # {
328 /// let device = libftd2xx::Ft232h::with_description("Single RS232-HS")?;
329 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
330 /// # }
331 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
332 /// ```
333 pub fn init_freq(device: Device, freq: u32) -> Result<FtHal<Device>, Error<E>> {
334 let settings: MpsseSettings = MpsseSettings {
335 clock_frequency: Some(freq),
336 ..Default::default()
337 };
338
339 Ok(FtHal::init(device, &settings)?)
340 }
341
342 /// Initialize the FTDI MPSSE with custom values.
343 ///
344 /// **Note:** The `mask` field of [`MpsseSettings`] is ignored for this function.
345 ///
346 /// **Note:** The clock frequency will be 2/3 of the specified value when in
347 /// I2C mode.
348 ///
349 /// # Panics
350 ///
351 /// Panics if the `clock_frequency` field of [`MpsseSettings`] is `None`.
352 ///
353 /// # Example
354 ///
355 /// ```no_run
356 /// use ftdi_embedded_hal as hal;
357 /// use ftdi_mpsse::MpsseSettings;
358 /// use std::time::Duration;
359 ///
360 /// let mpsse = MpsseSettings {
361 /// reset: false,
362 /// in_transfer_size: 4096,
363 /// read_timeout: Duration::from_secs(5),
364 /// write_timeout: Duration::from_secs(5),
365 /// latency_timer: Duration::from_millis(32),
366 /// mask: 0x00,
367 /// clock_frequency: Some(400_000),
368 /// };
369 ///
370 /// # #[cfg(feature = "libftd2xx")]
371 /// # {
372 /// let device = libftd2xx::Ft232h::with_description("Single RS232-HS")?;
373 /// let hal = hal::FtHal::init(device, &mpsse)?;
374 /// # }
375 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
376 /// ```
377 ///
378 /// [`MpsseSettings`]: ftdi_mpsse::MpsseSettings
379 pub fn init(mut device: Device, mpsse_settings: &MpsseSettings) -> Result<FtHal<Device>, E> {
380 device.init(mpsse_settings)?;
381
382 Ok(FtHal {
383 mtx: Arc::new(Mutex::new(device.into())),
384 })
385 }
386}
387
388impl<Device, E> FtHal<Device>
389where
390 Device: MpsseCmdExecutor<Error = E>,
391 E: std::error::Error,
392 Error<E>: From<E>,
393{
394 /// Aquire the SPI peripheral for the FT232H.
395 ///
396 /// Pin assignments:
397 /// * AD0 => SCK
398 /// * AD1 => MOSI
399 /// * AD2 => MISO
400 ///
401 /// # Panics
402 ///
403 /// Panics if pin 0, 1, or 2 are already in use.
404 ///
405 /// # Example
406 ///
407 /// ```no_run
408 /// use ftdi_embedded_hal as hal;
409 ///
410 /// # #[cfg(feature = "libftd2xx")]
411 /// # {
412 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
413 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
414 /// let spi = hal.spi()?;
415 /// # }
416 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
417 /// ```
418 pub fn spi(&self) -> Result<Spi<Device>, Error<E>> {
419 Spi::new(self.mtx.clone())
420 }
421
422 /// Aquire the SPI peripheral with a chip select pin.
423 ///
424 /// This is specific to embedded-hal version 1.
425 ///
426 /// Pin assignments:
427 /// * AD0 => SCK
428 /// * AD1 => MOSI
429 /// * AD2 => MISO
430 ///
431 /// # Panics
432 ///
433 /// Panics if pin 0, 1, 2 or the CS pin are already in use.
434 ///
435 /// # Example
436 ///
437 /// ```no_run
438 /// use ftdi_embedded_hal as hal;
439 ///
440 /// # #[cfg(feature = "libftd2xx")]
441 /// # {
442 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
443 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
444 /// let spi = hal.spi_device(3)?;
445 /// # }
446 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
447 /// ```
448 pub fn spi_device(&self, cs_idx: u8) -> Result<SpiDevice<Device>, Error<E>> {
449 SpiDevice::new(self.mtx.clone(), cs_idx)
450 }
451
452 /// Aquire the I2C peripheral for the FT232H.
453 ///
454 /// Pin assignments:
455 /// * AD0 => SCL
456 /// * AD1 => SDA
457 /// * AD2 => SDA
458 ///
459 /// Yes, AD1 and AD2 are both SDA.
460 /// These pins must be shorted together for I2C operation.
461 ///
462 /// # Panics
463 ///
464 /// Panics if pin 0, 1, or 2 are already in use.
465 ///
466 /// # Example
467 ///
468 /// ```no_run
469 /// use ftdi_embedded_hal as hal;
470 ///
471 /// # #[cfg(feature = "libftd2xx")]
472 /// # {
473 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
474 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
475 /// let i2c = hal.i2c()?;
476 /// # }
477 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
478 /// ```
479 pub fn i2c(&self) -> Result<I2c<Device>, Error<E>> {
480 I2c::new(self.mtx.clone())
481 }
482
483 /// Aquire the digital output pin 0 for the FT232H.
484 ///
485 /// # Panics
486 ///
487 /// Panics if the pin is already in-use.
488 pub fn ad0(&self) -> Result<OutputPin<Device>, Error<E>> {
489 OutputPin::new(self.mtx.clone(), Pin::Lower(0))
490 }
491
492 /// Aquire the digital input pin 0 for the FT232H.
493 ///
494 /// # Panics
495 ///
496 /// Panics if the pin is already in-use.
497 pub fn adi0(&self) -> Result<InputPin<Device>, Error<E>> {
498 InputPin::new(self.mtx.clone(), Pin::Lower(0))
499 }
500
501 /// Aquire the digital output pin 1 for the FT232H.
502 ///
503 /// # Panics
504 ///
505 /// Panics if the pin is already in-use.
506 pub fn ad1(&self) -> Result<OutputPin<Device>, Error<E>> {
507 OutputPin::new(self.mtx.clone(), Pin::Lower(1))
508 }
509
510 /// Aquire the digital input pin 1 for the FT232H.
511 ///
512 /// # Panics
513 ///
514 /// Panics if the pin is already in-use.
515 pub fn adi1(&self) -> Result<InputPin<Device>, Error<E>> {
516 InputPin::new(self.mtx.clone(), Pin::Lower(1))
517 }
518
519 /// Aquire the digital output pin 2 for the FT232H.
520 ///
521 /// # Panics
522 ///
523 /// Panics if the pin is already in-use.
524 pub fn ad2(&self) -> Result<OutputPin<Device>, Error<E>> {
525 OutputPin::new(self.mtx.clone(), Pin::Lower(2))
526 }
527
528 /// Aquire the digital input pin 2 for the FT232H.
529 ///
530 /// # Panics
531 ///
532 /// Panics if the pin is already in-use.
533 pub fn adi2(&self) -> Result<InputPin<Device>, Error<E>> {
534 InputPin::new(self.mtx.clone(), Pin::Lower(2))
535 }
536
537 /// Aquire the digital output pin 3 for the FT232H.
538 ///
539 /// # Panics
540 ///
541 /// Panics if the pin is already in-use.
542 pub fn ad3(&self) -> Result<OutputPin<Device>, Error<E>> {
543 OutputPin::new(self.mtx.clone(), Pin::Lower(3))
544 }
545
546 /// Aquire the digital input pin 3 for the FT232H.
547 ///
548 /// # Panics
549 ///
550 /// Panics if the pin is already in-use.
551 pub fn adi3(&self) -> Result<InputPin<Device>, Error<E>> {
552 InputPin::new(self.mtx.clone(), Pin::Lower(3))
553 }
554
555 /// Aquire the digital output pin 4 for the FT232H.
556 ///
557 /// # Panics
558 ///
559 /// Panics if the pin is already in-use.
560 pub fn ad4(&self) -> Result<OutputPin<Device>, Error<E>> {
561 OutputPin::new(self.mtx.clone(), Pin::Lower(4))
562 }
563
564 /// Aquire the digital input pin 4 for the FT232H.
565 ///
566 /// # Panics
567 ///
568 /// Panics if the pin is already in-use.
569 pub fn adi4(&self) -> Result<InputPin<Device>, Error<E>> {
570 InputPin::new(self.mtx.clone(), Pin::Lower(4))
571 }
572
573 /// Aquire the digital output pin 5 for the FT232H.
574 ///
575 /// # Panics
576 ///
577 /// Panics if the pin is already in-use.
578 pub fn ad5(&self) -> Result<OutputPin<Device>, Error<E>> {
579 OutputPin::new(self.mtx.clone(), Pin::Lower(5))
580 }
581
582 /// Aquire the digital input pin 5 for the FT232H.
583 ///
584 /// # Panics
585 ///
586 /// Panics if the pin is already in-use.
587 pub fn adi5(&self) -> Result<InputPin<Device>, Error<E>> {
588 InputPin::new(self.mtx.clone(), Pin::Lower(5))
589 }
590
591 /// Aquire the digital output pin 6 for the FT232H.
592 ///
593 /// # Panics
594 ///
595 /// Panics if the pin is already in-use.
596 pub fn ad6(&self) -> Result<OutputPin<Device>, Error<E>> {
597 OutputPin::new(self.mtx.clone(), Pin::Lower(6))
598 }
599
600 /// Aquire the digital input pin 6 for the FT232H.
601 ///
602 /// # Panics
603 ///
604 /// Panics if the pin is already in-use.
605 pub fn adi6(&self) -> Result<InputPin<Device>, Error<E>> {
606 InputPin::new(self.mtx.clone(), Pin::Lower(6))
607 }
608
609 /// Aquire the digital output pin 7 for the FT232H.
610 ///
611 /// # Panics
612 ///
613 /// Panics if the pin is already in-use.
614 pub fn ad7(&self) -> Result<OutputPin<Device>, Error<E>> {
615 OutputPin::new(self.mtx.clone(), Pin::Lower(7))
616 }
617
618 /// Aquire the digital input pin 7 for the FT232H.
619 ///
620 /// # Panics
621 ///
622 /// Panics if the pin is already in-use.
623 pub fn adi7(&self) -> Result<InputPin<Device>, Error<E>> {
624 InputPin::new(self.mtx.clone(), Pin::Lower(7))
625 }
626
627 /// Aquire the digital output upper pin 0 for the FT232H.
628 ///
629 /// # Panics
630 ///
631 /// Panics if the pin is already in-use.
632 pub fn c0(&self) -> Result<OutputPin<Device>, Error<E>> {
633 OutputPin::new(self.mtx.clone(), Pin::Upper(0))
634 }
635
636 /// Aquire the digital input upper pin 0 for the FT232H.
637 ///
638 /// # Panics
639 ///
640 /// Panics if the pin is already in-use.
641 pub fn ci0(&self) -> Result<InputPin<Device>, Error<E>> {
642 InputPin::new(self.mtx.clone(), Pin::Upper(0))
643 }
644
645 /// Aquire the digital output upper pin 1 for the FT232H.
646 ///
647 /// # Panics
648 ///
649 /// Panics if the pin is already in-use.
650 pub fn c1(&self) -> Result<OutputPin<Device>, Error<E>> {
651 OutputPin::new(self.mtx.clone(), Pin::Upper(1))
652 }
653
654 /// Aquire the digital input upper pin 1 for the FT232H.
655 ///
656 /// # Panics
657 ///
658 /// Panics if the pin is already in-use.
659 pub fn ci1(&self) -> Result<InputPin<Device>, Error<E>> {
660 InputPin::new(self.mtx.clone(), Pin::Upper(1))
661 }
662
663 /// Aquire the digital output upper pin 2 for the FT232H.
664 ///
665 /// # Panics
666 ///
667 /// Panics if the pin is already in-use.
668 pub fn c2(&self) -> Result<OutputPin<Device>, Error<E>> {
669 OutputPin::new(self.mtx.clone(), Pin::Upper(2))
670 }
671
672 /// Aquire the digital input upper pin 2 for the FT232H.
673 ///
674 /// # Panics
675 ///
676 /// Panics if the pin is already in-use.
677 pub fn ci2(&self) -> Result<InputPin<Device>, Error<E>> {
678 InputPin::new(self.mtx.clone(), Pin::Upper(2))
679 }
680
681 /// Aquire the digital output upper pin 3 for the FT232H.
682 ///
683 /// # Panics
684 ///
685 /// Panics if the pin is already in-use.
686 pub fn c3(&self) -> Result<OutputPin<Device>, Error<E>> {
687 OutputPin::new(self.mtx.clone(), Pin::Upper(3))
688 }
689
690 /// Aquire the digital input upper pin 3 for the FT232H.
691 ///
692 /// # Panics
693 ///
694 /// Panics if the pin is already in-use.
695 pub fn ci3(&self) -> Result<InputPin<Device>, Error<E>> {
696 InputPin::new(self.mtx.clone(), Pin::Upper(3))
697 }
698
699 /// Aquire the digital output upper pin 4 for the FT232H.
700 ///
701 /// # Panics
702 ///
703 /// Panics if the pin is already in-use.
704 pub fn c4(&self) -> Result<OutputPin<Device>, Error<E>> {
705 OutputPin::new(self.mtx.clone(), Pin::Upper(4))
706 }
707
708 /// Aquire the digital input upper pin 4 for the FT232H.
709 ///
710 /// # Panics
711 ///
712 /// Panics if the pin is already in-use.
713 pub fn ci4(&self) -> Result<InputPin<Device>, Error<E>> {
714 InputPin::new(self.mtx.clone(), Pin::Upper(4))
715 }
716
717 /// Aquire the digital output upper pin 5 for the FT232H.
718 ///
719 /// # Panics
720 ///
721 /// Panics if the pin is already in-use.
722 pub fn c5(&self) -> Result<OutputPin<Device>, Error<E>> {
723 OutputPin::new(self.mtx.clone(), Pin::Upper(5))
724 }
725
726 /// Aquire the digital input upper pin 5 for the FT232H.
727 ///
728 /// # Panics
729 ///
730 /// Panics if the pin is already in-use.
731 pub fn ci5(&self) -> Result<InputPin<Device>, Error<E>> {
732 InputPin::new(self.mtx.clone(), Pin::Upper(5))
733 }
734
735 /// Aquire the digital output upper pin 6 for the FT232H.
736 ///
737 /// # Panics
738 ///
739 /// Panics if the pin is already in-use.
740 pub fn c6(&self) -> Result<OutputPin<Device>, Error<E>> {
741 OutputPin::new(self.mtx.clone(), Pin::Upper(6))
742 }
743
744 /// Aquire the digital input upper pin 6 for the FT232H.
745 ///
746 /// # Panics
747 ///
748 /// Panics if the pin is already in-use.
749 pub fn ci6(&self) -> Result<InputPin<Device>, Error<E>> {
750 InputPin::new(self.mtx.clone(), Pin::Upper(6))
751 }
752
753 /// Aquire the digital output upper pin 7 for the FT232H.
754 ///
755 /// # Panics
756 ///
757 /// Panics if the pin is already in-use.
758 pub fn c7(&self) -> Result<OutputPin<Device>, Error<E>> {
759 OutputPin::new(self.mtx.clone(), Pin::Upper(7))
760 }
761
762 /// Aquire the digital input upper pin 7 for the FT232H.
763 ///
764 /// # Panics
765 ///
766 /// Panics if the pin is already in-use.
767 pub fn ci7(&self) -> Result<InputPin<Device>, Error<E>> {
768 InputPin::new(self.mtx.clone(), Pin::Upper(7))
769 }
770}