axi_uartlite/
tx.rs

1//! # Transmitter (TX) support module
2use core::convert::Infallible;
3
4use crate::{
5    RxErrors, handle_status_reg_errors,
6    registers::{self, Control, TxFifo},
7};
8
9/// AXI UARTLITE TX driver.
10///
11/// Can be created by [super::AxiUartlite::split]ting a regular AXI UARTLITE structure or
12/// by [Self::steal]ing it unsafely.
13pub struct Tx {
14    pub(crate) regs: registers::MmioRegisters<'static>,
15    pub(crate) errors: Option<RxErrors>,
16}
17
18impl Tx {
19    /// Steal the TX part of the UART Lite.
20    ///
21    /// You should only use this if you can not use the regular [super::AxiUartlite] constructor
22    /// and the [super::AxiUartlite::split] method.
23    ///
24    /// This function assumes that the setup of the UART was already done.
25    /// It can be used to create a TX handle inside an interrupt handler without having to use
26    /// a [critical_section::Mutex] if the user can guarantee that the TX handle will only be
27    /// used by the interrupt handler, or only interrupt specific API will be used.
28    ///
29    /// # Safety
30    ///
31    /// The same safey rules specified in [super::AxiUartlite] apply.
32    pub unsafe fn steal(base_addr: usize) -> Self {
33        let regs = unsafe { registers::Registers::new_mmio_at(base_addr) };
34        Self { regs, errors: None }
35    }
36
37    /// Write into the UART Lite.
38    ///
39    /// Returns [nb::Error::WouldBlock] if the TX FIFO is full.
40    #[inline]
41    pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
42        let status_reg = self.regs.read_stat_reg();
43        if status_reg.tx_fifo_full() {
44            return Err(nb::Error::WouldBlock);
45        }
46        self.write_fifo_unchecked(data);
47        if let Some(errors) = handle_status_reg_errors(&status_reg) {
48            self.errors = Some(errors);
49        }
50        Ok(())
51    }
52
53    /// Reset the TX FIFO.
54    #[inline]
55    pub fn reset_fifo(&mut self) {
56        let status = self.regs.read_stat_reg();
57        self.regs.write_ctrl_reg(
58            Control::builder()
59                .with_enable_interrupt(status.intr_enabled())
60                .with_reset_rx_fifo(false)
61                .with_reset_tx_fifo(true)
62                .build(),
63        );
64    }
65
66    /// Write into the FIFO without checking the FIFO fill status.
67    ///
68    /// This can be useful to completely fill the FIFO if it is known to be empty.
69    #[inline(always)]
70    pub fn write_fifo_unchecked(&mut self, data: u8) {
71        self.regs
72            .write_tx_fifo(TxFifo::new_with_raw_value(data as u32));
73    }
74
75    /// Is the TX FIFO empty?
76    #[inline(always)]
77    pub fn fifo_empty(&self) -> bool {
78        self.regs.read_stat_reg().tx_fifo_empty()
79    }
80
81    /// Is the TX FIFO full?
82    #[inline(always)]
83    pub fn fifo_full(&self) -> bool {
84        self.regs.read_stat_reg().tx_fifo_full()
85    }
86
87    /// Fills the FIFO with user provided data until the user data
88    /// is consumed or the FIFO is full.
89    ///
90    /// Returns the amount of written data, which might be smaller than the buffer size.
91    pub fn fill_fifo(&mut self, buf: &[u8]) -> usize {
92        let mut written = 0;
93        while written < buf.len() {
94            match self.write_fifo(buf[written]) {
95                Ok(_) => written += 1,
96                Err(nb::Error::WouldBlock) => break,
97            }
98        }
99        written
100    }
101
102    /// Read and clear the last recorded RX errors.
103    pub fn read_and_clear_last_error(&mut self) -> Option<RxErrors> {
104        let errors = self.errors?;
105        self.errors = None;
106        Some(errors)
107    }
108}
109
110impl embedded_hal_nb::serial::ErrorType for Tx {
111    type Error = Infallible;
112}
113
114impl embedded_hal_nb::serial::Write for Tx {
115    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
116        self.write_fifo(word)
117    }
118
119    fn flush(&mut self) -> nb::Result<(), Self::Error> {
120        while !self.fifo_empty() {}
121        Ok(())
122    }
123}
124
125impl embedded_io::ErrorType for Tx {
126    type Error = Infallible;
127}
128
129impl embedded_io::Write for Tx {
130    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
131        if buf.is_empty() {
132            return Ok(0);
133        }
134        while self.fifo_full() {}
135        let mut written = 0;
136        for &byte in buf.iter() {
137            match self.write_fifo(byte) {
138                Ok(_) => written += 1,
139                Err(nb::Error::WouldBlock) => break,
140            }
141        }
142        Ok(written)
143    }
144
145    fn flush(&mut self) -> Result<(), Self::Error> {
146        while !self.fifo_empty() {}
147        Ok(())
148    }
149}