extern crate nb;
use {
paste::paste,
core::marker::PhantomData,
crate::pac::{
UART0,
UART1,
},
crate::clock::{
UART0Clock,
UART1Clock,
Enabled,
},
crate::gpio::{ Pa9, Pa10, PfA },
crate::time::{ Bps },
embedded_hal::{serial::Read, serial::Write}
};
#[cfg(feature = "atsam4s")]
use {
crate::gpio::{ Pb2, Pb3 },
};
#[cfg(feature = "atsam4e")]
use {
crate::gpio::{ Pa5, Pa6, PfC },
};
#[derive(Debug)]
pub enum Parity {
Even,
Odd,
Space,
Mark,
}
#[derive(Debug)]
pub enum CharacterLength {
FiveBits,
SixBits,
SevenBits,
EightBits,
}
#[derive(Debug)]
pub enum StopBits {
One,
OnePointFive,
Two,
}
#[derive(Debug)]
pub enum Error {
Overrun,
}
macro_rules! serial_ports {
(
$($PortType:ident: (
$port_ident:ident,
$pin_rx:ty,
$pin_tx:ty,
$UART:ident,
$uart:ident
),)+
) => {
paste! {
$(
pub struct $PortType {
uart: $UART,
clock: PhantomData<[<$UART Clock>]<Enabled>>,
rx_pin: PhantomData<$pin_rx>,
tx_pin: PhantomData<$pin_tx>,
}
impl $PortType {
pub fn new (
mut uart: $port_ident,
clock: [<$UART Clock>]<Enabled>,
_rx_pin: $pin_rx,
_tx_pin: $pin_tx,
baud_rate: Bps,
parity: Option<Parity>,
) -> Self {
Self::reset_and_disable(&mut uart);
let clock_divisor:u32 = (clock.frequency().0 / baud_rate.0) / 16;
if clock_divisor < 1 || clock_divisor > 65535 {
panic!("Unsupported baud_rate specified for serial device (cd = {})", clock_divisor);
}
uart.brgr.write(|w| unsafe { w.bits(clock_divisor) });
uart.mr.write(|w| unsafe {
if let Some(parity) = parity {
let p = match parity {
Parity::Even => 0,
Parity::Odd => 1,
Parity::Space => 2,
Parity::Mark => 3,
};
w.par().bits(p);
}
else {
w.par().bits(4); }
w.chmode().bits(0) });
Self::enable(&mut uart);
$PortType {
uart: uart,
clock: PhantomData,
rx_pin: PhantomData,
tx_pin: PhantomData,
}
}
fn reset_and_disable(uart: &mut $UART) {
uart.cr.write_with_zero(|w| {
w.rstrx().set_bit().rsttx().set_bit().rxdis().set_bit().txdis().set_bit()
});
}
fn enable(uart: &mut $UART) {
uart.cr.write_with_zero(|w| {
w.rxen().set_bit().txen().set_bit()
});
}
pub fn write_string_blocking(&mut self, data: &str) {
for c in data.chars() {
loop {
if let Err(_e) = self.write(c as u8) {
continue;
}
break;
}
}
}
}
impl Read<u8> for $PortType {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let isr = self.uart.sr.read();
if isr.ovre().bit_is_set() {
Err(nb::Error::Other(Error::Overrun))
}
else if isr.rxrdy().bit_is_set() {
Ok(self.uart.rhr.read().bits() as u8)
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl Write<u8> for $PortType {
type Error = Error;
fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
let isr = self.uart.sr.read();
if isr.txrdy().bit_is_set() {
Ok(self.uart.thr.write_with_zero(|w| unsafe { w.txchr().bits(byte) }))
} else {
Err(nb::Error::WouldBlock)
}
}
fn flush(&mut self) -> nb::Result<(), Error> {
Err(nb::Error::WouldBlock)
}
}
)+
}
}
}
#[cfg(feature = "atsam4s")]
serial_ports! (
Serial0: (UART0, Pa9<PfA>, Pa10<PfA>, UART0, uart0),
Serial1: (UART1, Pb2<PfA>, Pb3<PfA>, UART1, uart1),
);
#[cfg(feature = "atsam4e")]
serial_ports! (
Serial0: (UART0, Pa9<PfA>, Pa10<PfA>, UART0, uart0),
Serial1: (UART1, Pa5<PfC>, Pa6<PfC>, UART1, uart1),
);