use socketcan::{CanAnyFrame, CanFdSocket, Frame, Socket, SocketOptions, id::ERR_MASK_ALL};
use std::env;
fn frame_info<F: Frame>(frame: &F) -> String {
let id = frame.raw_id();
let data = frame
.data()
.iter()
.fold(String::new(), |s, b| format!("{s} {b:02X}"));
format!("{id:08X} [{}]{data}", frame.data().len())
}
fn frame_str(frame: &CanAnyFrame) -> String {
match frame {
CanAnyFrame::Normal(frame) => format!("CAN {}", frame_info(frame)),
CanAnyFrame::Remote(frame) => format!("RTR {}", frame_info(frame)),
CanAnyFrame::Fd(frame) => {
let brs = if frame.is_brs() { 'B' } else { '-' };
let esi = if frame.is_esi() { 'E' } else { '-' };
format!("FD {brs}{esi} {}", frame_info(frame))
}
CanAnyFrame::Error(frame) => format!("ERROR: {}", frame.into_error()),
}
}
fn main() -> std::io::Result<()> {
let iface = env::args().nth(1).unwrap_or_else(|| "can0".to_string());
let sock = CanFdSocket::open(&iface)?;
sock.set_error_mask(ERR_MASK_ALL)?;
println!("Reading CAN / CAN FD / error frames on {iface}");
loop {
let frame = sock.read_frame()?;
println!("{}", frame_str(&frame));
}
}