1use core::convert::Infallible;
3
4use crate::{
5 InvalidWakerIndex, RxErrors, TxAsync, handle_status_reg_errors,
6 regs::{
7 self,
8 fields::{Control, TxFifo},
9 },
10};
11
12pub struct Tx {
17 pub(crate) regs: regs::MmioRegisters<'static>,
18 pub(crate) errors: Option<RxErrors>,
19}
20
21impl Tx {
22 pub unsafe fn steal(base_addr: usize) -> Self {
36 let regs = unsafe { regs::Registers::new_mmio_at(base_addr) };
37 Self { regs, errors: None }
38 }
39
40 #[inline]
44 pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
45 let status_reg = self.regs.read_stat_reg();
46 if status_reg.tx_fifo_full() {
47 return Err(nb::Error::WouldBlock);
48 }
49 self.write_fifo_unchecked(data);
50 if let Some(errors) = handle_status_reg_errors(&status_reg) {
51 self.errors = Some(errors);
52 }
53 Ok(())
54 }
55
56 #[inline]
58 pub fn reset_fifo(&mut self) {
59 let status = self.regs.read_stat_reg();
60 self.regs.write_ctrl_reg(
61 Control::builder()
62 .with_enable_interrupt(status.intr_enabled())
63 .with_reset_rx_fifo(false)
64 .with_reset_tx_fifo(true)
65 .build(),
66 );
67 }
68
69 #[inline(always)]
73 pub fn write_fifo_unchecked(&mut self, data: u8) {
74 self.regs
75 .write_tx_fifo(TxFifo::new_with_raw_value(data as u32));
76 }
77
78 #[inline(always)]
80 pub fn fifo_empty(&self) -> bool {
81 self.regs.read_stat_reg().tx_fifo_empty()
82 }
83
84 #[inline(always)]
86 pub fn fifo_full(&self) -> bool {
87 self.regs.read_stat_reg().tx_fifo_full()
88 }
89
90 pub fn fill_fifo(&mut self, buf: &[u8]) -> usize {
95 let mut written = 0;
96 while written < buf.len() {
97 match self.write_fifo(buf[written]) {
98 Ok(_) => written += 1,
99 Err(nb::Error::WouldBlock) => break,
100 }
101 }
102 written
103 }
104
105 pub fn read_and_clear_last_error(&mut self) -> Option<RxErrors> {
107 let errors = self.errors?;
108 self.errors = None;
109 Some(errors)
110 }
111
112 pub fn into_async(self, waker_idx: usize) -> Result<TxAsync, InvalidWakerIndex> {
116 TxAsync::new(self, waker_idx)
117 }
118}
119
120impl embedded_hal_nb::serial::ErrorType for Tx {
121 type Error = Infallible;
122}
123
124impl embedded_hal_nb::serial::Write for Tx {
125 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
126 self.write_fifo(word)
127 }
128
129 fn flush(&mut self) -> nb::Result<(), Self::Error> {
130 while !self.fifo_empty() {}
131 Ok(())
132 }
133}
134
135impl embedded_io::ErrorType for Tx {
136 type Error = Infallible;
137}
138
139impl embedded_io::Write for Tx {
140 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
141 if buf.is_empty() {
142 return Ok(0);
143 }
144 while self.fifo_full() {}
145 let mut written = 0;
146 for &byte in buf.iter() {
147 match self.write_fifo(byte) {
148 Ok(_) => written += 1,
149 Err(nb::Error::WouldBlock) => break,
150 }
151 }
152 Ok(written)
153 }
154
155 fn flush(&mut self) -> Result<(), Self::Error> {
156 while !self.fifo_empty() {}
157 Ok(())
158 }
159}