2022-07-11 20:13:52 +02:00
|
|
|
use std::error::Error;
|
|
|
|
use std::io;
|
|
|
|
use std::thread;
|
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
use embedded_hal::serial::{Read, Write};
|
|
|
|
use esp_idf_hal::serial::{self, Rx, Tx};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum SerialError {
|
|
|
|
ReadError,
|
2022-07-20 12:20:17 +02:00
|
|
|
WriteError,
|
2022-07-11 20:13:52 +02:00
|
|
|
TimeoutError,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for SerialError {}
|
|
|
|
|
|
|
|
impl std::fmt::Display for SerialError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type Result<T> = std::result::Result<T, SerialError>;
|
|
|
|
|
|
|
|
pub struct RxIter<UART: serial::Uart> {
|
|
|
|
inner: Rx<UART>,
|
|
|
|
timeout: Duration,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<UART: serial::Uart> RxIter<UART> {
|
|
|
|
pub fn reset(&mut self, timeout: Duration) -> &mut Self {
|
|
|
|
self.timeout = timeout;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self) -> () {
|
|
|
|
println!("clearing serial rx");
|
|
|
|
self.reset(Duration::from_millis(500)).for_each(drop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<UART: serial::Uart> Iterator for RxIter<UART> {
|
|
|
|
type Item = u8;
|
|
|
|
|
|
|
|
/// `nb` returns Ok(byte), or one of Err(WouldBlock) and Err(Other) which isn't of anyone's
|
|
|
|
/// interest, so the retry mechanism is triggered on _any_ error every 200ms until a byte is
|
|
|
|
/// received, or the timeout is reached.
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let start = Instant::now();
|
|
|
|
loop {
|
|
|
|
match self.inner.read() {
|
|
|
|
Ok(b) => {
|
|
|
|
self.timeout = self.timeout.saturating_sub(start.elapsed());
|
|
|
|
break Some(b)
|
|
|
|
},
|
|
|
|
Err(_) => {
|
|
|
|
if start.elapsed() > self.timeout {
|
|
|
|
self.timeout = Duration::ZERO;
|
|
|
|
break None
|
|
|
|
}
|
|
|
|
thread::sleep(Duration::from_millis(200));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SerialIO<UART: serial::Uart> {
|
|
|
|
pub rx: RxIter<UART>,
|
|
|
|
pub tx: Tx<UART>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<UART: serial::Uart> SerialIO<UART> {
|
|
|
|
pub fn new(tx: Tx<UART>, rx: Rx<UART>) -> Self {
|
|
|
|
Self {
|
|
|
|
rx: RxIter { inner: rx, timeout: Duration::from_millis(0) },
|
|
|
|
tx,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn send_bytes(&mut self, payload: &[u8], eos: Option<u8>) -> Result<usize> {
|
2022-07-20 12:20:17 +02:00
|
|
|
let mut num_bytes = 0;
|
2022-07-11 20:13:52 +02:00
|
|
|
for b in payload.iter() {
|
|
|
|
nb::block!(self.tx.write(*b))
|
2022-07-20 12:20:17 +02:00
|
|
|
.map_err(|err| SerialError::WriteError)?;
|
|
|
|
num_bytes += 1;
|
|
|
|
}
|
|
|
|
if num_bytes == payload.len() {
|
|
|
|
eos.map(|b| nb::block!(self.tx.write(b)));
|
|
|
|
Ok(num_bytes + if eos.is_none() { 0 } else { 1 })
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(SerialError::WriteError)
|
2022-07-11 20:13:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reads a whole line (that ends with \\n) within the given `timeout` passed on input.
|
|
|
|
pub fn read_line(&mut self, timeout: Duration) -> Result<String> {
|
|
|
|
let mut line: String = self.rx.reset(timeout)
|
|
|
|
.map(|b| char::from(b))
|
|
|
|
.take_while(|c| *c != '\n')
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
// \r must come right before \n on read; take_while excludes the matched element.
|
|
|
|
if line.ends_with('\r') {
|
|
|
|
line.push('\n');
|
|
|
|
Ok(line)
|
|
|
|
}
|
|
|
|
else if self.rx.timeout.as_millis() == 0 {
|
|
|
|
Err(SerialError::TimeoutError)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(SerialError::ReadError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<UART: serial::Uart> io::Read for SerialIO<UART> {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
|
let buf_size = buf.len();
|
|
|
|
let count = self.rx.reset(Duration::from_millis(1000))
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, b)| {
|
|
|
|
buf[i] = b;
|
|
|
|
i
|
|
|
|
})
|
|
|
|
.take_while(|i| i < &buf_size)
|
|
|
|
.count();
|
|
|
|
Ok(count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<UART: serial::Uart> io::Write for SerialIO<UART> {
|
|
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
|
self.send_bytes(buf, None)
|
|
|
|
.map_err(|_| io::Error::from(io::ErrorKind::Other))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
|
|
self.tx.flush()
|
2022-07-12 19:10:04 +02:00
|
|
|
.map_err(|_| io::Error::from(io::ErrorKind::Other))
|
2022-07-11 20:13:52 +02:00
|
|
|
}
|
|
|
|
}
|