ftdi_embedded_hal/
gpio.rs

1use crate::error::Error;
2use crate::{FtInner, PinUse};
3use ftdi_mpsse::{MpsseCmdBuilder, MpsseCmdExecutor};
4use std::sync::{Arc, Mutex};
5
6/// Pin number
7#[derive(Debug, Copy, Clone)]
8pub(crate) enum Pin {
9    Lower(u8),
10    Upper(u8),
11}
12
13/// FTDI output pin.
14///
15/// This is created by calling [`FtHal::ad0`] - [`FtHal::ad7`].
16///
17/// [`FtHal::ad0`]: crate::FtHal::ad0
18/// [`FtHal::ad7`]: crate::FtHal::ad7
19#[derive(Debug)]
20pub struct OutputPin<Device: MpsseCmdExecutor> {
21    /// Parent FTDI device.
22    mtx: Arc<Mutex<FtInner<Device>>>,
23    /// GPIO pin index.  0-7 for the FT232H.
24    pin: Pin,
25}
26
27impl<Device, E> OutputPin<Device>
28where
29    Device: MpsseCmdExecutor<Error = E>,
30    E: std::error::Error,
31    Error<E>: From<E>,
32{
33    pub(crate) fn new(
34        mtx: Arc<Mutex<FtInner<Device>>>,
35        pin: Pin,
36    ) -> Result<OutputPin<Device>, Error<E>> {
37        {
38            let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex");
39
40            lock.allocate_pin_any(pin, PinUse::Output);
41
42            let (byte, idx) = match pin {
43                Pin::Lower(idx) => (&mut lock.lower, idx),
44                Pin::Upper(idx) => (&mut lock.upper, idx),
45            };
46            byte.direction |= 1 << idx;
47            let cmd = MpsseCmdBuilder::new();
48            let cmd = match pin {
49                Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
50                Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
51            }
52            .send_immediate();
53            lock.ft.send(cmd.as_slice())?;
54        }
55        Ok(OutputPin { mtx, pin })
56    }
57
58    pub(crate) fn set(&self, state: bool) -> Result<(), Error<E>> {
59        let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
60
61        let byte = match self.pin {
62            Pin::Lower(_) => &mut lock.lower,
63            Pin::Upper(_) => &mut lock.upper,
64        };
65
66        if state {
67            byte.value |= self.mask();
68        } else {
69            byte.value &= !self.mask();
70        };
71
72        let cmd = MpsseCmdBuilder::new();
73        let cmd = match self.pin {
74            Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
75            Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
76        }
77        .send_immediate();
78        lock.ft.send(cmd.as_slice())?;
79
80        Ok(())
81    }
82}
83
84impl<Device: MpsseCmdExecutor> OutputPin<Device> {
85    /// Convert the GPIO pin index to a pin mask
86    pub(crate) fn mask(&self) -> u8 {
87        let idx = match self.pin {
88            Pin::Lower(idx) => idx,
89            Pin::Upper(idx) => idx,
90        };
91        1 << idx
92    }
93}
94
95impl<Device, E> eh1::digital::ErrorType for OutputPin<Device>
96where
97    Device: MpsseCmdExecutor<Error = E>,
98    E: std::error::Error,
99    Error<E>: From<E>,
100{
101    type Error = Error<E>;
102}
103
104impl<Device, E> eh1::digital::OutputPin for OutputPin<Device>
105where
106    Device: MpsseCmdExecutor<Error = E>,
107    E: std::error::Error,
108    Error<E>: From<E>,
109{
110    fn set_low(&mut self) -> Result<(), Error<E>> {
111        self.set(false)
112    }
113
114    fn set_high(&mut self) -> Result<(), Error<E>> {
115        self.set(true)
116    }
117}
118
119impl<Device, E> eh0::digital::v2::OutputPin for OutputPin<Device>
120where
121    Device: MpsseCmdExecutor<Error = E>,
122    E: std::error::Error,
123    Error<E>: From<E>,
124{
125    type Error = Error<E>;
126
127    fn set_low(&mut self) -> Result<(), Error<E>> {
128        self.set(false)
129    }
130
131    fn set_high(&mut self) -> Result<(), Error<E>> {
132        self.set(true)
133    }
134}
135
136/// FTDI input pin.
137///
138/// This is created by calling [`FtHal::adi0`] - [`FtHal::adi7`].
139///
140/// [`FtHal::adi0`]: crate::FtHal::adi0
141/// [`FtHal::adi7`]: crate::FtHal::adi7
142#[derive(Debug)]
143pub struct InputPin<Device: MpsseCmdExecutor> {
144    /// Parent FTDI device.
145    mtx: Arc<Mutex<FtInner<Device>>>,
146    /// GPIO pin index.  0-7 for the FT232H.
147    pin: Pin,
148}
149
150impl<Device, E> InputPin<Device>
151where
152    Device: MpsseCmdExecutor<Error = E>,
153    E: std::error::Error,
154    Error<E>: From<E>,
155{
156    pub(crate) fn new(
157        mtx: Arc<Mutex<FtInner<Device>>>,
158        pin: Pin,
159    ) -> Result<InputPin<Device>, Error<E>> {
160        {
161            let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex");
162
163            lock.allocate_pin_any(pin, PinUse::Input);
164
165            let (byte, idx) = match pin {
166                Pin::Lower(idx) => (&mut lock.lower, idx),
167                Pin::Upper(idx) => (&mut lock.upper, idx),
168            };
169            byte.direction &= !(1 << idx);
170            let cmd = MpsseCmdBuilder::new();
171            let cmd = match pin {
172                Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
173                Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
174            }
175            .send_immediate();
176            lock.ft.send(cmd.as_slice())?;
177        }
178        Ok(InputPin { mtx, pin })
179    }
180
181    pub(crate) fn get(&self) -> Result<bool, Error<E>> {
182        let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
183
184        let mut buffer = [0u8; 1];
185        let cmd = MpsseCmdBuilder::new();
186        let cmd = match self.pin {
187            Pin::Lower(_) => cmd.gpio_lower(),
188            Pin::Upper(_) => cmd.gpio_upper(),
189        }
190        .send_immediate();
191        lock.ft.send(cmd.as_slice())?;
192        lock.ft.recv(&mut buffer)?;
193
194        Ok((buffer[0] & self.mask()) != 0)
195    }
196}
197
198impl<Device: MpsseCmdExecutor> InputPin<Device> {
199    /// Convert the GPIO pin index to a pin mask
200    pub(crate) fn mask(&self) -> u8 {
201        let idx = match self.pin {
202            Pin::Lower(idx) => idx,
203            Pin::Upper(idx) => idx,
204        };
205        1 << idx
206    }
207}
208
209impl<Device, E> eh1::digital::ErrorType for InputPin<Device>
210where
211    Device: MpsseCmdExecutor<Error = E>,
212    E: std::error::Error,
213    Error<E>: From<E>,
214{
215    type Error = Error<E>;
216}
217
218impl<Device, E> eh1::digital::InputPin for InputPin<Device>
219where
220    Device: MpsseCmdExecutor<Error = E>,
221    E: std::error::Error,
222    Error<E>: From<E>,
223{
224    fn is_high(&mut self) -> Result<bool, Self::Error> {
225        self.get()
226    }
227
228    fn is_low(&mut self) -> Result<bool, Self::Error> {
229        self.get().map(|res| !res)
230    }
231}
232
233impl<Device, E> eh0::digital::v2::InputPin for InputPin<Device>
234where
235    Device: MpsseCmdExecutor<Error = E>,
236    E: std::error::Error,
237    Error<E>: From<E>,
238{
239    type Error = Error<E>;
240
241    fn is_high(&self) -> Result<bool, Self::Error> {
242        self.get()
243    }
244
245    fn is_low(&self) -> Result<bool, Self::Error> {
246        self.get().map(|res| !res)
247    }
248}