use std::env;
use std::process;
use falcon_mdf::{CanDatabase, IdMatching, Mf4File};
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("Usage: {} <file.mf4> <database.dbc> [--j1939]", args[0]);
eprintln!();
eprintln!("Decodes the CAN traffic in an MF4 bus log against a DBC.");
process::exit(1);
}
let (path, dbc_path) = (&args[1], &args[2]);
let matching = if args.iter().any(|arg| arg == "--j1939") {
IdMatching::J1939Pgn
} else {
IdMatching::Exact
};
let file = match Mf4File::open(path) {
Ok(file) => file,
Err(e) => {
eprintln!("Error opening {path}: {e}");
process::exit(1);
}
};
let database = match CanDatabase::from_dbc_path(dbc_path) {
Ok(database) => database.with_matching(matching),
Err(e) => {
eprintln!("Error reading {dbc_path}: {e}");
process::exit(1);
}
};
println!("{path}");
println!(
"{} messages in {dbc_path}, matched {}",
database.messages().len(),
match matching {
IdMatching::Exact => "by identifier",
IdMatching::J1939Pgn => "by J1939 parameter group",
IdMatching::J1939PgnAndSource => "by J1939 parameter group and source address",
}
);
let frames: usize = file
.can_frame_groups()
.iter()
.filter_map(|group| file.can_frames(group).ok())
.map(|frames| frames.len())
.sum();
println!("{frames} CAN frames logged\n");
let signals = match file.decode_bus(&database) {
Ok(signals) => signals,
Err(e) => {
eprintln!("Error decoding: {e}");
process::exit(1);
}
};
if signals.is_empty() {
println!("No frame matched any message in the database.");
if matching == IdMatching::Exact {
println!("If this is a J1939 log, try again with --j1939.");
}
return;
}
println!("{:<34} {:>9} {:>13} RANGE", "SIGNAL", "READINGS", "FIRST");
println!("{}", "─".repeat(78));
let mut sorted: Vec<_> = signals.iter().collect();
sorted.sort_by_key(|signal| (signal.bus_channel, signal.message, signal.name));
for signal in sorted {
let low = signal.values.iter().copied().fold(f64::INFINITY, f64::min);
let high = signal
.values
.iter()
.copied()
.fold(f64::NEG_INFINITY, f64::max);
let first = match signal.text_at(0) {
Some(text) => text.to_string(),
None => format!("{:.3}", signal.values[0]),
};
println!(
"{:<34} {:>9} {:>13} {low:.3} .. {high:.3} {}",
format!("{}.{}", signal.message, signal.name),
signal.len(),
first,
signal.unit,
);
}
}