use core::convert::Infallible;
use crate::{
RxErrors, handle_status_reg_errors,
registers::{self, Control, TxFifo},
};
pub struct Tx {
pub(crate) regs: registers::MmioRegisters<'static>,
pub(crate) errors: Option<RxErrors>,
}
impl Tx {
pub unsafe fn steal(base_addr: usize) -> Self {
let regs = unsafe { registers::Registers::new_mmio_at(base_addr) };
Self { regs, errors: None }
}
#[inline]
pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
let status_reg = self.regs.read_stat_reg();
if status_reg.tx_fifo_full() {
return Err(nb::Error::WouldBlock);
}
self.write_fifo_unchecked(data);
if let Some(errors) = handle_status_reg_errors(&status_reg) {
self.errors = Some(errors);
}
Ok(())
}
#[inline]
pub fn reset_fifo(&mut self) {
let status = self.regs.read_stat_reg();
self.regs.write_ctrl_reg(
Control::builder()
.with_enable_interrupt(status.intr_enabled())
.with_reset_rx_fifo(false)
.with_reset_tx_fifo(true)
.build(),
);
}
#[inline(always)]
pub fn write_fifo_unchecked(&mut self, data: u8) {
self.regs
.write_tx_fifo(TxFifo::new_with_raw_value(data as u32));
}
#[inline(always)]
pub fn fifo_empty(&self) -> bool {
self.regs.read_stat_reg().tx_fifo_empty()
}
#[inline(always)]
pub fn fifo_full(&self) -> bool {
self.regs.read_stat_reg().tx_fifo_full()
}
pub fn fill_fifo(&mut self, buf: &[u8]) -> usize {
let mut written = 0;
while written < buf.len() {
match self.write_fifo(buf[written]) {
Ok(_) => written += 1,
Err(nb::Error::WouldBlock) => break,
}
}
written
}
pub fn read_and_clear_last_error(&mut self) -> Option<RxErrors> {
let errors = self.errors?;
self.errors = None;
Some(errors)
}
}
impl embedded_hal_nb::serial::ErrorType for Tx {
type Error = Infallible;
}
impl embedded_hal_nb::serial::Write for Tx {
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.write_fifo(word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
while !self.fifo_empty() {}
Ok(())
}
}
impl embedded_io::ErrorType for Tx {
type Error = Infallible;
}
impl embedded_io::Write for Tx {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
while self.fifo_full() {}
let mut written = 0;
for &byte in buf.iter() {
match self.write_fifo(byte) {
Ok(_) => written += 1,
Err(nb::Error::WouldBlock) => break,
}
}
Ok(written)
}
fn flush(&mut self) -> Result<(), Self::Error> {
while !self.fifo_empty() {}
Ok(())
}
}