mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 13:50:38 +00:00
Split UART errors (#3138)
This commit is contained in:
parent
75ca8b6e3b
commit
0008bf5f8f
@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Uart `write_bytes` and `read_bytes` are now blocking and return the number of bytes written/read (#2882)
|
||||
- Uart `read_bytes` is now blocking returns the number of bytes read (#2882)
|
||||
- Uart `flush` is now blocking (#2882)
|
||||
- Uart errors have been split into `RxError` and `TxError`. A combined `IoError` has been created for embedded-io. (#3138)
|
||||
- `{Uart, UartTx}::flush()` is now fallible. (#3138)
|
||||
- Removed `embedded-hal-nb` traits (#2882)
|
||||
- `timer::wait` is now blocking (#2882)
|
||||
- By default, set `tx_idle_num` to 0 so that bytes written to TX FIFO are always immediately transmitted. (#2859)
|
||||
|
@ -123,6 +123,16 @@ e.g.
|
||||
+ uart.read_bytes(&mut byte);
|
||||
```
|
||||
|
||||
### UART errors have been split into `TxError` and `RxError`.
|
||||
|
||||
`read_*` and `write_*` functions now return different types. In practice this means you no longer
|
||||
need to check for RX errors that can't be returned by `write_*`.
|
||||
|
||||
The error type used by `embedded-io` has been updated to reflect this. A new `IoError` enum has been
|
||||
added for `embedded-io` errors associated to the unsplit `Uart` driver. On `Uart` (but not `UartRx`
|
||||
or `UartTx`) TX-related trait methods return `IoError::Tx(TxError)`, while RX-related methods return
|
||||
`IoError::Rx(RxError)`.
|
||||
|
||||
### UART halves have their configuration split too
|
||||
|
||||
`Uart::Config` structure now contains separate `RxConfig` and `TxConfig`:
|
||||
|
@ -133,11 +133,11 @@ use crate::{
|
||||
const UART_FIFO_SIZE: u16 = 128;
|
||||
const CMD_CHAR_DEFAULT: u8 = 0x2b;
|
||||
|
||||
/// UART Error
|
||||
/// UART RX Error
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
pub enum RxError {
|
||||
/// The RX FIFO overflow happened.
|
||||
///
|
||||
/// This error occurs when RX FIFO is full and a new byte is received.
|
||||
@ -163,21 +163,42 @@ pub enum Error {
|
||||
ParityMismatch,
|
||||
}
|
||||
|
||||
impl core::error::Error for Error {}
|
||||
impl core::error::Error for RxError {}
|
||||
|
||||
impl core::fmt::Display for Error {
|
||||
impl core::fmt::Display for RxError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Error::FifoOverflowed => write!(f, "The RX FIFO overflowed"),
|
||||
Error::GlitchOccurred => write!(f, "A glitch was detected on the RX line"),
|
||||
Error::FrameFormatViolated => write!(f, "A framing error was detected on the RX line"),
|
||||
Error::ParityMismatch => write!(f, "A parity error was detected on the RX line"),
|
||||
RxError::FifoOverflowed => write!(f, "The RX FIFO overflowed"),
|
||||
RxError::GlitchOccurred => write!(f, "A glitch was detected on the RX line"),
|
||||
RxError::FrameFormatViolated => {
|
||||
write!(f, "A framing error was detected on the RX line")
|
||||
}
|
||||
RxError::ParityMismatch => write!(f, "A parity error was detected on the RX line"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl embedded_io::Error for Error {
|
||||
impl embedded_io::Error for RxError {
|
||||
fn kind(&self) -> embedded_io::ErrorKind {
|
||||
embedded_io::ErrorKind::Other
|
||||
}
|
||||
}
|
||||
|
||||
/// UART TX Error
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub enum TxError {}
|
||||
|
||||
impl core::fmt::Display for TxError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "Tx error")
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl embedded_io::Error for TxError {
|
||||
fn kind(&self) -> embedded_io::ErrorKind {
|
||||
embedded_io::ErrorKind::Other
|
||||
}
|
||||
@ -597,21 +618,23 @@ where
|
||||
}
|
||||
|
||||
/// Writes bytes
|
||||
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
|
||||
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, TxError> {
|
||||
let count = data.len();
|
||||
|
||||
for &byte in data {
|
||||
self.write_byte(byte);
|
||||
self.write_byte(byte)?;
|
||||
}
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn write_byte(&mut self, word: u8) {
|
||||
fn write_byte(&mut self, word: u8) -> Result<(), TxError> {
|
||||
while self.tx_fifo_count() >= UART_FIFO_SIZE {}
|
||||
self.regs()
|
||||
.fifo()
|
||||
.write(|w| unsafe { w.rxfifo_rd_byte().bits(word) });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
@ -622,8 +645,9 @@ where
|
||||
}
|
||||
|
||||
/// Flush the transmit buffer of the UART
|
||||
pub fn flush(&mut self) {
|
||||
pub fn flush(&mut self) -> Result<(), TxError> {
|
||||
while !self.is_tx_idle() {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the TX line is idle for this UART instance.
|
||||
@ -813,7 +837,7 @@ where
|
||||
|
||||
/// Reads and clears errors.
|
||||
#[instability::unstable]
|
||||
pub fn check_for_errors(&mut self) -> Result<(), Error> {
|
||||
pub fn check_for_errors(&mut self) -> Result<(), RxError> {
|
||||
let errors = RxEvent::FifoOvf
|
||||
| RxEvent::FifoTout
|
||||
| RxEvent::GlitchDetected
|
||||
@ -858,7 +882,7 @@ where
|
||||
}
|
||||
|
||||
/// Reads bytes from the UART
|
||||
pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> {
|
||||
pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), RxError> {
|
||||
let buffered = self.read_buffered_bytes(buf)?;
|
||||
let buf = &mut buf[buffered..];
|
||||
|
||||
@ -876,7 +900,7 @@ where
|
||||
|
||||
/// Read all available bytes from the RX FIFO into the provided buffer and
|
||||
/// returns the number of read bytes without blocking.
|
||||
pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
||||
let mut count = 0;
|
||||
while count < buf.len() {
|
||||
if let Some(byte) = self.read_byte() {
|
||||
@ -1162,24 +1186,24 @@ where
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
|
||||
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, TxError> {
|
||||
self.tx.write_bytes(data)
|
||||
}
|
||||
|
||||
/// Reads and clears errors set by received data.
|
||||
#[instability::unstable]
|
||||
pub fn check_for_rx_errors(&mut self) -> Result<(), Error> {
|
||||
pub fn check_for_rx_errors(&mut self) -> Result<(), RxError> {
|
||||
self.rx.check_for_errors()
|
||||
}
|
||||
|
||||
/// Reads bytes from the UART
|
||||
pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> {
|
||||
pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), RxError> {
|
||||
self.rx.read_bytes(buf)
|
||||
}
|
||||
|
||||
/// Read all available bytes from the RX FIFO into the provided buffer and
|
||||
/// returns the number of read bytes without blocking.
|
||||
pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
||||
self.rx.read_buffered_bytes(buf)
|
||||
}
|
||||
|
||||
@ -1221,7 +1245,7 @@ where
|
||||
}
|
||||
|
||||
/// Flush the transmit buffer of the UART
|
||||
pub fn flush(&mut self) {
|
||||
pub fn flush(&mut self) -> Result<(), TxError> {
|
||||
self.tx.flush()
|
||||
}
|
||||
|
||||
@ -1380,7 +1404,7 @@ impl<Dm> ufmt_write::uWrite for Uart<'_, Dm>
|
||||
where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = TxError;
|
||||
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||
@ -1398,7 +1422,7 @@ impl<Dm> ufmt_write::uWrite for UartTx<'_, Dm>
|
||||
where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = TxError;
|
||||
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||
@ -1429,19 +1453,65 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// UART Tx or Rx Error
|
||||
#[instability::unstable]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub enum IoError {
|
||||
/// UART TX error
|
||||
Tx(TxError),
|
||||
/// UART RX error
|
||||
Rx(RxError),
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl core::error::Error for IoError {}
|
||||
|
||||
#[instability::unstable]
|
||||
impl core::fmt::Display for IoError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
IoError::Tx(e) => e.fmt(f),
|
||||
IoError::Rx(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl embedded_io::Error for IoError {
|
||||
fn kind(&self) -> embedded_io::ErrorKind {
|
||||
embedded_io::ErrorKind::Other
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl From<RxError> for IoError {
|
||||
fn from(e: RxError) -> Self {
|
||||
IoError::Rx(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl From<TxError> for IoError {
|
||||
fn from(e: TxError) -> Self {
|
||||
IoError::Tx(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl<Dm> embedded_io::ErrorType for Uart<'_, Dm> {
|
||||
type Error = Error;
|
||||
type Error = IoError;
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl<Dm> embedded_io::ErrorType for UartTx<'_, Dm> {
|
||||
type Error = Error;
|
||||
type Error = TxError;
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
impl<Dm> embedded_io::ErrorType for UartRx<'_, Dm> {
|
||||
type Error = Error;
|
||||
type Error = RxError;
|
||||
}
|
||||
|
||||
#[instability::unstable]
|
||||
@ -1450,7 +1520,7 @@ where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.rx.read(buf)
|
||||
self.rx.read(buf).map_err(IoError::Rx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1478,7 +1548,7 @@ where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
self.rx.read_ready()
|
||||
self.rx.read_ready().map_err(IoError::Rx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1498,11 +1568,11 @@ where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.tx.write(buf)
|
||||
self.tx.write(buf).map_err(IoError::Tx)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
embedded_io::Write::flush(&mut self.tx)
|
||||
embedded_io::Write::flush(&mut self.tx).map_err(IoError::Tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1516,8 +1586,7 @@ where
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.flush();
|
||||
Ok(())
|
||||
self.flush()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1538,13 +1607,13 @@ pub(crate) enum RxEvent {
|
||||
ParityError,
|
||||
}
|
||||
|
||||
fn rx_event_check_for_error(events: EnumSet<RxEvent>) -> Result<(), Error> {
|
||||
fn rx_event_check_for_error(events: EnumSet<RxEvent>) -> Result<(), RxError> {
|
||||
for event in events {
|
||||
match event {
|
||||
RxEvent::FifoOvf => return Err(Error::FifoOverflowed),
|
||||
RxEvent::GlitchDetected => return Err(Error::GlitchOccurred),
|
||||
RxEvent::FrameError => return Err(Error::FrameFormatViolated),
|
||||
RxEvent::ParityError => return Err(Error::ParityMismatch),
|
||||
RxEvent::FifoOvf => return Err(RxError::FifoOverflowed),
|
||||
RxEvent::GlitchDetected => return Err(RxError::GlitchOccurred),
|
||||
RxEvent::FrameError => return Err(RxError::FrameFormatViolated),
|
||||
RxEvent::ParityError => return Err(RxError::ParityMismatch),
|
||||
RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => continue,
|
||||
}
|
||||
}
|
||||
@ -1684,17 +1753,17 @@ impl Drop for UartTxFuture {
|
||||
impl Uart<'_, Async> {
|
||||
/// Asynchronously reads data from the UART receive buffer into the
|
||||
/// provided buffer.
|
||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
||||
self.rx.read_async(buf).await
|
||||
}
|
||||
|
||||
/// Asynchronously writes data to the UART transmit buffer.
|
||||
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, Error> {
|
||||
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, TxError> {
|
||||
self.tx.write_async(words).await
|
||||
}
|
||||
|
||||
/// Asynchronously flushes the UART transmit buffer.
|
||||
pub async fn flush_async(&mut self) -> Result<(), Error> {
|
||||
pub async fn flush_async(&mut self) -> Result<(), TxError> {
|
||||
self.tx.flush_async().await
|
||||
}
|
||||
}
|
||||
@ -1706,7 +1775,7 @@ impl UartTx<'_, Async> {
|
||||
/// the UART. Data is written in chunks to avoid overflowing the
|
||||
/// transmit FIFO, and the function waits asynchronously when
|
||||
/// necessary for space in the buffer to become available.
|
||||
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, Error> {
|
||||
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, TxError> {
|
||||
let mut count = 0;
|
||||
let mut offset: usize = 0;
|
||||
loop {
|
||||
@ -1716,7 +1785,7 @@ impl UartTx<'_, Async> {
|
||||
}
|
||||
|
||||
for byte in &words[offset..next_offset] {
|
||||
self.write_byte(*byte);
|
||||
self.write_byte(*byte)?;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@ -1736,7 +1805,7 @@ impl UartTx<'_, Async> {
|
||||
/// This function ensures that all pending data in the transmit FIFO has
|
||||
/// been sent over the UART. If the FIFO contains data, it waits
|
||||
/// for the transmission to complete before returning.
|
||||
pub async fn flush_async(&mut self) -> Result<(), Error> {
|
||||
pub async fn flush_async(&mut self) -> Result<(), TxError> {
|
||||
let count = self.tx_fifo_count();
|
||||
if count > 0 {
|
||||
UartTxFuture::new(self.uart.reborrow(), TxEvent::Done).await;
|
||||
@ -1767,7 +1836,7 @@ impl UartRx<'_, Async> {
|
||||
/// # Ok
|
||||
/// When successful, returns the number of bytes written to buf.
|
||||
/// If the passed in buffer is of length 0, Ok(0) is returned.
|
||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
||||
if buf.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
@ -1820,7 +1889,7 @@ impl embedded_io_async::Read for Uart<'_, Async> {
|
||||
/// method blocks until an uart interrupt occurs.
|
||||
/// See UartRx::read_async for more details.
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.read_async(buf).await
|
||||
self.read_async(buf).await.map_err(IoError::Rx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1837,11 +1906,11 @@ impl embedded_io_async::Read for UartRx<'_, Async> {
|
||||
#[instability::unstable]
|
||||
impl embedded_io_async::Write for Uart<'_, Async> {
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.write_async(buf).await
|
||||
self.write_async(buf).await.map_err(IoError::Tx)
|
||||
}
|
||||
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.flush_async().await
|
||||
self.flush_async().await.map_err(IoError::Tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1906,7 +1975,7 @@ pub mod lp_uart {
|
||||
/// Initialize the UART driver using the provided configuration
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
///
|
||||
/// [`Apb`] is a wrong clock source for LP_UART
|
||||
///
|
||||
/// [`Apb`]: super::ClockSource::Apb
|
||||
|
Loading…
x
Reference in New Issue
Block a user