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

Serial Tx, Rx containing pins #514

Merged
merged 1 commit into from
Aug 15, 2022
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Serial Tx, Rx containing pins [#514]
- Implementation of From trait for Pin-to-PartiallyErasedPin [#507]
- Implementation of From trait for Pin-to-ErasedPin [#507]
- Implementation of From trait for PartiallyErasedPin-to-ErasedPin [#507]
Expand All @@ -38,6 +39,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
[#507]: https://github.com/stm32-rs/stm32f4xx-hal/pull/507
[#508]: https://github.com/stm32-rs/stm32f4xx-hal/pull/508
[#510]: https://github.com/stm32-rs/stm32f4xx-hal/pull/510
[#510]: https://github.com/stm32-rs/stm32f4xx-hal/pull/514

## [v0.13.2] - 2022-05-16

Expand Down
229 changes: 229 additions & 0 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,123 @@ impl<USART, PINS, WORD> AsMut<Rx<USART, WORD>> for Serial<USART, PINS, WORD> {
}
}

/// Serial receiver containing RX pin
pub struct URx<USART, RX, WORD = u8> {
_usart: PhantomData<USART>,
pin: RX,
_word: PhantomData<WORD>,
}

/// Serial transmitter containing TX pin
pub struct UTx<USART, TX, WORD = u8> {
usart: USART,
pin: TX,
_word: PhantomData<WORD>,
}

impl<USART: Instance, RX, WORD> URx<USART, RX, WORD> {
fn new(pin: RX) -> Self {
Self {
_usart: PhantomData,
pin,
_word: PhantomData,
}
}

pub fn erase(self) -> Rx<USART, WORD> {
Rx::new()
}

/// Start listening for an rx not empty interrupt event
///
/// Note, you will also have to enable the corresponding interrupt
/// in the NVIC to start receiving events.
pub fn listen(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().set_bit()) }
}

/// Stop listening for the rx not empty interrupt event
pub fn unlisten(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().clear_bit()) }
}

/// Start listening for a line idle interrupt event
///
/// Note, you will also have to enable the corresponding interrupt
/// in the NVIC to start receiving events.
pub fn listen_idle(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()) }
}

/// Stop listening for the line idle interrupt event
pub fn unlisten_idle(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()) }
}

/// Return true if the line idle status is set
pub fn is_idle(&self) -> bool {
unsafe { (*USART::ptr()).sr.read().idle().bit_is_set() }
}

/// Return true if the rx register is not empty (and can be read)
pub fn is_rx_not_empty(&self) -> bool {
unsafe { (*USART::ptr()).sr.read().rxne().bit_is_set() }
}

/// Clear idle line interrupt flag
pub fn clear_idle_interrupt(&self) {
unsafe {
let _ = (*USART::ptr()).sr.read();
let _ = (*USART::ptr()).dr.read();
}
}
}

impl<USART: Instance, TX, WORD> UTx<USART, TX, WORD> {
fn new(usart: USART, pin: TX) -> Self {
Self {
usart,
pin,
_word: PhantomData,
}
}

pub fn erase(self) -> Tx<USART, WORD> {
Tx::new()
}

pub fn join<RX>(self, rx: URx<USART, RX, WORD>) -> Serial<USART, (TX, RX), WORD>
where
(TX, RX): Pins<USART>,
{
Serial {
usart: self.usart,
pins: (self.pin, rx.pin),
tx: Tx::new(),
rx: Rx::new(),
}
}

/// Start listening for a tx empty interrupt event
///
/// Note, you will also have to enable the corresponding interrupt
/// in the NVIC to start receiving events.
// TODO: replace with "self.usart"
pub fn listen(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().set_bit()) }
}

/// Stop listening for the tx empty interrupt event
pub fn unlisten(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().clear_bit()) }
}

/// Return true if the tx register is empty (and can accept data)
pub fn is_tx_empty(&self) -> bool {
unsafe { (*USART::ptr()).sr.read().txe().bit_is_set() }
}
}

pub trait SerialExt: Sized + Instance {
fn serial<TX, RX, WORD>(
self,
Expand Down Expand Up @@ -614,6 +731,12 @@ impl<USART: Instance, PINS, WORD> Serial<USART, PINS, WORD> {
}
}

impl<USART: Instance, TX, RX, WORD> Serial<USART, (TX, RX), WORD> {
pub fn split_nondestructive(self) -> (UTx<USART, TX, WORD>, URx<USART, RX, WORD>) {
(UTx::new(self.usart, self.pins.0), URx::new(self.pins.1))
}
burrbull marked this conversation as resolved.
Show resolved Hide resolved
}

impl<USART: Instance, PINS> Serial<USART, PINS, u8> {
/// Converts this Serial into a version that can read and write `u16` values instead of `u8`s
///
Expand Down Expand Up @@ -912,3 +1035,109 @@ impl<USART: Instance> Tx<USART, u16> {
nb::block!(self.flush())
}
}

impl<USART: Instance, TX> fmt::Write for UTx<USART, TX> {
fn write_str(&mut self, s: &str) -> fmt::Result {
s.bytes()
.try_for_each(|c| block!(self.write(c)))
.map_err(|_| fmt::Error)
}
}

impl<USART: Instance, RX> URx<USART, RX, u8> {
fn read(&mut self) -> nb::Result<u8, Error> {
// Delegate to the Read<u16> implementation, then truncate to 8 bits
Rx::<USART, u16>::new().read().map(|word16| word16 as u8)
}
}

impl<USART: Instance, RX> URx<USART, RX, u16> {
fn read(&mut self) -> nb::Result<u16, Error> {
// NOTE(unsafe) atomic read with no side effects
let sr = unsafe { (*USART::ptr()).sr.read() };

// Any error requires the dr to be read to clear
if sr.pe().bit_is_set()
|| sr.fe().bit_is_set()
|| sr.nf().bit_is_set()
|| sr.ore().bit_is_set()
{
unsafe { (*USART::ptr()).dr.read() };
}

Err(if sr.pe().bit_is_set() {
Error::Parity.into()
} else if sr.fe().bit_is_set() {
Error::FrameFormat.into()
} else if sr.nf().bit_is_set() {
Error::Noise.into()
} else if sr.ore().bit_is_set() {
Error::Overrun.into()
} else if sr.rxne().bit_is_set() {
// NOTE(unsafe) atomic read from stateless register
return Ok(unsafe { &*USART::ptr() }.dr.read().dr().bits());
} else {
nb::Error::WouldBlock
})
}
}

impl<USART: Instance, TX> UTx<USART, TX, u8> {
fn write(&mut self, word: u8) -> nb::Result<(), Error> {
// Delegate to u16 version
Tx::<USART, u16>::new().write(u16::from(word))
}

fn flush(&mut self) -> nb::Result<(), Error> {
// Delegate to u16 version
Tx::<USART, u16>::new().flush()
}

fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
for &b in bytes {
nb::block!(self.write(b))?;
}
Ok(())
}

fn bflush(&mut self) -> Result<(), Error> {
nb::block!(self.flush())
}
}

impl<USART: Instance, TX> UTx<USART, TX, u16> {
fn write(&mut self, word: u16) -> nb::Result<(), Error> {
// NOTE(unsafe) atomic read with no side effects
let sr = unsafe { (*USART::ptr()).sr.read() };

if sr.txe().bit_is_set() {
// NOTE(unsafe) atomic write to stateless register
unsafe { &*USART::ptr() }.dr.write(|w| w.dr().bits(word));
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}

fn flush(&mut self) -> nb::Result<(), Error> {
// NOTE(unsafe) atomic read with no side effects
let sr = unsafe { (*USART::ptr()).sr.read() };

if sr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}

fn bwrite_all(&mut self, buffer: &[u16]) -> Result<(), Error> {
for &b in buffer {
nb::block!(self.write(b))?;
}
Ok(())
}

fn bflush(&mut self) -> Result<(), Error> {
nb::block!(self.flush())
}
}
58 changes: 55 additions & 3 deletions src/serial/hal_02.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod nb {
use super::super::{Error, Instance, Rx, Serial, Tx};
use super::super::{Error, Instance, Rx, Serial, Tx, URx, UTx};
use embedded_hal::serial::{Read, Write};

impl<USART, PINS, WORD> Read<WORD> for Serial<USART, PINS, WORD>
Expand All @@ -22,6 +22,14 @@ mod nb {
}
}

impl<USART: Instance, RX> Read<u8> for URx<USART, RX, u8> {
type Error = Error;

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

/// Reads 9-bit words from the UART/USART
///
/// If the UART/USART was configured with `WordLength::DataBits9`, the returned value will contain
Expand All @@ -35,6 +43,14 @@ mod nb {
}
}

impl<USART: Instance, RX> Read<u16> for URx<USART, RX, u16> {
type Error = Error;

fn read(&mut self) -> nb::Result<u16, Self::Error> {
self.read()
}
}

impl<USART, PINS, WORD> Write<WORD> for Serial<USART, PINS, WORD>
where
USART: Instance,
Expand All @@ -51,7 +67,7 @@ mod nb {
}
}

impl<USART: Instance> Write<u8> for Tx<USART, u8> {
impl<USART: Instance, TX> Write<u8> for UTx<USART, TX, u8> {
type Error = Error;

fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
Expand Down Expand Up @@ -79,10 +95,22 @@ mod nb {
self.flush()
}
}

impl<USART: Instance, TX> Write<u16> for UTx<USART, TX, u16> {
type Error = Error;

fn write(&mut self, word: u16) -> nb::Result<(), Self::Error> {
self.write(word)
}

fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.flush()
}
}
}

mod blocking {
use super::super::{Error, Instance, Serial, Tx};
use super::super::{Error, Instance, Serial, Tx, UTx};
use embedded_hal::blocking::serial::Write;

impl<USART: Instance> Write<u8> for Tx<USART, u8> {
Expand All @@ -97,6 +125,18 @@ mod blocking {
}
}

impl<USART: Instance, TX> Write<u8> for UTx<USART, TX, u8> {
type Error = Error;

fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
self.bwrite_all(bytes)
}

fn bflush(&mut self) -> Result<(), Self::Error> {
self.bflush()
}
}

impl<USART: Instance, PINS> Write<u8> for Serial<USART, PINS, u8> {
type Error = Error;

Expand All @@ -121,6 +161,18 @@ mod blocking {
}
}

impl<USART: Instance, TX> Write<u16> for UTx<USART, TX, u16> {
type Error = Error;

fn bwrite_all(&mut self, slice: &[u16]) -> Result<(), Self::Error> {
self.bwrite_all(slice)
}

fn bflush(&mut self) -> Result<(), Self::Error> {
self.bflush()
}
}

impl<USART: Instance, PINS> Write<u16> for Serial<USART, PINS, u16> {
type Error = Error;

Expand Down
Loading