esp-idf-hal icon indicating copy to clipboard operation
esp-idf-hal copied to clipboard

UART read timeout?

Open marie-bnl opened this issue 1 year ago • 1 comments

I am trying to read a success code that is sent to my ESP by a UART sensor. To do so, I use read_exact this way

fn read_success(uart: &mut UartDriver) -> anyhow::Result<()> {
    let mut buffer = [0; 10];
    uart.read_exact(&mut buffer)?;
    assert_eq!(&buffer, b"$00023335&");
    Ok(())
}

Can I set a read timeout in case the sensor never responds?

There seems to be uart_set_rx_timeout but I couldn’t find any function that does this in the wrappers.

marie-bnl avatar Jul 18 '24 11:07 marie-bnl

I had the same problem. Not sure if that's the best way to solve this, but what I did is implement my own ReadWithTimeout trait, based on the Read trait from embedded_io:

use esp_idf_hal::delay::TickType;
use esp_idf_hal::io::{EspIOError, ReadExactError};
use esp_idf_hal::uart::UartDriver;

pub trait ReadWithTimeout {
    fn read(&mut self, buf: &mut [u8], timeout_ms: u64) -> Result<usize, EspIOError>;

    fn read_exact(
        &mut self,
        mut buf: &mut [u8],
        timeout_ms: u64,
    ) -> Result<(), ReadExactError<EspIOError>> {
        while !buf.is_empty() {
            match self.read(buf, timeout_ms) {
                Ok(0) => break,
                Ok(n) => buf = &mut buf[n..],
                Err(e) => return Err(ReadExactError::Other(e)),
            }
        }
        if buf.is_empty() {
            Ok(())
        } else {
            Err(ReadExactError::UnexpectedEof)
        }
    }
}

impl<'d> ReadWithTimeout for UartDriver<'d> {
    fn read(&mut self, buf: &mut [u8], timeout_ms: u64) -> Result<usize, EspIOError> {
        UartDriver::read(self, buf, TickType::new_millis(timeout_ms).ticks()).map_err(EspIOError)
    }
}

armandas avatar Jul 20 '24 05:07 armandas