zynq7000_hal/uart/
rx.rs

1use core::convert::Infallible;
2
3use arbitrary_int::prelude::*;
4use zynq7000::uart::{InterruptControl, InterruptStatus, MmioUart};
5
6use super::FIFO_DEPTH;
7
8pub struct Rx {
9    pub(crate) regs: MmioUart<'static>,
10}
11// TODO: Remove once this is impelemnted for MmioUart
12unsafe impl Send for Rx {}
13
14#[derive(Debug, Default, Clone, Copy)]
15pub struct RxErrors {
16    framing: bool,
17    overrun: bool,
18    parity: bool,
19}
20
21impl RxErrors {
22    #[inline]
23    pub const fn framing(&self) -> bool {
24        self.framing
25    }
26    #[inline]
27    pub const fn overrun(&self) -> bool {
28        self.overrun
29    }
30    #[inline]
31    pub const fn parity(&self) -> bool {
32        self.parity
33    }
34}
35
36#[derive(Debug, Default)]
37pub struct RxInterruptResult {
38    read_bytes: usize,
39    errors: Option<RxErrors>,
40}
41
42impl RxInterruptResult {
43    pub fn read_bytes(&self) -> usize {
44        self.read_bytes
45    }
46
47    pub fn errors(&self) -> Option<RxErrors> {
48        self.errors
49    }
50}
51
52impl Rx {
53    #[inline]
54    pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
55        if self.regs.read_sr().rx_empty() {
56            return Err(nb::Error::WouldBlock);
57        }
58        Ok(self.regs.read_fifo().fifo())
59    }
60
61    #[inline(always)]
62    pub fn read_fifo_unchecked(&mut self) -> u8 {
63        self.regs.read_fifo().fifo()
64    }
65
66    /// Write the receiver timeout value.
67    ///
68    /// A value of 0 will disable the receiver timeout.
69    /// Otherwise, the 10-bit counter used by the receiver timeout mechanism of the UART will
70    /// load this value for the upper 8 bits on a reload. The counter is clocked by the UART
71    /// bit clock, so this value times 4 is the number of UART clock ticks until a timeout occurs.
72    #[inline]
73    pub fn set_rx_timeout_value(&mut self, rto: u8) {
74        self.regs.write_rx_tout(rto as u32);
75    }
76
77    #[inline]
78    pub fn soft_reset(&mut self) {
79        self.regs.modify_cr(|mut cr| {
80            cr.set_rx_rst(true);
81            cr
82        });
83        while self.regs.read_cr().rx_rst() {}
84    }
85
86    /// Helper function to start the interrupt driven reception of data.
87    ///
88    /// This function will perform a soft-reset, clear RX related interrupts and then enable
89    /// all relevant interrupts for the RX side of the UART. These steps are recommended to have
90    /// a glitch-free start of the interrupt driven reception.
91    ///
92    /// This should be called once at system start-up. After that, you only need to call
93    /// [Self::on_interrupt] in the interrupt handler for the UART peripheral.
94    pub fn start_interrupt_driven_reception(&mut self) {
95        self.soft_reset();
96        self.clear_interrupts();
97        self.enable_interrupts();
98    }
99
100    /// Enables all interrupts relevant for the RX side of the UART.
101    ///
102    /// It is recommended to also clear all interrupts immediately after enabling them.
103    #[inline]
104    pub fn enable_interrupts(&mut self) {
105        self.regs.write_ier(
106            InterruptControl::builder()
107                .with_tx_over(false)
108                .with_tx_near_full(false)
109                .with_tx_trig(false)
110                .with_rx_dms(false)
111                .with_rx_timeout(true)
112                .with_rx_parity(true)
113                .with_rx_framing(true)
114                .with_rx_over(true)
115                .with_tx_full(false)
116                .with_tx_empty(false)
117                .with_rx_full(true)
118                .with_rx_empty(false)
119                .with_rx_trg(true)
120                .build(),
121        );
122    }
123
124    pub fn on_interrupt(
125        &mut self,
126        buf: &mut [u8; FIFO_DEPTH],
127        reset_rx_timeout: bool,
128    ) -> RxInterruptResult {
129        let mut result = RxInterruptResult::default();
130        let imr = self.regs.read_imr();
131        if !imr.rx_full()
132            && !imr.rx_trg()
133            && !imr.rx_parity()
134            && !imr.rx_framing()
135            && !imr.rx_over()
136            && !imr.rx_timeout()
137        {
138            return result;
139        }
140        let isr = self.regs.read_isr();
141        if isr.rx_full() {
142            // Read all bytes in the full RX fifo.
143            for byte in buf.iter_mut() {
144                *byte = self.read_fifo_unchecked();
145            }
146            result.read_bytes = FIFO_DEPTH;
147        } else if isr.rx_trg() {
148            // It is guaranteed that we can read the FIFO level amount of data
149            let fifo_trigger = self.regs.read_rx_fifo_trigger().trig().as_usize();
150            (0..fifo_trigger).for_each(|i| {
151                buf[i] = self.read_fifo_unchecked();
152            });
153            result.read_bytes = fifo_trigger;
154        }
155        // Read everything else that is available, as long as there is space left.
156        while result.read_bytes < buf.len() {
157            if let Ok(byte) = self.read_fifo() {
158                buf[result.read_bytes] = byte;
159                result.read_bytes += 1;
160            } else {
161                break;
162            }
163        }
164        // Handle error events.
165        if isr.rx_parity() || isr.rx_framing() || isr.rx_over() {
166            result.errors = Some(RxErrors {
167                framing: isr.rx_framing(),
168                overrun: isr.rx_over(),
169                parity: isr.rx_parity(),
170            });
171        }
172        // Handle timeout event.
173        if isr.rx_timeout() && reset_rx_timeout {
174            self.regs.modify_cr(|mut cr| {
175                cr.set_rstto(true);
176                cr
177            });
178        }
179        self.clear_interrupts();
180        result
181    }
182
183    // This clears all RX related interrupts.
184    #[inline]
185    pub fn clear_interrupts(&mut self) {
186        self.regs.write_isr(
187            InterruptStatus::builder()
188                .with_tx_over(false)
189                .with_tx_near_full(false)
190                .with_tx_trig(false)
191                .with_rx_dms(true)
192                .with_rx_timeout(true)
193                .with_rx_parity(true)
194                .with_rx_framing(true)
195                .with_rx_over(true)
196                .with_tx_full(false)
197                .with_tx_empty(false)
198                .with_rx_full(true)
199                .with_rx_empty(true)
200                .with_rx_trg(true)
201                .build(),
202        );
203    }
204}
205
206impl embedded_hal_nb::serial::ErrorType for Rx {
207    type Error = Infallible;
208}
209
210impl embedded_hal_nb::serial::Read for Rx {
211    /// Read one byte from the FIFO.
212    ///
213    /// This operation is infallible because pulling an available byte from the FIFO
214    /// always succeeds. If you want to be informed about RX errors, you should look at the
215    /// non-blocking API using interrupts, which also tracks the RX error bits.
216    #[inline]
217    fn read(&mut self) -> nb::Result<u8, Self::Error> {
218        self.read_fifo()
219    }
220}
221
222impl embedded_io::ErrorType for Rx {
223    type Error = Infallible;
224}
225
226impl embedded_io::Read for Rx {
227    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
228        if buf.is_empty() {
229            return Ok(0);
230        }
231        let mut read = 0;
232        loop {
233            if !self.regs.read_sr().rx_empty() {
234                break;
235            }
236        }
237        for byte in buf.iter_mut() {
238            match <Self as embedded_hal_nb::serial::Read<u8>>::read(self) {
239                Ok(w) => {
240                    *byte = w;
241                    read += 1;
242                }
243                Err(nb::Error::WouldBlock) => break,
244            }
245        }
246
247        Ok(read)
248    }
249}