use crate::{
frame::Frame,
id::{id_from_raw, FdFlags},
CanAnyFrame, CanDataFrame, CanFdFrame, CanFrame, CanRemoteFrame, ConstructionError,
};
use embedded_can::Frame as EmbeddedFrame;
use hex::FromHex;
use itertools::Itertools;
use libc::canid_t;
use std::{
fmt,
fs::File,
io::{self, BufRead, BufReader},
path::Path,
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParseError {
#[error(transparent)]
Io(#[from] io::Error),
#[error("Unexpected end of line")]
UnexpectedEndOfLine,
#[error("Invalid timestamp")]
InvalidTimestamp,
#[error("Invalid device name")]
InvalidDeviceName,
#[error("Invalid CAN frame")]
InvalidCanFrame,
#[error(transparent)]
ConstructionError(#[from] ConstructionError),
}
#[derive(Debug, Clone)]
pub struct CanDumpRecord {
pub t_us: u64,
pub device: String,
pub frame: CanAnyFrame,
}
impl fmt::Display for CanDumpRecord {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.6}) {} ", 1.0e-6 * self.t_us as f64, self.device)?;
use CanAnyFrame::*;
match self.frame {
Remote(frame) if frame.len() == 0 => {
Self::fmt_id(f, &frame)?;
f.write_str("#R")
}
Remote(frame) => {
Self::fmt_id(f, &frame)?;
write!(f, "#R{:X}", frame.dlc())
}
Error(frame) => {
write!(f, "{:08X}#", frame.error_bits())?;
let mut parts = frame.data().iter().map(|v| format!("{:02X}", v));
write!(f, "{}", parts.join(""))
}
Normal(frame) => {
Self::fmt_id(f, &frame)?;
let mut parts = frame.data().iter().map(|v| format!("{:02X}", v));
write!(f, "#{}", parts.join(""))
}
Fd(frame) => {
Self::fmt_id(f, &frame)?;
let mut parts = frame.data().iter().map(|v| format!("{:02X}", v));
write!(f, "##{:X}{}", frame.flags().bits() & 0x0F, parts.join(""))
}
}
}
}
impl CanDumpRecord {
fn fmt_id<F: Frame>(f: &mut fmt::Formatter<'_>, frame: &F) -> fmt::Result {
if frame.is_extended() {
write!(f, "{:08X}", frame.raw_id())
} else {
write!(f, "{:03X}", frame.raw_id())
}
}
}
#[derive(Debug)]
pub struct Reader<R> {
rdr: R,
buf: String,
}
impl<R: io::Read> Reader<R> {
pub fn from_reader(rdr: R) -> Reader<BufReader<R>> {
Reader {
rdr: BufReader::new(rdr),
buf: String::with_capacity(256),
}
}
}
impl Reader<File> {
pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Reader<BufReader<File>>> {
Ok(Reader::from_reader(File::open(path)?))
}
}
impl<R: BufRead> Reader<R> {
#[deprecated(since = "3.5.0", note = "Use `iter()`")]
pub fn records(&mut self) -> CanDumpRecords<'_, R> {
CanDumpRecords { src: self }
}
pub fn next_record(&mut self) -> Result<Option<CanDumpRecord>, ParseError> {
const MAX_LINE: u64 = 64 * 1024;
self.buf.clear();
let mut handle = io::Read::take(&mut self.rdr, MAX_LINE);
let nread = handle.read_line(&mut self.buf)?;
if nread == 0 {
return Ok(None);
}
if nread as u64 == MAX_LINE && !self.buf.ends_with('\n') {
return Err(ParseError::InvalidCanFrame);
}
let line = self.buf[..nread].trim();
let mut field_iter = line.split(' ');
let ts = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
if ts.len() < 3 || !ts.starts_with('(') || !ts.ends_with(')') {
return Err(ParseError::InvalidTimestamp);
}
let ts = &ts[1..ts.len() - 1];
let t_us = match ts.split_once('.') {
Some((num, mant)) => {
if mant.len() != 6 {
return Err(ParseError::InvalidTimestamp);
}
let num = num
.parse::<u64>()
.map_err(|_| ParseError::InvalidTimestamp)?;
let mant = mant
.parse::<u64>()
.map_err(|_| ParseError::InvalidTimestamp)?;
num.checked_mul(1_000_000)
.and_then(|v| v.checked_add(mant))
.ok_or(ParseError::InvalidTimestamp)?
}
_ => return Err(ParseError::InvalidTimestamp),
};
let device = field_iter
.next()
.ok_or(ParseError::UnexpectedEndOfLine)?
.to_string();
let can_raw = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
let (can_id_str, mut can_data) = match can_raw.split_once('#') {
Some((id, data)) => (id, data),
_ => return Err(ParseError::InvalidCanFrame),
};
let can_id = canid_t::from_str_radix(can_id_str, 16)
.ok()
.and_then(id_from_raw)
.ok_or(ParseError::InvalidCanFrame)?;
let frame: CanAnyFrame = if can_data.starts_with('#') {
let fd_flags = can_data
.get(1..2)
.and_then(|s| u8::from_str_radix(s, 16).ok())
.map(FdFlags::from_bits_truncate)
.ok_or(ParseError::InvalidCanFrame)?;
Vec::from_hex(&can_data[2..])
.ok()
.and_then(|data| CanFdFrame::with_flags(can_id, &data, fd_flags))
.map(CanAnyFrame::Fd)
} else if can_data.starts_with('R') {
can_data = &can_data[1..];
let rlen = if can_data.is_empty() {
0
} else {
usize::from_str_radix(can_data, 16).map_err(|_| ParseError::InvalidCanFrame)?
};
CanRemoteFrame::new_remote(can_id, rlen)
.map(CanFrame::Remote)
.map(CanAnyFrame::from)
} else {
Vec::from_hex(can_data)
.ok()
.and_then(|data| CanDataFrame::new(can_id, &data))
.map(CanFrame::Data)
.map(CanAnyFrame::from)
}
.ok_or(ParseError::InvalidCanFrame)?;
Ok(Some(CanDumpRecord {
t_us,
device,
frame,
}))
}
}
impl<R: BufRead> Iterator for Reader<R> {
type Item = Result<CanDumpRecord, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
match self.next_record() {
Ok(Some(rec)) => Some(Ok(rec)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug)]
pub struct CanDumpRecords<'a, R: 'a> {
src: &'a mut Reader<R>,
}
impl<R: io::Read> Iterator for CanDumpRecords<'_, BufReader<R>> {
type Item = Result<(u64, CanAnyFrame), ParseError>;
fn next(&mut self) -> Option<Self::Item> {
match self.src.next_record() {
Ok(Some(CanDumpRecord { t_us, frame, .. })) => Some(Ok((t_us, frame))),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{CanAnyFrame, Frame};
use embedded_can::Frame as EmbeddedFrame;
#[test]
fn test_simple_example() {
let input: &[u8] = b"(1469439874.299591) can1 080#\n\
(1469439874.299654) can1 701#7F";
let mut reader = Reader::from_reader(input);
let rec1 = reader.next_record().unwrap().unwrap();
assert_eq!(rec1.t_us, 1469439874299591);
assert_eq!(rec1.device, "can1");
if let CanAnyFrame::Normal(frame) = rec1.frame {
assert_eq!(frame.raw_id(), 0x080);
assert!(!frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(!frame.is_extended());
assert_eq!(frame.data(), &[]);
} else {
panic!("Expected Normal frame, got FD");
}
let rec2 = reader.next_record().unwrap().unwrap();
assert_eq!(rec2.t_us, 1469439874299654);
assert_eq!(rec2.device, "can1");
if let CanAnyFrame::Normal(frame) = rec2.frame {
assert_eq!(frame.raw_id(), 0x701);
assert!(!frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(!frame.is_extended());
assert_eq!(frame.data(), &[0x7F]);
} else {
panic!("Expected Normal frame, got FD");
}
assert!(reader.next_record().unwrap().is_none());
}
#[test]
fn test_extended_example() {
let input: &[u8] = b"(1469439874.299591) can1 080080#\n\
(1469439874.299654) can1 053701#7F";
let mut reader = Reader::from_reader(input);
let rec1 = reader.next_record().unwrap().unwrap();
assert_eq!(rec1.t_us, 1469439874299591);
assert_eq!(rec1.device, "can1");
if let CanAnyFrame::Normal(frame) = rec1.frame {
assert_eq!(frame.raw_id(), 0x080080);
assert_eq!(frame.is_remote_frame(), false);
assert_eq!(frame.is_error_frame(), false);
assert_eq!(frame.is_extended(), true);
assert_eq!(frame.data(), &[]);
} else {
panic!("Expected Normal frame, got FD");
}
let rec2 = reader.next_record().unwrap().unwrap();
assert_eq!(rec2.t_us, 1469439874299654);
assert_eq!(rec2.device, "can1");
if let CanAnyFrame::Normal(frame) = rec2.frame {
assert_eq!(frame.raw_id(), 0x053701);
assert_eq!(frame.is_remote_frame(), false);
assert_eq!(frame.is_error_frame(), false);
assert_eq!(frame.is_extended(), true);
assert_eq!(frame.data(), &[0x7F]);
} else {
panic!("Expected Normal frame, got FD");
}
assert!(reader.next_record().unwrap().is_none());
}
#[test]
fn test_remote() {
let input: &[u8] = b"(1469439874.299591) can0 080080#R\n\
(1469439874.299654) can0 053701#R4";
let mut reader = Reader::from_reader(input);
let rec1 = reader.next_record().unwrap().unwrap();
assert_eq!(rec1.t_us, 1469439874299591);
assert_eq!(rec1.device, "can0");
if let CanAnyFrame::Remote(frame) = rec1.frame {
assert_eq!(frame.raw_id(), 0x080080);
assert!(!frame.is_data_frame());
assert!(frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(frame.is_extended());
assert_eq!(frame.len(), 0);
assert_eq!(frame.data(), &[]);
} else {
panic!("Expected Remote frame");
}
let rec2 = reader.next_record().unwrap().unwrap();
assert_eq!(rec2.t_us, 1469439874299654);
assert_eq!(rec2.device, "can0");
if let CanAnyFrame::Remote(frame) = rec2.frame {
assert_eq!(frame.raw_id(), 0x053701);
assert!(!frame.is_data_frame());
assert!(frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(frame.is_extended());
assert_eq!(frame.len(), 4);
} else {
panic!("Expected Remote frame");
}
assert!(reader.next_record().unwrap().is_none());
}
#[test]
fn test_extended_id_fd() {
let input: &[u8] = b"(1234.567890) can0 12345678##500112233445566778899AABB";
let mut reader = Reader::from_reader(input);
let rec = reader.next_record().unwrap().unwrap();
let frame = CanFdFrame::try_from(rec.frame).unwrap();
assert!(frame.is_extended());
assert_eq!(0x12345678, frame.raw_id());
assert_eq!(5, frame.flags().bits());
assert_eq!(frame.dlc(), 0x09);
assert_eq!(frame.len(), 12);
assert_eq!(frame.data().len(), 12);
assert_eq!(
frame.data(),
&[0x0, 0x011, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB]
);
}
#[test]
fn test_fd() {
let input: &[u8] = b"(1469439874.299591) can1 080##0\n\
(1469439874.299654) can1 701##17F";
let mut reader = Reader::from_reader(input);
let rec1 = reader.next_record().unwrap().unwrap();
assert_eq!(rec1.t_us, 1469439874299591);
assert_eq!(rec1.device, "can1");
if let CanAnyFrame::Fd(frame) = rec1.frame {
assert_eq!(frame.raw_id(), 0x080);
assert!(!frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(!frame.is_extended());
assert!(!frame.is_brs());
assert!(!frame.is_esi());
assert_eq!(0x04, frame.flags().bits());
assert_eq!(frame.dlc(), 0);
assert_eq!(frame.len(), 0);
assert_eq!(frame.data().len(), 0);
assert_eq!(frame.data(), &[]);
} else {
panic!("Expected FD frame, got Normal");
}
let rec2 = reader.next_record().unwrap().unwrap();
assert_eq!(rec2.t_us, 1469439874299654);
assert_eq!(rec2.device, "can1");
if let CanAnyFrame::Fd(frame) = rec2.frame {
assert_eq!(frame.raw_id(), 0x701);
assert!(!frame.is_remote_frame());
assert!(!frame.is_error_frame());
assert!(!frame.is_extended());
assert!(frame.is_brs());
assert!(!frame.is_esi());
assert_eq!(0x05, frame.flags().bits());
assert_eq!(frame.dlc(), 1);
assert_eq!(frame.len(), 1);
assert_eq!(frame.data().len(), 1);
assert_eq!(frame.data(), &[0x7F]);
} else {
panic!("Expected FD frame, got Normal");
}
assert!(reader.next_record().unwrap().is_none());
}
}