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

Deref for UTx, URx #515

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

### Added

- Serial Tx, Rx containing pins [#514]
- Serial Tx, Rx containing pins [#514] [#515]
- 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 @@ -39,7 +39,8 @@ 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
[#514]: https://github.com/stm32-rs/stm32f4xx-hal/pull/514
[#515]: https://github.com/stm32-rs/stm32f4xx-hal/pull/515

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

Expand Down
240 changes: 72 additions & 168 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};

use crate::rcc;
use nb::block;
Expand Down Expand Up @@ -309,107 +310,77 @@ impl<USART: Instance, WORD> Tx<USART, WORD> {
}

impl<USART, PINS, WORD> AsRef<Tx<USART, WORD>> for Serial<USART, PINS, WORD> {
#[inline(always)]
fn as_ref(&self) -> &Tx<USART, WORD> {
&self.tx
}
}

impl<USART, PINS, WORD> AsRef<Rx<USART, WORD>> for Serial<USART, PINS, WORD> {
#[inline(always)]
fn as_ref(&self) -> &Rx<USART, WORD> {
&self.rx
}
}

impl<USART, PINS, WORD> AsMut<Tx<USART, WORD>> for Serial<USART, PINS, WORD> {
#[inline(always)]
fn as_mut(&mut self) -> &mut Tx<USART, WORD> {
&mut self.tx
}
}

impl<USART, PINS, WORD> AsMut<Rx<USART, WORD>> for Serial<USART, PINS, WORD> {
#[inline(always)]
fn as_mut(&mut self) -> &mut Rx<USART, WORD> {
&mut self.rx
}
}

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

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

impl<USART: Instance, RX, WORD> URx<USART, RX, WORD> {
fn new(pin: RX) -> Self {
Self {
_usart: PhantomData,
inner: Rx::new(),
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();
pub fn join<TX>(self, tx: UTx<USART, TX, WORD>) -> Serial<USART, (TX, RX), WORD>
where
(TX, RX): Pins<USART>,
{
Serial {
usart: tx.usart,
pins: (tx.pin, self.pin),
tx: tx.inner,
rx: self.inner,
}
}
}

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

Expand All @@ -424,28 +395,67 @@ impl<USART: Instance, TX, WORD> UTx<USART, TX, WORD> {
Serial {
usart: self.usart,
pins: (self.pin, rx.pin),
tx: Tx::new(),
rx: Rx::new(),
tx: self.inner,
rx: rx.inner,
}
}
}

/// 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()) }
impl<USART, TX, WORD> AsRef<Tx<USART, WORD>> for UTx<USART, TX, WORD> {
#[inline(always)]
fn as_ref(&self) -> &Tx<USART, WORD> {
&self.inner
}
}

/// Stop listening for the tx empty interrupt event
pub fn unlisten(&mut self) {
unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().clear_bit()) }
impl<USART, TX, WORD> Deref for UTx<USART, TX, WORD> {
type Target = Tx<USART, WORD>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}

/// 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() }
impl<USART, RX, WORD> AsRef<Rx<USART, WORD>> for URx<USART, RX, WORD> {
#[inline(always)]
fn as_ref(&self) -> &Rx<USART, WORD> {
&self.inner
}
}

impl<USART, RX, WORD> Deref for URx<USART, RX, WORD> {
type Target = Rx<USART, WORD>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<USART, TX, WORD> AsMut<Tx<USART, WORD>> for UTx<USART, TX, WORD> {
#[inline(always)]
fn as_mut(&mut self) -> &mut Tx<USART, WORD> {
&mut self.inner
}
}

impl<USART, TX, WORD> DerefMut for UTx<USART, TX, WORD> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

impl<USART, RX, WORD> AsMut<Rx<USART, WORD>> for URx<USART, RX, WORD> {
#[inline(always)]
fn as_mut(&mut self) -> &mut Rx<USART, WORD> {
&mut self.inner
}
}

impl<USART, RX, WORD> DerefMut for URx<USART, RX, WORD> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

Expand Down Expand Up @@ -1035,109 +1045,3 @@ 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())
}
}
Loading