use core::fmt;
use core::marker::PhantomData;
use core::ptr;
use core::sync::atomic::{self, Ordering};
use core::ops::DerefMut;
use stable_deref_trait::StableDeref;
use as_slice::AsMutSlice;
use cast::u16;
use crate::hal::serial::{self, Write};
use nb;
use crate::stm32::{USART1, USART2};
use void::Void;
use crate::gpio::gpioa::{PA10, PA2, PA3, PA9};
use crate::gpio::gpiod::{PD5, PD6};
use crate::gpio::gpiob::{PB6, PB7};
use crate::gpio::{AF7, Alternate, Input, Floating};
use crate::rcc::{APB1R1, APB2, Clocks};
use crate::time::Bps;
use crate::dma::{dma1, CircBuffer};
pub enum Event {
Rxne,
Txe,
Idle
}
#[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<AF7, Input<Floating>>>, PA10<Alternate<AF7, Input<Floating>>>) {
const REMAP: u8 = 0;
}
impl Pins<USART1> for (PB6<Alternate<AF7, Input<Floating>>>, PB7<Alternate<AF7, Input<Floating>>>) {
const REMAP: u8 = 1;
}
impl Pins<USART2> for (PA2<Alternate<AF7, Input<Floating>>>, PA3<Alternate<AF7, Input<Floating>>>) {
const REMAP: u8 = 0;
}
impl Pins<USART2> for (PD5<Alternate<AF7, Input<Floating>>>, PD6<Alternate<AF7, Input<Floating>>>) {
const REMAP: u8 = 0;
}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
macro_rules! hal {
($(
$USARTX:ident: ($usartX:ident, $APB:ident, $usartXen:ident, $usartXrst:ident, $pclkX:ident, tx: ($dmacst:ident, $tx_chan:path), rx: ($dmacsr:ident, $rx_chan:path)),
)+) => {
$(
impl<PINS> Serial<$USARTX, PINS> {
pub fn $usartX(
usart: $USARTX,
pins: PINS,
baud_rate: Bps,
clocks: Clocks,
apb: &mut $APB,
) -> Self
where
PINS: Pins<$USARTX>,
{
apb.enr().modify(|_, w| w.$usartXen().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
usart.cr3.write(|w| w.dmat().set_bit().dmar().set_bit());
let brr = clocks.$pclkX().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())
},
}
}
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())
},
}
}
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
pub fn free(self) -> ($USARTX, PINS) {
(self.usart, self.pins)
}
}
impl serial::Read<u8> for Rx<$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
Err(if isr.pe().bit_is_set() {
nb::Error::Other(Error::Parity)
} else if isr.fe().bit_is_set() {
nb::Error::Other(Error::Framing)
} else if isr.nf().bit_is_set() {
nb::Error::Other(Error::Noise)
} else if isr.ore().bit_is_set() {
nb::Error::Other(Error::Overrun)
} else if isr.rxne().bit_is_set() {
return Ok(unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _ as *const _)
});
} else {
nb::Error::WouldBlock
})
}
}
impl serial::Write<u8> for Tx<$USARTX> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Void> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
if isr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
if isr.txe().bit_is_set() {
unsafe {
ptr::write_volatile(&(*$USARTX::ptr()).tdr as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl Rx<$USARTX> {
pub fn circ_read<B, H>(
&self,
mut chan: $rx_chan,
mut buffer: B,
) -> CircBuffer<B, $rx_chan>
where
B: StableDeref<Target = [H; 2]> + DerefMut,
H: AsMutSlice<Element = u8>
{
{
chan.cmar().write(|w| {
w.ma().bits(buffer[0].as_mut_slice().as_ptr() as usize as u32)
});
chan.cndtr().write(|w|{
w.ndt().bits(u16(buffer[0].as_mut_slice().len() * 2).unwrap())
});
chan.cpar().write(|w| unsafe {
w.pa().bits(&(*$USARTX::ptr()).rdr as *const _ as usize as u32)
});
chan.cselr().write(|w| {
w.$dmacsr().bits(0b0010)
});
atomic::compiler_fence(Ordering::SeqCst);
chan.ccr().modify(|_, w| unsafe {
w.mem2mem()
.clear_bit()
.pl()
.bits(0b01)
.msize()
.bits(0b00)
.psize()
.bits(0b00)
.minc()
.set_bit()
.pinc()
.clear_bit()
.circ()
.set_bit()
.dir()
.clear_bit()
.en()
.set_bit()
});
}
CircBuffer::new(buffer, chan)
}
pub fn is_idle(&mut self, clear: bool) -> bool {
let isr = unsafe { &(*$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*$USARTX::ptr()).icr };
if isr.idle().bit_is_set() {
if clear {
icr.write(|w| {
w.idlecf()
.set_bit()
});
}
true
} else {
false
}
}
}
)+
}
}
hal! {
USART1: (usart1, APB2, usart1en, usart1rst, pclk2, tx: (c4s, dma1::C4), rx: (c5s, dma1::C5)),
USART2: (usart2, APB1R1, usart2en, usart2rst, pclk1, tx: (c7s, dma1::C7), rx: (c6s, dma1::C6)),
}
impl<USART> fmt::Write for Tx<USART>
where
Tx<USART>: crate::hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s
.as_bytes()
.into_iter()
.map(|c| nb::block!(self.write(*c)))
.last();
Ok(())
}
}