use std::env;
use j1939::Id;
use j1939::PGN;
use j1939::diagnostic;
use j1939::protocol;
use j1939::spn::*;
fn usage() {
println!("Usage: j1939decode <input>");
println!();
println!("Options:");
println!(" <input> 29-bit CAN ID in hexadecimal format (0x18EAFF00)");
println!(" or CAN ID and data separated by '#' (0x18FEE6EE#243412024029837D)");
}
fn decode_data(pgn: PGN, data: &[u8]) {
println!("Data Decoded:");
match pgn {
PGN::TorqueSpeedControl1 => {
println!(" {}", TorqueSpeedControl1Message::from_pdu(data));
}
PGN::ElectronicEngineController1 => {
println!(" {}", ElectronicEngineController1Message::from_pdu(data));
}
PGN::ElectronicEngineController2 => {
println!(" {}", ElectronicEngineController2Message::from_pdu(data));
}
PGN::ElectronicEngineController3 => {
println!(" {}", ElectronicEngineController3Message::from_pdu(data));
}
PGN::ElectronicBrakeController1 => {
println!(" {}", ElectronicBrakeController1Message::from_pdu(data));
}
PGN::AmbientConditions => {
println!(" {}", AmbientConditionsMessage::from_pdu(data));
}
PGN::VehiclePosition => {
println!(" {}", VehiclePositionMessage::from_pdu(data));
}
PGN::FuelEconomy => {
println!(" {}", FuelEconomyMessage::from_pdu(data));
}
PGN::EngineFluidLevelPressure1 => {
println!(" {}", EngineFluidLevelPressure1Message::from_pdu(data));
}
PGN::FuelConsumption => {
println!(" {}", FuelConsumptionMessage::from_pdu(data));
}
PGN::VehicleDistance => {
println!(" {}", VehicleDistanceMessage::from_pdu(data));
}
PGN::HighResolutionVehicleDistance => {
println!(" {}", HighResolutionVehicleDistanceMessage::from_pdu(data));
}
PGN::FanDrive => {
println!(" {}", FanDriveMessage::from_pdu(data));
}
PGN::Shutdown => {
println!(" {}", ShutdownMessage::from_pdu(data));
}
PGN::EngineTemperature1 => {
println!(" {}", EngineTemperature1Message::from_pdu(data));
}
PGN::InletExhaustConditions1 => {
println!(" {}", InletExhaustConditions1Message::from_pdu(data));
}
PGN::VehicleElectricalPower1 => {
println!(" {}", VehicleElectricalPowerMessage::from_pdu(data));
}
PGN::EngineFluidLevelPressure2 => {
println!(" {}", EngineFluidLevelPressure2Message::from_pdu(data));
}
PGN::AuxiliaryInputOutputStatus => {
println!(" {}", CabIlluminationMessage::from_pdu(data));
}
PGN::ECUHistory => {
println!(" {}", ECUHistoryMessage::from_pdu(data));
}
PGN::TANKInformation1 => {
println!(" {}", TankInformation1Message::from_pdu(data));
}
PGN::Tachograph => {
println!(" {}", TachographMessage::from_pdu(data));
}
PGN::PowerTakeoffInformation => {
println!(" {}", PowerTakeoffInformationMessage::from_pdu(data));
}
PGN::DiagnosticMessage1 => {
println!(" {}", diagnostic::Message1::from_pdu(data));
}
PGN::Request => {
println!(" Request PGN: {:?}", protocol::request_from_pdu(data));
}
PGN::TimeDate => {
println!(" {:?}", TimeDate::from_pdu(data));
}
_ => {
println!(" Unknown PGN for data decoding.");
}
}
}
fn main() {
let input = env::args().nth(1);
if input.is_none() {
usage();
return;
}
let input_str = input.unwrap();
let parts: Vec<&str> = input_str.split('#').collect();
let id_str = parts[0];
let id_raw = if id_str.starts_with("0x") {
u32::from_str_radix(id_str.trim_start_matches("0x"), 16).expect("Invalid ID")
} else {
u32::from_str_radix(id_str, 16).expect("Invalid ID")
};
let id = Id::new(id_raw);
println!("ID");
println!(" Hex: 0x{:08X}", id.as_raw());
println!(" Dec: {}", id.as_raw());
println!(" Bin: {:029b}", id.as_raw());
println!("Priority: {}", id.priority());
println!("Data Page (DP): {}", id.data_page());
println!("Parameter Group Number (PGN): {:?}", id.pgn());
println!(" Hex: 0x{:04X}", id.pgn_raw());
println!(" Dec: {}", id.pgn_raw());
println!("PDU Format: {:?}", id.pdu_format());
println!("Broadcast: {}", id.is_broadcast());
if let Some(ge) = id.group_extension() {
println!(
"Group Extension (GE)/PDU Specific (PS): 0x{:02X} ({})",
ge, ge
);
}
if let Some(da) = id.destination_address() {
println!("Destination Address (DA): 0x{:02X} ({})", da, da);
}
println!(
"Source Address (SA): 0x{:02X} ({})",
id.source_address(),
id.source_address()
);
if parts.len() > 1 {
let data_str = parts[1];
if data_str.len() % 2 != 0 {
eprintln!("Invalid data: hex string must have an even number of characters");
return;
}
let mut data = Vec::new();
for i in (0..data_str.len()).step_by(2) {
let byte = u8::from_str_radix(&data_str[i..i + 2], 16).expect("Invalid data byte");
data.push(byte);
}
println!();
println!("Data Hex: {:02X?}", data);
if !data.is_empty() {
decode_data(id.pgn(), &data);
}
}
}