1use crate::I2cExt;
3
4pub struct Pcal6416a<M>(M);
6
7impl<I2C> Pcal6416a<core::cell::RefCell<Driver<I2C>>>
8where
9 I2C: crate::I2cBus,
10{
11 pub fn new(i2c: I2C, addr: bool) -> Self {
12 Self::with_mutex(i2c, addr)
13 }
14}
15
16impl<I2C, M> Pcal6416a<M>
17where
18 I2C: crate::I2cBus,
19 M: crate::PortMutex<Port = Driver<I2C>>,
20{
21 pub fn with_mutex(i2c: I2C, addr: bool) -> Self {
22 Self(crate::PortMutex::create(Driver::new(i2c, addr)))
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 OutputDriveStrength0Port0 = 0x40,
82 OutputDriveStrength1Port0 = 0x41,
83 OutputDriveStrength0Port1 = 0x42,
84 OutputDriveStrength1Port1 = 0x43,
85 InputLatch0 = 0x44,
86 InputLatch1 = 0x45,
87 PullEnable0 = 0x46,
88 PullEnable1 = 0x47,
89 PullSelection0 = 0x48,
90 PullSelection1 = 0x49,
91 InterruptMask0 = 0x4A,
92 InterruptMask1 = 0x4B,
93 InterruptStatus0 = 0x4C,
94 InterruptStatus1 = 0x4D,
95 OutputPortConfiguration = 0x4F, }
97
98impl From<Regs> for u8 {
99 fn from(r: Regs) -> u8 {
100 r as u8
101 }
102}
103
104pub struct Driver<I2C> {
105 i2c: I2C,
106 out: Option<u16>,
107 addr: u8,
108}
109
110impl<I2C> Driver<I2C> {
111 pub fn new(i2c: I2C, addr: bool) -> Self {
112 let addr = 0x20 | (addr as u8);
113 Self {
114 i2c,
115 out: None,
116 addr,
117 }
118 }
119}
120
121impl<I2C: crate::I2cBus> Driver<I2C> {
122 fn get_out(&mut self) -> Result<u16, I2C::BusError> {
123 match self.out {
126 Some(out) => Ok(out),
127 None => {
128 let out_low = self.i2c.read_reg(self.addr, Regs::OutputPort0)? as u16;
129 let out_high = self.i2c.read_reg(self.addr, Regs::OutputPort1)? as u16;
130 let out = out_low | (out_high << 8);
131 self.out = Some(out);
132 Ok(out)
133 }
134 }
135 }
136}
137
138impl<I2C: crate::I2cBus> crate::PortDriver for Driver<I2C> {
139 type Error = I2C::BusError;
140
141 fn set(&mut self, mask_high: u32, mask_low: u32) -> Result<(), Self::Error> {
142 let mut out = self.get_out()?;
143 out |= mask_high as u16;
144 out &= !mask_low as u16;
145 self.out = Some(out);
146 if (mask_high | mask_low) & 0x00FF != 0 {
147 self.i2c
148 .write_reg(self.addr, Regs::OutputPort0, (out & 0xFF) as u8)?;
149 }
150 if (mask_high | mask_low) & 0xFF00 != 0 {
151 self.i2c
152 .write_reg(self.addr, Regs::OutputPort1, (out >> 8) as u8)?;
153 }
154 Ok(())
155 }
156
157 fn is_set(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
158 let out = self.get_out()?;
159 Ok(((out as u32) & mask_high) | (!(out as u32) & mask_low))
160 }
161
162 fn get(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
163 let io0 = if (mask_high | mask_low) & 0x00FF != 0 {
164 self.i2c.read_reg(self.addr, Regs::InputPort0)?
165 } else {
166 0
167 };
168 let io1 = if (mask_high | mask_low) & 0xFF00 != 0 {
169 self.i2c.read_reg(self.addr, Regs::InputPort1)?
170 } else {
171 0
172 };
173 let in_ = ((io1 as u32) << 8) | io0 as u32;
174 Ok((in_ & mask_high) | (!in_ & mask_low))
175 }
176}
177
178impl<I2C: crate::I2cBus> crate::PortDriverTotemPole for Driver<I2C> {
179 fn set_direction(
180 &mut self,
181 mask: u32,
182 dir: crate::Direction,
183 state: bool,
184 ) -> Result<(), Self::Error> {
185 if dir == crate::Direction::Output {
187 use crate::PortDriver;
188 if state {
189 self.set(mask, 0)?;
190 } else {
191 self.set(0, mask)?;
192 }
193 }
194
195 let (mask_set, mask_clear) = match dir {
196 crate::Direction::Input => (mask as u16, 0),
197 crate::Direction::Output => (0, mask as u16),
198 };
199 if mask & 0x00FF != 0 {
200 self.i2c.update_reg(
201 self.addr,
202 Regs::Configuration0,
203 (mask_set & 0xFF) as u8,
204 (mask_clear & 0xFF) as u8,
205 )?;
206 }
207 if mask & 0xFF00 != 0 {
208 self.i2c.update_reg(
209 self.addr,
210 Regs::Configuration1,
211 (mask_set >> 8) as u8,
212 (mask_clear >> 8) as u8,
213 )?;
214 }
215 Ok(())
216 }
217}
218
219impl<I2C: crate::I2cBus> crate::PortDriverPolarity for Driver<I2C> {
220 fn set_polarity(&mut self, mask: u32, inverted: bool) -> Result<(), Self::Error> {
221 let (mask_set, mask_clear) = match inverted {
222 false => (0, mask as u16),
223 true => (mask as u16, 0),
224 };
225
226 if mask & 0x00FF != 0 {
227 self.i2c.update_reg(
228 self.addr,
229 Regs::PolarityInversion0,
230 (mask_set & 0xFF) as u8,
231 (mask_clear & 0xFF) as u8,
232 )?;
233 }
234 if mask & 0xFF00 != 0 {
235 self.i2c.update_reg(
236 self.addr,
237 Regs::PolarityInversion1,
238 (mask_set >> 8) as u8,
239 (mask_clear >> 8) as u8,
240 )?;
241 }
242 Ok(())
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use embedded_hal_mock::eh1::i2c as mock_i2c;
249
250 #[test]
251 fn pca6416a() {
252 let expectations = [
253 mock_i2c::Transaction::write_read(0x21, vec![0x02], vec![0xff]),
255 mock_i2c::Transaction::write_read(0x21, vec![0x03], vec![0xff]),
256 mock_i2c::Transaction::write(0x21, vec![0x02, 0xfe]),
257 mock_i2c::Transaction::write_read(0x21, vec![0x06], vec![0xff]),
258 mock_i2c::Transaction::write(0x21, vec![0x06, 0xfe]),
259 mock_i2c::Transaction::write(0x21, vec![0x02, 0x7e]),
261 mock_i2c::Transaction::write_read(0x21, vec![0x06], vec![0xfe]),
262 mock_i2c::Transaction::write(0x21, vec![0x06, 0x7e]),
263 mock_i2c::Transaction::write_read(0x21, vec![0x06], vec![0x7e]),
264 mock_i2c::Transaction::write(0x21, vec![0x06, 0xfe]),
265 mock_i2c::Transaction::write(0x21, vec![0x03, 0xfe]),
267 mock_i2c::Transaction::write_read(0x21, vec![0x07], vec![0xff]),
268 mock_i2c::Transaction::write(0x21, vec![0x07, 0xfe]),
269 mock_i2c::Transaction::write(0x21, vec![0x03, 0x7e]),
271 mock_i2c::Transaction::write_read(0x21, vec![0x07], vec![0xfe]),
272 mock_i2c::Transaction::write(0x21, vec![0x07, 0x7e]),
273 mock_i2c::Transaction::write_read(0x21, vec![0x07], vec![0x7e]),
274 mock_i2c::Transaction::write(0x21, vec![0x07, 0xfe]),
275 mock_i2c::Transaction::write(0x21, vec![0x02, 0x7f]),
277 mock_i2c::Transaction::write(0x21, vec![0x02, 0x7e]),
278 mock_i2c::Transaction::write(0x21, vec![0x03, 0x7f]),
279 mock_i2c::Transaction::write(0x21, vec![0x03, 0x7e]),
280 mock_i2c::Transaction::write_read(0x21, vec![0x00], vec![0x80]),
282 mock_i2c::Transaction::write_read(0x21, vec![0x00], vec![0x7f]),
283 mock_i2c::Transaction::write_read(0x21, vec![0x01], vec![0x80]),
284 mock_i2c::Transaction::write_read(0x21, vec![0x01], vec![0x7f]),
285 mock_i2c::Transaction::write_read(0x21, vec![0x04], vec![0x00]),
287 mock_i2c::Transaction::write(0x21, vec![0x04, 0x80]),
288 mock_i2c::Transaction::write_read(0x21, vec![0x04], vec![0xff]),
289 mock_i2c::Transaction::write(0x21, vec![0x04, 0x7f]),
290 mock_i2c::Transaction::write_read(0x21, vec![0x05], vec![0x00]),
291 mock_i2c::Transaction::write(0x21, vec![0x05, 0x80]),
292 mock_i2c::Transaction::write_read(0x21, vec![0x05], vec![0xff]),
293 mock_i2c::Transaction::write(0x21, vec![0x05, 0x7f]),
294 ];
295 let mut bus = mock_i2c::Mock::new(&expectations);
296
297 let mut pcal = super::Pcal6416a::new(bus.clone(), true);
298 let pcal_pins = pcal.split();
299
300 let mut io0_0 = pcal_pins.io0_0.into_output().unwrap();
301 let io0_7 = pcal_pins.io0_7.into_output().unwrap();
302 let io0_7 = io0_7.into_input().unwrap();
303
304 let mut io1_0 = pcal_pins.io1_0.into_output().unwrap();
305 let io1_7 = pcal_pins.io1_7.into_output().unwrap();
306 let io1_7 = io1_7.into_input().unwrap();
307
308 io0_0.set_high().unwrap();
310 io0_0.set_low().unwrap();
311 io1_0.set_high().unwrap();
312 io1_0.set_low().unwrap();
313
314 assert!(io0_7.is_high().unwrap());
316 assert!(io0_7.is_low().unwrap());
317 assert!(io1_7.is_high().unwrap());
318 assert!(io1_7.is_low().unwrap());
319
320 let mut io0_7 = io0_7.into_inverted().unwrap();
321 io0_7.set_inverted(false).unwrap();
322 let mut io1_7 = io1_7.into_inverted().unwrap();
323 io1_7.set_inverted(false).unwrap();
324
325 bus.done();
326 }
327}