zynq7000_hal/uart/
tx.rs

1use core::convert::Infallible;
2
3use zynq7000::uart::{Fifo, InterruptControl, InterruptStatus, MmioUart};
4
5use super::UartId;
6
7pub struct Tx {
8    pub(crate) regs: MmioUart<'static>,
9    pub(crate) idx: UartId,
10}
11
12impl Tx {
13    /// Steal the TX side of the UART for a given UART index.
14    ///
15    /// # Safety
16    ///
17    /// Circumvents safety guarantees provided by the compiler.
18    #[inline]
19    pub const unsafe fn steal(idx: UartId) -> Self {
20        Tx {
21            regs: unsafe { idx.regs() },
22            idx,
23        }
24    }
25
26    #[inline]
27    pub const fn uart_idx(&self) -> UartId {
28        self.idx
29    }
30
31    #[inline]
32    pub const fn regs(&mut self) -> &mut MmioUart<'static> {
33        &mut self.regs
34    }
35
36    #[inline]
37    pub fn write_fifo(&mut self, word: u8) -> nb::Result<(), Infallible> {
38        if self.regs.read_sr().tx_full() {
39            return Err(nb::Error::WouldBlock);
40        }
41        self.write_fifo_unchecked(word);
42        Ok(())
43    }
44
45    /// Enables TX side of the UART.
46    #[inline]
47    pub fn enable(&mut self, with_reset: bool) {
48        if with_reset {
49            self.soft_reset();
50        }
51        self.regs.modify_cr(|mut val| {
52            val.set_tx_en(true);
53            val.set_tx_dis(false);
54            val
55        });
56    }
57
58    /// Disables TX side of the UART.
59    #[inline]
60    pub fn disable(&mut self) {
61        self.regs.modify_cr(|mut val| {
62            val.set_tx_en(false);
63            val.set_tx_dis(true);
64            val
65        });
66    }
67
68    #[inline]
69    pub fn soft_reset(&mut self) {
70        self.regs.modify_cr(|mut val| {
71            val.set_tx_rst(true);
72            val
73        });
74        loop {
75            if !self.regs.read_cr().tx_rst() {
76                break;
77            }
78        }
79    }
80
81    pub fn flush(&mut self) {
82        while !self.regs.read_sr().tx_empty() {}
83    }
84
85    #[inline]
86    pub fn write_fifo_unchecked(&mut self, word: u8) {
87        self.regs.write_fifo(Fifo::new_with_raw_value(word as u32));
88    }
89
90    /// Enables interrupts relevant for the TX side of the UART except the TX trigger interrupt.
91    #[inline]
92    pub fn enable_interrupts(&mut self) {
93        self.regs.write_ier(
94            InterruptControl::builder()
95                .with_tx_over(true)
96                .with_tx_near_full(true)
97                .with_tx_trig(false)
98                .with_rx_dms(false)
99                .with_rx_timeout(false)
100                .with_rx_parity(false)
101                .with_rx_framing(false)
102                .with_rx_over(false)
103                .with_tx_full(true)
104                .with_tx_empty(true)
105                .with_rx_full(false)
106                .with_rx_empty(false)
107                .with_rx_trg(false)
108                .build(),
109        );
110    }
111
112    /// Disable interrupts relevant for the TX side of the UART except the TX trigger interrupt.
113    #[inline]
114    pub fn disable_interrupts(&mut self) {
115        self.regs.write_idr(
116            InterruptControl::builder()
117                .with_tx_over(true)
118                .with_tx_near_full(true)
119                .with_tx_trig(false)
120                .with_rx_dms(false)
121                .with_rx_timeout(false)
122                .with_rx_parity(false)
123                .with_rx_framing(false)
124                .with_rx_over(false)
125                .with_tx_full(true)
126                .with_tx_empty(true)
127                .with_rx_full(false)
128                .with_rx_empty(false)
129                .with_rx_trg(false)
130                .build(),
131        );
132    }
133
134    /// Clears interrupts relevant for the TX side of the UART except the TX trigger interrupt.
135    #[inline]
136    pub fn clear_interrupts(&mut self) {
137        self.regs.write_isr(
138            InterruptStatus::builder()
139                .with_tx_over(true)
140                .with_tx_near_full(true)
141                .with_tx_trig(false)
142                .with_rx_dms(false)
143                .with_rx_timeout(false)
144                .with_rx_parity(false)
145                .with_rx_framing(false)
146                .with_rx_over(false)
147                .with_tx_full(true)
148                .with_tx_empty(true)
149                .with_rx_full(false)
150                .with_rx_empty(false)
151                .with_rx_trg(false)
152                .build(),
153        );
154    }
155}
156
157impl embedded_hal_nb::serial::ErrorType for Tx {
158    type Error = Infallible;
159}
160
161impl embedded_hal_nb::serial::Write for Tx {
162    #[inline]
163    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
164        self.write_fifo(word)
165    }
166
167    fn flush(&mut self) -> nb::Result<(), Self::Error> {
168        if self.regs.read_sr().tx_empty() {
169            return Ok(());
170        }
171        Err(nb::Error::WouldBlock)
172    }
173}
174
175impl embedded_io::ErrorType for Tx {
176    type Error = Infallible;
177}
178
179impl embedded_io::Write for Tx {
180    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
181        if buf.is_empty() {
182            return Ok(0);
183        }
184        let mut written = 0;
185        loop {
186            if !self.regs.read_sr().tx_full() {
187                break;
188            }
189        }
190        for byte in buf.iter() {
191            match self.write_fifo(*byte) {
192                Ok(_) => written += 1,
193                Err(nb::Error::WouldBlock) => return Ok(written),
194            }
195        }
196
197        Ok(written)
198    }
199
200    fn flush(&mut self) -> Result<(), Self::Error> {
201        self.flush();
202        Ok(())
203    }
204}