1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Module for common Diagnostic trouble code data
use bitflags::bitflags;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// DTC name interpretation format specifier
pub enum DTCFormatType {
/// ISO15031-6 DTC Format
Iso15031_6,
/// ISO14229-1 DTC Format
Iso14229_1,
/// SAE J1939-73 DTC Format
SaeJ1939_73,
/// ISO11992-4 DTC Format
Iso11992_4,
/// Unknown DTC Format
Unknown(u8),
/// 2 byte hex (KWP2000)
TwoByteHexKwp,
}
pub(crate) fn dtc_format_from_uds(fmt: u8) -> DTCFormatType {
match fmt {
0x00 => DTCFormatType::Iso15031_6,
0x01 => DTCFormatType::Iso14229_1,
0x02 => DTCFormatType::SaeJ1939_73,
0x03 => DTCFormatType::Iso11992_4,
x => DTCFormatType::Unknown(x),
}
}
bitflags! {
/// DTC Status byte according to D.2 of ISO14229
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DtcStatusByte: u8 {
/// Most recent check has failed
const TEST_FAILED = 0b00000001;
/// Test failed at any time in the most recent operation cycle
const TEST_FAILED_THIS_OPERATION_CYCLE = 0b00000010;
/// DTC is pending
const PENDING_DTC = 0b00000100;
/// DTC is stored
const CONFIRMED_DTC = 0b00001000;
/// DTC check has not been completed since cleared
const TEST_NOT_COMPLETED_SINCE_LAST_CLEAR = 0b00010000;
/// DTC failed since the last clear
const TEST_FAILED_SINCE_LAST_CLEAR = 0b00100000;
/// DTC check has not been completed this operation cycle
const TEST_NOT_COMPLETED_THIS_OP_CYCLE = 0b01000000;
/// Check engine lamp is requested
const WARNING_INDICATOR_REQUESTED = 0b10000000;
}
}
/// Diagnostic trouble code (DTC) storage struct
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DTC {
/// The [DTCFormatType] of the DTC. This is used
/// to interpret the raw value of the DTC
pub format: DTCFormatType,
/// The raw value of the DTC according to the ECU
pub raw: u32,
/// Status of the DTC
pub status: DtcStatusByte,
}
impl DTC {
/// Returns the error in a string format. EG: raw of 8276 = error P
pub fn get_name_as_string(&self) -> String {
match self.format {
DTCFormatType::Iso15031_6 => {
// 2 bytes
let b0 = (self.raw >> 8) as u8;
let b1 = self.raw as u8;
let component_prefix = match b0 >> 6 {
0 => "P",
1 => "C",
2 => "B",
3 => "U",
_ => "N", // Should never happen
};
format!(
"{}{:01X}{:01X}{:01X}{:01X}",
component_prefix,
((b0 & 0x30) >> 4),
b0 & 0x0F,
b1 >> 4,
b1 & 0x0F
)
}
DTCFormatType::TwoByteHexKwp => {
let component_prefix = match (self.raw as u16 & 0b110000000000000) >> 14 {
0b00 => "P",
0b01 => "C",
0b10 => "B",
0b11 => "U",
_ => "", // Should never happen
};
format!("{}{:04X}", component_prefix, self.raw & 0b11111111111111)
// 14 bits
}
_ => format!("{}", self.raw),
}
}
}
#[cfg(test)]
pub mod test {
use super::DTC;
#[test]
pub fn test_dtc_parse_raw() {
let iso15031_6_dtc = DTC {
format: super::DTCFormatType::Iso15031_6,
raw: 8276,
status: super::DtcStatusByte::empty()
};
println!("{:04X}", iso15031_6_dtc.raw);
println!("{}", iso15031_6_dtc.get_name_as_string());
}
}