opentitanlib/transport/ftdi/
gpio.rs1use anyhow::Result;
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::rc::Rc;
9
10use embedded_hal::digital::{InputPin, OutputPin};
11use ftdi_embedded_hal as ftdi_hal;
12
13use crate::io::gpio::{GpioError, GpioPin, PinMode, PullMode};
14use crate::transport::ftdi::Chip;
15
16#[derive(Default)]
17enum PinType {
18 Output(ftdi_hal::OutputPin<ftdi::Device>),
19 Input(ftdi_hal::InputPin<ftdi::Device>),
20 #[default]
21 None,
22}
23
24pub struct Pin {
25 pin: RefCell<PinType>,
26 ftdi: Rc<HashMap<ftdi::Interface, ftdi_hal::FtHal<ftdi::Device>>>,
27 pinname: String,
28}
29
30impl Pin {
31 pub fn open<C: Chip>(
32 ftdi: &Rc<HashMap<ftdi::Interface, ftdi_hal::FtHal<ftdi::Device>>>,
33 pinname: String,
34 ) -> Result<Self> {
35 Ok(Self {
36 pin: RefCell::new(PinType::None),
37 ftdi: Rc::clone(ftdi),
38 pinname,
39 })
40 }
41
42 fn map_outpin(&self) -> Result<ftdi_hal::OutputPin<ftdi::Device>> {
43 let pinname = self.pinname.to_lowercase();
44 let interface = match &pinname[0..1] {
45 "a" => ftdi::Interface::A,
46 "b" => ftdi::Interface::B,
47 "c" => ftdi::Interface::C,
48 "d" => ftdi::Interface::D,
49 &_ => return Err(GpioError::InvalidPinName(pinname).into()),
50 };
51 let hal = self
52 .ftdi
53 .get(&interface)
54 .ok_or_else(|| GpioError::InvalidPinName(pinname.clone()))?;
55
56 let pin = match &pinname[1..] {
57 "dbus0" => hal.ad0(),
58 "dbus1" => hal.ad1(),
59 "dbus2" => hal.ad2(),
60 "dbus3" => hal.ad3(),
61 "dbus4" => hal.ad4(),
62 "dbus5" => hal.ad5(),
63 "dbus6" => hal.ad6(),
64 "dbus7" => hal.ad7(),
65 _ => return Err(GpioError::InvalidPinName(self.pinname.to_owned()).into()),
66 }?;
67 Ok(pin)
68 }
69
70 fn map_inpin(&self) -> Result<ftdi_hal::InputPin<ftdi::Device>> {
71 let pinname = self.pinname.to_lowercase();
72 let interface = match &pinname[0..1] {
73 "a" => ftdi::Interface::A,
74 "b" => ftdi::Interface::B,
75 "c" => ftdi::Interface::C,
76 "d" => ftdi::Interface::D,
77 &_ => return Err(GpioError::InvalidPinName(pinname).into()),
78 };
79 let hal = self
80 .ftdi
81 .get(&interface)
82 .ok_or_else(|| GpioError::InvalidPinName(pinname.clone()))?;
83
84 let pin = match &pinname[1..] {
85 "dbus0" => hal.adi0(),
86 "dbus1" => hal.adi1(),
87 "dbus2" => hal.adi2(),
88 "dbus3" => hal.adi3(),
89 "dbus4" => hal.adi4(),
90 "dbus5" => hal.adi5(),
91 "dbus6" => hal.adi6(),
92 "dbus7" => hal.adi7(),
93 _ => return Err(GpioError::InvalidPinName(self.pinname.to_owned()).into()),
94 }?;
95 Ok(pin)
96 }
97}
98
99impl GpioPin for Pin {
100 fn read(&self) -> Result<bool> {
101 let mut pin = self.pin.borrow_mut();
102 match *pin {
103 PinType::Input(ref mut pin) => Ok(pin.is_high()?),
104 _ => Err(GpioError::InvalidPinMode(0).into()),
105 }
106 }
107
108 fn write(&self, value: bool) -> Result<()> {
109 let mut pin = self.pin.borrow_mut();
110 if let PinType::Output(ref mut pin) = *pin {
111 if value {
112 pin.set_high()?;
113 } else {
114 pin.set_low()?;
115 }
116 return Ok(());
117 };
118 Err(GpioError::InvalidPinMode(0).into())
119 }
120
121 fn set_mode(&self, mode: PinMode) -> Result<()> {
122 let mut pin = self.pin.borrow_mut();
123 *pin = match (&*pin, mode) {
124 (PinType::None, PinMode::Input) => PinType::Input(self.map_inpin()?),
125 (PinType::None, PinMode::PushPull | PinMode::OpenDrain) => {
126 PinType::Output(self.map_outpin()?)
127 }
128 _ => return Ok(()),
129 };
130 Ok(())
131 }
132
133 fn set_pull_mode(&self, _mode: PullMode) -> Result<()> {
134 Ok(())
135 }
136
137 fn get_internal_pin_name(&self) -> Option<&str> {
138 Some(&self.pinname)
139 }
140}