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);