use anyhow::{Context, bail};
use embedded_can::{Frame as EmbeddedFrame, StandardId, nb::Can};
use socketcan::{CanFrame, CanSocket, Frame, Socket};
use std::{
env,
thread::sleep,
time::{Duration, Instant},
};
const TIMEOUT: Duration = Duration::from_secs(5);
const POLL_INTERVAL: Duration = Duration::from_millis(10);
fn frame_to_string<F: Frame>(frame: &F) -> String {
let id = frame.raw_id();
let data_string = frame
.data()
.iter()
.fold(String::from(""), |a, b| format!("{} {:02x}", a, b));
format!("{:X} [{}] {}", id, frame.dlc(), data_string)
}
fn main() -> anyhow::Result<()> {
let iface = env::args().nth(1).unwrap_or_else(|| "can0".into());
let mut sock = CanSocket::open(&iface)
.with_context(|| format!("Failed to open socket on interface {}", iface))?;
sock.set_nonblocking(true)
.context("Failed to make socket non-blocking")?;
println!("Waiting up to {:?} for a frame on {}...", TIMEOUT, iface);
let deadline = Instant::now() + TIMEOUT;
let mut polls: u64 = 0;
let frame = loop {
match sock.receive() {
Ok(frame) => break frame,
Err(nb::Error::Other(err)) => return Err(err).context("Receiving frame"),
Err(nb::Error::WouldBlock) => {
if Instant::now() >= deadline {
bail!("No frame received on {} within {:?}", iface, TIMEOUT);
}
polls += 1;
sleep(POLL_INTERVAL);
}
}
};
println!("{} {}", iface, frame_to_string(&frame));
println!(" (idle through {} polls while waiting)", polls);
let frame = CanFrame::new(StandardId::new(0x1f1).unwrap(), &[1, 2, 3, 4])
.context("Creating CAN frame")?;
let deadline = Instant::now() + TIMEOUT;
loop {
match sock.transmit(&frame) {
Ok(_) => break,
Err(nb::Error::Other(err)) => return Err(err).context("Transmitting frame"),
Err(nb::Error::WouldBlock) => {
if Instant::now() >= deadline {
bail!("Send buffer stayed full for {:?}", TIMEOUT);
}
sleep(POLL_INTERVAL);
}
}
}
println!("Sent: {}", frame_to_string(&frame));
Ok(())
}