ftdi_embedded_hal/lib.rs
1//! This is an [embedded-hal] implementation for the FTDI chips
2//! that use the [libftd2xx] or [ftdi-rs] drivers.
3//!
4//! This enables development of embedded device drivers without the use of
5//! a microcontroller. The FTDI devices interface with a PC via USB, and
6//! provide a multi-protocol synchronous serial engine to interface
7//! with most GPIO, SPI, and 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.2"
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 /// Executes the closure with the device.
395 ///
396 /// Useful for accessing EEPROM, or other device-specific functionality.
397 ///
398 /// # Example
399 ///
400 /// ```no_run
401 /// use ftdi_embedded_hal as hal;
402 /// # #[cfg(feature = "libftd2xx")]
403 /// use hal::libftd2xx::FtdiEeprom;
404 ///
405 /// # #[cfg(feature = "libftd2xx")]
406 /// # {
407 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
408 /// let mut hal = hal::FtHal::init_default(device)?;
409 /// let serial_number: String =
410 /// hal.with_device(|d| d.eeprom_read().map(|(_, strings)| strings.serial_number()))?;
411 /// # }
412 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
413 /// ```
414 pub fn with_device<T, F>(&mut self, mut f: F) -> T
415 where
416 F: FnMut(&mut Device) -> T,
417 {
418 let mut inner = self.mtx.lock().expect("Failed to aquire FTDI mutex");
419 let result: T = f(&mut inner.ft);
420 result
421 }
422
423 /// Aquire the SPI peripheral for the FT232H.
424 ///
425 /// Pin assignments:
426 /// * AD0 => SCK
427 /// * AD1 => MOSI
428 /// * AD2 => MISO
429 ///
430 /// # Panics
431 ///
432 /// Panics if pin 0, 1, or 2 are already in use.
433 ///
434 /// # Example
435 ///
436 /// ```no_run
437 /// use ftdi_embedded_hal as hal;
438 ///
439 /// # #[cfg(feature = "libftd2xx")]
440 /// # {
441 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
442 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
443 /// let spi = hal.spi()?;
444 /// # }
445 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
446 /// ```
447 pub fn spi(&self) -> Result<Spi<Device>, Error<E>> {
448 Spi::new(self.mtx.clone())
449 }
450
451 /// Aquire the SPI peripheral with a chip select pin.
452 ///
453 /// This is specific to embedded-hal version 1.
454 ///
455 /// Pin assignments:
456 /// * AD0 => SCK
457 /// * AD1 => MOSI
458 /// * AD2 => MISO
459 ///
460 /// # Panics
461 ///
462 /// Panics if pin 0, 1, 2 or the CS pin are already in use.
463 ///
464 /// # Example
465 ///
466 /// ```no_run
467 /// use ftdi_embedded_hal as hal;
468 ///
469 /// # #[cfg(feature = "libftd2xx")]
470 /// # {
471 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
472 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
473 /// let spi = hal.spi_device(3)?;
474 /// # }
475 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
476 /// ```
477 pub fn spi_device(&self, cs_idx: u8) -> Result<SpiDevice<Device>, Error<E>> {
478 SpiDevice::new(self.mtx.clone(), cs_idx)
479 }
480
481 /// Aquire the I2C peripheral for the FT232H.
482 ///
483 /// Pin assignments:
484 /// * AD0 => SCL
485 /// * AD1 => SDA
486 /// * AD2 => SDA
487 ///
488 /// Yes, AD1 and AD2 are both SDA.
489 /// These pins must be shorted together for I2C operation.
490 ///
491 /// # Panics
492 ///
493 /// Panics if pin 0, 1, or 2 are already in use.
494 ///
495 /// # Example
496 ///
497 /// ```no_run
498 /// use ftdi_embedded_hal as hal;
499 ///
500 /// # #[cfg(feature = "libftd2xx")]
501 /// # {
502 /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?;
503 /// let hal = hal::FtHal::init_freq(device, 3_000_000)?;
504 /// let i2c = hal.i2c()?;
505 /// # }
506 /// # Ok::<(), std::boxed::Box<dyn std::error::Error>>(())
507 /// ```
508 pub fn i2c(&self) -> Result<I2c<Device>, Error<E>> {
509 I2c::new(self.mtx.clone())
510 }
511
512 /// Aquire the digital output pin 0 for the FT232H.
513 ///
514 /// # Panics
515 ///
516 /// Panics if the pin is already in-use.
517 pub fn ad0(&self) -> Result<OutputPin<Device>, Error<E>> {
518 OutputPin::new(self.mtx.clone(), Pin::Lower(0))
519 }
520
521 /// Aquire the digital input pin 0 for the FT232H.
522 ///
523 /// # Panics
524 ///
525 /// Panics if the pin is already in-use.
526 pub fn adi0(&self) -> Result<InputPin<Device>, Error<E>> {
527 InputPin::new(self.mtx.clone(), Pin::Lower(0))
528 }
529
530 /// Aquire the digital output pin 1 for the FT232H.
531 ///
532 /// # Panics
533 ///
534 /// Panics if the pin is already in-use.
535 pub fn ad1(&self) -> Result<OutputPin<Device>, Error<E>> {
536 OutputPin::new(self.mtx.clone(), Pin::Lower(1))
537 }
538
539 /// Aquire the digital input pin 1 for the FT232H.
540 ///
541 /// # Panics
542 ///
543 /// Panics if the pin is already in-use.
544 pub fn adi1(&self) -> Result<InputPin<Device>, Error<E>> {
545 InputPin::new(self.mtx.clone(), Pin::Lower(1))
546 }
547
548 /// Aquire the digital output pin 2 for the FT232H.
549 ///
550 /// # Panics
551 ///
552 /// Panics if the pin is already in-use.
553 pub fn ad2(&self) -> Result<OutputPin<Device>, Error<E>> {
554 OutputPin::new(self.mtx.clone(), Pin::Lower(2))
555 }
556
557 /// Aquire the digital input pin 2 for the FT232H.
558 ///
559 /// # Panics
560 ///
561 /// Panics if the pin is already in-use.
562 pub fn adi2(&self) -> Result<InputPin<Device>, Error<E>> {
563 InputPin::new(self.mtx.clone(), Pin::Lower(2))
564 }
565
566 /// Aquire the digital output pin 3 for the FT232H.
567 ///
568 /// # Panics
569 ///
570 /// Panics if the pin is already in-use.
571 pub fn ad3(&self) -> Result<OutputPin<Device>, Error<E>> {
572 OutputPin::new(self.mtx.clone(), Pin::Lower(3))
573 }
574
575 /// Aquire the digital input pin 3 for the FT232H.
576 ///
577 /// # Panics
578 ///
579 /// Panics if the pin is already in-use.
580 pub fn adi3(&self) -> Result<InputPin<Device>, Error<E>> {
581 InputPin::new(self.mtx.clone(), Pin::Lower(3))
582 }
583
584 /// Aquire the digital output pin 4 for the FT232H.
585 ///
586 /// # Panics
587 ///
588 /// Panics if the pin is already in-use.
589 pub fn ad4(&self) -> Result<OutputPin<Device>, Error<E>> {
590 OutputPin::new(self.mtx.clone(), Pin::Lower(4))
591 }
592
593 /// Aquire the digital input pin 4 for the FT232H.
594 ///
595 /// # Panics
596 ///
597 /// Panics if the pin is already in-use.
598 pub fn adi4(&self) -> Result<InputPin<Device>, Error<E>> {
599 InputPin::new(self.mtx.clone(), Pin::Lower(4))
600 }
601
602 /// Aquire the digital output pin 5 for the FT232H.
603 ///
604 /// # Panics
605 ///
606 /// Panics if the pin is already in-use.
607 pub fn ad5(&self) -> Result<OutputPin<Device>, Error<E>> {
608 OutputPin::new(self.mtx.clone(), Pin::Lower(5))
609 }
610
611 /// Aquire the digital input pin 5 for the FT232H.
612 ///
613 /// # Panics
614 ///
615 /// Panics if the pin is already in-use.
616 pub fn adi5(&self) -> Result<InputPin<Device>, Error<E>> {
617 InputPin::new(self.mtx.clone(), Pin::Lower(5))
618 }
619
620 /// Aquire the digital output pin 6 for the FT232H.
621 ///
622 /// # Panics
623 ///
624 /// Panics if the pin is already in-use.
625 pub fn ad6(&self) -> Result<OutputPin<Device>, Error<E>> {
626 OutputPin::new(self.mtx.clone(), Pin::Lower(6))
627 }
628
629 /// Aquire the digital input pin 6 for the FT232H.
630 ///
631 /// # Panics
632 ///
633 /// Panics if the pin is already in-use.
634 pub fn adi6(&self) -> Result<InputPin<Device>, Error<E>> {
635 InputPin::new(self.mtx.clone(), Pin::Lower(6))
636 }
637
638 /// Aquire the digital output pin 7 for the FT232H.
639 ///
640 /// # Panics
641 ///
642 /// Panics if the pin is already in-use.
643 pub fn ad7(&self) -> Result<OutputPin<Device>, Error<E>> {
644 OutputPin::new(self.mtx.clone(), Pin::Lower(7))
645 }
646
647 /// Aquire the digital input pin 7 for the FT232H.
648 ///
649 /// # Panics
650 ///
651 /// Panics if the pin is already in-use.
652 pub fn adi7(&self) -> Result<InputPin<Device>, Error<E>> {
653 InputPin::new(self.mtx.clone(), Pin::Lower(7))
654 }
655
656 /// Aquire the digital output upper pin 0 for the FT232H.
657 ///
658 /// # Panics
659 ///
660 /// Panics if the pin is already in-use.
661 pub fn c0(&self) -> Result<OutputPin<Device>, Error<E>> {
662 OutputPin::new(self.mtx.clone(), Pin::Upper(0))
663 }
664
665 /// Aquire the digital input upper pin 0 for the FT232H.
666 ///
667 /// # Panics
668 ///
669 /// Panics if the pin is already in-use.
670 pub fn ci0(&self) -> Result<InputPin<Device>, Error<E>> {
671 InputPin::new(self.mtx.clone(), Pin::Upper(0))
672 }
673
674 /// Aquire the digital output upper pin 1 for the FT232H.
675 ///
676 /// # Panics
677 ///
678 /// Panics if the pin is already in-use.
679 pub fn c1(&self) -> Result<OutputPin<Device>, Error<E>> {
680 OutputPin::new(self.mtx.clone(), Pin::Upper(1))
681 }
682
683 /// Aquire the digital input upper pin 1 for the FT232H.
684 ///
685 /// # Panics
686 ///
687 /// Panics if the pin is already in-use.
688 pub fn ci1(&self) -> Result<InputPin<Device>, Error<E>> {
689 InputPin::new(self.mtx.clone(), Pin::Upper(1))
690 }
691
692 /// Aquire the digital output upper pin 2 for the FT232H.
693 ///
694 /// # Panics
695 ///
696 /// Panics if the pin is already in-use.
697 pub fn c2(&self) -> Result<OutputPin<Device>, Error<E>> {
698 OutputPin::new(self.mtx.clone(), Pin::Upper(2))
699 }
700
701 /// Aquire the digital input upper pin 2 for the FT232H.
702 ///
703 /// # Panics
704 ///
705 /// Panics if the pin is already in-use.
706 pub fn ci2(&self) -> Result<InputPin<Device>, Error<E>> {
707 InputPin::new(self.mtx.clone(), Pin::Upper(2))
708 }
709
710 /// Aquire the digital output upper pin 3 for the FT232H.
711 ///
712 /// # Panics
713 ///
714 /// Panics if the pin is already in-use.
715 pub fn c3(&self) -> Result<OutputPin<Device>, Error<E>> {
716 OutputPin::new(self.mtx.clone(), Pin::Upper(3))
717 }
718
719 /// Aquire the digital input upper pin 3 for the FT232H.
720 ///
721 /// # Panics
722 ///
723 /// Panics if the pin is already in-use.
724 pub fn ci3(&self) -> Result<InputPin<Device>, Error<E>> {
725 InputPin::new(self.mtx.clone(), Pin::Upper(3))
726 }
727
728 /// Aquire the digital output upper pin 4 for the FT232H.
729 ///
730 /// # Panics
731 ///
732 /// Panics if the pin is already in-use.
733 pub fn c4(&self) -> Result<OutputPin<Device>, Error<E>> {
734 OutputPin::new(self.mtx.clone(), Pin::Upper(4))
735 }
736
737 /// Aquire the digital input upper pin 4 for the FT232H.
738 ///
739 /// # Panics
740 ///
741 /// Panics if the pin is already in-use.
742 pub fn ci4(&self) -> Result<InputPin<Device>, Error<E>> {
743 InputPin::new(self.mtx.clone(), Pin::Upper(4))
744 }
745
746 /// Aquire the digital output upper pin 5 for the FT232H.
747 ///
748 /// # Panics
749 ///
750 /// Panics if the pin is already in-use.
751 pub fn c5(&self) -> Result<OutputPin<Device>, Error<E>> {
752 OutputPin::new(self.mtx.clone(), Pin::Upper(5))
753 }
754
755 /// Aquire the digital input upper pin 5 for the FT232H.
756 ///
757 /// # Panics
758 ///
759 /// Panics if the pin is already in-use.
760 pub fn ci5(&self) -> Result<InputPin<Device>, Error<E>> {
761 InputPin::new(self.mtx.clone(), Pin::Upper(5))
762 }
763
764 /// Aquire the digital output upper pin 6 for the FT232H.
765 ///
766 /// # Panics
767 ///
768 /// Panics if the pin is already in-use.
769 pub fn c6(&self) -> Result<OutputPin<Device>, Error<E>> {
770 OutputPin::new(self.mtx.clone(), Pin::Upper(6))
771 }
772
773 /// Aquire the digital input upper pin 6 for the FT232H.
774 ///
775 /// # Panics
776 ///
777 /// Panics if the pin is already in-use.
778 pub fn ci6(&self) -> Result<InputPin<Device>, Error<E>> {
779 InputPin::new(self.mtx.clone(), Pin::Upper(6))
780 }
781
782 /// Aquire the digital output upper pin 7 for the FT232H.
783 ///
784 /// # Panics
785 ///
786 /// Panics if the pin is already in-use.
787 pub fn c7(&self) -> Result<OutputPin<Device>, Error<E>> {
788 OutputPin::new(self.mtx.clone(), Pin::Upper(7))
789 }
790
791 /// Aquire the digital input upper pin 7 for the FT232H.
792 ///
793 /// # Panics
794 ///
795 /// Panics if the pin is already in-use.
796 pub fn ci7(&self) -> Result<InputPin<Device>, Error<E>> {
797 InputPin::new(self.mtx.clone(), Pin::Upper(7))
798 }
799}