Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Rx/Tx reunification for Serial #390

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {}
}
162 changes: 135 additions & 27 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,11 @@ use crate::pac::usart1 as uart_base;

/// Serial abstraction
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
inner: ErasedSerial<USART>,
}

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

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

impl<USART> Rx<USART> {
Expand All @@ -214,17 +217,25 @@ 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 }
}
}

impl<USART, PINS> Serial<USART, PINS>
impl<USART> ErasedSerial<USART>
where
USART: Instance,
{
Expand All @@ -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());

Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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.
Expand All @@ -291,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 @@ -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()),
}
}

Expand All @@ -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
Expand All @@ -348,15 +360,85 @@ where
}
}

/// Separates the serial struct into separate channel objects for sending (Tx) and
/// receiving (Rx)
pub fn split(self) -> (Tx<USART>, Rx<USART>) {
(self.tx, self.rx)
}
}

impl<USART, PINS> Serial<USART, PINS>
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<USART> {
self.inner
}

/// Separates the serial struct into separate channel objects for sending (Tx) and
/// receiving (Rx)
#[inline(always)]
pub fn split(self) -> (Tx<USART>, Rx<USART>) {
(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<Config>,
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()
}
}

Expand Down Expand Up @@ -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))
})
})
}) }
}
}

Expand Down Expand Up @@ -557,7 +639,7 @@ where
}
}

impl<USART, PINS> crate::hal::serial::Read<u8> for Serial<USART, PINS>
impl<USART> crate::hal::serial::Read<u8> for ErasedSerial<USART>
where
USART: Instance,
{
Expand All @@ -568,7 +650,7 @@ where
}
}

impl<USART, PINS> crate::hal::serial::Write<u8> for Serial<USART, PINS>
impl<USART> crate::hal::serial::Write<u8> for ErasedSerial<USART>
where
USART: Instance,
{
Expand All @@ -583,6 +665,32 @@ where
}
}

impl<USART, PINS> crate::hal::serial::Read<u8> for Serial<USART, PINS>
where
USART: Instance,
{
type Error = Error;

fn read(&mut self) -> nb::Result<u8, Error> {
self.inner.rx.read()
}
}

impl<USART, PINS> crate::hal::serial::Write<u8> for Serial<USART, PINS>
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<USART> core::fmt::Write for Tx<USART>
where
Tx<USART>: embedded_hal::serial::Write<u8>,
Expand Down