1use crate::I2cExt;
3
4pub struct Pca9554<M>(M);
6pub struct Pca9554A<M>(M);
8
9impl<I2C> Pca9554<core::cell::RefCell<Driver<I2C>>>
10where
11 I2C: crate::I2cBus,
12{
13 pub fn new(i2c: I2C, a0: bool, a1: bool, a2: bool) -> Self {
14 Self::with_mutex(i2c, a0, a1, a2)
15 }
16}
17
18impl<I2C> Pca9554A<core::cell::RefCell<Driver<I2C>>>
19where
20 I2C: crate::I2cBus,
21{
22 pub fn new(i2c: I2C, a0: bool, a1: bool, a2: bool) -> Self {
23 Self::with_mutex(i2c, a0, a1, a2)
24 }
25}
26
27impl<I2C, M> Pca9554<M>
28where
29 I2C: crate::I2cBus,
30 M: crate::PortMutex<Port = Driver<I2C>>,
31{
32 pub fn with_mutex(i2c: I2C, a0: bool, a1: bool, a2: bool) -> Self {
33 Self(crate::PortMutex::create(Driver::new(
34 i2c, false, a0, a1, a2,
35 )))
36 }
37
38 pub fn split<'a>(&'a mut self) -> Parts<'a, I2C, M> {
39 Parts {
40 io0: crate::Pin::new(0, &self.0),
41 io1: crate::Pin::new(1, &self.0),
42 io2: crate::Pin::new(2, &self.0),
43 io3: crate::Pin::new(3, &self.0),
44 io4: crate::Pin::new(4, &self.0),
45 io5: crate::Pin::new(5, &self.0),
46 io6: crate::Pin::new(6, &self.0),
47 io7: crate::Pin::new(7, &self.0),
48 }
49 }
50}
51
52impl<I2C, M> Pca9554A<M>
53where
54 I2C: crate::I2cBus,
55 M: crate::PortMutex<Port = Driver<I2C>>,
56{
57 pub fn with_mutex(i2c: I2C, a0: bool, a1: bool, a2: bool) -> Self {
58 Self(crate::PortMutex::create(Driver::new(i2c, true, a0, a1, a2)))
59 }
60
61 pub fn split(&mut self) -> Parts<'_, I2C, M> {
62 Parts {
63 io0: crate::Pin::new(0, &self.0),
64 io1: crate::Pin::new(1, &self.0),
65 io2: crate::Pin::new(2, &self.0),
66 io3: crate::Pin::new(3, &self.0),
67 io4: crate::Pin::new(4, &self.0),
68 io5: crate::Pin::new(5, &self.0),
69 io6: crate::Pin::new(6, &self.0),
70 io7: crate::Pin::new(7, &self.0),
71 }
72 }
73}
74
75pub struct Parts<'a, I2C, M = core::cell::RefCell<Driver<I2C>>>
76where
77 I2C: crate::I2cBus,
78 M: crate::PortMutex<Port = Driver<I2C>>,
79{
80 pub io0: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
81 pub io1: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
82 pub io2: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
83 pub io3: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
84 pub io4: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
85 pub io5: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
86 pub io6: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
87 pub io7: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
88}
89
90#[allow(dead_code)]
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92enum Regs {
93 InputPort0 = 0x00,
94 OutputPort0 = 0x01,
95 PolarityInversion0 = 0x02,
96 Configuration0 = 0x03,
97}
98
99impl From<Regs> for u8 {
100 fn from(r: Regs) -> u8 {
101 r as u8
102 }
103}
104
105pub struct Driver<I2C> {
106 i2c: I2C,
107 out: u8,
108 addr: u8,
109}
110
111impl<I2C> Driver<I2C> {
112 pub fn new(i2c: I2C, is_a_variant: bool, a0: bool, a1: bool, a2: bool) -> Self {
113 let addr = if is_a_variant {
114 0x38 | ((a2 as u8) << 2) | ((a1 as u8) << 1) | (a0 as u8)
115 } else {
116 0x20 | ((a2 as u8) << 2) | ((a1 as u8) << 1) | (a0 as u8)
117 };
118 Self {
119 i2c,
120 out: 0xff,
121 addr,
122 }
123 }
124}
125
126impl<I2C: crate::I2cBus> crate::PortDriver for Driver<I2C> {
127 type Error = I2C::BusError;
128
129 fn set(&mut self, mask_high: u32, mask_low: u32) -> Result<(), Self::Error> {
130 self.out |= mask_high as u8;
131 self.out &= !mask_low as u8;
132 self.i2c
133 .write_reg(self.addr, Regs::OutputPort0, (self.out & 0xFF) as u8)?;
134 Ok(())
135 }
136
137 fn is_set(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
138 Ok(((self.out as u32) & mask_high) | (!(self.out as u32) & mask_low))
139 }
140
141 fn get(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
142 let io0 = if (mask_high | mask_low) & 0x00FF != 0 {
143 self.i2c.read_reg(self.addr, Regs::InputPort0)?
144 } else {
145 0
146 };
147 let in_ = io0 as u32;
148 Ok((in_ & mask_high) | (!in_ & mask_low))
149 }
150}
151
152impl<I2C: crate::I2cBus> crate::PortDriverTotemPole for Driver<I2C> {
153 fn set_direction(
154 &mut self,
155 mask: u32,
156 dir: crate::Direction,
157 state: bool,
158 ) -> Result<(), Self::Error> {
159 if dir == crate::Direction::Output {
161 use crate::PortDriver;
162 if state {
163 self.set(mask, 0)?;
164 } else {
165 self.set(0, mask)?;
166 }
167 }
168
169 let (mask_set, mask_clear) = match dir {
170 crate::Direction::Input => (mask as u16, 0),
171 crate::Direction::Output => (0, mask as u16),
172 };
173 if mask & 0x00FF != 0 {
174 self.i2c.update_reg(
175 self.addr,
176 Regs::Configuration0,
177 (mask_set & 0xFF) as u8,
178 (mask_clear & 0xFF) as u8,
179 )?;
180 }
181 Ok(())
182 }
183}
184
185impl<I2C: crate::I2cBus> crate::PortDriverPolarity for Driver<I2C> {
186 fn set_polarity(&mut self, mask: u32, inverted: bool) -> Result<(), Self::Error> {
187 let (mask_set, mask_clear) = match inverted {
188 false => (0, mask as u8),
189 true => (mask as u8, 0),
190 };
191
192 self.i2c.update_reg(
193 self.addr,
194 Regs::PolarityInversion0,
195 (mask_set & 0xFF) as u8,
196 (mask_clear & 0xFF) as u8,
197 )?;
198 Ok(())
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use embedded_hal_mock::eh1::i2c as mock_i2c;
205
206 #[test]
207 fn pca9554a() {
208 let expectations = [
209 mock_i2c::Transaction::write(0x39, vec![0x01, 0xfe]),
211 mock_i2c::Transaction::write(0x39, vec![0x01, 0xff]),
212 mock_i2c::Transaction::write_read(0x39, vec![0x00], vec![0xff]),
213 mock_i2c::Transaction::write(0x39, vec![0x01, 0xfd]),
215 mock_i2c::Transaction::write_read(0x39, vec![0x00], vec![0xfd]),
216 mock_i2c::Transaction::write(0x39, vec![0x01, 0xf9]),
218 mock_i2c::Transaction::write_read(0x39, vec![0x03], vec![0xff]),
219 mock_i2c::Transaction::write(0x39, vec![0x03, 0xfb]),
220 ];
221 let mut bus = mock_i2c::Mock::new(&expectations);
222
223 let mut pca = super::Pca9554A::new(bus.clone(), true, false, false);
224 let pca_pins = pca.split();
225
226 let mut pin0 = pca_pins.io0;
227 let mut pin1 = pca_pins.io1;
228 let pin2 = pca_pins.io2;
229
230 pin0.set_low().unwrap();
231 pin0.set_high().unwrap();
232 assert!(pin0.is_high().unwrap());
233 pin1.set_low().unwrap();
234 assert!(pin1.is_low().unwrap());
235 pin2.into_output().unwrap();
236
237 bus.done();
238 }
239
240 #[test]
241 fn pca9554() {
242 let expectations = [
243 mock_i2c::Transaction::write(0x21, vec![0x01, 0xfe]),
245 mock_i2c::Transaction::write(0x21, vec![0x01, 0xff]),
246 mock_i2c::Transaction::write_read(0x21, vec![0x00], vec![0xff]),
247 mock_i2c::Transaction::write(0x21, vec![0x01, 0xfd]),
249 mock_i2c::Transaction::write_read(0x21, vec![0x00], vec![0xfd]),
250 mock_i2c::Transaction::write(0x21, vec![0x01, 0xf9]),
252 mock_i2c::Transaction::write_read(0x21, vec![0x03], vec![0xff]),
253 mock_i2c::Transaction::write(0x21, vec![0x03, 0xfb]),
254 ];
255 let mut bus = mock_i2c::Mock::new(&expectations);
256
257 let mut pca = super::Pca9554::new(bus.clone(), true, false, false);
258 let pca_pins = pca.split();
259
260 let mut pin0 = pca_pins.io0;
261 let mut pin1 = pca_pins.io1;
262 let pin2 = pca_pins.io2;
263
264 pin0.set_low().unwrap();
265 pin0.set_high().unwrap();
266 assert!(pin0.is_high().unwrap());
267 pin1.set_low().unwrap();
268 assert!(pin1.is_low().unwrap());
269 pin2.into_output().unwrap();
270
271 bus.done();
272 }
273}