diff --git a/examples/serial.rs b/examples/serial.rs index c1b2ef49..95cc78b7 100644 --- a/examples/serial.rs +++ b/examples/serial.rs @@ -88,5 +88,13 @@ fn main() -> ! { assert_eq!(received, sent); asm::bkpt(); + // And later reunite it again + let mut serial = tx.reunite(rx); + let sent = b'Z'; + block!(serial.write(sent)).ok(); + let received = block!(serial.read()).unwrap(); + assert_eq!(received, sent); + asm::bkpt(); + loop {} } diff --git a/src/serial.rs b/src/serial.rs index 881bd595..b3b11f11 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -185,8 +185,11 @@ use crate::pac::usart1 as uart_base; /// Serial abstraction pub struct Serial { - usart: USART, pins: PINS, + inner: ErasedSerial, +} + +pub struct ErasedSerial { tx: Tx, rx: Rx, } @@ -205,7 +208,7 @@ pub struct Rx { /// Serial transmitter pub struct Tx { - _usart: PhantomData, + usart: USART, } impl Rx { @@ -214,17 +217,25 @@ impl Rx { _usart: PhantomData, } } + + /// Reunite the two halves of a split serial + pub fn reunite(self, tx: Tx) -> ErasedSerial { + ErasedSerial { rx: self, tx } + } } impl Tx { - fn new() -> Self { - Self { - _usart: PhantomData, - } + fn new(usart: USART) -> Self { + Self { usart } + } + + /// Reunite the two halves of a split serial + pub fn reunite(self, rx: Rx) -> ErasedSerial { + ErasedSerial { tx: self, rx } } } -impl Serial +impl ErasedSerial where USART: Instance, { @@ -240,7 +251,8 @@ where // UE: enable USART // RE: enable receiver // TE: enable transceiver - self.usart + self.tx + .usart .cr1 .modify(|_r, w| w.ue().set_bit().re().set_bit().te().set_bit()); @@ -251,7 +263,7 @@ where // Configure baud rate let brr = USART::get_frequency(&clocks).0 / config.baudrate.0; assert!(brr >= 16, "impossible baud rate"); - self.usart.brr.write(|w| unsafe { w.bits(brr) }); + self.tx.usart.brr.write(|w| unsafe { w.bits(brr) }); // Configure parity and word length // Unlike most uart devices, the "word length" of this usart device refers to @@ -263,7 +275,7 @@ where Parity::ParityEven => (true, true, false), Parity::ParityOdd => (true, true, true), }; - self.usart.cr1.modify(|_r, w| { + self.tx.usart.cr1.modify(|_r, w| { w.m() .bit(word_length) .ps() @@ -279,7 +291,7 @@ where StopBits::STOP2 => 0b10, StopBits::STOP1P5 => 0b11, }; - self.usart.cr2.modify(|_r, w| w.stop().bits(stop_bits)); + self.tx.usart.cr2.modify(|_r, w| w.stop().bits(stop_bits)); } /// Reconfigure the USART instance. @@ -291,7 +303,7 @@ where config: impl Into, clocks: Clocks, ) -> nb::Result<(), Infallible> { - let sr = self.usart.sr.read(); + let sr = self.tx.usart.sr.read(); // if we're currently busy transmitting, we have to wait until that is // over -- regarding reception, we assume that the caller -- with // exclusive access to the Serial instance due to &mut self -- knows @@ -308,9 +320,9 @@ where /// register empty (TXE)_ interrupt 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::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().set_bit()), + Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().set_bit()), + Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().set_bit()), } } @@ -319,25 +331,25 @@ where /// register empty (TXE)_ interrupt 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::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().clear_bit()), + Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().clear_bit()), + Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().clear_bit()), } } /// Returns true if the line idle status is set pub fn is_idle(&self) -> bool { - self.usart.sr.read().idle().bit_is_set() + self.tx.usart.sr.read().idle().bit_is_set() } /// Returns true if the tx register is empty (and can accept data) pub fn is_tx_empty(&self) -> bool { - self.usart.sr.read().txe().bit_is_set() + self.tx.usart.sr.read().txe().bit_is_set() } /// Returns true if the rx register is not empty (and can be read) pub fn is_rx_not_empty(&self) -> bool { - self.usart.sr.read().rxne().bit_is_set() + self.tx.usart.sr.read().rxne().bit_is_set() } /// Clear idle line interrupt flag @@ -348,15 +360,85 @@ where } } + /// Separates the serial struct into separate channel objects for sending (Tx) and + /// receiving (Rx) + pub fn split(self) -> (Tx, Rx) { + (self.tx, self.rx) + } +} + +impl Serial +where + USART: Instance, +{ /// Returns ownership of the borrowed register handles pub fn release(self) -> (USART, PINS) { - (self.usart, self.pins) + (self.inner.tx.usart, self.pins) + } + + /// Erase the pins used for the Serial from the type + pub fn erase(self) -> ErasedSerial { + self.inner } /// Separates the serial struct into separate channel objects for sending (Tx) and /// receiving (Rx) + #[inline(always)] pub fn split(self) -> (Tx, Rx) { - (self.tx, self.rx) + self.inner.split() + } + + /// Reconfigure the USART instance. + /// + /// If a transmission is currently in progress, this returns + /// [`nb::Error::WouldBlock`]. + #[inline(always)] + pub fn reconfigure( + &mut self, + config: impl Into, + clocks: Clocks, + ) -> nb::Result<(), Infallible> { + self.inner.reconfigure(config, clocks) + } + + /// Starts listening to the USART by enabling the _Received data + /// ready to be read (RXNE)_ interrupt and _Transmit data + /// register empty (TXE)_ interrupt + #[inline(always)] + pub fn listen(&mut self, event: Event) { + self.inner.listen(event) + } + + /// Stops listening to the USART by disabling the _Received data + /// ready to be read (RXNE)_ interrupt and _Transmit data + /// register empty (TXE)_ interrupt + #[inline(always)] + pub fn unlisten(&mut self, event: Event) { + self.inner.unlisten(event) + } + + /// Returns true if the line idle status is set + #[inline(always)] + pub fn is_idle(&self) -> bool { + self.inner.is_idle() + } + + /// Returns true if the tx register is empty (and can accept data) + #[inline(always)] + pub fn is_tx_empty(&self) -> bool { + self.inner.is_tx_empty() + } + + /// Returns true if the rx register is not empty (and can be read) + #[inline(always)] + pub fn is_rx_not_empty(&self) -> bool { + self.inner.is_rx_not_empty() + } + + /// Clear idle line interrupt flag + #[inline(always)] + pub fn clear_idle_interrupt(&self) { + self.inner.clear_idle_interrupt() } } @@ -406,12 +488,12 @@ macro_rules! hal { PINS: Pins<$USARTX>, { #[allow(unused_unsafe)] - Serial { usart, pins, tx: Tx::new(), rx: Rx::new() }.init(config.into(), clocks, || { + Serial { pins, inner: ErasedSerial{ tx: Tx::new(usart), rx: Rx::new() }.init(config.into(), clocks, || { mapr.modify_mapr(|_, w| unsafe { #[allow(clippy::redundant_closure_call)] w.$usartX_remap().$bit(($closure)(PINS::REMAP)) }) - }) + }) } } } @@ -557,7 +639,7 @@ where } } -impl crate::hal::serial::Read for Serial +impl crate::hal::serial::Read for ErasedSerial where USART: Instance, { @@ -568,7 +650,7 @@ where } } -impl crate::hal::serial::Write for Serial +impl crate::hal::serial::Write for ErasedSerial where USART: Instance, { @@ -583,6 +665,32 @@ where } } +impl crate::hal::serial::Read for Serial +where + USART: Instance, +{ + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.inner.rx.read() + } +} + +impl crate::hal::serial::Write for Serial +where + USART: Instance, +{ + type Error = Infallible; + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.inner.tx.flush() + } + + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + self.inner.tx.write(byte) + } +} + impl core::fmt::Write for Tx where Tx: embedded_hal::serial::Write,