Skip to main content

j1939decode/
j1939decode.rs

1use std::env;
2
3use j1939::Id;
4use j1939::PGN;
5use j1939::diagnostic;
6use j1939::protocol;
7use j1939::spn::*;
8
9fn usage() {
10    println!("Usage: j1939decode <input>");
11    println!();
12    println!("Options:");
13    println!("  <input>     29-bit CAN ID in hexadecimal format (0x18EAFF00)");
14    println!("              or CAN ID and data separated by '#' (0x18FEE6EE#243412024029837D)");
15}
16
17fn decode_data(pgn: PGN, data: &[u8]) {
18    println!("Data Decoded:");
19    match pgn {
20        PGN::TorqueSpeedControl1 => {
21            println!("  {}", TorqueSpeedControl1Message::from_pdu(data));
22        }
23        PGN::ElectronicEngineController1 => {
24            println!("  {}", ElectronicEngineController1Message::from_pdu(data));
25        }
26        PGN::ElectronicEngineController2 => {
27            println!("  {}", ElectronicEngineController2Message::from_pdu(data));
28        }
29        PGN::ElectronicEngineController3 => {
30            println!("  {}", ElectronicEngineController3Message::from_pdu(data));
31        }
32        PGN::ElectronicBrakeController1 => {
33            println!("  {}", ElectronicBrakeController1Message::from_pdu(data));
34        }
35        PGN::AmbientConditions => {
36            println!("  {}", AmbientConditionsMessage::from_pdu(data));
37        }
38        PGN::VehiclePosition => {
39            println!("  {}", VehiclePositionMessage::from_pdu(data));
40        }
41        PGN::FuelEconomy => {
42            println!("  {}", FuelEconomyMessage::from_pdu(data));
43        }
44        PGN::EngineFluidLevelPressure1 => {
45            println!("  {}", EngineFluidLevelPressure1Message::from_pdu(data));
46        }
47        PGN::FuelConsumption => {
48            println!("  {}", FuelConsumptionMessage::from_pdu(data));
49        }
50        PGN::VehicleDistance => {
51            println!("  {}", VehicleDistanceMessage::from_pdu(data));
52        }
53        PGN::HighResolutionVehicleDistance => {
54            println!("  {}", HighResolutionVehicleDistanceMessage::from_pdu(data));
55        }
56        PGN::FanDrive => {
57            println!("  {}", FanDriveMessage::from_pdu(data));
58        }
59        PGN::Shutdown => {
60            println!("  {}", ShutdownMessage::from_pdu(data));
61        }
62        PGN::EngineTemperature1 => {
63            println!("  {}", EngineTemperature1Message::from_pdu(data));
64        }
65        PGN::InletExhaustConditions1 => {
66            println!("  {}", InletExhaustConditions1Message::from_pdu(data));
67        }
68        PGN::VehicleElectricalPower1 => {
69            println!("  {}", VehicleElectricalPowerMessage::from_pdu(data));
70        }
71        PGN::EngineFluidLevelPressure2 => {
72            println!("  {}", EngineFluidLevelPressure2Message::from_pdu(data));
73        }
74        PGN::AuxiliaryInputOutputStatus => {
75            println!("  {}", CabIlluminationMessage::from_pdu(data));
76        }
77        PGN::ECUHistory => {
78            println!("  {}", ECUHistoryMessage::from_pdu(data));
79        }
80        PGN::TANKInformation1 => {
81            println!("  {}", TankInformation1Message::from_pdu(data));
82        }
83        PGN::Tachograph => {
84            println!("  {}", TachographMessage::from_pdu(data));
85        }
86        PGN::PowerTakeoffInformation => {
87            println!("  {}", PowerTakeoffInformationMessage::from_pdu(data));
88        }
89        PGN::DiagnosticMessage1 => {
90            println!("  {}", diagnostic::Message1::from_pdu(data));
91        }
92        PGN::Request => {
93            println!("  Request PGN: {:?}", protocol::request_from_pdu(data));
94        }
95        PGN::TimeDate => {
96            // TimeDate currently uses Debug formatting for its decoded representation,
97            // unlike other messages in this function that use Display. This is
98            // intentional because TimeDate does not provide a custom Display format.
99            println!("  {:?}", TimeDate::from_pdu(data));
100        }
101        _ => {
102            println!("  Unknown PGN for data decoding.");
103        }
104    }
105}
106
107fn main() {
108    let input = env::args().nth(1);
109
110    if input.is_none() {
111        usage();
112        return;
113    }
114
115    let input_str = input.unwrap();
116    let parts: Vec<&str> = input_str.split('#').collect();
117
118    let id_str = parts[0];
119    let id_raw = if id_str.starts_with("0x") {
120        u32::from_str_radix(id_str.trim_start_matches("0x"), 16).expect("Invalid ID")
121    } else {
122        u32::from_str_radix(id_str, 16).expect("Invalid ID")
123    };
124
125    let id = Id::new(id_raw);
126
127    println!("ID");
128    println!(" Hex: 0x{:08X}", id.as_raw());
129    println!(" Dec: {}", id.as_raw());
130    println!(" Bin: {:029b}", id.as_raw());
131    println!("Priority: {}", id.priority());
132    println!("Data Page (DP): {}", id.data_page());
133    println!("Parameter Group Number (PGN): {:?}", id.pgn());
134    println!(" Hex: 0x{:04X}", id.pgn_raw());
135    println!(" Dec: {}", id.pgn_raw());
136    println!("PDU Format: {:?}", id.pdu_format());
137    println!("Broadcast: {}", id.is_broadcast());
138
139    if let Some(ge) = id.group_extension() {
140        println!(
141            "Group Extension (GE)/PDU Specific (PS): 0x{:02X} ({})",
142            ge, ge
143        );
144    }
145
146    if let Some(da) = id.destination_address() {
147        println!("Destination Address (DA): 0x{:02X} ({})", da, da);
148    }
149
150    println!(
151        "Source Address (SA): 0x{:02X} ({})",
152        id.source_address(),
153        id.source_address()
154    );
155
156    if parts.len() > 1 {
157        let data_str = parts[1];
158
159        if data_str.len() % 2 != 0 {
160            eprintln!("Invalid data: hex string must have an even number of characters");
161            return;
162        }
163
164        let mut data = Vec::new();
165        for i in (0..data_str.len()).step_by(2) {
166            let byte = u8::from_str_radix(&data_str[i..i + 2], 16).expect("Invalid data byte");
167            data.push(byte);
168        }
169        println!();
170        println!("Data Hex: {:02X?}", data);
171        if !data.is_empty() {
172            decode_data(id.pgn(), &data);
173        }
174    }
175}