Skip to content

Commit

Permalink
Deref for UTx
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Aug 15, 2022
1 parent 1e12e92 commit 2553bd9
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 286 deletions.
228 changes: 60 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 @@ -334,82 +335,48 @@ 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>,
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 +391,59 @@ 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> {
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>;
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> {
fn as_ref(&self) -> &Rx<USART, WORD> {
&self.inner
}
}

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

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

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

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

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

Expand Down Expand Up @@ -1035,109 +1033,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

0 comments on commit 2553bd9

Please sign in to comment.