ecu_diagnostics/
dtc.rs

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