use std::io;
use std::path::Path;
use serial2::os::windows::CommTimeouts;
use serial2::{SerialPort, Settings};
use super::{CTRL_BAUD, IO_TIMEOUT};
use crate::transport::Transport;
const DCB_ABORT_ON_ERROR: u32 = 1 << 14;
#[derive(Debug)]
pub(crate) struct SerialTransport {
port: SerialPort,
}
impl SerialTransport {
pub(crate) fn open(path: &Path) -> io::Result<Self> {
let path = path.to_string_lossy();
let name = path
.strip_prefix(r"\\.\")
.or_else(|| path.strip_prefix(r"\\?\"))
.unwrap_or(&path);
let port = SerialPort::open(name, |mut settings: Settings| {
settings.set_raw();
settings.set_baud_rate(CTRL_BAUD)?;
settings.as_raw_dbc_mut()._bitfield &= !DCB_ABORT_ON_ERROR;
Ok(settings)
})?;
port.set_windows_timeouts(&CommTimeouts {
read_interval_timeout: u32::MAX,
read_total_timeout_multiplier: 0,
read_total_timeout_constant: 0,
write_total_timeout_multiplier: 0,
write_total_timeout_constant: IO_TIMEOUT.as_millis().try_into().unwrap_or(u32::MAX),
})?;
let _ = port.discard_input_buffer();
Ok(SerialTransport { port })
}
}
impl Transport for SerialTransport {
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.port.write_all(buf)
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
match self.port.read(buf) {
Ok(0) => Err(io::Error::from(io::ErrorKind::BrokenPipe)),
Ok(n) => Ok(n),
Err(e) if e.kind() == io::ErrorKind::TimedOut => Ok(0),
Err(e) => Err(e),
}
}
}