use core::fmt;
use core::marker::PhantomData;
use crate::hal::prelude::*;
use crate::hal::serial;
use nb::{self, block};
pub use tm4c123x::{UART0, UART1, UART2, UART3, UART4, UART5, UART6, UART7};
use void::Void;
use crate::gpio::{gpioa, gpiob, gpioc, gpiod, gpioe, gpiof};
use crate::gpio::{AlternateFunction, OutputMode, AF1, AF2, AF8};
use crate::sysctl;
use crate::sysctl::Clocks;
use crate::time::Bps;
pub unsafe trait TxPin<UART> {}
pub unsafe trait RxPin<UART> {}
pub unsafe trait RtsPin<UART> {
fn enable(&mut self, _uart: &mut UART) {}
}
pub unsafe trait CtsPin<UART> {
fn enable(&mut self, _uart: &mut UART) {}
}
unsafe impl CtsPin<UART0> for () {}
unsafe impl RtsPin<UART0> for () {}
unsafe impl CtsPin<UART1> for () {}
unsafe impl RtsPin<UART1> for () {}
unsafe impl CtsPin<UART2> for () {}
unsafe impl RtsPin<UART2> for () {}
unsafe impl CtsPin<UART3> for () {}
unsafe impl RtsPin<UART3> for () {}
unsafe impl CtsPin<UART4> for () {}
unsafe impl RtsPin<UART4> for () {}
unsafe impl CtsPin<UART5> for () {}
unsafe impl RtsPin<UART5> for () {}
unsafe impl CtsPin<UART6> for () {}
unsafe impl RtsPin<UART6> for () {}
unsafe impl CtsPin<UART7> for () {}
unsafe impl RtsPin<UART7> for () {}
unsafe impl<T> CtsPin<UART1> for gpiof::PF1<AlternateFunction<AF1, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut UART1) {
uart.ctl.modify(|_, w| w.ctsen().set_bit());
}
}
unsafe impl<T> CtsPin<UART1> for gpioc::PC5<AlternateFunction<AF8, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut UART1) {
uart.ctl.modify(|_, w| w.ctsen().set_bit());
}
}
unsafe impl<T> RtsPin<UART1> for gpioc::PC4<AlternateFunction<AF8, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut UART1) {
uart.ctl.modify(|_, w| w.rtsen().set_bit());
}
}
unsafe impl<T> RtsPin<UART1> for gpiof::PF0<AlternateFunction<AF1, T>>
where
T: OutputMode,
{
fn enable(&mut self, uart: &mut UART1) {
uart.ctl.modify(|_, w| w.rtsen().set_bit());
}
}
unsafe impl<T> RxPin<UART0> for gpioa::PA0<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART1> for gpiob::PB0<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART1> for gpioc::PC4<AlternateFunction<AF2, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART2> for gpiod::PD6<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART3> for gpioc::PC6<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART4> for gpioc::PC4<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART5> for gpioe::PE4<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART6> for gpiod::PD4<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> RxPin<UART7> for gpioe::PE0<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART0> for gpioa::PA1<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART1> for gpiob::PB1<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART1> for gpioc::PC5<AlternateFunction<AF2, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART2> for gpiod::PD7<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART3> for gpioc::PC7<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART4> for gpioc::PC5<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART5> for gpioe::PE5<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART6> for gpiod::PD5<AlternateFunction<AF1, T>> where T: OutputMode {}
unsafe impl<T> TxPin<UART7> for gpioe::PE1<AlternateFunction<AF1, T>> where T: OutputMode {}
pub struct Serial<UART, TX, RX, RTS, CTS> {
uart: UART,
tx_pin: TX,
rx_pin: RX,
rts_pin: RTS,
cts_pin: CTS,
nl_mode: NewlineMode,
}
#[derive(PartialEq, Clone, Copy)]
pub enum NewlineMode {
Binary,
SwapLFtoCRLF,
}
pub struct Rx<UART, RX, CTS> {
_uart: PhantomData<UART>,
pin: RX,
flow_pin: CTS,
}
pub struct Tx<UART, TX, RTS> {
uart: UART,
pin: TX,
flow_pin: RTS,
nl_mode: NewlineMode,
}
macro_rules! hal {
($(
$UARTX:ident: ($powerDomain:ident, $uartX:ident),
)+) => {
$(
impl<TX, RX, RTS, CTS> Serial<$UARTX, TX, RX, RTS, CTS> {
/// Configures a UART peripheral to provide serial communication
pub fn $uartX(
mut uart: $UARTX,
tx_pin: TX,
rx_pin: RX,
mut rts_pin: RTS,
mut cts_pin: CTS,
baud_rate: Bps,
nl_mode: NewlineMode,
clocks: &Clocks,
pc: &sysctl::PowerControl
) -> Self
where
TX: TxPin<$UARTX>,
RX: RxPin<$UARTX>,
CTS: CtsPin<$UARTX>,
RTS: RtsPin<$UARTX>,
{
sysctl::control_power(
pc, sysctl::Domain::$powerDomain,
sysctl::RunMode::Run, sysctl::PowerState::On);
sysctl::reset(pc, sysctl::Domain::$powerDomain);
uart.ctl.reset();
let baud_int: u32 = (((clocks.sysclk.0 * 8) / baud_rate.0) + 1) / 2;
uart.ibrd.write(|w|
unsafe { w.divint().bits((baud_int / 64) as u16) });
uart.fbrd.write(|w|
unsafe { w.divfrac().bits((baud_int % 64) as u8) });
uart.lcrh.write(|w| w.wlen()._8().fen().bit(true));
rts_pin.enable(&mut uart);
cts_pin.enable(&mut uart);
uart.ctl.modify(|_, w| w.rxe().bit(true).txe().bit(true).uarten().bit(true));
Serial { uart, tx_pin, rx_pin, rts_pin, cts_pin, nl_mode }
}
pub fn split(self) -> (Tx<$UARTX, TX, RTS>, Rx<$UARTX, RX, CTS>) {
(
Tx {
uart: self.uart,
pin: self.tx_pin,
nl_mode: self.nl_mode,
flow_pin: self.rts_pin,
},
Rx {
_uart: PhantomData,
pin: self.rx_pin,
flow_pin: self.cts_pin,
},
)
}
pub fn write_all<I: ?Sized>(&mut self, data: &I)
where
I: AsRef<[u8]>,
{
for octet in data.as_ref().iter() {
block!(self.write(*octet)).unwrap(); }
}
pub fn combine(tx: Tx<$UARTX, TX, RTS>, rx: Rx<$UARTX, RX, CTS>) -> Serial<$UARTX, TX, RX, RTS, CTS> {
Serial {
uart: tx.uart,
nl_mode: tx.nl_mode,
rx_pin: rx.pin,
tx_pin: tx.pin,
rts_pin: tx.flow_pin,
cts_pin: rx.flow_pin,
}
}
pub fn free(self) -> ($UARTX, TX, RX, RTS, CTS) {
(self.uart, self.tx_pin, self.rx_pin, self.rts_pin, self.cts_pin)
}
}
impl<TX, RTS> Tx<$UARTX, TX, RTS> {
pub fn write_all<I: ?Sized>(&mut self, data: &I)
where
I: AsRef<[u8]>,
{
for octet in data.as_ref().iter() {
block!(self.write(*octet)).unwrap(); }
}
}
impl<TX, RX, RTS, CTS> serial::Read<u8> for Serial<$UARTX, TX, RX, RTS, CTS> {
type Error = Void;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if self.uart.fr.read().rxfe().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(self.uart.dr.read().data().bits())
}
}
impl<RX, CTS> serial::Read<u8> for Rx<$UARTX, RX, CTS> {
type Error = Void;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let p = unsafe { &*$UARTX::ptr() };
if p.fr.read().rxfe().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(p.dr.read().data().bits())
}
}
impl<TX, RX, RTS, CTS> serial::Write<u8> for Serial<$UARTX, TX, RX, RTS, CTS> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
self.uart.dr.write(|w| unsafe { w.data().bits(byte) });
Ok(())
}
}
impl<TX, RTS> serial::Write<u8> for Tx<$UARTX, TX, RTS> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
if self.uart.fr.read().txff().bit() {
return Err(nb::Error::WouldBlock);
}
self.uart.dr.write(|w| unsafe { w.data().bits(byte) });
Ok(())
}
}
impl<TX, RX, RTS, CTS> fmt::Write for Serial<$UARTX, TX, RX, RTS, CTS> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.nl_mode {
NewlineMode::Binary => self.write_all(s),
NewlineMode::SwapLFtoCRLF => {
for byte in s.bytes() {
if byte == 0x0A {
block!(self.write(0x0D)).unwrap(); }
block!(self.write(byte)).unwrap(); }
}
}
Ok(())
}
}
impl<TX, RTS> fmt::Write for Tx<$UARTX, TX, RTS> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.nl_mode {
NewlineMode::Binary => self.write_all(s),
NewlineMode::SwapLFtoCRLF => {
for byte in s.bytes() {
if byte == 0x0A {
block!(self.write(0x0D)).unwrap(); }
block!(self.write(byte)).unwrap(); }
}
}
Ok(())
}
}
)+
}
}
hal! {
UART0: (Uart0, uart0),
UART1: (Uart1, uart1),
UART2: (Uart2, uart2),
UART3: (Uart3, uart3),
UART4: (Uart4, uart4),
UART5: (Uart5, uart5),
UART6: (Uart6, uart6),
UART7: (Uart7, uart7),
}