avr_simulator/
twi.rs

1use super::*;
2use std::ptr::NonNull;
3
4#[derive(Debug)]
5pub struct Twi {
6    state: NonNull<TwiState>,
7}
8
9impl Twi {
10    /// Initializes the subsystem; returns `None` if current AVR doesn't have
11    /// this TWI.
12    ///
13    /// # Safety
14    ///
15    /// - Because this function registers an IRQ notification, the object
16    ///   returned from here must be kept alive for at least as long as `avr`.
17    pub unsafe fn new(id: u8, avr: &Avr) -> Option<Self> {
18        let ioctl = IoCtl::TwiGetIrq { id };
19        let irq_input = avr.try_io_getirq(ioctl, ffi::TWI_IRQ_INPUT)?;
20        let irq_output = avr.try_io_getirq(ioctl, ffi::TWI_IRQ_OUTPUT)?;
21
22        let this = Self {
23            state: NonNull::from(Box::leak(Box::new(TwiState {
24                slave: None,
25                irq_input,
26            }))),
27        };
28
29        unsafe {
30            Avr::irq_register_notify(
31                irq_output,
32                Some(Self::on_output),
33                this.state.as_ptr(),
34            );
35        }
36
37        Some(this)
38    }
39
40    pub fn set_slave(&mut self, slave: impl TwiSlave + 'static) {
41        self.state_mut().slave = Some(Box::new(slave));
42    }
43
44    fn state_mut(&mut self) -> &mut TwiState {
45        // Safety: `state` points to a valid object; nothing else is writing
46        // there at the moment, as guarded by `&mut self` here and on
47        // `Avr::run()`
48        unsafe { self.state.as_mut() }
49    }
50
51    unsafe extern "C" fn on_output(
52        _: NonNull<ffi::avr_irq_t>,
53        value: u32,
54        mut state: NonNull<TwiState>,
55    ) {
56        unsafe {
57            let state = state.as_mut();
58
59            if let Some(slave) = &mut state.slave {
60                if let Some(packet) = slave.recv(TwiPacket::decode(value)) {
61                    ffi::avr_raise_irq(
62                        state.irq_input.as_ptr(),
63                        packet.encode(),
64                    );
65                }
66            }
67        }
68    }
69}
70
71impl Drop for Twi {
72    fn drop(&mut self) {
73        unsafe {
74            drop(Box::from_raw(self.state.as_ptr()));
75        }
76    }
77}
78
79struct TwiState {
80    slave: Option<Box<dyn TwiSlave>>,
81    irq_input: NonNull<ffi::avr_irq_t>,
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
85pub struct TwiPacket {
86    pub msg: u8,
87    pub addr: u8,
88    pub data: u8,
89}
90
91impl TwiPacket {
92    fn decode(packet: u32) -> Self {
93        let [_, msg, addr, data] = packet.to_le_bytes();
94
95        Self { msg, addr, data }
96    }
97
98    fn encode(self) -> u32 {
99        u32::from_le_bytes([0, self.msg, self.addr, self.data])
100    }
101
102    pub const MSG_START: u8 = ffi::TWI_COND_START as u8;
103    pub const MSG_STOP: u8 = ffi::TWI_COND_STOP as u8;
104    pub const MSG_ADDR: u8 = ffi::TWI_COND_ADDR as u8;
105    pub const MSG_ACK: u8 = ffi::TWI_COND_ACK as u8;
106    pub const MSG_WRITE: u8 = ffi::TWI_COND_WRITE as u8;
107    pub const MSG_READ: u8 = ffi::TWI_COND_READ as u8;
108
109    pub fn is_start(&self) -> bool {
110        self.msg & Self::MSG_START > 0
111    }
112
113    pub fn is_stop(&self) -> bool {
114        self.msg & Self::MSG_STOP > 0
115    }
116
117    pub fn is_addr(&self) -> bool {
118        self.msg & Self::MSG_ADDR > 0
119    }
120
121    pub fn is_ack(&self) -> bool {
122        self.msg & Self::MSG_ACK > 0
123    }
124
125    pub fn is_write(&self) -> bool {
126        self.msg & Self::MSG_WRITE > 0
127    }
128
129    pub fn is_read(&self) -> bool {
130        self.msg & Self::MSG_READ > 0
131    }
132
133    pub fn respond_ack(&self) -> Self {
134        Self {
135            msg: Self::MSG_ACK,
136            addr: self.addr,
137            data: 1,
138        }
139    }
140
141    pub fn respond_data(&self, data: u8) -> Self {
142        Self {
143            msg: Self::MSG_READ,
144            addr: self.addr,
145            data,
146        }
147    }
148}
149
150pub trait TwiSlave {
151    fn recv(&mut self, packet: TwiPacket) -> Option<TwiPacket>;
152}
153
154impl<T> TwiSlave for T
155where
156    T: FnMut(TwiPacket) -> Option<TwiPacket>,
157{
158    fn recv(&mut self, packet: TwiPacket) -> Option<TwiPacket> {
159        (self)(packet)
160    }
161}