diff --git a/rp2040-hal/src/uart/mod.rs b/rp2040-hal/src/uart/mod.rs index d980e93..729f865 100644 --- a/rp2040-hal/src/uart/mod.rs +++ b/rp2040-hal/src/uart/mod.rs @@ -35,11 +35,15 @@ mod peripheral; mod pins; +mod reader; mod utils; +mod writer; pub use self::peripheral::UartPeripheral; pub use self::pins::*; +pub use self::reader::{ReadError, ReadErrorType, Reader}; pub use self::utils::*; +pub use self::writer::Writer; /// Common configurations for UART. pub mod common_configs; diff --git a/rp2040-hal/src/uart/peripheral.rs b/rp2040-hal/src/uart/peripheral.rs index 385342c..cb6e83e 100644 --- a/rp2040-hal/src/uart/peripheral.rs +++ b/rp2040-hal/src/uart/peripheral.rs @@ -39,6 +39,7 @@ use embedded_time::fixed_point::FixedPoint; use embedded_time::rate::Baud; use embedded_time::rate::Hertz; use nb::Error::{Other, WouldBlock}; +use rp2040_pac::{UART0, UART1}; /// An UART Peripheral based on an underlying UART device. pub struct UartPeripheral> { @@ -139,47 +140,13 @@ impl> UartPeripheral { self.transition(Disabled) } - pub(crate) fn transmit_flushed(&self) -> nb::Result<(), Infallible> { - if self.device.uartfr.read().txfe().bit_is_set() { - Ok(()) - } else { - Err(WouldBlock) - } - } - - fn uart_is_writable(&self) -> bool { - self.device.uartfr.read().txff().bit_is_clear() - } - - fn uart_is_readable(&self) -> bool { - self.device.uartfr.read().rxfe().bit_is_clear() - } - /// Writes bytes to the UART. /// This function writes as long as it can. As soon that the FIFO is full, if : /// - 0 bytes were written, a WouldBlock Error is returned /// - some bytes were written, it is deemed to be a success /// Upon success, the remaining slice is returned. pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { - let mut bytes_written = 0; - - for c in data { - if !self.uart_is_writable() { - if bytes_written == 0 { - return Err(WouldBlock); - } else { - return Ok(&data[bytes_written..]); - } - } - - self.device.uartdr.write(|w| unsafe { - w.data().bits(*c); - w - }); - - bytes_written += 1; - } - Ok(&data[bytes_written..]) + super::writer::write_raw(&self.device, data) } /// Reads bytes from the UART. @@ -188,83 +155,73 @@ impl> UartPeripheral { /// - some bytes were read, it is deemed to be a success /// Upon success, it will return how many bytes were read. pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result> { - let mut bytes_read = 0; - - Ok(loop { - if !self.uart_is_readable() { - if bytes_read == 0 { - return Err(WouldBlock); - } else { - break bytes_read; - } - } - - if bytes_read < buffer.len() { - let mut error: Option = None; - - let read = self.device.uartdr.read(); - - if read.oe().bit_is_set() { - error = Some(ReadErrorType::Overrun); - } - - if read.be().bit_is_set() { - error = Some(ReadErrorType::Break); - } - - if read.pe().bit_is_set() { - error = Some(ReadErrorType::Parity); - } - - if read.fe().bit_is_set() { - error = Some(ReadErrorType::Framing); - } - - if let Some(err_type) = error { - return Err(Other(ReadError { - err_type, - discared: buffer, - })); - } - - buffer[bytes_read] = read.data().bits(); - bytes_read += 1; - } else { - break bytes_read; - } - }) + super::reader::read_raw(&self.device, buffer) } /// Writes bytes to the UART. /// This function blocks until the full buffer has been sent. pub fn write_full_blocking(&self, data: &[u8]) { - let mut temp = data; - - while !temp.is_empty() { - temp = match self.write_raw(temp) { - Ok(remaining) => remaining, - Err(WouldBlock) => continue, - Err(_) => unreachable!(), - } - } + super::writer::write_full_blocking(&self.device, data); } /// Reads bytes from the UART. /// This function blocks until the full buffer has been received. pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> { - let mut offset = 0; + super::reader::read_full_blocking(&self.device, buffer) + } - while offset != buffer.len() { - offset += match self.read_raw(&mut buffer[offset..]) { - Ok(bytes_read) => bytes_read, - Err(e) => match e { - Other(inner) => return Err(inner.err_type), - WouldBlock => continue, - }, - } + /// Join the reader and writer halves together back into the original Uart peripheral. + /// + /// A reader/writer pair can be obtained by calling [`split`]. + pub fn join(reader: Reader, writer: Writer) -> Self { + let _ = writer; + Self { + device: reader.device, + _state: Enabled, + pins: reader.pins, + config: reader.config, + effective_baudrate: reader.effective_baudrate, } + } +} - Ok(()) +impl> UartPeripheral { + /// Split this peripheral into a separate reader and writer. + pub fn split(self) -> (Reader, Writer) { + let reader = Reader { + device: self.device, + pins: self.pins, + config: self.config, + effective_baudrate: self.effective_baudrate, + }; + // Safety: reader and writer will never write to the same address + let device_copy = unsafe { &*UART0::ptr() }; + let writer = Writer { + device: device_copy, + device_marker: core::marker::PhantomData, + pins: core::marker::PhantomData, + }; + (reader, writer) + } +} + +impl> UartPeripheral { + /// Split this peripheral into a separate reader and writer. + pub fn split(self) -> (Reader, Writer) { + let reader = Reader { + device: self.device, + pins: self.pins, + config: self.config, + effective_baudrate: self.effective_baudrate, + }; + // Safety: reader and writer will never write to the same address + let device_copy = unsafe { &*UART1::ptr() }; + let writer = Writer { + device: device_copy, + device_marker: core::marker::PhantomData, + pins: core::marker::PhantomData, + }; + (reader, writer) } } @@ -390,30 +347,6 @@ impl> eh1::Read for UartPeripheral) -> core::fmt::Result { - match *self {} - } -} - -#[cfg(feature = "eh1_0_alpha")] -impl eh1_0_alpha::serial::Error for SerialInfallible { - fn kind(&self) -> eh1_0_alpha::serial::ErrorKind { - match *self {} - } -} - impl> Write for UartPeripheral { type Error = Infallible; @@ -426,7 +359,7 @@ impl> Write for UartPeripheral nb::Result<(), Self::Error> { - self.transmit_flushed() + super::writer::transmit_flushed(&self.device) } } @@ -443,7 +376,7 @@ impl> eh1::Write for UartPeripheral nb::Result<(), Self::Error> { - self.transmit_flushed().map_err(|e| match e { + super::writer::transmit_flushed(&self.device).map_err(|e| match e { WouldBlock => WouldBlock, Other(v) => match v {}, }) diff --git a/rp2040-hal/src/uart/reader.rs b/rp2040-hal/src/uart/reader.rs new file mode 100644 index 0000000..b6e126d --- /dev/null +++ b/rp2040-hal/src/uart/reader.rs @@ -0,0 +1,176 @@ +use super::{UartConfig, UartDevice, ValidUartPinout}; +use embedded_hal::serial::Read; +use embedded_time::rate::Baud; +use nb::Error::*; + +#[cfg(feature = "eh1_0_alpha")] +use eh1_0_alpha::serial::nb as eh1; + +/// When there's a read error. +pub struct ReadError<'err> { + /// The type of error + pub err_type: ReadErrorType, + + /// Reference to the data that was read but eventually discared because of the error. + pub discared: &'err [u8], +} + +/// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register" +#[cfg_attr(feature = "eh1_0_alpha", derive(Debug))] +pub enum ReadErrorType { + /// Triggered when the FIFO (or shift-register) is overflowed. + Overrun, + + /// Triggered when a break is received + Break, + + /// Triggered when there is a parity mismatch between what's received and our settings. + Parity, + + /// Triggered when the received character didn't have a valid stop bit. + Framing, +} + +#[cfg(feature = "eh1_0_alpha")] +impl eh1_0_alpha::serial::Error for ReadErrorType { + fn kind(&self) -> eh1_0_alpha::serial::ErrorKind { + match self { + ReadErrorType::Overrun => eh1_0_alpha::serial::ErrorKind::Overrun, + ReadErrorType::Break => eh1_0_alpha::serial::ErrorKind::Other, + ReadErrorType::Parity => eh1_0_alpha::serial::ErrorKind::Parity, + ReadErrorType::Framing => eh1_0_alpha::serial::ErrorKind::FrameFormat, + } + } +} + +pub(crate) fn is_readable(device: &D) -> bool { + device.uartfr.read().rxfe().bit_is_clear() +} + +pub(crate) fn read_raw<'b, D: UartDevice>( + device: &D, + buffer: &'b mut [u8], +) -> nb::Result> { + let mut bytes_read = 0; + + Ok(loop { + if !is_readable(device) { + if bytes_read == 0 { + return Err(WouldBlock); + } else { + break bytes_read; + } + } + + if bytes_read < buffer.len() { + let mut error: Option = None; + + let read = device.uartdr.read(); + + if read.oe().bit_is_set() { + error = Some(ReadErrorType::Overrun); + } + + if read.be().bit_is_set() { + error = Some(ReadErrorType::Break); + } + + if read.pe().bit_is_set() { + error = Some(ReadErrorType::Parity); + } + + if read.fe().bit_is_set() { + error = Some(ReadErrorType::Framing); + } + + if let Some(err_type) = error { + return Err(Other(ReadError { + err_type, + discared: buffer, + })); + } + + buffer[bytes_read] = read.data().bits(); + bytes_read += 1; + } else { + break bytes_read; + } + }) +} + +pub(crate) fn read_full_blocking( + device: &D, + buffer: &mut [u8], +) -> Result<(), ReadErrorType> { + let mut offset = 0; + + while offset != buffer.len() { + offset += match read_raw(device, &mut buffer[offset..]) { + Ok(bytes_read) => bytes_read, + Err(e) => match e { + Other(inner) => return Err(inner.err_type), + WouldBlock => continue, + }, + } + } + + Ok(()) +} + +/// Half of an [`UartPeripheral`] that is only capable of reading. Obtained by calling [`UartPeripheral::split()`] +pub struct Reader> { + pub(super) device: D, + pub(super) pins: P, + pub(super) config: UartConfig, + pub(super) effective_baudrate: Baud, +} + +impl> Reader { + /// Reads bytes from the UART. + /// This function reads as long as it can. As soon that the FIFO is empty, if : + /// - 0 bytes were read, a WouldBlock Error is returned + /// - some bytes were read, it is deemed to be a success + /// Upon success, it will return how many bytes were read. + pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result> { + read_raw(&self.device, buffer) + } + + /// Reads bytes from the UART. + /// This function blocks until the full buffer has been received. + pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> { + read_full_blocking(&self.device, buffer) + } +} + +impl> Read for Reader { + type Error = ReadErrorType; + + fn read(&mut self) -> nb::Result { + let byte: &mut [u8] = &mut [0; 1]; + + match self.read_raw(byte) { + Ok(_) => Ok(byte[0]), + Err(e) => match e { + Other(inner) => Err(Other(inner.err_type)), + WouldBlock => Err(WouldBlock), + }, + } + } +} + +#[cfg(feature = "eh1_0_alpha")] +impl> eh1::Read for Reader { + type Error = ReadErrorType; + + fn read(&mut self) -> nb::Result { + let byte: &mut [u8] = &mut [0; 1]; + + match self.read_raw(byte) { + Ok(_) => Ok(byte[0]), + Err(e) => match e { + Other(inner) => Err(Other(inner.err_type)), + WouldBlock => Err(WouldBlock), + }, + } + } +} diff --git a/rp2040-hal/src/uart/utils.rs b/rp2040-hal/src/uart/utils.rs index 8997b7c..9d9e540 100644 --- a/rp2040-hal/src/uart/utils.rs +++ b/rp2040-hal/src/uart/utils.rs @@ -9,49 +9,11 @@ pub enum Error { /// Bad argument : when things overflow, ... BadArgument, } - -/// When there's a read error. -pub struct ReadError<'err> { - /// The type of error - pub err_type: ReadErrorType, - - /// Reference to the data that was read but eventually discared because of the error. - pub discared: &'err [u8], -} - -/// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register" -#[cfg_attr(feature = "eh1_0_alpha", derive(Debug))] -pub enum ReadErrorType { - /// Triggered when the FIFO (or shift-register) is overflowed. - Overrun, - - /// Triggered when a break is received - Break, - - /// Triggered when there is a parity mismatch between what's received and our settings. - Parity, - - /// Triggered when the received character didn't have a valid stop bit. - Framing, -} - -#[cfg(feature = "eh1_0_alpha")] -impl eh1_0_alpha::serial::Error for ReadErrorType { - fn kind(&self) -> eh1_0_alpha::serial::ErrorKind { - match self { - ReadErrorType::Overrun => eh1_0_alpha::serial::ErrorKind::Overrun, - ReadErrorType::Break => eh1_0_alpha::serial::ErrorKind::Other, - ReadErrorType::Parity => eh1_0_alpha::serial::ErrorKind::Parity, - ReadErrorType::Framing => eh1_0_alpha::serial::ErrorKind::FrameFormat, - } - } -} - /// State of the UART Peripheral. pub trait State {} /// Trait to handle both underlying devices (UART0 & UART1) -pub trait UartDevice: Deref + SubsystemReset {} +pub trait UartDevice: Deref + SubsystemReset + 'static {} impl UartDevice for UART0 {} impl UartDevice for UART1 {} @@ -111,3 +73,26 @@ pub struct UartConfig { /// The parity that this uart should have pub parity: Option, } + +/// Same as core::convert::Infallible, but implementing spi::Error +/// +/// For eh 1.0.0-alpha.6, Infallible doesn't implement spi::Error, +/// so use a locally defined type instead. +/// This should be removed with the next release of e-h. +/// (https://github.com/rust-embedded/embedded-hal/pull/328) +#[cfg(feature = "eh1_0_alpha")] +pub enum SerialInfallible {} + +#[cfg(feature = "eh1_0_alpha")] +impl core::fmt::Debug for SerialInfallible { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self {} + } +} + +#[cfg(feature = "eh1_0_alpha")] +impl eh1_0_alpha::serial::Error for SerialInfallible { + fn kind(&self) -> eh1_0_alpha::serial::ErrorKind { + match *self {} + } +} diff --git a/rp2040-hal/src/uart/writer.rs b/rp2040-hal/src/uart/writer.rs new file mode 100644 index 0000000..7b81808 --- /dev/null +++ b/rp2040-hal/src/uart/writer.rs @@ -0,0 +1,126 @@ +use super::{UartDevice, ValidUartPinout}; +use core::fmt; +use core::{convert::Infallible, marker::PhantomData}; +use embedded_hal::serial::Write; +use nb::Error::*; +use rp2040_pac::uart0::RegisterBlock; + +#[cfg(feature = "eh1_0_alpha")] +use eh1_0_alpha::serial::nb as eh1; + +pub(crate) fn transmit_flushed(rb: &RegisterBlock) -> nb::Result<(), Infallible> { + if rb.uartfr.read().txfe().bit_is_set() { + Ok(()) + } else { + Err(WouldBlock) + } +} + +fn uart_is_writable(rb: &RegisterBlock) -> bool { + rb.uartfr.read().txff().bit_is_clear() +} + +pub(crate) fn write_raw<'d>( + rb: &RegisterBlock, + data: &'d [u8], +) -> nb::Result<&'d [u8], Infallible> { + let mut bytes_written = 0; + + for c in data { + if !uart_is_writable(rb) { + if bytes_written == 0 { + return Err(WouldBlock); + } else { + return Ok(&data[bytes_written..]); + } + } + + rb.uartdr.write(|w| unsafe { + w.data().bits(*c); + w + }); + + bytes_written += 1; + } + Ok(&data[bytes_written..]) +} + +pub(crate) fn write_full_blocking(rb: &RegisterBlock, data: &[u8]) { + let mut temp = data; + + while !temp.is_empty() { + temp = match write_raw(rb, temp) { + Ok(remaining) => remaining, + Err(WouldBlock) => continue, + Err(_) => unreachable!(), + } + } +} + +/// Half of an [`UartPeripheral`] that is only capable of writing. Obtained by calling [`UartPeripheral::split()`] +pub struct Writer> { + pub(super) device: &'static RegisterBlock, + pub(super) device_marker: PhantomData, + pub(super) pins: PhantomData

, +} + +impl> Writer { + /// Writes bytes to the UART. + /// This function writes as long as it can. As soon that the FIFO is full, if : + /// - 0 bytes were written, a WouldBlock Error is returned + /// - some bytes were written, it is deemed to be a success + /// Upon success, the remaining slice is returned. + pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { + write_raw(self.device, data) + } + + /// Writes bytes to the UART. + /// This function blocks until the full buffer has been sent. + pub fn write_full_blocking(&self, data: &[u8]) { + super::writer::write_full_blocking(self.device, data); + } +} + +impl> Write for Writer { + type Error = Infallible; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + if self.write_raw(&[word]).is_err() { + Err(WouldBlock) + } else { + Ok(()) + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + super::writer::transmit_flushed(self.device) + } +} + +#[cfg(feature = "eh1_0_alpha")] +impl> eh1::Write for Writer { + type Error = super::utils::SerialInfallible; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + if self.write_raw(&[word]).is_err() { + Err(WouldBlock) + } else { + Ok(()) + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + transmit_flushed(&self.device).map_err(|e| match e { + WouldBlock => WouldBlock, + Other(v) => match v {}, + }) + } +} + +impl> fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + s.bytes() + .try_for_each(|c| nb::block!(self.write(c))) + .map_err(|_| fmt::Error) + } +}