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 #[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 #[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 #[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 #[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 #[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 #[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}