use core::fmt;
use core::ops::Deref;
use core::marker::PhantomData;
use crate::{
typestates::{
pin::{
flexcomm::{
Usart,
UsartPins,
},
PinId,
},
},
traits::wg::serial,
time::Hertz,
};
pub mod config;
#[derive(Debug)]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
#[doc(hidden)]
_Extensible,
}
pub struct Serial<TX, RX, USART, PINS>
where
TX: PinId,
RX: PinId,
USART: Usart,
PINS: UsartPins<TX, RX, USART>,
{
usart: USART,
pins: PINS,
_tx: PhantomData<TX>,
_rx: PhantomData<RX>,
}
pub struct Tx<USART: Usart> {
addr: usize,
_usart: PhantomData<USART>,
}
pub struct Rx<USART: Usart> {
addr: usize,
_usart: PhantomData<USART>,
}
impl<USART: Usart> Deref for Tx<USART> {
type Target = raw::usart0::RegisterBlock;
fn deref(&self) -> &Self::Target {
let ptr = self.addr as *const _;
unsafe { &*ptr }
}
}
impl<USART: Usart> Deref for Rx<USART> {
type Target = raw::usart0::RegisterBlock;
fn deref(&self) -> &Self::Target {
let ptr = self.addr as *const _;
unsafe { &*ptr }
}
}
impl<TX, RX, USART, PINS> Serial<TX, RX, USART, PINS>
where
TX: PinId,
RX: PinId,
USART: Usart,
PINS: UsartPins<TX, RX, USART>,
{
const CLOCK_SPEED: u32 = 12_000_000;
pub fn new(usart: USART, pins: PINS, config: config::Config) -> Self {
use self::config::*;
let speed: Hertz = config.speed.into();
let speed: u32 = speed.0;
usart.fifocfg.modify(|_, w| w
.enabletx().enabled()
.enablerx().enabled()
);
usart.fifotrig.modify(|_, w| unsafe { w
.txlvl().bits(0)
.txlvlena().enabled()
.rxlvl().bits(1)
.rxlvlena().enabled()
});
usart.cfg.write(|w| unsafe { w
.paritysel().bits(match config.parity {
Parity::ParityNone => 0,
Parity::ParityEven => 2,
Parity::ParityOdd => 3,
})
.stoplen().bit(match config.stopbits {
StopBits::STOP1 => false,
StopBits::STOP2 => true,
})
.datalen().bits(match config.wordlength {
WordLength::DataBits7 => 0,
WordLength::DataBits8 => 1,
WordLength::DataBits9 => 2,
})
.loop_().normal()
.syncen().asynchronous_mode()
.clkpol().falling_edge()
.enable().enabled()
});
let mut best_diff = !0;
let mut best_osr = 15;
let mut best_brg = !0;
for osr in (9..=16).rev() {
let brg = Self::CLOCK_SPEED / (osr * speed);
if brg >= 0xffff {
continue;
}
let realized_speed = Self::CLOCK_SPEED / (osr * brg);
let diff = if speed > realized_speed { speed - realized_speed} else { realized_speed - speed };
if diff < best_diff {
best_diff = diff;
best_osr = osr;
best_brg = brg;
}
}
if best_brg >= 0xffff {
panic!("baudrate not supported");
}
usart.brg.write(|w| unsafe { w.brgval().bits(best_brg as u16 - 1) });
usart.osr.write(|w| unsafe { w.osrval().bits(best_osr as u8 - 1) });
Self {
usart,
pins,
_tx: PhantomData,
_rx: PhantomData,
}
}
fn addr(&self) -> usize {
&(*self.usart) as *const _ as usize
}
pub fn split(self) -> (Tx<USART>, Rx<USART>) {
(
Tx {
addr: self.addr(),
_usart: PhantomData,
},
Rx {
addr: self.addr(),
_usart: PhantomData,
},
)
}
pub fn release(self) -> (USART, PINS) {
(self.usart, self.pins)
}
}
impl<TX, RX, USART, PINS> serial::Read<u8> for Serial<TX, RX, USART, PINS>
where
TX: PinId,
RX: PinId,
USART: Usart,
PINS: UsartPins<TX, RX, USART>,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let mut rx: Rx<USART> = Rx {
addr: self.addr(),
_usart: PhantomData,
};
rx.read()
}
}
impl<USART: Usart> serial::Read<u8> for Rx<USART> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let fifostat = self.fifostat.read();
if fifostat.rxnotempty().bit() {
let fiford = self.fiford.read();
if fiford.framerr().bit_is_set() {
return Err(nb::Error::Other(Error::Framing));
}
if fiford.parityerr().bit_is_set() {
return Err(nb::Error::Other(Error::Parity));
}
if fiford.rxnoise().bit_is_set() {
return Err(nb::Error::Other(Error::Noise));
}
if fifostat.rxerr().bit_is_set() {
self.fifocfg.modify(|_, w| w.emptyrx().set_bit());
self.fifostat.modify(|_, w| w.rxerr().set_bit());
return Err(nb::Error::Other(Error::Overrun));
}
Ok(fiford.rxdata().bits() as u8)
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<TX, RX, USART, PINS> serial::Write<u8> for Serial<TX, RX, USART, PINS>
where
TX: PinId,
RX: PinId,
USART: Usart,
PINS: UsartPins<TX, RX, USART>,
{
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let mut tx: Tx<USART> = Tx {
addr: self.addr(),
_usart: PhantomData,
};
tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let mut tx: Tx<USART> = Tx {
addr: self.addr(),
_usart: PhantomData,
};
tx.write(byte)
}
}
impl<USART: Usart> serial::Write<u8> for Tx<USART> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.stat.read().txidle().bit() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
if self.fifostat.read().txnotfull().bit() {
self.fifowr.write(|w| unsafe { w.bits(byte as u32) } );
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<USART: Usart> fmt::Write for Tx<USART>
where
Tx<USART>: serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
use crate::traits::wg::serial::Write;
let _ = s
.as_bytes()
.iter()
.map(|c| nb::block!(self.write(*c)))
.last();
Ok(())
}
}