lpc8xx_hal/i2c/
slave.rs

1//! API for the I2C slave mode
2
3use core::{fmt, marker::PhantomData};
4
5use crate::{
6    init_state,
7    pac::i2c0::{SLVCTL, SLVDAT},
8    reg_proxy::{Reg, RegProxy},
9};
10
11use super::{Error, Instance};
12
13/// API for I2C slave mode
14///
15/// You can get access to this struct through the [`I2C`] struct.
16///
17/// This struct has two type parameters that track its state:
18/// - `State` tracks whether the I2C instance is enabled.
19/// - `ModeState` tracks whether the master mode is enabled.
20///
21/// [`I2C`]: ../struct.I2C.html
22pub struct Slave<I: Instance, State, ModeState> {
23    _state: PhantomData<State>,
24    _mode_state: PhantomData<ModeState>,
25
26    slvctl: RegProxy<SlvCtl<I>>,
27    slvdat: RegProxy<SlvDat<I>>,
28}
29
30impl<I, State, ModeState> Slave<I, State, ModeState>
31where
32    I: Instance,
33{
34    pub(super) fn new() -> Self {
35        Self {
36            _state: PhantomData,
37            _mode_state: PhantomData,
38
39            slvctl: RegProxy::new(),
40            slvdat: RegProxy::new(),
41        }
42    }
43}
44
45impl<I, C> Slave<I, init_state::Enabled<PhantomData<C>>, init_state::Enabled>
46where
47    I: Instance,
48{
49    /// Wait until software intervention is required
50    ///
51    /// The returned enum indicates the current state. Each variant provides an
52    /// API to react to that state.
53    pub fn wait(&mut self) -> nb::Result<State<I>, Error> {
54        // Sound, as we're only reading from the STAT register.
55        let i2c = unsafe { &*I::REGISTERS };
56
57        Error::read::<I>()?;
58
59        if i2c.stat.read().slvpending().is_in_progress() {
60            return Err(nb::Error::WouldBlock);
61        }
62
63        let slave_state = i2c.stat.read().slvstate();
64
65        if slave_state.is_slave_address() {
66            return Ok(State::AddressMatched(AddressMatched {
67                slvctl: &self.slvctl,
68                slvdat: &self.slvdat,
69            }));
70        }
71        if slave_state.is_slave_receive() {
72            return Ok(State::RxReady(RxReady {
73                slvctl: &self.slvctl,
74                slvdat: &self.slvdat,
75            }));
76        }
77        if slave_state.is_slave_transmit() {
78            return Ok(State::TxReady(TxReady {
79                slvctl: &self.slvctl,
80                slvdat: &self.slvdat,
81            }));
82        }
83
84        Err(nb::Error::Other(Error::UnknownSlaveState(
85            slave_state.bits(),
86        )))
87    }
88}
89
90// Can't derive, because peripheral structs from the PAC don't implement
91// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
92impl<I, State, ModeState> fmt::Debug for Slave<I, State, ModeState>
93where
94    I: Instance,
95{
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        f.debug_struct("Slave")
98            .field("_state", &self._state)
99            .field("_mode_state", &self._mode_state)
100            .field("slvctl", &self.slvctl)
101            .field("slvdat", &self.slvdat)
102            .finish()
103    }
104}
105
106/// The current state of the slave
107///
108/// Each variant provides an API to react to that state. Call [`I2C::wait`] to
109/// get an instance of this struct.
110///
111/// [`I2c::wait`]: ../struct.I2C.html#method.wait
112pub enum State<'r, I: Instance> {
113    /// Address sent by master has been matched
114    AddressMatched(AddressMatched<'r, I>),
115
116    /// Data has been received from master
117    RxReady(RxReady<'r, I>),
118
119    /// Ready to transmit data to master
120    TxReady(TxReady<'r, I>),
121}
122
123/// API for handling the "address matched" state
124///
125/// You can gain access to this API through [`State`].
126///
127/// [`State`]: enum.State.html
128pub struct AddressMatched<'r, I: Instance> {
129    slvctl: &'r RegProxy<SlvCtl<I>>,
130    slvdat: &'r RegProxy<SlvDat<I>>,
131}
132
133impl<'r, I> AddressMatched<'r, I>
134where
135    I: Instance,
136{
137    /// Return the received address
138    pub fn address(&self) -> Result<u8, Error> {
139        Error::read::<I>()?;
140
141        let address = self.slvdat.read().data().bits() >> 1;
142        Ok(address)
143    }
144
145    /// Acknowledge the matched address
146    pub fn ack(self) -> Result<(), Error> {
147        Error::read::<I>()?;
148
149        self.slvctl.write(|w| w.slvcontinue().continue_());
150
151        Ok(())
152    }
153
154    /// Reject the matched address
155    pub fn nack(self) -> Result<(), Error> {
156        Error::read::<I>()?;
157
158        self.slvctl.write(|w| w.slvnack().nack());
159
160        Ok(())
161    }
162}
163
164/// API for handling the "data received" state
165///
166/// You can gain access to this API through [`State`].
167///
168/// [`State`]: enum.State.html
169pub struct RxReady<'r, I: Instance> {
170    slvctl: &'r RegProxy<SlvCtl<I>>,
171    slvdat: &'r RegProxy<SlvDat<I>>,
172}
173
174impl<'r, I> RxReady<'r, I>
175where
176    I: Instance,
177{
178    /// Read the available data
179    ///
180    /// If you call this method multiple times, the same data will be returned
181    /// each time. To receive the next byte, acknowledge the current one using
182    /// [`ack`], then call [`I2C::wait`] again.
183    ///
184    /// [`ack`]: #method.ack
185    /// [`I2C::wait`]: ../struct.I2C.html#method.wait
186    pub fn read(&self) -> Result<u8, Error> {
187        Error::read::<I>()?;
188
189        let data = self.slvdat.read().data().bits();
190        Ok(data)
191    }
192
193    /// Acknowledge the received data
194    pub fn ack(self) -> Result<(), Error> {
195        Error::read::<I>()?;
196
197        self.slvctl.write(|w| w.slvcontinue().continue_());
198
199        Ok(())
200    }
201
202    /// Reject the received data
203    pub fn nack(self) -> Result<(), Error> {
204        Error::read::<I>()?;
205
206        self.slvctl.write(|w| w.slvnack().nack());
207
208        Ok(())
209    }
210}
211
212/// API for handling the "ready to transmit" state
213///
214/// You can gain access to this API through [`State`].
215///
216/// [`State`]: enum.State.html
217pub struct TxReady<'r, I: Instance> {
218    slvctl: &'r RegProxy<SlvCtl<I>>,
219    slvdat: &'r RegProxy<SlvDat<I>>,
220}
221
222impl<'r, I> TxReady<'r, I>
223where
224    I: Instance,
225{
226    /// Transmit data
227    pub fn transmit(self, data: u8) -> Result<(), Error> {
228        Error::read::<I>()?;
229
230        // Sound, as all possible values of `u8` are accepted by the DATA field.
231        unsafe {
232            self.slvdat.write(|w| w.data().bits(data));
233        }
234
235        self.slvctl.write(|w| w.slvcontinue().continue_());
236
237        Ok(())
238    }
239}
240
241struct SlvCtl<I>(PhantomData<I>);
242
243// Sound, as the pointer returned is valid for the duration of the program.
244unsafe impl<I> Reg for SlvCtl<I>
245where
246    I: Instance,
247{
248    type Target = SLVCTL;
249
250    fn get() -> *const Self::Target {
251        // Sound, as SLVCTL is exclusively used by `Slave`, and only one
252        // `RegProxy` instance for it exists.
253        unsafe { &(*I::REGISTERS).slvctl as *const _ }
254    }
255}
256
257// Can't derive, because peripheral structs from the PAC don't implement
258// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
259impl<I> fmt::Debug for SlvCtl<I> {
260    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
261        write!(f, "SlvCtl(...)")
262    }
263}
264
265struct SlvDat<I>(PhantomData<I>);
266
267// Sound, as the pointer returned is valid for the duration of the program.
268unsafe impl<I> Reg for SlvDat<I>
269where
270    I: Instance,
271{
272    type Target = SLVDAT;
273
274    fn get() -> *const Self::Target {
275        // Sound, as SLVDAT is exclusively used by `Slave`, and only one
276        // `RegProxy` instance for it exists.
277        unsafe { &(*I::REGISTERS).slvdat as *const _ }
278    }
279}
280
281// Can't derive, because peripheral structs from the PAC don't implement
282// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
283impl<I> fmt::Debug for SlvDat<I> {
284    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285        write!(f, "SlvDat(...)")
286    }
287}