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