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}
11unsafe 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 #[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 pub fn start_interrupt_driven_reception(&mut self) {
95 self.soft_reset();
96 self.clear_interrupts();
97 self.enable_interrupts();
98 }
99
100 #[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 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 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 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 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 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 #[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 #[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}