use std::io::{self, Read};
use std::rc::Rc;
use std::time::Duration;
use anyhow::Result;
use clap::Args;
use serde::{Deserialize, Serialize};
pub use serialport::Parity;
use thiserror::Error;
use super::nonblocking_help::{NoNonblockingHelp, NonblockingHelp};
use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::io::console::ConsoleDevice;
use crate::transport::TransportError;
#[derive(Clone, Debug, Args, Serialize, Deserialize)]
pub struct UartParams {
#[arg(long, default_value = "CONSOLE")]
uart: String,
#[arg(long)]
baudrate: Option<u32>,
#[arg(long)]
flow_control: bool,
}
impl UartParams {
pub fn create(&self, transport: &TransportWrapper) -> Result<Rc<dyn Uart>> {
let uart = transport.uart(&self.uart)?;
if let Some(baudrate) = self.baudrate {
uart.set_baudrate(baudrate)?;
}
log::info!("set_flow_control to {}", self.flow_control);
uart.set_flow_control(self.flow_control)?;
Ok(uart)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum FlowControl {
None = 0,
Pause = 19,
Resume = 17,
}
pub trait Uart {
fn get_baudrate(&self) -> Result<u32>;
fn set_baudrate(&self, baudrate: u32) -> Result<()>;
fn set_flow_control(&self, flow_control: bool) -> Result<()> {
if flow_control {
unimplemented!();
}
Ok(())
}
fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn read_timeout(&self, buf: &mut [u8], timeout: Duration) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<()>;
fn clear_rx_buffer(&self) -> Result<()> {
const TIMEOUT: Duration = Duration::from_millis(5);
let mut buf = [0u8; 256];
while self.read_timeout(&mut buf, TIMEOUT)? > 0 {}
Ok(())
}
fn set_break(&self, _enable: bool) -> Result<()> {
Err(TransportError::UnsupportedOperation.into())
}
fn set_parity(&self, _parity: Parity) -> Result<()> {
Err(TransportError::UnsupportedOperation.into())
}
fn supports_nonblocking_read(&self) -> Result<bool> {
Ok(false)
}
fn register_nonblocking_read(
&self,
_registry: &mio::Registry,
_token: mio::Token,
) -> Result<()> {
unimplemented!();
}
fn nonblocking_help(&self) -> Result<Rc<dyn NonblockingHelp>> {
Ok(Rc::new(NoNonblockingHelp))
}
}
impl Read for &dyn Uart {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Uart::read(&**self, buf).map_err(io::Error::other)
}
}
impl<'a> ConsoleDevice for dyn Uart + 'a {
fn console_read(&self, buf: &mut [u8], timeout: Duration) -> Result<usize> {
self.read_timeout(buf, timeout)
}
fn console_write(&self, buf: &[u8]) -> Result<()> {
self.write(buf)
}
fn set_break(&self, enable: bool) -> Result<()> {
<Self as Uart>::set_break(self, enable)
}
fn supports_nonblocking_read(&self) -> Result<bool> {
self.supports_nonblocking_read()
}
fn register_nonblocking_read(&self, registry: &mio::Registry, token: mio::Token) -> Result<()> {
self.register_nonblocking_read(registry, token)
}
fn nonblocking_help(&self) -> Result<Rc<dyn NonblockingHelp>> {
self.nonblocking_help()
}
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum UartError {
#[error("Enumerating: {0}")]
EnumerationError(String),
#[error("Opening: {0}")]
OpenError(String),
#[error("Invalid option: {0}")]
InvalidOption(String),
#[error("Invalid speed: {0}")]
InvalidSpeed(u32),
#[error("Reading: {0}")]
ReadError(String),
#[error("Writing: {0}")]
WriteError(String),
#[error("{0}")]
GenericError(String),
}
impl_serializable_error!(UartError);