use core::marker::PhantomData;
use core::ptr;
use core::sync::atomic::{self, Ordering};
use core::any::TypeId;
use cast::u16;
use nb;
use crate::device::{USART1, USART2, USART3};
use void::Void;
use crate::afio::MAPR;
use crate::dma::{dma1, CircBuffer, Static, Transfer, R, W};
use crate::gpio::gpioa::{PA10, PA2, PA3, PA9};
use crate::gpio::gpiob::{PB10, PB11, PB6, PB7};
use crate::gpio::{Alternate, Floating, Input, PushPull};
use crate::rcc::{APB1, APB2, Clocks};
use crate::time::Bps;
use embedded_hal::serial::Write;
pub enum Event {
Rxne,
Txe,
Idle,
Tc,
}
#[derive(Debug)]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
#[doc(hidden)]
_Extensible,
}
pub trait Pins<USART> {
const REMAP: u8;
}
impl Pins<USART1> for (PA9<Alternate<PushPull>>, PA10<Input<Floating>>) {
const REMAP: u8 = 0;
}
impl Pins<USART1> for (PB6<Alternate<PushPull>>, PB7<Input<Floating>>) {
const REMAP: u8 = 1;
}
impl Pins<USART2> for (PA2<Alternate<PushPull>>, PA3<Input<Floating>>) {
const REMAP: u8 = 0;
}
impl Pins<USART3> for (PB10<Alternate<PushPull>>, PB11<Input<Floating>>) {
const REMAP: u8 = 0;
}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
pub struct ReleaseToken<USART, PINS> {
serial: Serial<USART, PINS>
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
impl<USART, PINS: Pins<USART>> ReleaseToken<USART, PINS> {
pub fn release(self, _rx: Rx<USART>, mut tx: Tx<USART>) -> Serial<USART, PINS>
where Tx<USART>: crate::hal::serial::Write<u8> {
nb::block!(tx.flush()).ok();
self.serial
}
}
macro_rules! hal {
($(
$USARTX:ident: (
$usartX:ident,
$usartXen:ident,
$usartXrst:ident,
$usartX_remap:ident,
$bit:ident,
$closure:expr,
$APB:ident
),
)+) => {
$(
impl<PINS> Serial<$USARTX, PINS> {
pub fn $usartX(
usart: $USARTX,
pins: PINS,
mapr: &mut MAPR,
baud_rate: Bps,
clocks: Clocks,
apb: &mut $APB,
) -> Self
where
PINS: Pins<$USARTX>,
{
apb.enr().modify(|_, w| w.$usartXen().enabled());
apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
#[allow(unused_unsafe)]
mapr.mapr()
.modify(|_, w| unsafe{
w.$usartX_remap().$bit(($closure)(PINS::REMAP))
});
usart.cr3.write(|w| w.dmat().set_bit().dmar().set_bit());
let bus_freq = if TypeId::of::<$APB>() == TypeId::of::<APB1>() {
clocks.pclk1()
} else if TypeId::of::<$APB>() == TypeId::of::<APB2>() {
clocks.pclk2()
} else {
unreachable!()
};
let brr = bus_freq.0 / baud_rate.0;
assert!(brr >= 16, "impossible baud rate");
usart.brr.write(|w| unsafe { w.bits(brr) });
usart
.cr1
.write(|w| w.ue().set_bit().re().set_bit().te().set_bit());
Serial { usart, pins }
}
pub fn listen(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().set_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().set_bit()),
Event::Idle => self.usart.cr1.modify(|_, w| w.idleie().set_bit()),
Event::Tc => self.usart.cr1.modify(|_, w| w.tcie().set_bit()),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().clear_bit()),
Event::Idle => self.usart.cr1.modify(|_, w| w.idleie().clear_bit()),
Event::Tc => self.usart.cr1.modify(|_, w| w.tcie().clear_bit()),
}
}
pub fn release(self) -> ($USARTX, PINS) {
(self.usart, self.pins)
}
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>, ReleaseToken<$USARTX, PINS>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
ReleaseToken {
serial: self
},
)
}
}
impl crate::hal::serial::Read<u8> for Rx<$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
let err = if sr.pe().bit_is_set() {
Some(Error::Parity)
} else if sr.fe().bit_is_set() {
Some(Error::Framing)
} else if sr.ne().bit_is_set() {
Some(Error::Noise)
} else if sr.ore().bit_is_set() {
Some(Error::Overrun)
} else {
None
};
if let Some(err) = err {
unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).sr as *const _ as *const _);
ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _);
}
Err(nb::Error::Other(err))
} else {
if sr.rxne().bit_is_set() {
Ok(unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _)
})
} else {
Err(nb::Error::WouldBlock)
}
}
}
}
impl<B> ReadDma<B> for Rx<$USARTX> where B: AsMut<[u8]> {
fn circ_read(self, mut chan: Self::Dma, buffer: &'static mut [B; 2],
) -> CircBuffer<B, Self::Dma, Self>
{
{
let buffer = buffer[0].as_mut();
chan.cmar().write(|w| unsafe {
w.ma().bits(buffer.as_ptr() as usize as u32)
});
chan.cndtr().write(|w| unsafe{
w.ndt().bits(u16(buffer.len() * 2).unwrap())
});
chan.cpar().write(|w| unsafe {
w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
});
atomic::compiler_fence(Ordering::SeqCst);
chan.ccr().modify(|_, w| {
w.mem2mem()
.clear_bit()
.pl()
.medium()
.msize()
.bit8()
.psize()
.bit8()
.minc()
.set_bit()
.pinc()
.clear_bit()
.circ()
.set_bit()
.dir()
.clear_bit()
.en()
.set_bit()
});
}
CircBuffer::new(buffer, chan, self)
}
fn read_exact(self, mut chan: Self::Dma, buffer: &'static mut B,
) -> Transfer<W, &'static mut B, Self::Dma, Self>
{
{
let buffer = buffer.as_mut();
chan.cmar().write(|w| unsafe {
w.ma().bits(buffer.as_ptr() as usize as u32)
});
chan.cndtr().write(|w| unsafe{
w.ndt().bits(u16(buffer.len()).unwrap())
});
chan.cpar().write(|w| unsafe {
w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
});
atomic::compiler_fence(Ordering::SeqCst);
chan.ccr().modify(|_, w| {
w.mem2mem()
.clear_bit()
.pl()
.medium()
.msize()
.bit8()
.psize()
.bit8()
.minc()
.set_bit()
.pinc()
.clear_bit()
.circ()
.clear_bit()
.dir()
.clear_bit()
.en()
.set_bit()
});
}
Transfer::w(buffer, chan, self)
}
}
impl<A, B> WriteDma<A, B> for Tx<$USARTX> where A: AsRef<[u8]> + ?Sized, B: Static<A> {
fn write_all(self, mut chan: Self::Dma, buffer: B) -> Transfer<R, B, Self::Dma, Self>
{
self.start_dma(&mut chan, &buffer.borrow());
Transfer::r(buffer, chan, self)
}
}
impl<B: AsRef<[u8]>> DmaWriter<B> for Tx<$USARTX> {
fn start_dma(&self, chan: &mut Self::Dma, buffer:& B) {
let buffer = buffer.as_ref();
chan.cmar().write(|w| unsafe {
w.ma().bits(buffer.as_ptr() as usize as u32)
});
chan.cndtr().write(|w| unsafe{
w.ndt().bits(u16(buffer.len()).unwrap())
});
chan.cpar().write(|w| unsafe {
w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
});
atomic::compiler_fence(Ordering::SeqCst);
chan.ccr().modify(|_, w| {
w.mem2mem()
.clear_bit()
.pl()
.medium()
.msize()
.bit8()
.psize()
.bit8()
.minc()
.set_bit()
.pinc()
.clear_bit()
.circ()
.clear_bit()
.dir()
.set_bit()
.en()
.set_bit()
});
}
}
impl<A> WriteDmaImmediately<A> for Tx<$USARTX> where A: AsRef<[u8]> + ?Sized {
fn write_immediately(&mut self, chan: &mut Self::Dma, buffer: &A) {
self.start_dma(chan, &buffer);
chan.wait_for_tranfer(buffer);
}
}
impl crate::hal::serial::Write<u8> for Tx<$USARTX> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
if sr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
if sr.txe().bit_is_set() {
unsafe {
ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
)+
}
}
hal! {
USART1: (
usart1,
usart1en,
usart1rst,
usart1_remap,
bit,
|remap| remap == 1,
APB2
),
USART2: (
usart2,
usart2en,
usart2rst,
usart2_remap,
bit,
|remap| remap == 1,
APB1
),
USART3: (
usart3,
usart3en,
usart3rst,
usart3_remap,
bits,
|remap| remap,
APB1
),
}
use crate::dma::DmaChannel;
impl DmaChannel for Rx<USART1> {
type Dma = dma1::C5;
}
impl DmaChannel for Tx<USART1> {
type Dma = dma1::C4;
}
impl DmaChannel for Rx<USART2> {
type Dma = dma1::C6;
}
impl DmaChannel for Tx<USART2> {
type Dma = dma1::C7;
}
impl DmaChannel for Rx<USART3> {
type Dma = dma1::C3;
}
impl DmaChannel for Tx<USART3> {
type Dma = dma1::C2;
}
pub trait ReadDma<B>: DmaChannel
where
B: AsMut<[u8]>,
Self: core::marker::Sized,
{
fn circ_read(self, chan: Self::Dma, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::Dma, Self>;
fn read_exact(
self,
chan: Self::Dma,
buffer: &'static mut B,
) -> Transfer<W, &'static mut B, Self::Dma, Self>;
}
trait DmaWriter<B: AsRef<[u8]> + ?Sized>: DmaChannel
where
Self: core::marker::Sized,
{
fn start_dma(&self, chan: &mut Self::Dma, buffer: &B);
}
pub trait WriteDma<A, B>: DmaChannel
where
A: AsRef<[u8]> + ?Sized,
B: Static<A>,
Self: core::marker::Sized,
{
fn write_all(self, chan: Self::Dma, buffer: B) -> Transfer<R, B, Self::Dma, Self>;
}
pub trait WriteDmaImmediately<A>: DmaChannel
where
A: AsRef<[u8]> + ?Sized,
Self: core::marker::Sized,
{
fn write_immediately(&mut self, chan: &mut Self::Dma, buffer: &A) -> ();
}