pca9539/
pin_refreshable.rs

1use crate::expander::{Bank, Mode, PinID, RefreshInputError};
2use crate::guard::RefGuard;
3use crate::pins::{Input, Output, Pin, PinMode, RefreshMode};
4use core::convert::Infallible;
5use core::marker::PhantomData;
6use embedded_hal::digital::{ErrorType, InputPin, OutputPin, PinState, StatefulOutputPin};
7use embedded_hal::i2c::{I2c, SevenBitAddress};
8
9/// Trait for refreshable pins in output mode
10pub trait RefreshableOutputPin {
11    type Error;
12
13    /// Updates the output state of all pins of the same bank
14    fn update_bank(&self) -> Result<(), Self::Error>;
15
16    /// Updates the output state of all pins (on all banks)
17    fn update_all(&self) -> Result<(), Self::Error>;
18}
19
20/// Trait for refreshable pins in input mode
21pub trait RefreshableInputPin {
22    type Error;
23
24    /// Refreshes the input state of all pins of the same bank
25    fn refresh_bank(&self) -> Result<(), Self::Error>;
26
27    /// Refreshes the input state of all pins (on all banks)
28    fn refresh_all(&self) -> Result<(), Self::Error>;
29}
30
31impl<'a, B, R> Pin<'a, B, R, Input, RefreshMode>
32where
33    B: I2c<SevenBitAddress>,
34    R: RefGuard<B>,
35{
36    pub fn refreshable(expander: &'a R, bank: Bank, id: PinID) -> Self {
37        Self {
38            expander,
39            bus: PhantomData,
40            bank,
41            id,
42            access_mode: PhantomData,
43            mode: PhantomData,
44        }
45    }
46
47    /// Refreshes the input state of the given bank
48    fn refresh(&self, bank: Bank) -> Result<(), RefreshInputError<B>> {
49        let mut result = Ok(());
50
51        self.expander.access(|expander| {
52            result = expander.refresh_input_state(bank);
53        });
54
55        result
56    }
57}
58
59impl<B, R> RefreshableInputPin for Pin<'_, B, R, Input, RefreshMode>
60where
61    B: I2c<SevenBitAddress>,
62    R: RefGuard<B>,
63{
64    type Error = RefreshInputError<B>;
65
66    /// Refreshes the input state of all pins of the same bank
67    fn refresh_bank(&self) -> Result<(), Self::Error> {
68        self.refresh(self.bank)
69    }
70
71    /// Refreshes the input state of all pins (on all banks)
72    fn refresh_all(&self) -> Result<(), Self::Error> {
73        self.refresh(Bank::Bank0)?;
74        self.refresh(Bank::Bank1)
75    }
76}
77
78impl<B, R> RefreshableOutputPin for Pin<'_, B, R, Output, RefreshMode>
79where
80    B: I2c<SevenBitAddress>,
81    R: RefGuard<B>,
82{
83    type Error = B::Error;
84
85    /// Updates the output state of all pins of the same bank
86    fn update_bank(&self) -> Result<(), Self::Error> {
87        self.update(self.bank)
88    }
89
90    /// Updates the output state of all pins (on all banks)
91    fn update_all(&self) -> Result<(), Self::Error> {
92        self.update(Bank::Bank0)?;
93        self.update(Bank::Bank1)
94    }
95}
96
97impl<B, R> Pin<'_, B, R, Output, RefreshMode>
98where
99    B: I2c<SevenBitAddress>,
100    R: RefGuard<B>,
101{
102    /// Writes the output state of the given bank
103    fn update(&self, bank: Bank) -> Result<(), B::Error> {
104        let mut result = Ok(());
105
106        self.expander.access(|expander| {
107            result = expander.write_output_state(bank);
108        });
109
110        result
111    }
112}
113
114impl<B, R> ErrorType for Pin<'_, B, R, Input, RefreshMode>
115where
116    B: I2c<SevenBitAddress>,
117    R: RefGuard<B>,
118{
119    type Error = Infallible;
120}
121
122impl<B, R> InputPin for Pin<'_, B, R, Input, RefreshMode>
123where
124    B: I2c<SevenBitAddress>,
125    R: RefGuard<B>,
126{
127    fn is_high(&mut self) -> Result<bool, Self::Error> {
128        let mut state = false;
129
130        self.expander.access(|expander| {
131            state = expander.is_pin_input_high(self.bank, self.id);
132        });
133
134        Ok(state)
135    }
136
137    fn is_low(&mut self) -> Result<bool, Self::Error> {
138        Ok(!self.is_high()?)
139    }
140}
141
142impl<B, R> ErrorType for Pin<'_, B, R, Output, RefreshMode>
143where
144    B: I2c<SevenBitAddress>,
145    R: RefGuard<B>,
146{
147    type Error = Infallible;
148}
149
150impl<B, R> OutputPin for Pin<'_, B, R, Output, RefreshMode>
151where
152    B: I2c<SevenBitAddress>,
153    R: RefGuard<B>,
154{
155    fn set_low(&mut self) -> Result<(), Self::Error> {
156        self.set_state(PinState::Low)
157    }
158
159    fn set_high(&mut self) -> Result<(), Self::Error> {
160        self.set_state(PinState::High)
161    }
162
163    fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> {
164        self.expander.access(|expander| {
165            expander.set_state(self.bank, self.id, state == PinState::High);
166        });
167
168        Ok(())
169    }
170}
171
172impl<B, R> StatefulOutputPin for Pin<'_, B, R, Output, RefreshMode>
173where
174    B: I2c<SevenBitAddress>,
175    R: RefGuard<B>,
176{
177    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
178        Ok(self.is_pin_output_high())
179    }
180
181    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
182        Ok(!self.is_pin_output_high())
183    }
184}
185
186impl<'a, B, M, R> Pin<'a, B, R, M, RefreshMode>
187where
188    B: I2c<SevenBitAddress>,
189    R: RefGuard<B>,
190    M: PinMode,
191{
192    pub fn into_input_pin(self) -> Result<Pin<'a, B, R, Input, RefreshMode>, B::Error> {
193        self.change_mode(Mode::Input)?;
194
195        Ok(Pin {
196            expander: self.expander,
197            bank: self.bank,
198            id: self.id,
199            bus: PhantomData,
200            mode: PhantomData,
201            access_mode: PhantomData,
202        })
203    }
204
205    pub fn into_output_pin(self, state: PinState) -> Result<Pin<'a, B, R, Output, RefreshMode>, B::Error> {
206        self.change_mode(Mode::Output)?;
207
208        let mut pin = Pin {
209            expander: self.expander,
210            bank: self.bank,
211            id: self.id,
212            bus: PhantomData,
213            mode: PhantomData,
214            access_mode: PhantomData,
215        };
216
217        let _ = pin.set_state(state);
218        pin.update_bank()?;
219        Ok(pin)
220    }
221}