Skip to main content

axi_uartlite/
rx.rs

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