Skip to content

Commit

Permalink
Support reunite in serial::{Rx,Tx}
Browse files Browse the repository at this point in the history
This becomes relevant as more functions like reconfigure are added to the
Serial structs.

Fixes stm32-rs#386.
  • Loading branch information
horazont committed Jan 9, 2022
1 parent 1c285b1 commit c608b8e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 23 deletions.
8 changes: 8 additions & 0 deletions examples/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
58 changes: 35 additions & 23 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ pub struct Serial<USART, PINS> {
}

pub struct ErasedSerial<USART> {
usart: USART,
tx: Tx<USART>,
rx: Rx<USART>,
}
Expand All @@ -209,7 +208,7 @@ pub struct Rx<USART> {

/// Serial transmitter
pub struct Tx<USART> {
_usart: PhantomData<USART>,
usart: USART,
}

impl<USART> Rx<USART> {
Expand All @@ -218,13 +217,21 @@ impl<USART> Rx<USART> {
_usart: PhantomData,
}
}

/// Reunite the two halves of a split serial
pub fn reunite(self, tx: Tx<USART>) -> ErasedSerial<USART> {
ErasedSerial { rx: self, tx }
}
}

impl<USART> Tx<USART> {
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<USART>) -> ErasedSerial<USART> {
ErasedSerial { tx: self, rx }
}
}

Expand All @@ -244,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());

Expand All @@ -255,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
Expand All @@ -267,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()
Expand All @@ -283,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.
Expand All @@ -295,7 +303,7 @@ where
config: impl Into<Config>,
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
Expand All @@ -312,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()),
}
}

Expand All @@ -323,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
Expand All @@ -365,7 +373,7 @@ where
{
/// Returns ownership of the borrowed register handles
pub fn release(self) -> (USART, PINS) {
(self.inner.usart, self.pins)
(self.inner.tx.usart, self.pins)
}

/// Erase the pins used for the Serial from the type
Expand All @@ -385,7 +393,11 @@ where
/// If a transmission is currently in progress, this returns
/// [`nb::Error::WouldBlock`].
#[inline(always)]
pub fn reconfigure(&mut self, config: impl Into<Config>, clocks: Clocks) -> nb::Result<(), ()> {
pub fn reconfigure(
&mut self,
config: impl Into<Config>,
clocks: Clocks,
) -> nb::Result<(), Infallible> {
self.inner.reconfigure(config, clocks)
}

Expand Down Expand Up @@ -476,7 +488,7 @@ macro_rules! hal {
PINS: Pins<$USARTX>,
{
#[allow(unused_unsafe)]
Serial { pins, inner: ErasedSerial{ usart, 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))
Expand Down

0 comments on commit c608b8e

Please sign in to comment.