avr_tester/
twi.rs

1use crate::*;
2
3/// Provides access to the TWI (aka I2C).
4///
5/// See: [`Twi::attach_slave()`] and [`Twi::detach_slave()`].
6#[doc(alias = "i2c")]
7pub struct Twi<'a> {
8    mgr: &'a RefCell<TwiManager>,
9}
10
11impl<'a> Twi<'a> {
12    pub(crate) fn new(tester: &'a mut AvrTester, id: u8) -> Self {
13        let mgr = tester.twis.entry(id).or_insert_with(|| {
14            let mgr = Rc::new(RefCell::new(TwiManager::default()));
15
16            tester.sim.as_mut().unwrap().set_twi_slave(id, {
17                let mgr = mgr.clone();
18
19                move |packet: TwiPacket| -> Option<TwiPacket> {
20                    for slave in mgr.borrow_mut().slaves.values_mut() {
21                        if let Some(packet) = slave.recv(packet) {
22                            return Some(packet);
23                        }
24                    }
25
26                    None
27                }
28            });
29
30            mgr
31        });
32
33        Self { mgr }
34    }
35
36    /// Attaches given slave into this TWI, executing it for each packet
37    /// received on this interface - slave can then decide whether to respond or
38    /// ignore the packet.
39    ///
40    /// When multiple slaves are attached, they all get executed in the order of
41    /// the attachment until any slave responds (if any).
42    ///
43    /// See the `twi.rs` example for usage.
44    ///
45    /// See also: [`Self::attach_slave_fn()`].
46    pub fn attach_slave(
47        &mut self,
48        slave: impl TwiSlave + 'static,
49    ) -> TwiSlaveId {
50        let mut mgr = self.mgr.borrow_mut();
51        let id = TwiSlaveId(mgr.next_slave_id);
52
53        mgr.slaves.insert(id, Box::new(slave));
54
55        mgr.next_slave_id = mgr
56            .next_slave_id
57            .checked_add(1)
58            .expect("Too many TWI slaves got attached, ran out of indices");
59
60        id
61    }
62
63    /// Shortcut for [`Self::attach_slave()`] that allows to create a device
64    /// with just a function:
65    ///
66    /// ```no_run
67    /// # use avr_tester::*;
68    /// #
69    /// let mut avr = AvrTester::test();
70    ///
71    /// avr.twi0().attach_slave_fn(|packet| {
72    ///     if packet.addr != 0x33 {
73    ///         return None;
74    ///     }
75    ///
76    ///     if packet.is_start() || packet.is_stop() {
77    ///         return Some(packet.respond_ack());
78    ///     }
79    ///
80    ///     if packet.is_write() {
81    ///         todo!();
82    ///     }
83    ///
84    ///     if packet.is_read() {
85    ///         todo!();
86    ///     }
87    ///
88    ///     None
89    /// });
90    /// ```
91    ///
92    /// See [`Self::attach_slave()`] for details.
93    pub fn attach_slave_fn(
94        &mut self,
95        slave: impl FnMut(TwiPacket) -> Option<TwiPacket> + 'static,
96    ) -> TwiSlaveId {
97        self.attach_slave(slave)
98    }
99
100    /// Detaches given slave from this TWI, preventing it from being executed
101    /// again.
102    ///
103    /// See: [`Self::attach_slave()`].
104    pub fn detach_slave(&mut self, id: TwiSlaveId) {
105        self.mgr.borrow_mut().slaves.remove(&id);
106    }
107}
108
109#[derive(Default)]
110pub(crate) struct TwiManager {
111    slaves: BTreeMap<TwiSlaveId, Box<dyn TwiSlave>>,
112    next_slave_id: u32,
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct TwiSlaveId(u32);