port_expander/dev/
max7321.rs

1//! Support for the Maxim 7321 I2C 8-Port Open Drain port expander
2pub struct Max7321<M>(M);
3
4/// MAX7321 "I2C Port Expander with 8 Open-Drain I/Os"
5impl<I2C> Max7321<core::cell::RefCell<Driver<I2C>>>
6where
7    I2C: crate::I2cBus,
8{
9    pub fn new(i2c: I2C, a3: bool, a2: bool, a1: bool, a0: bool) -> Self {
10        Self::with_mutex(i2c, a3, a2, a1, a0)
11    }
12}
13
14impl<I2C, M> Max7321<M>
15where
16    I2C: crate::I2cBus,
17    M: crate::PortMutex<Port = Driver<I2C>>,
18{
19    pub fn with_mutex(i2c: I2C, a3: bool, a2: bool, a1: bool, a0: bool) -> Self {
20        Self(crate::PortMutex::create(Driver::new(i2c, a3, a2, a1, a0)))
21    }
22
23    pub fn split(&mut self) -> Parts<'_, I2C, M> {
24        Parts {
25            p0: crate::Pin::new(0, &self.0),
26            p1: crate::Pin::new(1, &self.0),
27            p2: crate::Pin::new(2, &self.0),
28            p3: crate::Pin::new(3, &self.0),
29            p4: crate::Pin::new(4, &self.0),
30            p5: crate::Pin::new(5, &self.0),
31            p6: crate::Pin::new(6, &self.0),
32            p7: crate::Pin::new(7, &self.0),
33        }
34    }
35}
36
37pub struct Parts<'a, I2C, M = core::cell::RefCell<Driver<I2C>>>
38where
39    I2C: crate::I2cBus,
40    M: crate::PortMutex<Port = Driver<I2C>>,
41{
42    pub p0: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
43    pub p1: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
44    pub p2: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
45    pub p3: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
46    pub p4: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
47    pub p5: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
48    pub p6: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
49    pub p7: crate::Pin<'a, crate::mode::QuasiBidirectional, M>,
50}
51
52pub struct Driver<I2C> {
53    i2c: I2C,
54    out: u8,
55    addr: u8,
56}
57
58impl<I2C> Driver<I2C> {
59    pub fn new(i2c: I2C, a3: bool, a2: bool, a1: bool, a0: bool) -> Self {
60        let addr = 0x60 | ((a3 as u8) << 3) | ((a2 as u8) << 2) | ((a1 as u8) << 1) | (a0 as u8);
61        Self {
62            i2c,
63            out: 0xff,
64            addr,
65        }
66    }
67}
68
69impl<I2C: crate::I2cBus> crate::PortDriver for Driver<I2C> {
70    type Error = I2C::BusError;
71
72    fn set(&mut self, mask_high: u32, mask_low: u32) -> Result<(), Self::Error> {
73        self.out |= mask_high as u8;
74        self.out &= !mask_low as u8;
75        self.i2c.write(self.addr, &[self.out])?;
76        Ok(())
77    }
78
79    fn is_set(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
80        Ok(((self.out as u32) & mask_high) | (!(self.out as u32) & mask_low))
81    }
82
83    fn get(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
84        let mut buf = [0x00];
85        self.i2c.read(self.addr, &mut buf)?;
86        let in_ = buf[0] as u32;
87        Ok((in_ & mask_high) | (!in_ & mask_low))
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use embedded_hal_mock::eh1::i2c as mock_i2c;
94
95    #[test]
96    fn max7321() {
97        let expectations = [
98            mock_i2c::Transaction::write(0b01101101, vec![0b11111111]),
99            mock_i2c::Transaction::write(0b01101101, vec![0b11111011]),
100            mock_i2c::Transaction::read(0b01101101, vec![0b01000000]),
101            mock_i2c::Transaction::read(0b01101101, vec![0b10111111]),
102        ];
103        let mut bus = mock_i2c::Mock::new(&expectations);
104
105        let mut max = super::Max7321::new(bus.clone(), true, true, false, true);
106        let mut max_pins = max.split();
107
108        max_pins.p2.set_high().unwrap();
109        max_pins.p2.set_low().unwrap();
110
111        assert!(max_pins.p6.is_high().unwrap());
112        assert!(max_pins.p6.is_low().unwrap());
113
114        bus.done();
115    }
116}