use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use core::ops::DerefMut;
use core::pin::Pin;
use core::ptr;
use as_slice::{AsMutSlice, AsSlice};
use crate::dma;
use crate::hal::prelude::*;
use crate::hal::serial;
use crate::pac;
use crate::rcc::{BusClock, Enable, Reset};
use crate::state;
use nb::block;
use crate::pac::{RCC, UART4, UART5, UART7, USART1, USART2, USART3, USART6};
use crate::gpio::{self, Alternate};
use crate::rcc::Clocks;
use crate::{BitsPerSecond, U32Ext};
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
}
pub trait Pins<USART> {}
pub trait PinTx<USART> {}
pub trait PinRx<USART> {}
impl<USART, TX, RX> Pins<USART> for (TX, RX)
where
TX: PinTx<USART>,
RX: PinRx<USART>,
{
}
mod f7xx_pins {
use super::{PinRx, PinTx};
use crate::gpio::{self, Alternate};
use crate::pac::{UART4, UART5, UART7, USART1};
impl PinTx<USART1> for gpio::PB14<Alternate<4>> {}
impl PinRx<USART1> for gpio::PB15<Alternate<4>> {}
impl PinTx<UART4> for gpio::PA11<Alternate<6>> {}
impl PinRx<UART4> for gpio::PA12<Alternate<6>> {}
impl PinTx<UART4> for gpio::PD1<Alternate<8>> {}
impl PinRx<UART4> for gpio::PD0<Alternate<8>> {}
impl PinTx<UART4> for gpio::PH13<Alternate<8>> {}
impl PinRx<UART4> for gpio::PH14<Alternate<8>> {}
impl PinRx<UART4> for gpio::PI9<Alternate<8>> {}
impl PinTx<UART5> for gpio::PB6<Alternate<1>> {}
impl PinRx<UART5> for gpio::PB5<Alternate<1>> {}
impl PinTx<UART5> for gpio::PB9<Alternate<7>> {}
impl PinRx<UART5> for gpio::PB8<Alternate<7>> {}
impl PinTx<UART5> for gpio::PB13<Alternate<8>> {}
impl PinRx<UART5> for gpio::PB12<Alternate<8>> {}
impl PinTx<UART7> for gpio::PA15<Alternate<12>> {}
impl PinRx<UART7> for gpio::PA8<Alternate<12>> {}
impl PinTx<UART7> for gpio::PB4<Alternate<12>> {}
impl PinRx<UART7> for gpio::PB3<Alternate<12>> {}
}
impl PinTx<USART1> for gpio::PA9<Alternate<7>> {}
impl PinTx<USART1> for gpio::PB6<Alternate<7>> {}
impl PinTx<USART2> for gpio::PA2<Alternate<7>> {}
impl PinTx<USART2> for gpio::PD5<Alternate<7>> {}
impl PinTx<USART3> for gpio::PB10<Alternate<7>> {}
impl PinTx<USART3> for gpio::PC10<Alternate<7>> {}
impl PinTx<USART3> for gpio::PD8<Alternate<7>> {}
impl PinTx<UART4> for gpio::PA0<Alternate<8>> {}
impl PinTx<UART4> for gpio::PC10<Alternate<8>> {}
impl PinTx<UART5> for gpio::PC12<Alternate<8>> {}
impl PinTx<USART6> for gpio::PC6<Alternate<8>> {}
impl PinTx<USART6> for gpio::PG14<Alternate<8>> {}
impl PinTx<UART7> for gpio::PE8<Alternate<8>> {}
impl PinTx<UART7> for gpio::PF7<Alternate<8>> {}
impl PinRx<USART1> for gpio::PA10<Alternate<7>> {}
impl PinRx<USART1> for gpio::PB7<Alternate<7>> {}
impl PinRx<USART2> for gpio::PA3<Alternate<7>> {}
impl PinRx<USART2> for gpio::PD6<Alternate<7>> {}
impl PinRx<USART3> for gpio::PB11<Alternate<7>> {}
impl PinRx<USART3> for gpio::PC11<Alternate<7>> {}
impl PinRx<USART3> for gpio::PD9<Alternate<7>> {}
impl PinRx<UART4> for gpio::PA1<Alternate<8>> {}
impl PinRx<UART4> for gpio::PC11<Alternate<8>> {}
impl PinRx<UART5> for gpio::PD2<Alternate<8>> {}
impl PinRx<USART6> for gpio::PC7<Alternate<8>> {}
impl PinRx<USART6> for gpio::PG9<Alternate<8>> {}
impl PinRx<UART7> for gpio::PE7<Alternate<8>> {}
impl PinRx<UART7> for gpio::PF6<Alternate<8>> {}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
impl<USART, PINS> Serial<USART, PINS>
where
PINS: Pins<USART>,
USART: Instance,
{
pub fn new(usart: USART, pins: PINS, clocks: &Clocks, config: Config) -> Self {
let rcc = unsafe { &(*RCC::ptr()) };
USART::select_sysclock(rcc, config.sysclock);
unsafe {
USART::enable_unchecked();
}
let clk = if config.sysclock {
clocks.sysclk()
} else {
USART::clock(clocks)
};
let brr = match config.oversampling {
Oversampling::By8 => {
usart.cr1.modify(|_, w| w.over8().set_bit());
let usart_div = 2 * clk / config.baud_rate;
0xfff0 & usart_div | 0x0007 & ((usart_div & 0x000f) >> 1)
}
Oversampling::By16 => {
usart.cr1.modify(|_, w| w.over8().clear_bit());
clk / config.baud_rate
}
};
usart.brr.write(|w| unsafe { w.bits(brr) });
let ch = config.character_match.unwrap_or(0);
usart.cr2.write(|w| w.add().bits(ch));
usart.cr1.modify(|_, w| {
w
.te().enabled()
.re().enabled()
.ue().enabled();
match config.data_bits {
DataBits::Bits8 => w.m1().clear_bit().m0().bit8(),
DataBits::Bits9 => w.m1().clear_bit().m0().bit9(),
DataBits::Bits7 => w.m0().clear_bit().m1().bit7(),
};
match config.parity {
Parity::ParityEven => w.ps().even().pce().enabled(),
Parity::ParityOdd => w.ps().odd().pce().enabled(),
Parity::ParityNone => w.pce().disabled(),
}
});
usart.cr3.write(|w| w.dmat().enabled().dmar().enabled());
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::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().set_bit()),
Event::Error => self.usart.cr3.modify(|_, w| w.eie().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::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().clear_bit()),
Event::Error => self.usart.cr3.modify(|_, w| w.eie().clear_bit()),
}
}
pub fn split(self) -> (Tx<USART>, Rx<USART>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
pub fn release(self) -> (USART, PINS) {
(self.usart, self.pins)
}
}
impl<USART, PINS> serial::Read<u8> for Serial<USART, PINS>
where
USART: Instance,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let mut rx: Rx<USART> = Rx {
_usart: PhantomData,
};
rx.read()
}
}
impl<USART, PINS> serial::Write<u8> for Serial<USART, PINS>
where
USART: Instance,
{
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let mut tx: Tx<USART> = Tx {
_usart: PhantomData,
};
tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let mut tx: Tx<USART> = Tx {
_usart: PhantomData,
};
tx.write(byte)
}
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
impl<USART> Rx<USART>
where
USART: Instance,
Self: dma::Target,
{
pub fn read_all<B>(
self,
buffer: Pin<B>,
dma: &dma::Handle<<Self as dma::Target>::Instance, state::Enabled>,
stream: <Self as dma::Target>::Stream,
) -> dma::Transfer<Self, B, dma::Ready>
where
B: DerefMut + 'static,
B::Target: AsMutSlice<Element = u8>,
{
let address = &unsafe { &*USART::ptr() }.rdr as *const _ as _;
unsafe {
dma::Transfer::new(
dma,
stream,
buffer,
self,
address,
dma::Direction::PeripheralToMemory,
)
}
}
}
impl<USART> serial::Read<u8> for Rx<USART>
where
USART: Instance,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let isr = unsafe { (*USART::ptr()).isr.read() };
let icr = unsafe { &(*USART::ptr()).icr };
if isr.pe().bit_is_set() {
icr.write(|w| w.pecf().clear());
return Err(nb::Error::Other(Error::Parity));
}
if isr.fe().bit_is_set() {
icr.write(|w| w.fecf().clear());
return Err(nb::Error::Other(Error::Framing));
}
if isr.nf().bit_is_set() {
icr.write(|w| w.ncf().clear());
return Err(nb::Error::Other(Error::Noise));
}
if isr.ore().bit_is_set() {
icr.write(|w| w.orecf().clear());
return Err(nb::Error::Other(Error::Overrun));
}
if isr.rxne().bit_is_set() {
return Ok(unsafe {
(*USART::ptr()).rdr.read().rdr().bits() as u8
});
}
Err(nb::Error::WouldBlock)
}
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
impl<USART> Tx<USART>
where
Self: dma::Target,
USART: Instance,
{
pub fn write_all<B>(
self,
data: Pin<B>,
dma: &dma::Handle<<Self as dma::Target>::Instance, state::Enabled>,
stream: <Self as dma::Target>::Stream,
) -> dma::Transfer<Self, B, dma::Ready>
where
B: Deref + 'static,
B::Target: AsSlice<Element = u8>,
{
let usart = unsafe { &*USART::ptr() };
usart.icr.write(|w| w.tccf().clear());
unsafe {
dma::Transfer::new(
dma,
stream,
data,
self,
&usart.tdr as *const _ as _,
dma::Direction::MemoryToPeripheral,
)
}
}
}
impl<USART> serial::Write<u8> for Tx<USART>
where
USART: Instance,
{
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let isr = unsafe { (*USART::ptr()).isr.read() };
if isr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let isr = unsafe { (*USART::ptr()).isr.read() };
if isr.txe().bit_is_set() {
unsafe { ptr::write_volatile(&(*USART::ptr()).tdr as *const _ as *mut _, byte) }
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
pub struct Config {
pub baud_rate: BitsPerSecond,
pub oversampling: Oversampling,
pub character_match: Option<u8>,
pub sysclock: bool,
pub parity: Parity,
pub data_bits: DataBits,
}
pub enum Oversampling {
By8,
By16,
}
pub enum DataBits {
Bits8,
Bits9,
Bits7,
}
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
impl Default for Config {
fn default() -> Self {
Self {
baud_rate: 115_200.bps(),
oversampling: Oversampling::By16,
character_match: None,
sysclock: false,
parity: Parity::ParityNone,
data_bits: DataBits::Bits8,
}
}
}
#[derive(Debug)]
pub enum Event {
Rxne,
Txe,
CharacterMatch,
Error,
}
pub trait Instance: Deref<Target = pac::usart1::RegisterBlock> + Enable + Reset + BusClock {
fn ptr() -> *const pac::usart1::RegisterBlock;
fn select_sysclock(rcc: &pac::rcc::RegisterBlock, sys: bool);
}
macro_rules! impl_instance {
($(
$USARTX:ident: ($usartXsel:ident),
)+) => {
$(
impl Instance for $USARTX {
fn ptr() -> *const pac::usart1::RegisterBlock {
$USARTX::ptr()
}
fn select_sysclock(rcc: &pac::rcc::RegisterBlock, sys: bool) {
rcc.dckcfgr2.modify(|_, w| w.$usartXsel().bits(sys as _));
}
}
)+
}
}
#[cfg(any(feature = "device-selected",))]
impl_instance! {
USART1: (usart1sel),
USART2: (usart2sel),
USART3: (usart3sel),
UART4: (uart4sel),
UART5: (uart5sel),
USART6: (usart6sel),
UART7: (uart7sel),
}
impl<USART> fmt::Write for Tx<USART>
where
Tx<USART>: serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last();
Ok(())
}
}