axi_uartlite/
rx.rs

1//! # Receiver (RX) support module
2use core::convert::Infallible;
3
4use crate::registers::{self, Registers, Status};
5
6/// RX error structure which tracks if an error has occurred.
7#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
8pub struct RxErrors {
9    parity: bool,
10    frame: bool,
11    overrun: bool,
12}
13
14impl RxErrors {
15    /// Create a new empty RX error structure.
16    pub const fn new() -> Self {
17        Self {
18            parity: false,
19            frame: false,
20            overrun: false,
21        }
22    }
23
24    /// Parity error occurred.
25    pub const fn parity(&self) -> bool {
26        self.parity
27    }
28
29    /// Frame error occurred.
30    pub const fn frame(&self) -> bool {
31        self.frame
32    }
33
34    /// Overrun error occurred.
35    pub const fn overrun(&self) -> bool {
36        self.overrun
37    }
38
39    /// Any error has occurred.
40    pub const fn has_errors(&self) -> bool {
41        self.parity || self.frame || self.overrun
42    }
43}
44
45/// AXI UARTLITE TX driver.
46///
47/// Can be created by [super::AxiUartlite::split]ting a regular AXI UARTLITE structure or
48/// by [Self::steal]ing it unsafely.
49pub struct Rx {
50    pub(crate) regs: registers::MmioRegisters<'static>,
51    pub(crate) errors: Option<RxErrors>,
52}
53
54impl Rx {
55    /// Steal the RX part of the UART Lite.
56    ///
57    /// You should only use this if you can not use the regular [super::AxiUartlite] constructor
58    /// and the [super::AxiUartlite::split] method.
59    ///
60    /// This function assumes that the setup of the UART was already done.
61    /// It can be used to create an RX handle inside an interrupt handler without having to use
62    /// a [critical_section::Mutex] if the user can guarantee that the RX handle will only be
63    /// used by the interrupt handler or only interrupt specific API will be used.
64    ///
65    /// # Safety
66    ///
67    /// The same safey rules specified in [super::AxiUartlite] apply.
68    #[inline]
69    pub const unsafe fn steal(base_addr: usize) -> Self {
70        Self {
71            regs: unsafe { Registers::new_mmio_at(base_addr) },
72            errors: None,
73        }
74    }
75
76    /// Read the RX FIFO.
77    ///
78    /// This functions offers a [nb::Result] based API and returns [nb::Error::WouldBlock] if there
79    /// is nothing to read.
80    #[inline]
81    pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
82        let status_reg = self.regs.read_stat_reg();
83        if !status_reg.rx_fifo_valid_data() {
84            return Err(nb::Error::WouldBlock);
85        }
86        let val = self.read_fifo_unchecked();
87        if let Some(errors) = handle_status_reg_errors(&status_reg) {
88            self.errors = Some(errors);
89        }
90        Ok(val)
91    }
92
93    /// Read from the FIFO without checking the FIFO fill status.
94    #[inline(always)]
95    pub fn read_fifo_unchecked(&mut self) -> u8 {
96        self.regs.read_rx_fifo().data()
97    }
98
99    /// Does the RX FIFO have valid data?
100    #[inline(always)]
101    pub fn has_data(&self) -> bool {
102        self.regs.read_stat_reg().rx_fifo_valid_data()
103    }
104
105    /// This simply reads all available bytes in the RX FIFO.
106    ///
107    /// It returns the number of read bytes.
108    #[inline]
109    pub fn read_whole_fifo(&mut self, buf: &mut [u8; 16]) -> usize {
110        let mut read = 0;
111        while read < buf.len() {
112            match self.read_fifo() {
113                Ok(byte) => {
114                    buf[read] = byte;
115                    read += 1;
116                }
117                Err(nb::Error::WouldBlock) => break,
118            }
119        }
120        read
121    }
122
123    /// Can be called in the interrupt handler for the UART Lite to handle RX reception.
124    ///
125    /// Simply calls [Rx::read_whole_fifo].
126    #[inline]
127    pub fn on_interrupt_rx(&mut self, buf: &mut [u8; 16]) -> usize {
128        self.read_whole_fifo(buf)
129    }
130
131    /// Read and clear the last RX errors.
132    ///
133    /// Returns [None] if no errors have occured.
134    pub fn read_and_clear_last_error(&mut self) -> Option<RxErrors> {
135        let errors = self.errors?;
136        self.errors = None;
137        Some(errors)
138    }
139}
140
141impl embedded_hal_nb::serial::ErrorType for Rx {
142    type Error = Infallible;
143}
144
145impl embedded_hal_nb::serial::Read for Rx {
146    #[inline]
147    fn read(&mut self) -> nb::Result<u8, Self::Error> {
148        self.read_fifo()
149    }
150}
151
152impl embedded_io::ErrorType for Rx {
153    type Error = Infallible;
154}
155
156impl embedded_io::Read for Rx {
157    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
158        if buf.is_empty() {
159            return Ok(0);
160        }
161        while !self.has_data() {}
162        let mut read = 0;
163        for byte in buf.iter_mut() {
164            match self.read_fifo() {
165                Ok(data) => {
166                    *byte = data;
167                    read += 1;
168                }
169                Err(nb::Error::WouldBlock) => break,
170            }
171        }
172        Ok(read)
173    }
174}
175
176/// Extract RX errors from the status register.
177pub const fn handle_status_reg_errors(status_reg: &Status) -> Option<RxErrors> {
178    let mut errors = RxErrors::new();
179    if status_reg.frame_error() {
180        errors.frame = true;
181    }
182    if status_reg.parity_error() {
183        errors.parity = true;
184    }
185    if status_reg.overrun_error() {
186        errors.overrun = true;
187    }
188    if !errors.has_errors() {
189        return None;
190    }
191    Some(errors)
192}