use super::{FifoWatermark, UartDevice, ValidUartPinout};
use crate::dma::{EndlessWriteTarget, WriteTarget};
use crate::pac::uart0::RegisterBlock;
use core::fmt;
use core::{convert::Infallible, marker::PhantomData};
use embedded_hal_0_2::serial::Write as Write02;
use embedded_hal_nb::serial::{ErrorType, Write};
use nb::Error::*;
pub fn set_tx_watermark(rb: &RegisterBlock, watermark: FifoWatermark) {
let wm = match watermark {
FifoWatermark::Bytes4 => 4,
FifoWatermark::Bytes8 => 3,
FifoWatermark::Bytes16 => 2,
FifoWatermark::Bytes24 => 1,
FifoWatermark::Bytes28 => 0,
};
rb.uartifls()
.modify(|_r, w| unsafe { w.txiflsel().bits(wm) });
}
pub(crate) fn transmit_flushed(rb: &RegisterBlock) -> nb::Result<(), Infallible> {
if rb.uartfr().read().busy().bit_is_set() {
Err(WouldBlock)
} else {
Ok(())
}
}
pub(crate) fn uart_is_writable(rb: &RegisterBlock) -> bool {
rb.uartfr().read().txff().bit_is_clear()
}
pub(crate) fn uart_is_busy(rb: &RegisterBlock) -> bool {
rb.uartfr().read().busy().bit_is_set()
}
pub(crate) fn write_raw<'d>(
rb: &RegisterBlock,
data: &'d [u8],
) -> nb::Result<&'d [u8], Infallible> {
let mut bytes_written = 0;
for c in data {
if !uart_is_writable(rb) {
if bytes_written == 0 {
return Err(WouldBlock);
} else {
return Ok(&data[bytes_written..]);
}
}
rb.uartdr().write(|w| unsafe {
w.data().bits(*c);
w
});
bytes_written += 1;
}
Ok(&data[bytes_written..])
}
pub(crate) fn write_full_blocking(rb: &RegisterBlock, data: &[u8]) {
let mut temp = data;
while !temp.is_empty() {
temp = match write_raw(rb, temp) {
Ok(remaining) => remaining,
Err(WouldBlock) => continue,
Err(_) => unreachable!(),
}
}
}
pub(crate) fn enable_tx_interrupt(rb: &RegisterBlock) {
rb.uartifls()
.modify(|_r, w| unsafe { w.txiflsel().bits(2) });
rb.uartimsc().modify(|_r, w| {
w.txim().set_bit();
w
});
}
pub(crate) fn disable_tx_interrupt(rb: &RegisterBlock) {
rb.uartimsc().modify(|_r, w| {
w.txim().clear_bit();
w
});
}
pub struct Writer<D: UartDevice, P: ValidUartPinout<D>> {
pub(super) device: D,
pub(super) device_marker: PhantomData<D>,
pub(super) pins: PhantomData<P>,
}
impl<D: UartDevice, P: ValidUartPinout<D>> Writer<D, P> {
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
write_raw(&self.device, data)
}
pub fn write_full_blocking(&self, data: &[u8]) {
write_full_blocking(&self.device, data);
}
pub fn enable_tx_interrupt(&mut self) {
enable_tx_interrupt(&self.device)
}
pub fn disable_tx_interrupt(&mut self) {
disable_tx_interrupt(&self.device)
}
pub fn lowlevel_break_start(&mut self) {
self.device.uartlcr_h().modify(|_, w| w.brk().set_bit());
}
pub fn lowlevel_break_stop(&mut self) {
self.device.uartlcr_h().modify(|_, w| w.brk().clear_bit());
}
}
impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::ErrorType for Writer<D, P> {
type Error = Infallible;
}
impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::Write for Writer<D, P> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
let remaining = nb::block!(write_raw(&self.device, buf)).unwrap(); Ok(buf.len() - remaining.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(transmit_flushed(&self.device)).unwrap(); Ok(())
}
}
impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::WriteReady for Writer<D, P> {
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(uart_is_writable(&self.device))
}
}
impl<D: UartDevice, P: ValidUartPinout<D>> Write02<u8> for Writer<D, P> {
type Error = Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.write_raw(&[word]).is_err() {
Err(WouldBlock)
} else {
Ok(())
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
transmit_flushed(&self.device)
}
}
unsafe impl<D: UartDevice, P: ValidUartPinout<D>> WriteTarget for Writer<D, P> {
type TransmittedWord = u8;
fn tx_treq() -> Option<u8> {
Some(D::tx_dreq())
}
fn tx_address_count(&mut self) -> (u32, u32) {
(self.device.uartdr().as_ptr() as u32, u32::MAX)
}
fn tx_increment(&self) -> bool {
false
}
}
impl<D: UartDevice, P: ValidUartPinout<D>> EndlessWriteTarget for Writer<D, P> {}
impl<D: UartDevice, P: ValidUartPinout<D>> ErrorType for Writer<D, P> {
type Error = Infallible;
}
impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for Writer<D, P> {
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.write_raw(&[word]).is_err() {
Err(WouldBlock)
} else {
Ok(())
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
transmit_flushed(&self.device).map_err(|e| match e {
WouldBlock => WouldBlock,
Other(v) => match v {},
})
}
}
impl<D: UartDevice, P: ValidUartPinout<D>> fmt::Write for Writer<D, P> {
fn write_str(&mut self, s: &str) -> fmt::Result {
s.bytes()
.try_for_each(|c| nb::block!(Write::write(self, c)))
.map_err(|_| fmt::Error)
}
}