use core::marker::PhantomData;
use core::{fmt, ops::Deref};
use nb::block;
use crate::pac::{
uart0::RegisterBlock, UART0, UART0_SECURE, UART1, UART1_SECURE, UART2, UART2_SECURE, UART3,
UART3_SECURE, UART4, UART4_SECURE, UART5, UART5_SECURE,
};
pub trait ValidUart: Deref<Target = RegisterBlock> {
const PTR: *const RegisterBlock;
}
pub trait Pins<UART> {}
pub trait PinTx<UART> {}
pub trait PinRx<UART> {}
macro_rules! impl_valid_uart {
($($name: ty),+) => {
$(
impl ValidUart for $name {
const PTR: *const RegisterBlock = <$name>::PTR;
}
)+
}
}
impl_valid_uart!(UART0, UART1, UART2, UART3, UART4, UART5);
impl<UART, TX, RX> Pins<UART> for (RX, TX)
where
TX: PinTx<UART>,
RX: PinRx<UART>,
{
}
pub struct AutoTx;
pub struct AutoRx;
impl PinRx<UART0> for AutoRx {}
impl PinTx<UART0> for AutoTx {}
impl PinRx<UART1> for AutoRx {}
impl PinTx<UART1> for AutoTx {}
impl PinRx<UART2> for AutoRx {}
impl PinTx<UART2> for AutoTx {}
impl PinRx<UART3> for crate::shield::Pin<0, 0, crate::shield::Uart> {}
impl PinTx<UART3> for crate::shield::Pin<0, 1, crate::shield::Uart> {}
impl PinRx<UART4> for crate::shield::Pin<1, 0, crate::shield::Uart> {}
impl PinTx<UART4> for crate::shield::Pin<1, 1, crate::shield::Uart> {}
impl PinRx<UART5> for AutoRx {}
impl PinTx<UART5> for AutoTx {}
impl PinRx<UART0_SECURE> for AutoRx {}
impl PinTx<UART0_SECURE> for AutoTx {}
impl PinRx<UART1_SECURE> for AutoRx {}
impl PinTx<UART1_SECURE> for AutoTx {}
impl PinRx<UART2_SECURE> for AutoRx {}
impl PinTx<UART2_SECURE> for AutoTx {}
impl PinRx<UART3_SECURE> for crate::shield::Pin<0, 0, crate::shield::Uart> {}
impl PinTx<UART3_SECURE> for crate::shield::Pin<0, 1, crate::shield::Uart> {}
impl PinRx<UART4_SECURE> for crate::shield::Pin<1, 0, crate::shield::Uart> {}
impl PinTx<UART4_SECURE> for crate::shield::Pin<1, 1, crate::shield::Uart> {}
impl PinRx<UART5_SECURE> for AutoRx {}
impl PinTx<UART5_SECURE> for AutoTx {}
pub struct Serial<UART, RxPin, TxPin> {
rx: Rx<UART, RxPin>,
tx: Tx<UART, TxPin>,
}
pub struct Rx<UART, RxPin> {
_serial: PhantomData<UART>,
_pin: RxPin,
}
pub struct Tx<UART, TxPin> {
_serial: PhantomData<UART>,
_pin: TxPin,
}
#[derive(Debug, Clone, Copy)]
pub enum Error {
Overrun,
}
pub mod config {
#[derive(Debug, Clone, Copy)]
pub enum Error {
UnreachableBaudrate,
}
}
impl<U: ValidUart, RxPin, TxPin> Serial<U, RxPin, TxPin>
where
(RxPin, TxPin): Pins<U>,
{
pub fn new(
uart: U,
(rx, tx): (RxPin, TxPin),
baudrate: fugit::HertzU32,
) -> Result<Self, (U, (RxPin, TxPin), config::Error)> {
if let Some(bauddiv) = (baudrate.to_Hz() != 0)
.then(|| crate::PERIPHERAL_CLOCK.to_Hz() / baudrate.to_Hz())
.filter(|&bauddiv| bauddiv >= 16)
{
uart.bauddiv.write(|w| unsafe { w.bits(bauddiv) });
} else {
return Err((uart, (rx, tx), config::Error::UnreachableBaudrate));
}
uart.ctrl.modify(|_, w| w.rxen().set_bit().txen().set_bit());
Ok(Serial {
rx: Rx {
_serial: PhantomData,
_pin: rx,
},
tx: Tx {
_serial: PhantomData,
_pin: tx,
},
})
}
pub fn split(self) -> (Rx<U, RxPin>, Tx<U, TxPin>) {
let Self { rx, tx } = self;
(rx, tx)
}
}
impl<U: ValidUart, P: PinRx<U>> embedded_hal::serial::Read<u8> for Rx<U, P> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let serial = unsafe { &*U::PTR };
if serial.state.read().rxbf().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
Ok(serial.data.read().bits())
}
}
}
impl<U: ValidUart, P: PinTx<U>> embedded_hal::serial::Write<u8> for Tx<U, P> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let serial = unsafe { &*U::PTR };
if serial.state.read().txbf().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let serial = unsafe { &*U::PTR };
if serial.state.read().txbf().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
unsafe {
serial.data.write_with_zero(|w| w.bits(byte));
}
Ok(())
}
}
}
impl<U: ValidUart, RxPin, TxPin> embedded_hal::serial::Read<u8> for Serial<U, RxPin, TxPin>
where
(RxPin, TxPin): Pins<U>,
RxPin: PinRx<U>,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}
impl<U: ValidUart, RxPin, TxPin> embedded_hal::serial::Write<u8> for Serial<U, RxPin, TxPin>
where
(RxPin, TxPin): Pins<U>,
TxPin: PinTx<U>,
{
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
self.tx.write(byte)
}
}
impl<U, RxPin, TxPin> fmt::Write for Serial<U, RxPin, TxPin>
where
U: ValidUart,
(RxPin, TxPin): Pins<U>,
TxPin: PinTx<U>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
use embedded_hal::serial::Write;
for &b in s.as_bytes() {
block!(self.write(b)).map_err(|_| core::fmt::Error)?;
}
Ok(())
}
}
impl<UART, P> fmt::Write for Tx<UART, P>
where
Tx<UART, P>: embedded_hal::serial::Write<u8>,
P: PinTx<UART>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
use embedded_hal::serial::Write;
for &b in s.as_bytes() {
block!(self.write(b)).map_err(|_| core::fmt::Error)?;
}
Ok(())
}
}
#[cfg(feature = "eh1-0-alpha")]
mod eh1 {
use eh1_0_alpha::serial::ErrorKind;
use super::{Error, Rx, Serial, Tx};
impl eh1_0_alpha::serial::Error for Error {
fn kind(&self) -> ErrorKind {
match self {
Error::Overrun => ErrorKind::Overrun,
}
}
}
impl<UART, RxPin, TxPin> eh1_0_alpha::serial::ErrorType for Serial<UART, RxPin, TxPin> {
type Error = Error;
}
impl<UART, RxPin, TxPin> eh1_0_alpha::serial::nb::Read for Serial<UART, RxPin, TxPin>
where
Self: embedded_hal::serial::Read<u8, Error = Error>,
{
fn read(&mut self) -> nb::Result<u8, Self::Error> {
<Self as embedded_hal::serial::Read<_>>::read(self)
}
}
impl<UART, RxPin, TxPin> eh1_0_alpha::serial::nb::Write for Serial<UART, RxPin, TxPin>
where
Self: embedded_hal::serial::Write<u8, Error = Error>,
{
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
<Self as embedded_hal::serial::Write<u8>>::write(self, word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
<Self as embedded_hal::serial::Write<u8>>::flush(self)
}
}
impl<UART, RxPin, TxPin> eh1_0_alpha::serial::blocking::Write for Serial<UART, RxPin, TxPin>
where
Self: embedded_hal::serial::Write<u8, Error = Error>,
{
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
for &b in buffer {
nb::block!(<Self as eh1_0_alpha::serial::nb::Write>::write(self, b))?
}
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(<Self as eh1_0_alpha::serial::nb::Write>::flush(self))
}
}
impl<UART, RxPin> eh1_0_alpha::serial::ErrorType for Rx<UART, RxPin> {
type Error = Error;
}
impl<UART, RxPin> eh1_0_alpha::serial::nb::Read for Rx<UART, RxPin>
where
Self: embedded_hal::serial::Read<u8, Error = Error>,
{
fn read(&mut self) -> nb::Result<u8, Self::Error> {
<Self as embedded_hal::serial::Read<_>>::read(self)
}
}
impl<UART, TxPin> eh1_0_alpha::serial::ErrorType for Tx<UART, TxPin> {
type Error = Error;
}
impl<UART, TxPin> eh1_0_alpha::serial::nb::Write for Tx<UART, TxPin>
where
Self: embedded_hal::serial::Write<u8, Error = Error>,
{
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
<Self as embedded_hal::serial::Write<u8>>::write(self, word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
<Self as embedded_hal::serial::Write<u8>>::flush(self)
}
}
impl<UART, TxPin> eh1_0_alpha::serial::blocking::Write for Tx<UART, TxPin>
where
Self: embedded_hal::serial::Write<u8, Error = Error>,
{
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
for &b in buffer {
nb::block!(<Self as eh1_0_alpha::serial::nb::Write>::write(self, b))?
}
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(<Self as eh1_0_alpha::serial::nb::Write>::flush(self))
}
}
}