use crate::error::{ReadError, TransferError, WriteError};
use crate::frames::{CanFdFrame, FdCanUSBFrame};
#[cfg(unix)]
use libc::{ECHO, ECHOE, ICANON, ISIG, OPOST};
use serial2::SerialPort;
use std::time::Duration;
#[derive(derive_more::Debug)]
pub struct FdCanUSB<Buffer = Vec<u8>>
where
Buffer: AsRef<[u8]> + AsMut<[u8]>,
{
#[debug(skip)]
transport: SerialPort,
buffer: Buffer,
read_len: usize,
used_bytes: usize,
}
impl FdCanUSB<Vec<u8>> {
pub fn open(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
let mut transport = SerialPort::open(path, |mut settings: serial2::Settings| {
settings.set_raw();
#[cfg(unix)]
{
let t = settings.as_termios_mut();
t.c_lflag &= !(ICANON | ECHO | ECHOE | ISIG);
t.c_oflag &= !OPOST;
}
Ok(settings)
})?;
transport.set_read_timeout(std::time::Duration::from_millis(100))?;
transport.flush()?;
transport.discard_buffers()?;
Ok(Self::new(transport))
}
pub fn new(transport: SerialPort) -> Self {
Self::new_with_buffer(transport, vec![0; 256])
}
}
impl<Buffer> FdCanUSB<Buffer>
where
Buffer: AsRef<[u8]> + AsMut<[u8]>,
{
pub fn new_with_buffer(transport: SerialPort, buffer: Buffer) -> Self {
FdCanUSB {
transport,
buffer,
read_len: 0,
used_bytes: 0,
}
}
pub fn flush(&mut self) -> std::io::Result<()> {
self.transport.flush()?;
self.transport.discard_buffers()?;
Ok(())
}
pub fn transfer_single(
&mut self,
frame: CanFdFrame,
response: bool,
) -> Result<Option<CanFdFrame>, TransferError> {
self.write(frame)?;
if response {
Ok(Some(self.read()?))
} else {
Ok(None)
}
}
pub fn write(&mut self, frame: CanFdFrame) -> Result<(), TransferError> {
let frame: FdCanUSBFrame = frame.into();
self.write_frame(frame)?;
self.read_len = 0;
self.used_bytes = 0;
self.read_ok()?;
Ok(())
}
pub fn read(&mut self) -> Result<CanFdFrame, ReadError> {
let packet = self.read_newline(Duration::from_millis(500))?;
let packet = &self.buffer.as_ref()[self.used_bytes..packet];
self.used_bytes += packet.len();
if packet.starts_with(b"rcv") {
let response = std::str::from_utf8(packet)?;
debug!("< {:?}", response);
let response = FdCanUSBFrame::from(response);
let response = response.try_into()?;
Ok(response)
} else {
Err(ReadError::LostSync {
expected: "rcv".to_string(),
received: String::from_utf8_lossy(packet).to_string(),
})
}
}
fn write_frame(&mut self, frame: FdCanUSBFrame) -> Result<(), WriteError> {
debug!("> {:?}", frame);
self.transport.write_all(frame.as_bytes())?;
Ok(())
}
fn read_newline(&mut self, timeout: Duration) -> Result<usize, std::io::Error> {
let buffer = self.buffer.as_mut();
let deadline = std::time::Instant::now() + timeout;
loop {
if let Some(pos) = buffer[self.used_bytes..self.read_len]
.iter()
.position(|&c| c == b'\n')
{
trace!(
"packet {:?}",
&buffer[self.used_bytes..self.used_bytes + pos + 1]
);
return Ok(self.used_bytes + pos + 1);
}
if std::time::Instant::now() > deadline {
return Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"Timed out waiting for newline",
));
}
let read_num = self.transport.read(&mut buffer[self.read_len..])?;
trace!(
"read {} {:?}",
read_num,
&buffer[self.read_len..self.read_len + read_num]
);
self.read_len += read_num;
}
}
fn read_ok(&mut self) -> Result<(), ReadError> {
let packet = self.read_newline(Duration::from_millis(50))?;
let packet = &self.buffer.as_ref()[self.used_bytes..packet];
self.used_bytes += packet.len();
if packet.starts_with(b"OK") {
Ok(())
} else {
Err(ReadError::LostSync {
expected: "OK".to_string(),
received: String::from_utf8_lossy(packet).to_string(),
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fdcanusb() {
let mut fdcanusb = FdCanUSB::open("/dev/fdcanusb").expect("Failed to open fdcanusb");
let frame = FdCanUSBFrame::from(
"can send 8001 01000A0D200000C07F0D270000004011001F01130D505050 b\n",
);
fdcanusb.write_frame(frame).expect("Failed to write frame");
fdcanusb.read_ok().expect("Failed to read ok");
let response = fdcanusb.read();
dbg!(&response);
assert!(response.is_ok());
}
}