diff --git a/Cargo.toml b/Cargo.toml index 25cf58bf..77c9dd02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,10 @@ version = "0.2" package = "embedded-hal" version = "1.0.0" +[dependencies.eio06] +package = "embedded-io" +version = "0.6.1" + [dependencies.rand_core] version = "0.5" default-features = false diff --git a/src/common/lpuart.rs b/src/common/lpuart.rs index 337029a2..3dffe030 100644 --- a/src/common/lpuart.rs +++ b/src/common/lpuart.rs @@ -349,6 +349,35 @@ impl Lpuart { ral::modify_reg!(ral::lpuart, self.lpuart, BAUD, RDMAE: 0); } } + + /// Attempts to write a single byte to the bus. + /// + /// Returns `false` if the fifo was already full. + pub fn try_write(&mut self, byte: u8) -> bool { + ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, TXOF: TXOF_1); + self.write_byte(byte); + ral::read_reg!(ral::lpuart, self.lpuart, FIFO, TXOF == TXOF_0) + } + + /// Attempts to read a single byte from the bus. + /// + /// Returns: + /// - `Ok(Some(u8))` if data was read + /// - `Ok(None)` if the fifo was empty + /// - `Err(..)` if a read error happened + pub fn try_read(&mut self) -> Result, ReadFlags> { + let data = self.read_data(); + if data.flags().contains(ReadFlags::RXEMPT) { + Ok(None) + } else if data + .flags() + .intersects(ReadFlags::PARITY_ERROR | ReadFlags::FRAME_ERROR | ReadFlags::NOISY) + { + Err(data.flags()) + } else { + Ok(Some(data.into())) + } + } } fn flush_fifo(lpuart: &Instance, direction: Direction) { @@ -930,6 +959,88 @@ impl eh02::blocking::serial::Write for Lpuart { } } +impl eio06::Error for ReadFlags { + fn kind(&self) -> eio06::ErrorKind { + eio06::ErrorKind::Other + } +} + +impl eio06::ErrorType for Lpuart { + type Error = ReadFlags; +} + +impl eio06::WriteReady for Lpuart { + fn write_ready(&mut self) -> Result { + Ok(self.status().contains(Status::TRANSMIT_EMPTY)) + } +} + +impl eio06::ReadReady for Lpuart { + fn read_ready(&mut self) -> Result { + Ok(self.status().contains(Status::RECEIVE_FULL)) + } +} + +impl eio06::Write for Lpuart { + fn write(&mut self, buf: &[u8]) -> Result { + let mut num_written = 0; + for word in buf { + if num_written == 0 { + // For the first word, continue trying until we send. + // This function is supposed to block until at least one word is + // sent. + while !self.try_write(*word) {} + } else { + // If we already sent at least one word, return once + // the buffer is full + if !self.try_write(*word) { + break; + } + } + num_written += 1; + } + + Ok(num_written) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + while !self.status().contains(Status::TRANSMIT_COMPLETE) {} + + Ok(()) + } +} + +impl eio06::Read for Lpuart { + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut num_read = 0; + for word in buf { + let data = if num_read == 0 { + // For the first word, continue querying until we receive something. + // This function is supposed to block until at least one word is + // received. + loop { + if let Some(data) = self.try_read()? { + break data; + } + } + } else { + // If we already read at least one word, return once + // the buffer is empty + if let Some(data) = self.try_read()? { + data + } else { + break; + } + }; + + *word = data; + num_read += 1; + } + + Ok(num_read) + } +} + #[cfg(test)] mod tests { use super::{Baud, ReadData, ReadFlags, Status};