Skip to content

Commit c1a2abb

Browse files
committed
Add example application that's a primitive candump
1 parent 7bd7640 commit c1a2abb

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

candumpr/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ ci = []
1313
eyre.workspace = true
1414
io-uring.workspace = true
1515
libc.workspace = true
16+
tracing.workspace = true
1617

1718
[dev-dependencies]
1819
ctor.workspace = true
1920
gungraun.workspace = true
2021
tabled.workspace = true
21-
tracing.workspace = true
2222
tracing-subscriber.workspace = true
2323
vcan-fixture = { path = "../vcan-fixture" }
2424

candumpr/examples/dump.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//! Listen on CAN interfaces using the io_uring multishot backend and print received frames.
2+
//!
3+
//! Usage: uring_multi_dump <iface> [iface...]
4+
5+
use std::sync::Arc;
6+
use std::sync::atomic::{AtomicBool, Ordering};
7+
8+
use candumpr::can::{self, CanFrame};
9+
use candumpr::recv::uring_multi::UringMultiRecv;
10+
11+
fn main() -> std::io::Result<()> {
12+
tracing_subscriber::fmt()
13+
.with_writer(std::io::stderr)
14+
.with_max_level(tracing::Level::DEBUG)
15+
.init();
16+
17+
let ifaces: Vec<String> = std::env::args().skip(1).collect();
18+
if ifaces.is_empty() {
19+
eprintln!("usage: uring_multi_dump <iface> [iface...]");
20+
std::process::exit(1);
21+
}
22+
23+
let sockets: Vec<_> = ifaces
24+
.iter()
25+
.map(|name| can::open_can_raw(name))
26+
.collect::<std::io::Result<_>>()?;
27+
28+
let mut backend = UringMultiRecv::new(sockets)?;
29+
30+
let stop = Arc::new(AtomicBool::new(false));
31+
let stop2 = stop.clone();
32+
ctrlc(stop2);
33+
34+
let total = backend.run(stop, &mut |idx, frame, _meta| {
35+
print_frame(idx, frame);
36+
})?;
37+
38+
eprintln!("{total} frames received");
39+
Ok(())
40+
}
41+
42+
fn print_frame(idx: usize, frame: &CanFrame) {
43+
let id = frame.can_id & !libc::CAN_EFF_FLAG & !libc::CAN_RTR_FLAG & !libc::CAN_ERR_FLAG;
44+
45+
print!("{idx} {id:08X} [{}]", frame.len);
46+
for i in 0..frame.len as usize {
47+
print!(" {:02X}", frame.data[i]);
48+
}
49+
println!();
50+
}
51+
52+
/// Install a Ctrl-C handler that sets the stop flag.
53+
fn ctrlc(stop: Arc<AtomicBool>) {
54+
unsafe {
55+
libc::signal(
56+
libc::SIGINT,
57+
signal_handler as *const () as libc::sighandler_t,
58+
);
59+
}
60+
// Leak the Arc into a raw pointer so the signal handler can access it.
61+
STOP_FLAG.store(Arc::into_raw(stop) as *mut _, Ordering::Release);
62+
}
63+
64+
static STOP_FLAG: std::sync::atomic::AtomicPtr<AtomicBool> =
65+
std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());
66+
67+
extern "C" fn signal_handler(_sig: libc::c_int) {
68+
let ptr = STOP_FLAG.load(Ordering::Acquire);
69+
if !ptr.is_null() {
70+
unsafe { &*ptr }.store(true, Ordering::Relaxed);
71+
}
72+
}

0 commit comments

Comments
 (0)