j1939decode/
j1939decode.rs1use 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 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}