Skip to content

Commit 4f15555

Browse files
committed
Implement embedded-io traits for uarte types.
1 parent 574005a commit 4f15555

File tree

1 file changed

+122
-6
lines changed

1 file changed

+122
-6
lines changed

nrf-hal-common/src/uarte.rs

Lines changed: 122 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
//!
55
//! - nrf52832: Section 35
66
//! - nrf52840: Section 6.34
7+
8+
use core::cmp::min;
79
use core::fmt;
10+
use core::hint::spin_loop;
811
use core::ops::Deref;
912
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
10-
1113
use embedded_hal_02::blocking::serial as bserial;
1214
use embedded_hal_02::digital::v2::OutputPin;
1315
use embedded_hal_02::serial;
16+
use embedded_io::{ErrorKind, ErrorType, ReadReady, WriteReady};
1417

1518
#[cfg(any(feature = "52833", feature = "52840"))]
1619
use crate::pac::UARTE1;
1720

1821
#[cfg(feature = "9160")]
1922
use crate::pac::{
20-
uarte0_ns as uarte0,
21-
UARTE0_NS as UARTE0,
22-
UARTE1_NS as UARTE1,
23-
UARTE2_NS as UARTE2,
23+
uarte0_ns as uarte0, UARTE0_NS as UARTE0, UARTE1_NS as UARTE1, UARTE2_NS as UARTE2,
2424
UARTE3_NS as UARTE3,
2525
};
2626

@@ -421,6 +421,9 @@ fn start_read(uarte: &uarte0::RegisterBlock, rx_buffer: &mut [u8]) -> Result<(),
421421
uarte.tasks_startrx.write(|w|
422422
// `1` is a valid value to write to task registers.
423423
unsafe { w.bits(1) });
424+
while uarte.events_rxstarted.read().bits() == 0 {
425+
spin_loop();
426+
}
424427

425428
Ok(())
426429
}
@@ -492,6 +495,20 @@ pub enum Error {
492495
BufferNotInRAM,
493496
}
494497

498+
impl embedded_io::Error for Error {
499+
fn kind(&self) -> ErrorKind {
500+
match self {
501+
Self::TxBufferTooSmall
502+
| Self::RxBufferTooSmall
503+
| Self::TxBufferTooLong
504+
| Self::RxBufferTooLong
505+
| Self::BufferNotInRAM => ErrorKind::InvalidInput,
506+
Self::Transmit | Self::Receive => ErrorKind::Interrupted,
507+
Self::Timeout(_) => ErrorKind::TimedOut,
508+
}
509+
}
510+
}
511+
495512
pub trait Instance: Deref<Target = uarte0::RegisterBlock> + sealed::Sealed {
496513
fn ptr() -> *const uarte0::RegisterBlock;
497514
}
@@ -662,6 +679,52 @@ where
662679
}
663680
}
664681

682+
impl<T: Instance> ErrorType for UarteTx<T> {
683+
type Error = Error;
684+
}
685+
686+
impl<T: Instance> WriteReady for UarteTx<T> {
687+
fn write_ready(&mut self) -> Result<bool, Self::Error> {
688+
let uarte = unsafe { &*T::ptr() };
689+
690+
let dma_transfer_in_progress =
691+
uarte.events_txstarted.read().bits() == 1 && uarte.events_endtx.read().bits() == 0;
692+
693+
Ok(!dma_transfer_in_progress && self.written < self.tx_buf.len())
694+
}
695+
}
696+
697+
impl<T: Instance> embedded_io::Write for UarteTx<T> {
698+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
699+
if buf.is_empty() {
700+
return Ok(0);
701+
}
702+
703+
// If the internal buffer is full or a DMA transfer is in progress, flush and block until it
704+
// is finished.
705+
if !self.write_ready()? {
706+
nb::block!(serial::Write::flush(self))?;
707+
}
708+
709+
// Copy as many bytes as possible to the internal TX buffer.
710+
let length_to_copy = min(buf.len(), self.tx_buf.len() - self.written);
711+
self.tx_buf[self.written..].copy_from_slice(&buf[..length_to_copy]);
712+
self.written += length_to_copy;
713+
714+
// If the internal buffer is now full, flush but don't block.
715+
match serial::Write::flush(self) {
716+
Err(nb::Error::Other(e)) => return Err(e),
717+
_ => {}
718+
}
719+
720+
Ok(length_to_copy)
721+
}
722+
723+
fn flush(&mut self) -> Result<(), Self::Error> {
724+
nb::block!(serial::Write::flush(self))
725+
}
726+
}
727+
665728
impl<T> serial::Write<u8> for UarteTx<T>
666729
where
667730
T: Instance,
@@ -748,6 +811,59 @@ where
748811
}
749812
}
750813

814+
impl<T: Instance> ErrorType for UarteRx<T> {
815+
type Error = Error;
816+
}
817+
818+
impl<T: Instance> ReadReady for UarteRx<T> {
819+
fn read_ready(&mut self) -> Result<bool, Self::Error> {
820+
let uarte = unsafe { &*T::ptr() };
821+
822+
compiler_fence(SeqCst);
823+
824+
if uarte.events_rxstarted.read().bits() == 0 {
825+
start_read(uarte, self.rx_buf)?;
826+
Ok(false)
827+
} else {
828+
Ok(uarte.events_endrx.read().bits() != 0)
829+
}
830+
}
831+
}
832+
833+
impl<T: Instance> embedded_io::Read for UarteRx<T> {
834+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
835+
if buf.is_empty() {
836+
return Ok(0);
837+
}
838+
839+
let uarte = unsafe { &*T::ptr() };
840+
841+
compiler_fence(SeqCst);
842+
843+
// This complexity to handle in-progress reads is needed because calls to this read method
844+
// might be interleaved with calls to serial::Read::read.
845+
846+
// If no read transaction is started yet, start one and wait for it to start.
847+
if uarte.events_rxstarted.read().bits() == 0 {
848+
start_read(&uarte, self.rx_buf)?;
849+
}
850+
851+
// Wait for the transaction to finish.
852+
while uarte.events_endrx.read().bits() == 0 {
853+
spin_loop();
854+
}
855+
856+
// Tidy up and return the byte read.
857+
uarte.events_rxstarted.reset();
858+
finalize_read(uarte);
859+
if uarte.rxd.amount.read().bits() != 1 {
860+
return Err(Error::Receive);
861+
}
862+
buf[0] = self.rx_buf[0];
863+
Ok(1)
864+
}
865+
}
866+
751867
impl<T> serial::Read<u8> for UarteRx<T>
752868
where
753869
T: Instance,
@@ -768,7 +884,7 @@ where
768884

769885
finalize_read(uarte);
770886

771-
if uarte.rxd.amount.read().bits() != 1 as u32 {
887+
if uarte.rxd.amount.read().bits() != 1 {
772888
return Err(nb::Error::Other(Error::Receive));
773889
}
774890
Ok(self.rx_buf[0])

0 commit comments

Comments
 (0)