From 4ddaf2fa7e1d91e86cf5e94dd72042a9c2263455 Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Thu, 16 Oct 2025 15:29:26 -0400 Subject: [PATCH 1/6] feat: add num_enum crate to implement enum<>number conversion - uses procedural macros to use the determinant of enum to convert number<>enum Signed-off-by: Parth Patel --- Cargo.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d67101..dce3bd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,13 +134,14 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", "serde", + "serde_core", ] [[package]] @@ -161,6 +162,28 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -179,6 +202,15 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -197,6 +229,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.20" @@ -292,6 +330,36 @@ dependencies = [ "syn", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "tracing" version = "0.1.41" @@ -330,6 +398,7 @@ dependencies = [ "bitmask-enum", "byteorder", "clap", + "num_enum", "serde", "serde_bytes", "thiserror", @@ -461,3 +530,12 @@ name = "windows_x86_64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 6c412f7..1a29ca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,4 @@ serde = { version = "1", optional = true, features = ["derive"] } serde_bytes = { version = "0.11", optional = true } utoipa = { version = "5", optional = true } clap = { version = "4", optional = true, features = ["derive"] } +num_enum = "0.7.4" From e2055b5611fa82f52f71b6b1a88ca03ed99481f5 Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Thu, 16 Oct 2025 15:30:00 -0400 Subject: [PATCH 2/6] feat: implement and test num_enum macro for RoutineControlSubfunction Signed-off-by: Parth Patel --- src/common/communication_type.rs | 37 +++--------- src/error.rs | 2 + src/lib.rs | 88 ++++++++++++++-------------- src/services/control_dtc_settings.rs | 4 +- src/services/routine_control.rs | 6 +- 5 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/common/communication_type.rs b/src/common/communication_type.rs index d4b6231..89b7fdb 100644 --- a/src/common/communication_type.rs +++ b/src/common/communication_type.rs @@ -1,4 +1,5 @@ use crate::Error; +use num_enum::{IntoPrimitive, TryFromPrimitive}; /// `CommunicationType` is used to specify the type of communication behavior to be modified. /// @@ -11,40 +12,18 @@ use crate::Error; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[num_enum(error_type(name = crate::Error, constructor = Error::InvalidCommunicationType))] +#[repr(u8)] pub enum CommunicationType { /// This value is reserved by the ISO 14229-1 Specification - ISOSAEReserved, + ISOSAEReserved = 0x00, /// This value represents all application related communication. - Normal, + Normal = 0x01, /// This value represents all network management related communication. - NetworkManagement, + NetworkManagement = 0x02, /// This value represents all application and network management related communication. - NormalAndNetworkManagement, -} - -impl From for u8 { - fn from(value: CommunicationType) -> Self { - match value { - CommunicationType::ISOSAEReserved => 0x00, - CommunicationType::Normal => 0x01, - CommunicationType::NetworkManagement => 0x02, - CommunicationType::NormalAndNetworkManagement => 0x03, - } - } -} - -impl TryFrom for CommunicationType { - type Error = Error; - fn try_from(value: u8) -> Result { - match value { - 0x00 => Ok(Self::ISOSAEReserved), - 0x01 => Ok(Self::Normal), - 0x02 => Ok(CommunicationType::NetworkManagement), - 0x03 => Ok(CommunicationType::NormalAndNetworkManagement), - val => Err(Error::InvalidCommunicationType(val)), - } - } + NormalAndNetworkManagement = 0x03, } #[cfg(test)] diff --git a/src/error.rs b/src/error.rs index fe69c1f..5a0846e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -38,6 +38,8 @@ pub enum Error { InvalidDtcSubfunctionType(u8), #[error("Invalid DTC Format Identifier: {0}")] InvalidDtcFormatIdentifier(u8), + #[error("Invalid UDS Message Value in WireFormat: {0}")] + InvalidUDSMessageValue(u8), #[error("Reserved for legislative use: {0} ({1})")] ReservedForLegislativeUse(String, u8), } diff --git a/src/lib.rs b/src/lib.rs index 53adc36..fc7b208 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub use common::*; mod error; pub use error::Error; +use num_enum::{IntoPrimitive, TryFromPrimitive}; // Export the Identifier derive macro pub use uds_protocol_derive::Identifier; @@ -58,42 +59,22 @@ pub type ProtocolResponse = Response; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[num_enum(error_type(name = crate::Error, constructor = Error::InvalidUDSMessageValue))] +#[repr(u8)] pub enum RoutineControlSubFunction { - /// Routine will be started sometime between completion of the `StartRoutine` request and the completion of the 1st response message - /// which indicates that the routine has already been performed, or is in progress + /// Routine will be started sometime between completion of the `StartRoutine` request and the completion of the 1st response message which indicates that the routine has already been performed, or is in progress /// /// It might be necessary to switch the server to a specific Diagnostic Session via [`DiagnosticSessionControlRequest`] before starting the routine, /// or unlock the server using [`SecurityAccessRequest`] before starting the routine. - StartRoutine, + StartRoutine = 0x01, /// The server routine shall be stopped in the server's memory sometime between the completion of the `StopRoutine` request and the completion of the 1st response message /// which indicates that the routine has already been stopped, or is in progress - StopRoutine, + StopRoutine = 0x02, /// Request results for the specified routineIdentifier - RequestRoutineResults, -} - -impl From for u8 { - fn from(value: RoutineControlSubFunction) -> Self { - match value { - RoutineControlSubFunction::StartRoutine => 0x01, - RoutineControlSubFunction::StopRoutine => 0x02, - RoutineControlSubFunction::RequestRoutineResults => 0x03, - } - } -} - -impl From for RoutineControlSubFunction { - fn from(value: u8) -> Self { - match value { - 0x01 => RoutineControlSubFunction::StartRoutine, - 0x02 => RoutineControlSubFunction::StopRoutine, - 0x03 => RoutineControlSubFunction::RequestRoutineResults, - _ => panic!("Invalid routine control subfunction: {value}"), - } - } + RequestRoutineResults = 0x03, } impl WireFormat for Vec { @@ -119,27 +100,46 @@ impl IterableWireFormat for Vec {} #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[num_enum(error_type(name = crate::Error, constructor = Error::InvalidUDSMessageValue))] +#[repr(u8)] pub enum DtcSettings { - On, - Off, + On = 0x01, + Off = 0x02, } -impl From for u8 { - fn from(value: DtcSettings) -> Self { - match value { - DtcSettings::On => 0x01, - DtcSettings::Off => 0x02, - } +#[cfg(test)] +mod tests { + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_correct_discriminant() { + let raw_disciminant: u8 = 0x01; + let discriminant_from_id: u8 = RoutineControlSubFunction::StartRoutine.into(); + + let id_from_discriminant: RoutineControlSubFunction = + RoutineControlSubFunction::try_from(raw_disciminant).unwrap(); + + assert_eq!(discriminant_from_id, raw_disciminant); + assert_eq!( + id_from_discriminant, + RoutineControlSubFunction::StartRoutine + ); } -} -impl From for DtcSettings { - fn from(value: u8) -> Self { - match value { - 0x01 => Self::On, - 0x02 => Self::Off, - _ => panic!("Invalid DTC setting: {value}"), - } + #[test] + fn test_incorrect_discriminant() { + let raw_disciminant: u8 = 0x04; + + let id_from_discriminant = RoutineControlSubFunction::try_from(raw_disciminant) + .err() + .unwrap() + .to_string(); + + assert_eq!( + id_from_discriminant, + Error::InvalidUDSMessageValue(raw_disciminant).to_string() + ); } } diff --git a/src/services/control_dtc_settings.rs b/src/services/control_dtc_settings.rs index 1d6db54..c07d645 100644 --- a/src/services/control_dtc_settings.rs +++ b/src/services/control_dtc_settings.rs @@ -25,7 +25,7 @@ impl ControlDTCSettingsRequest { impl WireFormat for ControlDTCSettingsRequest { fn decode(reader: &mut T) -> Result, Error> { let request_byte = reader.read_u8()?; - let setting = DtcSettings::from(request_byte & !SUCCESS); + let setting = DtcSettings::try_from(request_byte & !SUCCESS)?; let suppress_response = request_byte & SUCCESS != 0; Ok(Some(Self { setting, @@ -71,7 +71,7 @@ impl ControlDTCSettingsResponse { impl WireFormat for ControlDTCSettingsResponse { fn decode(reader: &mut T) -> Result, Error> { - let setting = DtcSettings::from(reader.read_u8()?); + let setting = DtcSettings::try_from(reader.read_u8()?)?; Ok(Some(Self { setting })) } diff --git a/src/services/routine_control.rs b/src/services/routine_control.rs index 623e6b0..a083168 100644 --- a/src/services/routine_control.rs +++ b/src/services/routine_control.rs @@ -37,7 +37,8 @@ impl WireFormat for RoutineControlRequest { fn decode(reader: &mut T) -> Result, Error> { - let sub_function = RoutineControlSubFunction::from(reader.read_u8()?); + let sub_function = RoutineControlSubFunction::try_from(reader.read_u8()?) + .expect("Expected Valid UDS Message"); let routine_id = RoutineIdentifier::decode(reader)?.unwrap(); let data = RoutinePayload::decode(reader)?; Ok(Some(Self { @@ -113,7 +114,8 @@ impl RoutineControlResponse WireFormat for RoutineControlResponse { fn decode(reader: &mut T) -> Result, Error> { - let routine_control_type = RoutineControlSubFunction::from(reader.read_u8()?); + let routine_control_type = RoutineControlSubFunction::try_from(reader.read_u8()?) + .expect("Expected Valid UDS Message ID"); // Reads the identifier, then can read 0 bytes, 1 byte, or more let routine_status_record = RoutineStatusRecord::decode(reader)?.unwrap(); Ok(Some(Self { From 1e95d14bdd188935c5445902a0397d0db3916093 Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Fri, 17 Oct 2025 12:49:21 -0400 Subject: [PATCH 3/6] feat: implement const based descriminant for non-unit enum types Signed-off-by: Parth Patel --- src/common/communication_control_type.rs | 78 +++-- src/common/diagnostic_identifier.rs | 345 ++++++++++++++------- src/common/diagnostic_session_type.rs | 62 ++-- src/common/dtc_ext_data.rs | 53 +++- src/common/dtc_snapshot.rs | 13 +- src/common/dtc_status.rs | 148 ++++++--- src/common/negative_response_code.rs | 350 +++++++++++++-------- src/common/reset_type.rs | 61 ++-- src/common/security_access_type.rs | 40 ++- src/service.rs | 368 +++++++++++++--------- src/services/read_dtc_information.rs | 377 ++++++++++++++++------- src/services/request_file_transfer.rs | 52 ++-- 12 files changed, 1322 insertions(+), 625 deletions(-) diff --git a/src/common/communication_control_type.rs b/src/common/communication_control_type.rs index 271beea..f37dec2 100644 --- a/src/common/communication_control_type.rs +++ b/src/common/communication_control_type.rs @@ -10,27 +10,29 @@ use crate::Error; #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum CommunicationControlType { /// This value indicates that the reception and transmission of messages /// shall be enabled for the specified [`CommunicationType`](crate::CommunicationType) - EnableRxAndTx, + EnableRxAndTx = Self::ENABLE_RX_AND_TX, /// This value indicates that the reception of messages shall be enabled /// and the transmission of messages shall be disabled for the specified [`CommunicationType`](crate::CommunicationType) - EnableRxAndDisableTx, + EnableRxAndDisableTx = Self::ENABLE_RX_AND_DISABLE_TX, /// This value indicates that the reception of messages shall be disabled /// and the transmission of messages shall be enabled for the specified [`CommunicationType`](crate::CommunicationType) - DisableRxAndEnableTx, + DisableRxAndEnableTx = Self::DISABLE_RX_AND_ENABLE_TX, /// This value indicates that the reception and transmission of messages /// shall be disabled for the specified [`CommunicationType`](crate::CommunicationType) - DisableRxAndTx, + DisableRxAndTx = Self::DISABLE_RX_AND_TX, /// This value indicates that the reception of messages shall be enabled /// and the transmission of messages shall be disabled for the specified [`CommunicationType`](crate::CommunicationType) /// Additionally, enhanced address information shall be included in the request - EnableRxAndDisableTxWithEnhancedAddressInfo, + EnableRxAndDisableTxWithEnhancedAddressInfo = + Self::ENABLE_RX_AND_DISABLE_TX_WITH_ENHANCED_ADDRESS_INFO, /// This value indicates that the reception and transmission of messages /// shall be enabled for the specified [`CommunicationType`](crate::CommunicationType) /// Additionally, enhanced address information shall be included in the request - EnableRxAndTxWithEnhancedAddressInfo, + EnableRxAndTxWithEnhancedAddressInfo = Self::ENABLE_RX_AND_TX_WITH_ENHANCED_ADDRESS_INFO, /// These values are reserved by the ISO 14229-1 Specification #[cfg_attr(feature = "clap", clap(skip))] ISOSAEReserved(u8), @@ -42,6 +44,22 @@ pub enum CommunicationControlType { SystemSupplierSpecific(u8), } +impl CommunicationControlType { + pub const ENABLE_RX_AND_TX: u8 = 0x00; + pub const ENABLE_RX_AND_DISABLE_TX: u8 = 0x01; + pub const DISABLE_RX_AND_ENABLE_TX: u8 = 0x02; + pub const DISABLE_RX_AND_TX: u8 = 0x03; + pub const ENABLE_RX_AND_DISABLE_TX_WITH_ENHANCED_ADDRESS_INFO: u8 = 0x04; + pub const ENABLE_RX_AND_TX_WITH_ENHANCED_ADDRESS_INFO: u8 = 0x05; + pub const ISO_RESERVED_START: u8 = 0x06; + pub const ISO_RESERVED_END: u8 = 0x3F; + pub const VEHICLE_MANUFACTURER_START: u8 = 0x40; + pub const VEHICLE_MANUFACTURER_END: u8 = 0x5F; + pub const SYSTEM_SUPPLIER_START: u8 = 0x60; + pub const SYSTEM_SUPPLIER_END: u8 = 0x7E; + pub const ISO_RESERVED_EXTENSION: u8 = 0x7F; +} + impl CommunicationControlType { #[must_use] pub const fn is_extended_address_variant(&self) -> bool { @@ -57,12 +75,20 @@ impl From for u8 { #[allow(clippy::match_same_arms)] fn from(value: CommunicationControlType) -> Self { match value { - CommunicationControlType::EnableRxAndTx => 0x00, - CommunicationControlType::EnableRxAndDisableTx => 0x01, - CommunicationControlType::DisableRxAndEnableTx => 0x02, - CommunicationControlType::DisableRxAndTx => 0x03, - CommunicationControlType::EnableRxAndDisableTxWithEnhancedAddressInfo => 0x04, - CommunicationControlType::EnableRxAndTxWithEnhancedAddressInfo => 0x05, + CommunicationControlType::EnableRxAndTx => CommunicationControlType::ENABLE_RX_AND_TX, + CommunicationControlType::EnableRxAndDisableTx => { + CommunicationControlType::ENABLE_RX_AND_DISABLE_TX + } + CommunicationControlType::DisableRxAndEnableTx => { + CommunicationControlType::DISABLE_RX_AND_ENABLE_TX + } + CommunicationControlType::DisableRxAndTx => CommunicationControlType::DISABLE_RX_AND_TX, + CommunicationControlType::EnableRxAndDisableTxWithEnhancedAddressInfo => { + CommunicationControlType::ENABLE_RX_AND_DISABLE_TX_WITH_ENHANCED_ADDRESS_INFO + } + CommunicationControlType::EnableRxAndTxWithEnhancedAddressInfo => { + CommunicationControlType::ENABLE_RX_AND_TX_WITH_ENHANCED_ADDRESS_INFO + } CommunicationControlType::ISOSAEReserved(val) => val, CommunicationControlType::VehicleManufacturerSpecific(val) => val, CommunicationControlType::SystemSupplierSpecific(val) => val, @@ -74,15 +100,25 @@ impl TryFrom for CommunicationControlType { type Error = Error; fn try_from(value: u8) -> Result { match value { - 0x00 => Ok(Self::EnableRxAndTx), - 0x01 => Ok(Self::EnableRxAndDisableTx), - 0x02 => Ok(Self::DisableRxAndEnableTx), - 0x03 => Ok(Self::DisableRxAndTx), - 0x04 => Ok(Self::EnableRxAndDisableTxWithEnhancedAddressInfo), - 0x05 => Ok(Self::EnableRxAndTxWithEnhancedAddressInfo), - 0x06..=0x3F | 0x7F => Ok(Self::ISOSAEReserved(value)), - 0x40..=0x5F => Ok(Self::VehicleManufacturerSpecific(value)), - 0x60..=0x7E => Ok(Self::SystemSupplierSpecific(value)), + Self::ENABLE_RX_AND_TX => Ok(Self::EnableRxAndTx), + Self::ENABLE_RX_AND_DISABLE_TX => Ok(Self::EnableRxAndDisableTx), + Self::DISABLE_RX_AND_ENABLE_TX => Ok(Self::DisableRxAndEnableTx), + Self::DISABLE_RX_AND_TX => Ok(Self::DisableRxAndTx), + Self::ENABLE_RX_AND_DISABLE_TX_WITH_ENHANCED_ADDRESS_INFO => { + Ok(Self::EnableRxAndDisableTxWithEnhancedAddressInfo) + } + Self::ENABLE_RX_AND_TX_WITH_ENHANCED_ADDRESS_INFO => { + Ok(Self::EnableRxAndTxWithEnhancedAddressInfo) + } + Self::ISO_RESERVED_START..=Self::ISO_RESERVED_END | Self::ISO_RESERVED_EXTENSION => { + Ok(Self::ISOSAEReserved(value)) + } + Self::VEHICLE_MANUFACTURER_START..=Self::VEHICLE_MANUFACTURER_END => { + Ok(Self::VehicleManufacturerSpecific(value)) + } + Self::SYSTEM_SUPPLIER_START..=Self::SYSTEM_SUPPLIER_END => { + Ok(Self::SystemSupplierSpecific(value)) + } _ => Err(Error::InvalidCommunicationControlType(value)), } } diff --git a/src/common/diagnostic_identifier.rs b/src/common/diagnostic_identifier.rs index 278043b..691a6ce 100644 --- a/src/common/diagnostic_identifier.rs +++ b/src/common/diagnostic_identifier.rs @@ -16,52 +16,99 @@ pub enum UDSIdentifier { VehicleManufacturerSpecific(u16), #[cfg_attr(feature = "clap", clap(skip))] SystemSupplierSpecific(u16), - BootSoftwareIdentification = 0xF180, - ApplicationSoftwareIdentification = 0xF181, - ApplicationDataIdentification = 0xF182, - BootSoftwareFingerprint = 0xF183, - ApplicationSoftwareFingerprint = 0xF184, - ApplicationDataFingerprint = 0xF185, - ActiveDiagnosticSession = 0xF186, - VehicleManufacturerSparePartNumber = 0xF187, - VehicleManufacturerECUSoftwareNumber = 0xF188, - VehicleManufacturerECUSoftwareVersionNumber = 0xF189, - SystemSupplierIdentifier = 0xF18A, + BootSoftwareIdentification = Self::BOOT_SOFTWARE_IDENTIFICATION, + ApplicationSoftwareIdentification = Self::APPLICATION_SOFTWARE_IDENTIFICATION, + ApplicationDataIdentification = Self::APPLICATION_DATA_IDENTIFICATION, + BootSoftwareFingerprint = Self::BOOT_SOFTWARE_FINGERPRINT, + ApplicationSoftwareFingerprint = Self::APPLICATION_SOFTWARE_FINGERPRINT, + ApplicationDataFingerprint = Self::APPLICATION_DATA_FINGERPRINT, + ActiveDiagnosticSession = Self::ACTIVE_DIAGNOSTIC_SESSION, + VehicleManufacturerSparePartNumber = Self::VEHICLE_MANUFACTURER_SPARE_PART_NUMBER, + VehicleManufacturerECUSoftwareNumber = Self::VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER, + VehicleManufacturerECUSoftwareVersionNumber = + Self::VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER, + SystemSupplierIdentifier = Self::SYSTEM_SUPPLIER_IDENTIFIER, /// This value shall be used to reference the ECU (server) manufacturing date. Record data content and format shall be /// unsigned numeric, ASCII or BCD, and shall be ordered as Year, Month, Day. - ECUManufacturingData = 0xF18B, + ECUManufacturingData = Self::ECU_MANUFACTURING_DATA, /// Get the serial number of the ECU, format shall be server specific. - ECUSerialNumber = 0xF18C, + ECUSerialNumber = Self::ECU_SERIAL_NUMBER, /// Request the supported functional units of the ECU. - SupportedFunctionalUnits = 0xF18D, + SupportedFunctionalUnits = Self::SUPPORTED_FUNCTIONAL_UNITS, /// This value shall be used to reference the vehicle manufacturer order number for a kit (assembled parts bought as a whole for /// production e.g. cockpit), when the spare part number designates only the server (e.g. for aftersales). The record data content and /// format shall be server specific and defined by the vehicle manufacturer. - VehicleManufacturerKitAssemblyPartNumber = 0xF18E, + VehicleManufacturerKitAssemblyPartNumber = Self::VEHICLE_MANUFACTURER_KIT_ASSEMBLY_PART_NUMBER, /// See 14229-1 C.1 for details on Regulation X information. /// Recurive ASCII string - RegulationXSoftwareIdentificationNumbers = 0xF18F, - VIN = 0xF190, - VehicleManufacturerECUHardwareNumber = 0xF191, - SystemSupplierECUHardwareNumber = 0xF192, - SystemSupplierECUHardwareVersionNumber = 0xF193, - SystemSupplierECUSoftwareNumber = 0xF194, - SystemSupplierECUSoftwareVersionNumber = 0xF195, - ExhaustRegulationOrTypeApprovalNumber = 0xF196, - SystemNameOrEngineType = 0xF197, - RepairShopOrTesterSerialNumber = 0xF198, + RegulationXSoftwareIdentificationNumbers = Self::REGULATION_X_SOFTWARE_IDENTIFICATION_NUMBERS, + VehicleIdentificationNumber = Self::VEHICLE_IDENTIFICATION_NUMBER, + VehicleManufacturerECUHardwareNumber = Self::VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER, + SystemSupplierECUHardwareNumber = Self::SYSTEM_SUPPLIER_ECU_HARDWARE_NUMBER, + SystemSupplierECUHardwareVersionNumber = Self::SYSTEM_SUPPLIER_ECU_HARDWARE_VERSION_NUMBER, + SystemSupplierECUSoftwareNumber = Self::SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER, + SystemSupplierECUSoftwareVersionNumber = Self::SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION_NUMBER, + ExhaustRegulationOrTypeApprovalNumber = Self::EXHAUST_REGULATION_OR_TYPE_APPROVAL_NUMBER, + SystemNameOrEngineType = Self::SYSTEM_NAME_OR_ENGINE_TYPE, + RepairShopOrTesterSerialNumber = Self::REPAIR_SHOP_OR_TESTER_SERIAL_NUMBER, /// When the server was last programmed, the record data content and format shall be /// unsigned numeric, ASCII or BCD, and shall be ordered as Year, Month, Day. - ProgrammingDate = 0xF199, - CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber = 0xF19A, - CalibrationDate = 0xF19B, - CalibrationEquipmentSoftwareNumber = 0xF19C, - ECUInstallationDate = 0xF19D, - ODXFile = 0xF19E, + ProgrammingDate = Self::PROGRAMMING_DATE, + CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber = + Self::CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER, + CalibrationDate = Self::CALIBRATION_DATE, + CalibrationEquipmentSoftwareNumber = Self::CALIBRATION_EQUIPMENT_SOFTWARE_NUMBER, + ECUInstallationDate = Self::ECU_INSTALLATION_DATE, + ODXFile = Self::ODX_FILE, /// Used to reference the entity data identifier for a secured data transfer - Entity = 0xF19F, - UDSVersionData = 0xFF00, - ReservedForISO15765_5 = 0xFF01, + Entity = Self::ENTITY, + UDSVersionData = Self::UDS_VERSION_DATA, + ReservedForISO15765_5 = Self::RESERVED_FOR_ISO15765_5, +} + +impl UDSIdentifier { + pub const ISO_SAE_RESERVED_START: u16 = 0x0000; + pub const ISO_SAE_RESERVED_END: u16 = 0x00FF; + pub const VEHICLE_MANUFACTURER_SPECIFIC_START: u16 = 0xF100; + pub const VEHICLE_MANUFACTURER_SPECIFIC_END: u16 = 0xF17F; + pub const BOOT_SOFTWARE_IDENTIFICATION: u16 = 0xF180; + pub const APPLICATION_SOFTWARE_IDENTIFICATION: u16 = 0xF181; + pub const APPLICATION_DATA_IDENTIFICATION: u16 = 0xF182; + pub const BOOT_SOFTWARE_FINGERPRINT: u16 = 0xF183; + pub const APPLICATION_SOFTWARE_FINGERPRINT: u16 = 0xF184; + pub const APPLICATION_DATA_FINGERPRINT: u16 = 0xF185; + pub const ACTIVE_DIAGNOSTIC_SESSION: u16 = 0xF186; + pub const VEHICLE_MANUFACTURER_SPARE_PART_NUMBER: u16 = 0xF187; + pub const VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER: u16 = 0xF188; + pub const VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER: u16 = 0xF189; + pub const SYSTEM_SUPPLIER_IDENTIFIER: u16 = 0xF18A; + pub const ECU_MANUFACTURING_DATA: u16 = 0xF18B; + pub const ECU_SERIAL_NUMBER: u16 = 0xF18C; + pub const SUPPORTED_FUNCTIONAL_UNITS: u16 = 0xF18D; + pub const VEHICLE_MANUFACTURER_KIT_ASSEMBLY_PART_NUMBER: u16 = 0xF18E; + pub const REGULATION_X_SOFTWARE_IDENTIFICATION_NUMBERS: u16 = 0xF18F; + pub const VEHICLE_IDENTIFICATION_NUMBER: u16 = 0xF190; + pub const VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER: u16 = 0xF191; + pub const SYSTEM_SUPPLIER_ECU_HARDWARE_NUMBER: u16 = 0xF192; + pub const SYSTEM_SUPPLIER_ECU_HARDWARE_VERSION_NUMBER: u16 = 0xF193; + pub const SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER: u16 = 0xF194; + pub const SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION_NUMBER: u16 = 0xF195; + pub const EXHAUST_REGULATION_OR_TYPE_APPROVAL_NUMBER: u16 = 0xF196; + pub const SYSTEM_NAME_OR_ENGINE_TYPE: u16 = 0xF197; + pub const REPAIR_SHOP_OR_TESTER_SERIAL_NUMBER: u16 = 0xF198; + pub const PROGRAMMING_DATE: u16 = 0xF199; + pub const CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER: u16 = 0xF19A; + pub const CALIBRATION_DATE: u16 = 0xF19B; + pub const CALIBRATION_EQUIPMENT_SOFTWARE_NUMBER: u16 = 0xF19C; + pub const ECU_INSTALLATION_DATE: u16 = 0xF19D; + pub const ODX_FILE: u16 = 0xF19E; + pub const ENTITY: u16 = 0xF19F; + pub const UDS_VERSION_DATA: u16 = 0xFF00; + pub const RESERVED_FOR_ISO15765_5: u16 = 0xFF01; + pub const SYSTEM_SUPPLIER_SPECIFIC_START: u16 = 0xFD00; + pub const SYSTEM_SUPPLIER_SPECIFIC_END: u16 = 0xFEFF; + pub const ISO_RESERVED_START: u16 = 0xFF02; + pub const ISO_RESERVED_END: u16 = 0xFFFF; } impl TryFrom for UDSIdentifier { @@ -70,43 +117,93 @@ impl TryFrom for UDSIdentifier { #[allow(clippy::match_same_arms)] fn try_from(value: u16) -> Result { Ok(match value { - 0x0000..=0x00FF => Self::ISOSAEReserved(value), - 0xF100..=0xF17F => Self::VehicleManufacturerSpecific(value), + UDSIdentifier::ISO_SAE_RESERVED_START..=UDSIdentifier::ISO_SAE_RESERVED_END => { + UDSIdentifier::ISOSAEReserved(value) + } + UDSIdentifier::VEHICLE_MANUFACTURER_SPECIFIC_START + ..=UDSIdentifier::VEHICLE_MANUFACTURER_SPECIFIC_END => { + UDSIdentifier::VehicleManufacturerSpecific(value) + } // 0x0100..0xA5FF => Manufacturer Specific, - 0xF180 => Self::BootSoftwareIdentification, - 0xF181 => Self::ApplicationSoftwareIdentification, - 0xF182 => Self::ApplicationDataIdentification, - 0xF183 => Self::BootSoftwareFingerprint, - 0xF184 => Self::ApplicationSoftwareFingerprint, - 0xF185 => Self::ApplicationDataFingerprint, - 0xF186 => Self::ActiveDiagnosticSession, - 0xF187 => Self::VehicleManufacturerSparePartNumber, - 0xF188 => Self::VehicleManufacturerECUSoftwareNumber, - 0xF189 => Self::VehicleManufacturerECUSoftwareVersionNumber, - 0xF18A => Self::SystemSupplierIdentifier, - 0xF18B => Self::ECUManufacturingData, - 0xF18C => Self::ECUSerialNumber, - 0xF18D => Self::SupportedFunctionalUnits, - 0xF18E => Self::VehicleManufacturerKitAssemblyPartNumber, - 0xF18F => Self::RegulationXSoftwareIdentificationNumbers, - 0xF190 => Self::VIN, - 0xF191 => Self::VehicleManufacturerECUHardwareNumber, - 0xF192 => Self::SystemSupplierECUHardwareNumber, - 0xF193 => Self::SystemSupplierECUHardwareVersionNumber, - 0xF194 => Self::SystemSupplierECUSoftwareNumber, - 0xF195 => Self::SystemSupplierECUSoftwareVersionNumber, - 0xF196 => Self::ExhaustRegulationOrTypeApprovalNumber, - 0xF197 => Self::SystemNameOrEngineType, - 0xF198 => Self::RepairShopOrTesterSerialNumber, - 0xF199 => Self::ProgrammingDate, - 0xF19A => Self::CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber, - 0xF19B => Self::CalibrationDate, - 0xF19C => Self::CalibrationEquipmentSoftwareNumber, - 0xF19D => Self::ECUInstallationDate, - 0xF19E => Self::ODXFile, - 0xF19F => Self::Entity, - 0xFD00..=0xFEFF => Self::SystemSupplierSpecific(value), - 0xFF02..=0xFFFF => Self::ISOSAEReserved(value), + UDSIdentifier::BOOT_SOFTWARE_IDENTIFICATION => { + UDSIdentifier::BootSoftwareIdentification + } + UDSIdentifier::APPLICATION_SOFTWARE_IDENTIFICATION => { + UDSIdentifier::ApplicationSoftwareIdentification + } + UDSIdentifier::APPLICATION_DATA_IDENTIFICATION => { + UDSIdentifier::ApplicationDataIdentification + } + UDSIdentifier::BOOT_SOFTWARE_FINGERPRINT => UDSIdentifier::BootSoftwareFingerprint, + UDSIdentifier::APPLICATION_SOFTWARE_FINGERPRINT => { + UDSIdentifier::ApplicationSoftwareFingerprint + } + UDSIdentifier::APPLICATION_DATA_FINGERPRINT => { + UDSIdentifier::ApplicationDataFingerprint + } + UDSIdentifier::ACTIVE_DIAGNOSTIC_SESSION => UDSIdentifier::ActiveDiagnosticSession, + UDSIdentifier::VEHICLE_MANUFACTURER_SPARE_PART_NUMBER => { + UDSIdentifier::VehicleManufacturerSparePartNumber + } + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER => { + UDSIdentifier::VehicleManufacturerECUSoftwareNumber + } + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER => { + UDSIdentifier::VehicleManufacturerECUSoftwareVersionNumber + } + UDSIdentifier::SYSTEM_SUPPLIER_IDENTIFIER => UDSIdentifier::SystemSupplierIdentifier, + UDSIdentifier::ECU_MANUFACTURING_DATA => UDSIdentifier::ECUManufacturingData, + UDSIdentifier::ECU_SERIAL_NUMBER => UDSIdentifier::ECUSerialNumber, + UDSIdentifier::SUPPORTED_FUNCTIONAL_UNITS => UDSIdentifier::SupportedFunctionalUnits, + UDSIdentifier::VEHICLE_MANUFACTURER_KIT_ASSEMBLY_PART_NUMBER => { + UDSIdentifier::VehicleManufacturerKitAssemblyPartNumber + } + UDSIdentifier::REGULATION_X_SOFTWARE_IDENTIFICATION_NUMBERS => { + UDSIdentifier::RegulationXSoftwareIdentificationNumbers + } + UDSIdentifier::VEHICLE_IDENTIFICATION_NUMBER => { + UDSIdentifier::VehicleIdentificationNumber + } + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER => { + UDSIdentifier::VehicleManufacturerECUHardwareNumber + } + UDSIdentifier::SYSTEM_SUPPLIER_ECU_HARDWARE_NUMBER => { + UDSIdentifier::SystemSupplierECUHardwareNumber + } + UDSIdentifier::SYSTEM_SUPPLIER_ECU_HARDWARE_VERSION_NUMBER => { + UDSIdentifier::SystemSupplierECUHardwareVersionNumber + } + UDSIdentifier::SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER => { + UDSIdentifier::SystemSupplierECUSoftwareNumber + } + UDSIdentifier::SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION_NUMBER => { + UDSIdentifier::SystemSupplierECUSoftwareVersionNumber + } + UDSIdentifier::EXHAUST_REGULATION_OR_TYPE_APPROVAL_NUMBER => { + UDSIdentifier::ExhaustRegulationOrTypeApprovalNumber + } + UDSIdentifier::SYSTEM_NAME_OR_ENGINE_TYPE => UDSIdentifier::SystemNameOrEngineType, + UDSIdentifier::REPAIR_SHOP_OR_TESTER_SERIAL_NUMBER => { + UDSIdentifier::RepairShopOrTesterSerialNumber + } + UDSIdentifier::PROGRAMMING_DATE => UDSIdentifier::ProgrammingDate, + UDSIdentifier::CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER => { + UDSIdentifier::CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber + } + UDSIdentifier::CALIBRATION_DATE => UDSIdentifier::CalibrationDate, + UDSIdentifier::CALIBRATION_EQUIPMENT_SOFTWARE_NUMBER => { + UDSIdentifier::CalibrationEquipmentSoftwareNumber + } + UDSIdentifier::ECU_INSTALLATION_DATE => UDSIdentifier::ECUInstallationDate, + UDSIdentifier::ODX_FILE => UDSIdentifier::ODXFile, + UDSIdentifier::ENTITY => UDSIdentifier::Entity, + UDSIdentifier::SYSTEM_SUPPLIER_SPECIFIC_START + ..=UDSIdentifier::SYSTEM_SUPPLIER_SPECIFIC_END => { + UDSIdentifier::SystemSupplierSpecific(value) + } + UDSIdentifier::ISO_RESERVED_START..=UDSIdentifier::ISO_RESERVED_END => { + UDSIdentifier::ISOSAEReserved(value) + } _ => return Err(Error::InvalidDiagnosticIdentifier(value)), }) @@ -120,40 +217,80 @@ impl From for u16 { UDSIdentifier::ISOSAEReserved(identifier) => identifier, UDSIdentifier::VehicleManufacturerSpecific(identifier) => identifier, UDSIdentifier::SystemSupplierSpecific(identifier) => identifier, - UDSIdentifier::BootSoftwareIdentification => 0xF180, - UDSIdentifier::ApplicationSoftwareIdentification => 0xF181, - UDSIdentifier::ApplicationDataIdentification => 0xF182, - UDSIdentifier::BootSoftwareFingerprint => 0xF183, - UDSIdentifier::ApplicationSoftwareFingerprint => 0xF184, - UDSIdentifier::ApplicationDataFingerprint => 0xF185, - UDSIdentifier::ActiveDiagnosticSession => 0xF186, - UDSIdentifier::VehicleManufacturerSparePartNumber => 0xF187, - UDSIdentifier::VehicleManufacturerECUSoftwareNumber => 0xF188, - UDSIdentifier::VehicleManufacturerECUSoftwareVersionNumber => 0xF189, - UDSIdentifier::SystemSupplierIdentifier => 0xF18A, - UDSIdentifier::ECUManufacturingData => 0xF18B, - UDSIdentifier::ECUSerialNumber => 0xF18C, - UDSIdentifier::SupportedFunctionalUnits => 0xF18D, - UDSIdentifier::VehicleManufacturerKitAssemblyPartNumber => 0xF18E, - UDSIdentifier::RegulationXSoftwareIdentificationNumbers => 0xF18F, - UDSIdentifier::VIN => 0xF190, - UDSIdentifier::VehicleManufacturerECUHardwareNumber => 0xF191, - UDSIdentifier::SystemSupplierECUHardwareNumber => 0xF192, - UDSIdentifier::SystemSupplierECUHardwareVersionNumber => 0xF193, - UDSIdentifier::SystemSupplierECUSoftwareNumber => 0xF194, - UDSIdentifier::SystemSupplierECUSoftwareVersionNumber => 0xF195, - UDSIdentifier::ExhaustRegulationOrTypeApprovalNumber => 0xF196, - UDSIdentifier::SystemNameOrEngineType => 0xF197, - UDSIdentifier::RepairShopOrTesterSerialNumber => 0xF198, - UDSIdentifier::ProgrammingDate => 0xF199, - UDSIdentifier::CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber => 0xF19A, - UDSIdentifier::CalibrationDate => 0xF19B, - UDSIdentifier::CalibrationEquipmentSoftwareNumber => 0xF19C, - UDSIdentifier::ECUInstallationDate => 0xF19D, - UDSIdentifier::ODXFile => 0xF19E, - UDSIdentifier::Entity => 0xF19F, - UDSIdentifier::UDSVersionData => 0xFF00, - UDSIdentifier::ReservedForISO15765_5 => 0xFF01, + UDSIdentifier::BootSoftwareIdentification => { + UDSIdentifier::BOOT_SOFTWARE_IDENTIFICATION + } + UDSIdentifier::ApplicationSoftwareIdentification => { + UDSIdentifier::APPLICATION_SOFTWARE_IDENTIFICATION + } + UDSIdentifier::ApplicationDataIdentification => { + UDSIdentifier::APPLICATION_DATA_IDENTIFICATION + } + UDSIdentifier::BootSoftwareFingerprint => UDSIdentifier::BOOT_SOFTWARE_FINGERPRINT, + UDSIdentifier::ApplicationSoftwareFingerprint => { + UDSIdentifier::APPLICATION_SOFTWARE_FINGERPRINT + } + UDSIdentifier::ApplicationDataFingerprint => { + UDSIdentifier::APPLICATION_DATA_FINGERPRINT + } + UDSIdentifier::ActiveDiagnosticSession => UDSIdentifier::ACTIVE_DIAGNOSTIC_SESSION, + UDSIdentifier::VehicleManufacturerSparePartNumber => { + UDSIdentifier::VEHICLE_MANUFACTURER_SPARE_PART_NUMBER + } + UDSIdentifier::VehicleManufacturerECUSoftwareNumber => { + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER + } + UDSIdentifier::VehicleManufacturerECUSoftwareVersionNumber => { + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER + } + UDSIdentifier::SystemSupplierIdentifier => UDSIdentifier::SYSTEM_SUPPLIER_IDENTIFIER, + UDSIdentifier::ECUManufacturingData => UDSIdentifier::ECU_MANUFACTURING_DATA, + UDSIdentifier::ECUSerialNumber => UDSIdentifier::ECU_SERIAL_NUMBER, + UDSIdentifier::SupportedFunctionalUnits => UDSIdentifier::SUPPORTED_FUNCTIONAL_UNITS, + UDSIdentifier::VehicleManufacturerKitAssemblyPartNumber => { + UDSIdentifier::VEHICLE_MANUFACTURER_KIT_ASSEMBLY_PART_NUMBER + } + UDSIdentifier::RegulationXSoftwareIdentificationNumbers => { + UDSIdentifier::REGULATION_X_SOFTWARE_IDENTIFICATION_NUMBERS + } + UDSIdentifier::VehicleIdentificationNumber => { + UDSIdentifier::VEHICLE_IDENTIFICATION_NUMBER + } + UDSIdentifier::VehicleManufacturerECUHardwareNumber => { + UDSIdentifier::VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER + } + UDSIdentifier::SystemSupplierECUHardwareNumber => { + UDSIdentifier::SYSTEM_SUPPLIER_ECU_HARDWARE_NUMBER + } + UDSIdentifier::SystemSupplierECUHardwareVersionNumber => { + UDSIdentifier::SYSTEM_SUPPLIER_ECU_HARDWARE_VERSION_NUMBER + } + UDSIdentifier::SystemSupplierECUSoftwareNumber => { + UDSIdentifier::SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER + } + UDSIdentifier::SystemSupplierECUSoftwareVersionNumber => { + UDSIdentifier::SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION_NUMBER + } + UDSIdentifier::ExhaustRegulationOrTypeApprovalNumber => { + UDSIdentifier::EXHAUST_REGULATION_OR_TYPE_APPROVAL_NUMBER + } + UDSIdentifier::SystemNameOrEngineType => UDSIdentifier::SYSTEM_NAME_OR_ENGINE_TYPE, + UDSIdentifier::RepairShopOrTesterSerialNumber => { + UDSIdentifier::REPAIR_SHOP_OR_TESTER_SERIAL_NUMBER + } + UDSIdentifier::ProgrammingDate => UDSIdentifier::PROGRAMMING_DATE, + UDSIdentifier::CalibrationRepairShopCodeOrCalibrationEquipmentSerialNumber => { + UDSIdentifier::CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER + } + UDSIdentifier::CalibrationDate => UDSIdentifier::CALIBRATION_DATE, + UDSIdentifier::CalibrationEquipmentSoftwareNumber => { + UDSIdentifier::CALIBRATION_EQUIPMENT_SOFTWARE_NUMBER + } + UDSIdentifier::ECUInstallationDate => UDSIdentifier::ECU_INSTALLATION_DATE, + UDSIdentifier::ODXFile => UDSIdentifier::ODX_FILE, + UDSIdentifier::Entity => UDSIdentifier::ENTITY, + UDSIdentifier::UDSVersionData => UDSIdentifier::UDS_VERSION_DATA, + UDSIdentifier::ReservedForISO15765_5 => UDSIdentifier::RESERVED_FOR_ISO15765_5, } } } diff --git a/src/common/diagnostic_session_type.rs b/src/common/diagnostic_session_type.rs index 70bdb65..72f365d 100644 --- a/src/common/diagnostic_session_type.rs +++ b/src/common/diagnostic_session_type.rs @@ -10,6 +10,7 @@ use crate::Error; #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum DiagnosticSessionType { /// This value is reserved by the ISO 14229-1 Specification #[cfg_attr(feature = "clap", clap(skip))] @@ -19,15 +20,15 @@ pub enum DiagnosticSessionType { /// - Any other diagnostic sessions are stopped upon succesful entry into this session /// - Any security authorization is revoked /// - This session is initialized on startup - DefaultSession, + DefaultSession = Self::DEFAULT_SESSION, /// The `ProgrammingSession` (0x02) enables services required to support writing server memory /// - Upon timeout the server shall return to the `DefaultSession` /// - Success response may be sent before or after session is actually entered - ProgrammingSession, + ProgrammingSession = Self::PROGRAMMING_SESSION, /// The `ExtendedDiagnosticSession` (0x03) enables additional diagnostics functionality which can modify server behavior - ExtendedDiagnosticSession, + ExtendedDiagnosticSession = Self::EXTENDED_SESSION, /// The `SafetySystemDiagnosticSession` (0x04) enables diagnostics functionality for safety systems - SafetySystemDiagnosticSession, + SafetySystemDiagnosticSession = Self::SAFETY_SYSTEM_SESSION, /// Value reserved for use by vehicle manufacturers #[cfg_attr(feature = "clap", clap(skip))] VehicleManufacturerSpecificSession(u8), @@ -36,15 +37,34 @@ pub enum DiagnosticSessionType { SystemSupplierSpecificSession(u8), } +impl DiagnosticSessionType { + pub const ISO_RESERVED: u8 = 0x00; + pub const DEFAULT_SESSION: u8 = 0x01; + pub const PROGRAMMING_SESSION: u8 = 0x02; + pub const EXTENDED_SESSION: u8 = 0x03; + pub const SAFETY_SYSTEM_SESSION: u8 = 0x04; + pub const RESERVED_START: u8 = 0x05; + pub const RESERVED_END: u8 = 0x3F; + pub const VEHICLE_MANUFACTURER_START: u8 = 0x40; + pub const VEHICLE_MANUFACTURER_END: u8 = 0x5F; + pub const SYSTEM_SUPPLIER_START: u8 = 0x60; + pub const SYSTEM_SUPPLIER_END: u8 = 0x7E; + pub const ISO_RESERVED_EXTENSION: u8 = 0x7F; +} + impl From for u8 { #[allow(clippy::match_same_arms)] fn from(value: DiagnosticSessionType) -> Self { match value { DiagnosticSessionType::ISOSAEReserved(value) => value, - DiagnosticSessionType::DefaultSession => 0x01, - DiagnosticSessionType::ProgrammingSession => 0x02, - DiagnosticSessionType::ExtendedDiagnosticSession => 0x03, - DiagnosticSessionType::SafetySystemDiagnosticSession => 0x04, + DiagnosticSessionType::DefaultSession => DiagnosticSessionType::DEFAULT_SESSION, + DiagnosticSessionType::ProgrammingSession => DiagnosticSessionType::PROGRAMMING_SESSION, + DiagnosticSessionType::ExtendedDiagnosticSession => { + DiagnosticSessionType::EXTENDED_SESSION + } + DiagnosticSessionType::SafetySystemDiagnosticSession => { + DiagnosticSessionType::SAFETY_SYSTEM_SESSION + } DiagnosticSessionType::VehicleManufacturerSpecificSession(value) => value, DiagnosticSessionType::SystemSupplierSpecificSession(value) => value, } @@ -56,17 +76,21 @@ impl TryFrom for DiagnosticSessionType { #[allow(clippy::match_same_arms)] fn try_from(value: u8) -> Result { match value { - 0x00 => Ok(DiagnosticSessionType::ISOSAEReserved(value)), - 0x01 => Ok(DiagnosticSessionType::DefaultSession), - 0x02 => Ok(DiagnosticSessionType::ProgrammingSession), - 0x03 => Ok(DiagnosticSessionType::ExtendedDiagnosticSession), - 0x04 => Ok(DiagnosticSessionType::SafetySystemDiagnosticSession), - 0x05..=0x3F => Ok(DiagnosticSessionType::ISOSAEReserved(value)), - 0x40..=0x5F => Ok(DiagnosticSessionType::VehicleManufacturerSpecificSession( - value, - )), - 0x60..=0x7E => Ok(DiagnosticSessionType::SystemSupplierSpecificSession(value)), - 0x7F => Ok(DiagnosticSessionType::ISOSAEReserved(value)), + Self::ISO_RESERVED => Ok(DiagnosticSessionType::ISOSAEReserved(value)), + Self::DEFAULT_SESSION => Ok(DiagnosticSessionType::DefaultSession), + Self::PROGRAMMING_SESSION => Ok(DiagnosticSessionType::ProgrammingSession), + Self::EXTENDED_SESSION => Ok(DiagnosticSessionType::ExtendedDiagnosticSession), + Self::SAFETY_SYSTEM_SESSION => Ok(DiagnosticSessionType::SafetySystemDiagnosticSession), + Self::RESERVED_START..=Self::RESERVED_END => { + Ok(DiagnosticSessionType::ISOSAEReserved(value)) + } + Self::VEHICLE_MANUFACTURER_START..=Self::VEHICLE_MANUFACTURER_END => Ok( + DiagnosticSessionType::VehicleManufacturerSpecificSession(value), + ), + Self::SYSTEM_SUPPLIER_START..=Self::SYSTEM_SUPPLIER_END => { + Ok(DiagnosticSessionType::SystemSupplierSpecificSession(value)) + } + Self::ISO_RESERVED_EXTENSION => Ok(DiagnosticSessionType::ISOSAEReserved(value)), _ => Err(Error::InvalidDiagnosticSessionType(value)), } } diff --git a/src/common/dtc_ext_data.rs b/src/common/dtc_ext_data.rs index 716df29..f629a27 100644 --- a/src/common/dtc_ext_data.rs +++ b/src/common/dtc_ext_data.rs @@ -9,6 +9,7 @@ use crate::{ #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum DTCExtDataRecordNumber { // 0x00, 0xF0-0xFD are reserved ISOSAEReserved(u8), @@ -30,22 +31,52 @@ pub enum DTCExtDataRecordNumber { RegulatedDTCExtDataRecords(u8), /// Requests the server to report all regulated emissions OBD stored `DTCExtendedDataRecords`. - AllRegulatedEmissionsOBDDTCExtDataRecords, + AllRegulatedEmissionsOBDDTCExtDataRecords = + Self::ALL_REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS, /// Requests the server to report all stored `DTCExtendedDataRecords` - AllDTCExtDataRecords, + AllDTCExtDataRecords = Self::ALL_DTC_EXT_DATA_RECORDS, } impl DTCExtDataRecordNumber { + pub const ISO_SAE_RESERVED: u8 = 0x00; + pub const ISO_SAE_RESERVED_START: u8 = 0xF0; + pub const ISO_SAE_RESERVED_END: u8 = 0xFD; + pub const VEHICLE_MANUFACTURER_START: u8 = 0x01; + pub const VEHICLE_MANUFACTURER_END: u8 = 0x8F; + pub const REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS_START: u8 = 0x90; + pub const REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS_END: u8 = 0x9F; + pub const REGULATED_DTC_EXT_DATA_RECORDS_START: u8 = 0xA0; + pub const REGULATED_DTC_EXT_DATA_RECORDS_END: u8 = 0xEF; + pub const ALL_REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS: u8 = 0xFE; + pub const ALL_DTC_EXT_DATA_RECORDS: u8 = 0xFF; + #[must_use] pub fn new(value: u8) -> Self { match value { - 0x00 | 0xF0..=0xFD => Self::ISOSAEReserved(value), - 0x01..=0x8F => Self::VehicleManufacturer(value), - 0x90..=0x9F => Self::RegulatedEmissionsOBDDTCExtDataRecords(value), - 0xA0..=0xEF => Self::RegulatedDTCExtDataRecords(value), - 0xFE => Self::AllRegulatedEmissionsOBDDTCExtDataRecords, - 0xFF => Self::AllDTCExtDataRecords, + DTCExtDataRecordNumber::ISO_SAE_RESERVED + | DTCExtDataRecordNumber::ISO_SAE_RESERVED_START + ..=DTCExtDataRecordNumber::ISO_SAE_RESERVED_END => { + DTCExtDataRecordNumber::ISOSAEReserved(value) + } + DTCExtDataRecordNumber::VEHICLE_MANUFACTURER_START + ..=DTCExtDataRecordNumber::VEHICLE_MANUFACTURER_END => { + DTCExtDataRecordNumber::VehicleManufacturer(value) + } + DTCExtDataRecordNumber::REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS_START + ..=DTCExtDataRecordNumber::REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS_END => { + DTCExtDataRecordNumber::RegulatedEmissionsOBDDTCExtDataRecords(value) + } + DTCExtDataRecordNumber::REGULATED_DTC_EXT_DATA_RECORDS_START + ..=DTCExtDataRecordNumber::REGULATED_DTC_EXT_DATA_RECORDS_END => { + DTCExtDataRecordNumber::RegulatedDTCExtDataRecords(value) + } + DTCExtDataRecordNumber::ALL_REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS => { + DTCExtDataRecordNumber::AllRegulatedEmissionsOBDDTCExtDataRecords + } + DTCExtDataRecordNumber::ALL_DTC_EXT_DATA_RECORDS => { + DTCExtDataRecordNumber::AllDTCExtDataRecords + } } } @@ -57,8 +88,10 @@ impl DTCExtDataRecordNumber { Self::VehicleManufacturer(value) => *value, Self::RegulatedEmissionsOBDDTCExtDataRecords(value) => *value, Self::RegulatedDTCExtDataRecords(value) => *value, - Self::AllRegulatedEmissionsOBDDTCExtDataRecords => 0xFE, - Self::AllDTCExtDataRecords => 0xFF, + Self::AllRegulatedEmissionsOBDDTCExtDataRecords => { + DTCExtDataRecordNumber::ALL_REGULATED_EMISSIONS_OBD_DTC_EXT_DATA_RECORDS + } + Self::AllDTCExtDataRecords => DTCExtDataRecordNumber::ALL_DTC_EXT_DATA_RECORDS, } } } diff --git a/src/common/dtc_snapshot.rs b/src/common/dtc_snapshot.rs index 7b5b8f0..62ded7a 100644 --- a/src/common/dtc_snapshot.rs +++ b/src/common/dtc_snapshot.rs @@ -163,22 +163,27 @@ pub type UserDefDTCSnapshotRecordNumber = DTCSnapshotRecordNumber; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum DTCSnapshotRecordNumber { /// Reserved for Legislative purposes Reserved(u8), /// Indicates the number of the specific `DTCSnapshot` data record requested Number(u8), /// Requests that the server report all `DTCSnapshot` data records at once - All, + All = Self::ALL, } impl DTCSnapshotRecordNumber { + pub const RESERVED_START: u8 = 0x00; + pub const RESERVED_STOP: u8 = 0xF0; + pub const ALL: u8 = 0xFF; + /// Create a new `DTCSnapshotRecordNumber` validating that it is in the range we expect #[must_use] pub fn new(record_number: u8) -> Self { match record_number { - 0x00 | 0xF0 => Self::Reserved(record_number), - 0xFF => Self::All, + Self::RESERVED_START | Self::RESERVED_STOP => Self::Reserved(record_number), + Self::ALL => Self::All, _ => Self::Number(record_number), } } @@ -188,7 +193,7 @@ impl DTCSnapshotRecordNumber { match self { DTCSnapshotRecordNumber::Reserved(value) => *value, DTCSnapshotRecordNumber::Number(value) => *value, - DTCSnapshotRecordNumber::All => 0xFF, + DTCSnapshotRecordNumber::All => Self::ALL, } } } diff --git a/src/common/dtc_status.rs b/src/common/dtc_status.rs index 7379bde..ae0fcf1 100644 --- a/src/common/dtc_status.rs +++ b/src/common/dtc_status.rs @@ -45,7 +45,7 @@ pub enum DTCStatusMask { /// * 1 shall indicate the last matured test **failed** /// /// Will be 0 after a successful [`ClearDiagnosticInformation`](crate::services::ClearDiagnosticInformation) service - TestFailed, + TestFailed = Self::TEST_FAILED, /// Whether or not a diagnostic test has reported a test failed result during the current operation cycle, /// or that it's been reported during this operation and after `ClearDiagnosticInformation` /// @@ -54,7 +54,7 @@ pub enum DTCStatusMask { /// * 1 shall indicate that a test failed during the current operation cycle or after a `ClearDiagnosticInformation` /// /// Shall remain a 1 until a new operation cycle is started - TestFailedThisOperationCycle, + TestFailedThisOperationCycle = Self::TEST_FAILED_THIS_OPERATION_CYCLE, /// Similar to [`Self::TestFailedThisOperationCycle`], but will only clear after /// a cycle is finished and there is a passed test w/ no failure @@ -62,7 +62,7 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - Test passed **with no failure** after completing a cycle /// * 1 - Test failed during the current operation cycle - PendingDTC, + PendingDTC = Self::PENDING_DTC, /// Indicates whether a malfunction was detected enough times to warrant the DTC being stored /// in long term memory. This doesn't mean that the DTC failure is present at the time of the request. @@ -71,7 +71,7 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - DTC has **never been confirmed** since last `ClearDiagnosticInformation`, or after aging criteria have been met /// * 1 - DTC has been confirmed at least once - ConfirmedDTC, + ConfirmedDTC = Self::CONFIRMED_DTC, /// Indicates whether a test has run and completed since last `ClearDiagnosticInformation` /// Will not reset to 1 by any method other than calling `ClearDiagnosticInformation` @@ -79,7 +79,7 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - Test has returned passed or failed at least once since last `ClearDiagnosticInformation` /// * 1 - Test has **not** run to completion - TestNotCompletedSinceLastClear, + TestNotCompletedSinceLastClear = Self::TEST_NOT_COMPLETED_SINCE_LAST_CLEAR, /// Indicates whether a test has failed since the last `ClearDiagnosticInformation` /// This is a latched [`Self::TestFailedThisOperationCycle`] @@ -88,7 +88,7 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - Test has **not** failed since last `ClearDiagnosticInformation` /// * 1 - Test has failed at least once since last `ClearDiagnosticInformation` - TestFailedSinceLastClear, + TestFailedSinceLastClear = Self::TEST_FAILED_SINCE_LAST_CLEAR, /// Indicates whether a test has run and completed during the current operation cycle, /// or whether is has run and completed after the last `ClearDiagnosticInformation` during the current operation cycle @@ -96,7 +96,7 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - Test has run and completed during the current operation cycle /// * 1 - Test has **not** run to completion during the current operation cycle - TestNotCompletedThisOperationCycle, + TestNotCompletedThisOperationCycle = Self::TEST_NOT_COMPLETED_THIS_OPERATION_CYCLE, /// Shall report the status of any warning indicators associated with a certain DTC. Warning outputs may consist /// of indicator lamp(s), displayed text information, etc. @@ -104,7 +104,18 @@ pub enum DTCStatusMask { /// Bit state definition: /// * 0 - Server is **not** requesting a warningIndicator to be active /// * 1 - Server is requesting a warningIndicator to be active - WarningIndicatorRequested, + WarningIndicatorRequested = Self::WARNING_INDICATOR_REQUESTED, +} + +impl DTCStatusMask { + pub const TEST_FAILED: u8 = 0b0000_0001; + pub const TEST_FAILED_THIS_OPERATION_CYCLE: u8 = 0b0000_0010; + pub const PENDING_DTC: u8 = 0b0000_0100; + pub const CONFIRMED_DTC: u8 = 0b0000_1000; + pub const TEST_NOT_COMPLETED_SINCE_LAST_CLEAR: u8 = 0b0001_0000; + pub const TEST_FAILED_SINCE_LAST_CLEAR: u8 = 0b0010_0000; + pub const TEST_NOT_COMPLETED_THIS_OPERATION_CYCLE: u8 = 0b0100_0000; + pub const WARNING_INDICATOR_REQUESTED: u8 = 0b1000_0000; } impl WireFormat for DTCStatusMask { @@ -136,34 +147,50 @@ impl SingleValueWireFormat for DTCStatusMask {} #[repr(u8)] pub enum DTCFormatIdentifier { /// Defined in [SAE J2012-DA]() DTC Format - SAE_J2012_DA_DTCFormat_00 = 0x00, + SAE_J2012_DA_DTCFormat_00 = Self::SAE_J2012_DA_DTC_FORMAT_00, /// reported for `DTCAndStatusRecord` - ISO_14229_1_DTCFormat = 0x01, + ISO_14229_1_DTCFormat = Self::ISO_14229_1_DTC_FORMAT, /// Defined in [SAE J1939-73]() - SAE_J1939_73_DTCFormat = 0x02, + SAE_J1939_73_DTCFormat = Self::SAE_J1939_73_DTC_FORMAT, /// Defined in [ISO-11992]() - ISO_11992_4_DTCFormat = 0x03, + ISO_11992_4_DTCFormat = Self::ISO_11992_4_DTC_FORMAT, /// Defined in SAE J2012-DA]() - SAE_J2012_DA_DTCFormat_04 = 0x04, + SAE_J2012_DA_DTCFormat_04 = Self::SAE_J2012_DA_DTC_FORMAT_04, /// Reserved for future usage /// 0x05 - 0xFF ISOSAEReserved(u8), } -impl DTCFormatIdentifier {} +impl DTCFormatIdentifier { + pub const SAE_J2012_DA_DTC_FORMAT_00: u8 = 0x00; + pub const ISO_14229_1_DTC_FORMAT: u8 = 0x01; + pub const SAE_J1939_73_DTC_FORMAT: u8 = 0x02; + pub const ISO_11992_4_DTC_FORMAT: u8 = 0x03; + pub const SAE_J2012_DA_DTC_FORMAT_04: u8 = 0x04; +} impl From for DTCFormatIdentifier { fn from(value: u8) -> Self { match value { - 0x00 => DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_00, - 0x01 => DTCFormatIdentifier::ISO_14229_1_DTCFormat, - 0x02 => DTCFormatIdentifier::SAE_J1939_73_DTCFormat, - 0x03 => DTCFormatIdentifier::ISO_11992_4_DTCFormat, - 0x04 => DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_04, + DTCFormatIdentifier::SAE_J2012_DA_DTC_FORMAT_00 => { + DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_00 + } + DTCFormatIdentifier::ISO_14229_1_DTC_FORMAT => { + DTCFormatIdentifier::ISO_14229_1_DTCFormat + } + DTCFormatIdentifier::SAE_J1939_73_DTC_FORMAT => { + DTCFormatIdentifier::SAE_J1939_73_DTCFormat + } + DTCFormatIdentifier::ISO_11992_4_DTC_FORMAT => { + DTCFormatIdentifier::ISO_11992_4_DTCFormat + } + DTCFormatIdentifier::SAE_J2012_DA_DTC_FORMAT_04 => { + DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_04 + } val => DTCFormatIdentifier::ISOSAEReserved(val), } } @@ -172,11 +199,21 @@ impl From for DTCFormatIdentifier { impl From for u8 { fn from(val: DTCFormatIdentifier) -> Self { match val { - DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_00 => 0x00, - DTCFormatIdentifier::ISO_14229_1_DTCFormat => 0x01, - DTCFormatIdentifier::SAE_J1939_73_DTCFormat => 0x02, - DTCFormatIdentifier::ISO_11992_4_DTCFormat => 0x03, - DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_04 => 0x04, + DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_00 => { + DTCFormatIdentifier::SAE_J2012_DA_DTC_FORMAT_00 + } + DTCFormatIdentifier::ISO_14229_1_DTCFormat => { + DTCFormatIdentifier::ISO_14229_1_DTC_FORMAT + } + DTCFormatIdentifier::SAE_J1939_73_DTCFormat => { + DTCFormatIdentifier::SAE_J1939_73_DTC_FORMAT + } + DTCFormatIdentifier::ISO_11992_4_DTCFormat => { + DTCFormatIdentifier::ISO_11992_4_DTC_FORMAT + } + DTCFormatIdentifier::SAE_J2012_DA_DTCFormat_04 => { + DTCFormatIdentifier::SAE_J2012_DA_DTC_FORMAT_04 + } DTCFormatIdentifier::ISOSAEReserved(value) => value, // Default value for reserved } } @@ -264,6 +301,7 @@ impl SingleValueWireFormat for DTCRecord {} #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] +#[repr(u8)] pub enum FunctionalGroupIdentifier { /// 0x00 to 0x32 /// 0x34 to 0xCF @@ -271,25 +309,35 @@ pub enum FunctionalGroupIdentifier { /// 0xFF ISOSAEReserved(u8), /// 0x33 - EmissionsSystemGroup, + EmissionsSystemGroup = Self::EMISSIONS_SYSTEM_GROUP, /// 0xD0 - SafetySystemGroup, + SafetySystemGroup = Self::SAFETY_SYSTEM_GROUP, /// 0xD1 to 0xDF /// For future use LegislativeSystemGroup(u8), /// 0xFE - VODBSystem, + VODBSystem = Self::VODB_SYSTEM, } impl FunctionalGroupIdentifier { + pub const EMISSIONS_SYSTEM_GROUP: u8 = 0x33; + pub const SAFETY_SYSTEM_GROUP: u8 = 0xD0; + pub const LEGISLATIVE_SYSTEM_GROUP_START: u8 = 0xD1; + pub const LEGISLATIVE_SYSTEM_GROUP_END: u8 = 0xDF; + pub const VODB_SYSTEM: u8 = 0xFE; + #[must_use] pub fn value(&self) -> u8 { match self { - FunctionalGroupIdentifier::EmissionsSystemGroup => 0x33, - FunctionalGroupIdentifier::SafetySystemGroup => 0xD0, - FunctionalGroupIdentifier::VODBSystem => 0xFE, + FunctionalGroupIdentifier::EmissionsSystemGroup => { + FunctionalGroupIdentifier::EMISSIONS_SYSTEM_GROUP + } + FunctionalGroupIdentifier::SafetySystemGroup => { + FunctionalGroupIdentifier::SAFETY_SYSTEM_GROUP + } + FunctionalGroupIdentifier::VODBSystem => FunctionalGroupIdentifier::VODB_SYSTEM, FunctionalGroupIdentifier::LegislativeSystemGroup(value) => { todo!( "FunctionalGroupIdentifiers::LegislativeSystemGroup is not a valid value {}", @@ -309,10 +357,17 @@ impl FunctionalGroupIdentifier { impl From for FunctionalGroupIdentifier { fn from(value: u8) -> Self { match value { - 0x33 => FunctionalGroupIdentifier::EmissionsSystemGroup, - 0xD0 => FunctionalGroupIdentifier::SafetySystemGroup, - 0xFE => FunctionalGroupIdentifier::VODBSystem, - 0xD1..=0xDF => FunctionalGroupIdentifier::LegislativeSystemGroup(value), + FunctionalGroupIdentifier::EMISSIONS_SYSTEM_GROUP => { + FunctionalGroupIdentifier::EmissionsSystemGroup + } + FunctionalGroupIdentifier::SAFETY_SYSTEM_GROUP => { + FunctionalGroupIdentifier::SafetySystemGroup + } + FunctionalGroupIdentifier::VODB_SYSTEM => FunctionalGroupIdentifier::VODBSystem, + FunctionalGroupIdentifier::LEGISLATIVE_SYSTEM_GROUP_START + ..=FunctionalGroupIdentifier::LEGISLATIVE_SYSTEM_GROUP_END => { + FunctionalGroupIdentifier::LegislativeSystemGroup(value) + } _ => FunctionalGroupIdentifier::ISOSAEReserved(value), } } @@ -337,38 +392,47 @@ impl From for u8 { pub enum DTCSeverityMask { // GtrDtcClassInfo /// Unclassified - DTCClass_0, + DTCClass_0 = Self::DTC_CLASS_0, /// Matches GTR module B Class A definition /// Malfunction is Class A when On-Board Diagnostic (OBD) threshold limits (OTL) are assumed to be exceeded /// It is accepted that the emissions may not be above the OTLs when this class of malfunction occurs - DTCClass_1, + DTCClass_1 = Self::DTC_CLASS_1, /// Matches GTR module B Class B1 definition - DTCClass_2, + DTCClass_2 = Self::DTC_CLASS_2, /// Matches GTR module B Class B2 definition - DTCClass_3, + DTCClass_3 = Self::DTC_CLASS_3, /// Matches GTR module B Class C definition - DTCClass_4, + DTCClass_4 = Self::DTC_CLASS_4, // DTCSeverityInfo section /// Failure requests maintenance only /// /// MO - MaintenanceOnly = 0b0010_0000, // bit 5 + MaintenanceOnly = Self::MAINTENANCE_ONLY, /// Indicates to the failure that a check of the vehicle is required at the next halt /// /// CHKANH - CheckAtNextHalt = 0b0100_0000, // bit 6 + CheckAtNextHalt = Self::CHECK_AT_NEXT_HALT, /// Immediate check of the vehicle is required, /// /// CHKI - CheckImmediately = 0b1000_0000, // bit 7 + CheckImmediately = Self::CHECK_IMMEDIATELY, } impl DTCSeverityMask { + pub const DTC_CLASS_0: u8 = 0b0000_0001; + pub const DTC_CLASS_1: u8 = 0b0000_0010; + pub const DTC_CLASS_2: u8 = 0b0000_0100; + pub const DTC_CLASS_3: u8 = 0b0000_1000; + pub const DTC_CLASS_4: u8 = 0b0001_0000; + pub const MAINTENANCE_ONLY: u8 = 0b0010_0000; + pub const CHECK_AT_NEXT_HALT: u8 = 0b0100_0000; + pub const CHECK_IMMEDIATELY: u8 = 0b1000_0000; + // Validate that at least one of the DTCClass bits is set // Multiple Class bits may be set to get info for multiple DTC classes #[must_use] diff --git a/src/common/negative_response_code.rs b/src/common/negative_response_code.rs index b7978a0..8c264cc 100644 --- a/src/common/negative_response_code.rs +++ b/src/common/negative_response_code.rs @@ -3,45 +3,46 @@ #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum NegativeResponseCode { /// This response code shall not be used in a negative response message. /// This positiveResponse parameter value is reserved for server internal implementation - PositiveResponse, + PositiveResponse = Self::POSITIVE_RESPONSE, /// This range of values is reserved for future definition. #[cfg_attr(feature = "clap", clap(skip))] ISOSAEReserved(u8), /// This response code indicates that the requested action has been rejected by the server. /// The `GeneralReject` response code shall only be implemented in the server if none of the negative response codes meet the needs of the implementation. /// This response code shall not be used as a general replacement for other response codes defined. - GeneralReject, + GeneralReject = Self::GENERAL_REJECT, /// This response code indicates that the requested action will not be taken because the server does not support the requested service. /// The server shall send this response code in the case where the client has sent a request message with a service identifier which is either unknown or not supported. /// This negative response code is not shown in the list of negative response codes to be supported for a diagnostic service, /// because this negative response code is not applicable for supported services. - ServiceNotSupported, + ServiceNotSupported = Self::SERVICE_NOT_SUPPORTED, /// This response code indicates that the requested action will not be taken because the server does not support the service specific parameters of the request message. /// The server shall send this response code in case the client has sent a request message with a known and supported service identifier but with "sub function“ which is either unknown or not supported. - SubFunctionNotSupported, + SubFunctionNotSupported = Self::SUB_FUNCTION_NOT_SUPPORTED, /// This response code indicates that the requested action will not be taken because the length of the received request message does not match the prescribed length for the specified service, /// or that the format of the parameters do not match the prescribed format for the specified service. - IncorrectMessageLengthOrInvalidFormat, + IncorrectMessageLengthOrInvalidFormat = Self::INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT, /// This response code shall be reported by the server if the response to be generated exceeds the maximum number of bytes available by the underlying network layer. - ResponseTooLong, + ResponseTooLong = Self::RESPONSE_TOO_LONG, /// This response code indicates that the server is temporarily too busy to perform the requested operation. /// In this circumstance the client shall perform repetition of the request message or "try again later". /// The repetition of the request shall be delayed by a time specified in the respective implementation documents. - BusyRepeatRequest, + BusyRepeatRequest = Self::BUSY_REPEAT_REQUEST, /// This response code indicates that the requested action will not be taken because the server prerequisite conditions are not met. - ConditionsNotCorrect, + ConditionsNotCorrect = Self::CONDITIONS_NOT_CORRECT, /// This response code indicates that the requested action will not be taken because the server expects a different sequence of request messages or message as sent by the client. /// This may occur when sequence sensitive requests are issued in the wrong order. - RequestSequenceError, + RequestSequenceError = Self::REQUEST_SEQUENCE_ERROR, /// This response code indicates that the requested action will not be taken because the server has detected that the request message contains a parameter which attempts to substitute a value beyond its range of authority /// (e.g. attempting to substitute a data byte of 111 when the data is only defined to 100), /// or which attempts to access a dataIdentifier/routineIdentifer that is not supported or not supported in active session. /// This response code shall be implemented for all services which allow the client to read data, /// write data, or adjust functions by data in the server. - RequestOutOfRange, + RequestOutOfRange = Self::REQUEST_OUT_OF_RANGE, /// This response code indicates that the requested action will not be taken because the server's security strategy has not been satisfied by the client. The server shall send this response code if one of the following cases occur: /// - the test conditions of the server are not met, /// - the required message sequence e.g. `DiagnosticSessionControl`, securityAccess is not met, @@ -49,32 +50,32 @@ pub enum NegativeResponseCode { /// /// Beside the mandatory use of this negative response code as specified in the applicable services within this standard, /// this negative response code can also be used for any case where security is required and is not yet granted to perform the required service. - SecurityAccessDenied, + SecurityAccessDenied = Self::SECURITY_ACCESS_DENIED, /// This response code indicates that the requested action will not be taken because the client has insufficient rights based on its Authentication state. - AuthenticationRequired, + AuthenticationRequired = Self::AUTHENTICATION_REQUIRED, /// This response code indicates that the server has not given security access because the key sent by the client did not match with the key in the server's memory. /// This counts as an attempt to gain security. /// The server shall remain locked and increment its internal securityAccessFailed counter. - InvalidKey, + InvalidKey = Self::INVALID_KEY, /// This response code indicates that the requested action will not be taken because the client has unsuccessfully attempted to gain security access more times than the server's security strategy will allow. - ExceedNumberOfAttempts, + ExceedNumberOfAttempts = Self::EXCEED_NUMBER_OF_ATTEMPTS, /// This response code indicates that the requested action will not be taken because the client's latest attempt to gain security access was initiated before the server's required timeout period had elapsed. - RequiredTimeDelayNotExpired, + RequiredTimeDelayNotExpired = Self::REQUIRED_TIME_DELAY_NOT_EXPIRED, /// Reserved by ISO 15764 #[cfg_attr(feature = "clap", clap(skip))] ExtendedDataLinkSecurityReserved(u8), /// This response code indicates that an attempt to upload/download to a server's memory cannot be accomplished due to some fault conditions. - UploadDownloadNotAccepted, + UploadDownloadNotAccepted = Self::UPLOAD_DOWNLOAD_NOT_ACCEPTED, /// This response code indicates that a data transfer operation was halted due to some fault. /// The active transferData sequence shall be aborted. - TransferDataSuspended, + TransferDataSuspended = Self::TRANSFER_DATA_SUSPENDED, /// This response code indicates that the server detected an error when erasing or programming a memory location in the permanent memory device (e.g. Flash Memory). - GeneralProgrammingFailure, + GeneralProgrammingFailure = Self::GENERAL_PROGRAMMING_FAILURE, /// This response code indicates that the server detected an error in the sequence of `BlockSequenceCounter` values. /// Note that the repetition of a `TransferDataRequest` message with a `BlockSequenceCounter` equal to the one included in the previous `TransferDataRequest` message shall be accepted by the server. - WrongBlockSequenceCounter, + WrongBlockSequenceCounter = Self::WRONG_BLOCK_SEQUENCE_COUNTER, /// This response code indicates that the server detected an error in the sequence of `BlockSequenceCounter` values. - RequestCorrectlyReceivedResponsePending, + RequestCorrectlyReceivedResponsePending = Self::REQUEST_CORRECTLY_RECEIVED_RESPONSE_PENDING, /// This response code indicates that the requested action will not be taken because the server does not support the requested sub-function in the session currently active. /// Within the programmingSession negative response code 0x12 (subFunctionNotSupported) may optionally be reported instead of negative response code 0x7F (subFunctionNotSupportedInActiveSession). /// This response code shall only be used when the requested sub-function is known to be supported in another session, @@ -82,118 +83,211 @@ pub enum NegativeResponseCode { /// This response code shall be supported by each diagnostic service with a sub-function parameter, /// if not otherwise stated in the data link specific implementation document, /// therefore it is not listed in the list of applicable response codes of the diagnostic services. - SubFunctionNotSupportedInActiveSession, + SubFunctionNotSupportedInActiveSession = Self::SUB_FUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION, /// This response code indicates that the requested action will not be taken because the server does not support the requested service in the session currently active. /// This response code shall only be used when the requested service is known to be supported in another session, otherwise response code 0x11 (serviceNotSupported) shall be used. /// This response code is in general supported by each diagnostic service, /// as not otherwise stated in the data link specific implementation document, /// therefore it is not listed in the list of applicable response codes of the diagnostic services. - ServiceNotSupportedInActiveSession, + ServiceNotSupportedInActiveSession = Self::SERVICE_NOT_SUPPORTED_IN_ACTIVE_SESSION, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for RPM is not met (current RPM is above a pre-programmed maximum threshold). - RPMTooHigh, + RPMTooHigh = Self::RPM_TOO_HIGH, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for RPM is not met (current RPM is below a pre-programmed minimum threshold). - RPMTooLow, + RPMTooLow = Self::RPM_TOO_LOW, /// This is required for those actuator tests which cannot be actuated while the Engine is running. /// This is different from RPM too high negative response and needs to be allowed. - EngineIsRunning, + EngineIsRunning = Self::ENGINE_IS_RUNNING, /// This is required for those actuator tests which cannot be actuated unless the Engine is running. /// This is different from RPM too low negative response, and needs to be allowed. - EngineIsNotRunning, + EngineIsNotRunning = Self::ENGINE_IS_NOT_RUNNING, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for engine run time is not met /// (current engine run time is below a preprogrammed limit). - EngineRunTimeTooLow, + EngineRunTimeTooLow = Self::ENGINE_RUN_TIME_TOO_LOW, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for temperature is not met /// (current temperature is above a preprogrammed maximum threshold). - TemperatureTooHigh, + TemperatureTooHigh = Self::TEMPERATURE_TOO_HIGH, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for temperature is not met /// (current temperature is below a preprogrammed minimum threshold). - TemperatureTooLow, + TemperatureTooLow = Self::TEMPERATURE_TOO_LOW, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for vehicle speed is not met /// (current VS is above a pre-programmed maximum threshold). - VehicleSpeedTooHigh, + VehicleSpeedTooHigh = Self::VEHICLE_SPEED_TOO_HIGH, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for vehicle speed is not met /// (current VS is below a pre-programmed minimum threshold). - VehicleSpeedTooLow, + VehicleSpeedTooLow = Self::VEHICLE_SPEED_TOO_LOW, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for throttle/pedal position is not met /// (current TP/APP is above a preprogrammed maximum threshold). - ThrottleOrPedalTooHigh, + ThrottleOrPedalTooHigh = Self::THROTTLE_OR_PEDAL_TOO_HIGH, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for throttle/pedal position is not met /// (current TP/APP is below a preprogrammed minimum threshold). - ThrottleOrPedalTooLow, + ThrottleOrPedalTooLow = Self::THROTTLE_OR_PEDAL_TOO_LOW, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for being in neutral is not met /// (current transmission range is not in neutral). - TransmissionRangeNotInNeutral, + TransmissionRangeNotInNeutral = Self::TRANSMISSION_RANGE_NOT_IN_NEUTRAL, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for being in gear is not met /// (current transmission range is not in gear). - TransmissionRangeNotInGear, + TransmissionRangeNotInGear = Self::TRANSMISSION_RANGE_NOT_IN_GEAR, /// For safety reasons, this is required for certain tests before it begins, /// and must be maintained for the entire duration of the test. - BrakeSwitchNotClosed, + BrakeSwitchNotClosed = Self::BRAKE_SWITCH_NOT_CLOSED, /// For safety reasons, this is required for certain tests before it begins, /// and must be maintained for the entire duration of the test. - ShifterLeverNotInPark, + ShifterLeverNotInPark = Self::SHIFTER_LEVER_NOT_IN_PARK, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for torque converter clutch is not met /// (current TCC status above a preprogrammed limit or locked). - TorqueConverterClutchLocked, + TorqueConverterClutchLocked = Self::TORQUE_CONVERTER_CLUTCH_LOCKED, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for voltage at the primary pin of the server /// (ECU) is not met /// (current voltage is above a pre-programmed maximum threshold). - VoltageTooHigh, + VoltageTooHigh = Self::VOLTAGE_TOO_HIGH, /// This response code indicates that the requested action will not be taken because the server prerequisite condition for voltage at the primary pin of the server /// (ECU) is not met /// (current voltage is below a pre-programmed maximum threshold). - VoltageTooLow, + VoltageTooLow = Self::VOLTAGE_TOO_LOW, /// This range of values is reserved for future definition. #[cfg_attr(feature = "clap", clap(skip))] ReservedForSpecificConditionsNotMet(u8), } +impl NegativeResponseCode { + pub const POSITIVE_RESPONSE: u8 = 0x00; + pub const GENERAL_REJECT: u8 = 0x10; + pub const SERVICE_NOT_SUPPORTED: u8 = 0x11; + pub const SUB_FUNCTION_NOT_SUPPORTED: u8 = 0x12; + pub const INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT: u8 = 0x13; + pub const RESPONSE_TOO_LONG: u8 = 0x14; + pub const BUSY_REPEAT_REQUEST: u8 = 0x21; + pub const CONDITIONS_NOT_CORRECT: u8 = 0x22; + pub const REQUEST_SEQUENCE_ERROR: u8 = 0x24; + pub const REQUEST_OUT_OF_RANGE: u8 = 0x31; + pub const SECURITY_ACCESS_DENIED: u8 = 0x33; + pub const AUTHENTICATION_REQUIRED: u8 = 0x34; + pub const INVALID_KEY: u8 = 0x35; + pub const EXCEED_NUMBER_OF_ATTEMPTS: u8 = 0x36; + pub const REQUIRED_TIME_DELAY_NOT_EXPIRED: u8 = 0x37; + pub const UPLOAD_DOWNLOAD_NOT_ACCEPTED: u8 = 0x70; + pub const TRANSFER_DATA_SUSPENDED: u8 = 0x71; + pub const GENERAL_PROGRAMMING_FAILURE: u8 = 0x72; + pub const WRONG_BLOCK_SEQUENCE_COUNTER: u8 = 0x73; + pub const REQUEST_CORRECTLY_RECEIVED_RESPONSE_PENDING: u8 = 0x78; + pub const SUB_FUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION: u8 = 0x7E; + pub const SERVICE_NOT_SUPPORTED_IN_ACTIVE_SESSION: u8 = 0x7F; + pub const RPM_TOO_HIGH: u8 = 0x81; + pub const RPM_TOO_LOW: u8 = 0x82; + pub const ENGINE_IS_RUNNING: u8 = 0x83; + pub const ENGINE_IS_NOT_RUNNING: u8 = 0x84; + pub const ENGINE_RUN_TIME_TOO_LOW: u8 = 0x85; + pub const TEMPERATURE_TOO_HIGH: u8 = 0x86; + pub const TEMPERATURE_TOO_LOW: u8 = 0x87; + pub const VEHICLE_SPEED_TOO_HIGH: u8 = 0x88; + pub const VEHICLE_SPEED_TOO_LOW: u8 = 0x89; + pub const THROTTLE_OR_PEDAL_TOO_HIGH: u8 = 0x8A; + pub const THROTTLE_OR_PEDAL_TOO_LOW: u8 = 0x8B; + pub const TRANSMISSION_RANGE_NOT_IN_NEUTRAL: u8 = 0x8C; + pub const TRANSMISSION_RANGE_NOT_IN_GEAR: u8 = 0x8D; + pub const BRAKE_SWITCH_NOT_CLOSED: u8 = 0x8F; + pub const SHIFTER_LEVER_NOT_IN_PARK: u8 = 0x90; + pub const TORQUE_CONVERTER_CLUTCH_LOCKED: u8 = 0x91; + pub const VOLTAGE_TOO_HIGH: u8 = 0x92; + pub const VOLTAGE_TOO_LOW: u8 = 0x93; +} + impl From for u8 { #[allow(clippy::match_same_arms)] fn from(value: NegativeResponseCode) -> Self { match value { - NegativeResponseCode::PositiveResponse => 0x00, + NegativeResponseCode::PositiveResponse => NegativeResponseCode::POSITIVE_RESPONSE, NegativeResponseCode::ISOSAEReserved(value) => value, - NegativeResponseCode::GeneralReject => 0x10, - NegativeResponseCode::ServiceNotSupported => 0x11, - NegativeResponseCode::SubFunctionNotSupported => 0x12, - NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat => 0x13, - NegativeResponseCode::ResponseTooLong => 0x14, - NegativeResponseCode::BusyRepeatRequest => 0x21, - NegativeResponseCode::ConditionsNotCorrect => 0x22, - NegativeResponseCode::RequestSequenceError => 0x24, - NegativeResponseCode::RequestOutOfRange => 0x31, - NegativeResponseCode::SecurityAccessDenied => 0x33, - NegativeResponseCode::AuthenticationRequired => 0x34, - NegativeResponseCode::InvalidKey => 0x35, - NegativeResponseCode::ExceedNumberOfAttempts => 0x36, - NegativeResponseCode::RequiredTimeDelayNotExpired => 0x37, + NegativeResponseCode::GeneralReject => NegativeResponseCode::GENERAL_REJECT, + NegativeResponseCode::ServiceNotSupported => { + NegativeResponseCode::SERVICE_NOT_SUPPORTED + } + NegativeResponseCode::SubFunctionNotSupported => { + NegativeResponseCode::SUB_FUNCTION_NOT_SUPPORTED + } + NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat => { + NegativeResponseCode::INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT + } + NegativeResponseCode::ResponseTooLong => NegativeResponseCode::RESPONSE_TOO_LONG, + NegativeResponseCode::BusyRepeatRequest => NegativeResponseCode::BUSY_REPEAT_REQUEST, + NegativeResponseCode::ConditionsNotCorrect => { + NegativeResponseCode::CONDITIONS_NOT_CORRECT + } + NegativeResponseCode::RequestSequenceError => { + NegativeResponseCode::REQUEST_SEQUENCE_ERROR + } + NegativeResponseCode::RequestOutOfRange => NegativeResponseCode::REQUEST_OUT_OF_RANGE, + NegativeResponseCode::SecurityAccessDenied => { + NegativeResponseCode::SECURITY_ACCESS_DENIED + } + NegativeResponseCode::AuthenticationRequired => { + NegativeResponseCode::AUTHENTICATION_REQUIRED + } + NegativeResponseCode::InvalidKey => NegativeResponseCode::INVALID_KEY, + NegativeResponseCode::ExceedNumberOfAttempts => { + NegativeResponseCode::EXCEED_NUMBER_OF_ATTEMPTS + } + NegativeResponseCode::RequiredTimeDelayNotExpired => { + NegativeResponseCode::REQUIRED_TIME_DELAY_NOT_EXPIRED + } NegativeResponseCode::ExtendedDataLinkSecurityReserved(value) => value, - NegativeResponseCode::UploadDownloadNotAccepted => 0x70, - NegativeResponseCode::TransferDataSuspended => 0x71, - NegativeResponseCode::GeneralProgrammingFailure => 0x72, - NegativeResponseCode::WrongBlockSequenceCounter => 0x73, - NegativeResponseCode::RequestCorrectlyReceivedResponsePending => 0x78, - NegativeResponseCode::SubFunctionNotSupportedInActiveSession => 0x7E, - NegativeResponseCode::ServiceNotSupportedInActiveSession => 0x7F, - NegativeResponseCode::RPMTooHigh => 0x81, - NegativeResponseCode::RPMTooLow => 0x82, - NegativeResponseCode::EngineIsRunning => 0x83, - NegativeResponseCode::EngineIsNotRunning => 0x84, - NegativeResponseCode::EngineRunTimeTooLow => 0x85, - NegativeResponseCode::TemperatureTooHigh => 0x86, - NegativeResponseCode::TemperatureTooLow => 0x87, - NegativeResponseCode::VehicleSpeedTooHigh => 0x88, - NegativeResponseCode::VehicleSpeedTooLow => 0x89, - NegativeResponseCode::ThrottleOrPedalTooHigh => 0x8A, - NegativeResponseCode::ThrottleOrPedalTooLow => 0x8B, - NegativeResponseCode::TransmissionRangeNotInNeutral => 0x8C, - NegativeResponseCode::TransmissionRangeNotInGear => 0x8D, - NegativeResponseCode::BrakeSwitchNotClosed => 0x8F, - NegativeResponseCode::ShifterLeverNotInPark => 0x90, - NegativeResponseCode::TorqueConverterClutchLocked => 0x91, - NegativeResponseCode::VoltageTooHigh => 0x92, - NegativeResponseCode::VoltageTooLow => 0x93, + NegativeResponseCode::UploadDownloadNotAccepted => { + NegativeResponseCode::UPLOAD_DOWNLOAD_NOT_ACCEPTED + } + NegativeResponseCode::TransferDataSuspended => { + NegativeResponseCode::TRANSFER_DATA_SUSPENDED + } + NegativeResponseCode::GeneralProgrammingFailure => { + NegativeResponseCode::GENERAL_PROGRAMMING_FAILURE + } + NegativeResponseCode::WrongBlockSequenceCounter => { + NegativeResponseCode::WRONG_BLOCK_SEQUENCE_COUNTER + } + NegativeResponseCode::RequestCorrectlyReceivedResponsePending => { + NegativeResponseCode::REQUEST_CORRECTLY_RECEIVED_RESPONSE_PENDING + } + NegativeResponseCode::SubFunctionNotSupportedInActiveSession => { + NegativeResponseCode::SUB_FUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION + } + NegativeResponseCode::ServiceNotSupportedInActiveSession => { + NegativeResponseCode::SERVICE_NOT_SUPPORTED_IN_ACTIVE_SESSION + } + NegativeResponseCode::RPMTooHigh => NegativeResponseCode::RPM_TOO_HIGH, + NegativeResponseCode::RPMTooLow => NegativeResponseCode::RPM_TOO_LOW, + NegativeResponseCode::EngineIsRunning => NegativeResponseCode::ENGINE_IS_RUNNING, + NegativeResponseCode::EngineIsNotRunning => NegativeResponseCode::ENGINE_IS_NOT_RUNNING, + NegativeResponseCode::EngineRunTimeTooLow => { + NegativeResponseCode::ENGINE_RUN_TIME_TOO_LOW + } + NegativeResponseCode::TemperatureTooHigh => NegativeResponseCode::TEMPERATURE_TOO_HIGH, + NegativeResponseCode::TemperatureTooLow => NegativeResponseCode::TEMPERATURE_TOO_LOW, + NegativeResponseCode::VehicleSpeedTooHigh => { + NegativeResponseCode::VEHICLE_SPEED_TOO_HIGH + } + NegativeResponseCode::VehicleSpeedTooLow => NegativeResponseCode::VEHICLE_SPEED_TOO_LOW, + NegativeResponseCode::ThrottleOrPedalTooHigh => { + NegativeResponseCode::THROTTLE_OR_PEDAL_TOO_HIGH + } + NegativeResponseCode::ThrottleOrPedalTooLow => { + NegativeResponseCode::THROTTLE_OR_PEDAL_TOO_LOW + } + NegativeResponseCode::TransmissionRangeNotInNeutral => { + NegativeResponseCode::TRANSMISSION_RANGE_NOT_IN_NEUTRAL + } + NegativeResponseCode::TransmissionRangeNotInGear => { + NegativeResponseCode::TRANSMISSION_RANGE_NOT_IN_GEAR + } + NegativeResponseCode::BrakeSwitchNotClosed => { + NegativeResponseCode::BRAKE_SWITCH_NOT_CLOSED + } + NegativeResponseCode::ShifterLeverNotInPark => { + NegativeResponseCode::SHIFTER_LEVER_NOT_IN_PARK + } + NegativeResponseCode::TorqueConverterClutchLocked => { + NegativeResponseCode::TORQUE_CONVERTER_CLUTCH_LOCKED + } + NegativeResponseCode::VoltageTooHigh => NegativeResponseCode::VOLTAGE_TOO_HIGH, + NegativeResponseCode::VoltageTooLow => NegativeResponseCode::VOLTAGE_TOO_LOW, NegativeResponseCode::ReservedForSpecificConditionsNotMet(value) => value, } } @@ -203,57 +297,73 @@ impl From for NegativeResponseCode { #[allow(clippy::match_same_arms)] fn from(value: u8) -> Self { match value { - 0x00 => Self::PositiveResponse, + NegativeResponseCode::POSITIVE_RESPONSE => Self::PositiveResponse, 0x01..=0x0F => Self::ISOSAEReserved(value), - 0x10 => Self::GeneralReject, - 0x11 => Self::ServiceNotSupported, - 0x12 => Self::SubFunctionNotSupported, - 0x13 => Self::IncorrectMessageLengthOrInvalidFormat, - 0x14 => Self::ResponseTooLong, + NegativeResponseCode::GENERAL_REJECT => Self::GeneralReject, + NegativeResponseCode::SERVICE_NOT_SUPPORTED => Self::ServiceNotSupported, + NegativeResponseCode::SUB_FUNCTION_NOT_SUPPORTED => Self::SubFunctionNotSupported, + NegativeResponseCode::INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT => { + Self::IncorrectMessageLengthOrInvalidFormat + } + NegativeResponseCode::RESPONSE_TOO_LONG => Self::ResponseTooLong, 0x15..=0x20 => Self::ISOSAEReserved(value), - 0x21 => Self::BusyRepeatRequest, - 0x22 => Self::ConditionsNotCorrect, + NegativeResponseCode::BUSY_REPEAT_REQUEST => Self::BusyRepeatRequest, + NegativeResponseCode::CONDITIONS_NOT_CORRECT => Self::ConditionsNotCorrect, 0x23 => Self::ISOSAEReserved(value), - 0x24 => Self::RequestSequenceError, + NegativeResponseCode::REQUEST_SEQUENCE_ERROR => Self::RequestSequenceError, 0x25..=0x30 => Self::ISOSAEReserved(value), - 0x31 => Self::RequestOutOfRange, + NegativeResponseCode::REQUEST_OUT_OF_RANGE => Self::RequestOutOfRange, 0x32 => Self::ISOSAEReserved(value), - 0x33 => Self::SecurityAccessDenied, - 0x34 => Self::AuthenticationRequired, - 0x35 => Self::InvalidKey, - 0x36 => Self::ExceedNumberOfAttempts, - 0x37 => Self::RequiredTimeDelayNotExpired, + NegativeResponseCode::SECURITY_ACCESS_DENIED => Self::SecurityAccessDenied, + NegativeResponseCode::AUTHENTICATION_REQUIRED => Self::AuthenticationRequired, + NegativeResponseCode::INVALID_KEY => Self::InvalidKey, + NegativeResponseCode::EXCEED_NUMBER_OF_ATTEMPTS => Self::ExceedNumberOfAttempts, + NegativeResponseCode::REQUIRED_TIME_DELAY_NOT_EXPIRED => { + Self::RequiredTimeDelayNotExpired + } 0x38..=0x4F => Self::ExtendedDataLinkSecurityReserved(value), 0x50..=0x6F => Self::ISOSAEReserved(value), - 0x70 => Self::UploadDownloadNotAccepted, - 0x71 => Self::TransferDataSuspended, - 0x72 => Self::GeneralProgrammingFailure, - 0x73 => Self::WrongBlockSequenceCounter, + NegativeResponseCode::UPLOAD_DOWNLOAD_NOT_ACCEPTED => Self::UploadDownloadNotAccepted, + NegativeResponseCode::TRANSFER_DATA_SUSPENDED => Self::TransferDataSuspended, + NegativeResponseCode::GENERAL_PROGRAMMING_FAILURE => Self::GeneralProgrammingFailure, + NegativeResponseCode::WRONG_BLOCK_SEQUENCE_COUNTER => Self::WrongBlockSequenceCounter, 0x74..=0x77 => Self::ISOSAEReserved(value), - 0x78 => Self::RequestCorrectlyReceivedResponsePending, + NegativeResponseCode::REQUEST_CORRECTLY_RECEIVED_RESPONSE_PENDING => { + Self::RequestCorrectlyReceivedResponsePending + } 0x79..=0x7D => Self::ISOSAEReserved(value), - 0x7E => Self::SubFunctionNotSupportedInActiveSession, - 0x7F => Self::ServiceNotSupportedInActiveSession, + NegativeResponseCode::SUB_FUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION => { + Self::SubFunctionNotSupportedInActiveSession + } + NegativeResponseCode::SERVICE_NOT_SUPPORTED_IN_ACTIVE_SESSION => { + Self::ServiceNotSupportedInActiveSession + } 0x80 => Self::ISOSAEReserved(value), - 0x81 => Self::RPMTooHigh, - 0x82 => Self::RPMTooLow, - 0x83 => Self::EngineIsRunning, - 0x84 => Self::EngineIsNotRunning, - 0x85 => Self::EngineRunTimeTooLow, - 0x86 => Self::TemperatureTooHigh, - 0x87 => Self::TemperatureTooLow, - 0x88 => Self::VehicleSpeedTooHigh, - 0x89 => Self::VehicleSpeedTooLow, - 0x8A => Self::ThrottleOrPedalTooHigh, - 0x8B => Self::ThrottleOrPedalTooLow, - 0x8C => Self::TransmissionRangeNotInNeutral, - 0x8D => Self::TransmissionRangeNotInGear, + NegativeResponseCode::RPM_TOO_HIGH => Self::RPMTooHigh, + NegativeResponseCode::RPM_TOO_LOW => Self::RPMTooLow, + NegativeResponseCode::ENGINE_IS_RUNNING => Self::EngineIsRunning, + NegativeResponseCode::ENGINE_IS_NOT_RUNNING => Self::EngineIsNotRunning, + NegativeResponseCode::ENGINE_RUN_TIME_TOO_LOW => Self::EngineRunTimeTooLow, + NegativeResponseCode::TEMPERATURE_TOO_HIGH => Self::TemperatureTooHigh, + NegativeResponseCode::TEMPERATURE_TOO_LOW => Self::TemperatureTooLow, + NegativeResponseCode::VEHICLE_SPEED_TOO_HIGH => Self::VehicleSpeedTooHigh, + NegativeResponseCode::VEHICLE_SPEED_TOO_LOW => Self::VehicleSpeedTooLow, + NegativeResponseCode::THROTTLE_OR_PEDAL_TOO_HIGH => Self::ThrottleOrPedalTooHigh, + NegativeResponseCode::THROTTLE_OR_PEDAL_TOO_LOW => Self::ThrottleOrPedalTooLow, + NegativeResponseCode::TRANSMISSION_RANGE_NOT_IN_NEUTRAL => { + Self::TransmissionRangeNotInNeutral + } + NegativeResponseCode::TRANSMISSION_RANGE_NOT_IN_GEAR => { + Self::TransmissionRangeNotInGear + } 0x8E => Self::ISOSAEReserved(value), - 0x8F => Self::BrakeSwitchNotClosed, - 0x90 => Self::ShifterLeverNotInPark, - 0x91 => Self::TorqueConverterClutchLocked, - 0x92 => Self::VoltageTooHigh, - 0x93 => Self::VoltageTooLow, + NegativeResponseCode::BRAKE_SWITCH_NOT_CLOSED => Self::BrakeSwitchNotClosed, + NegativeResponseCode::SHIFTER_LEVER_NOT_IN_PARK => Self::ShifterLeverNotInPark, + NegativeResponseCode::TORQUE_CONVERTER_CLUTCH_LOCKED => { + Self::TorqueConverterClutchLocked + } + NegativeResponseCode::VOLTAGE_TOO_HIGH => Self::VoltageTooHigh, + NegativeResponseCode::VOLTAGE_TOO_LOW => Self::VoltageTooLow, 0x94..=0xFE => Self::ReservedForSpecificConditionsNotMet(value), 0xFF => Self::ISOSAEReserved(value), } diff --git a/src/common/reset_type.rs b/src/common/reset_type.rs index 534c634..ca4ece7 100644 --- a/src/common/reset_type.rs +++ b/src/common/reset_type.rs @@ -11,6 +11,7 @@ use crate::Error; #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum ResetType { /// This value is reserved #[cfg_attr(feature = "clap", clap(skip))] @@ -19,18 +20,18 @@ pub enum ResetType { /// typically performed after a server has been previously disconnected from its power supply (i.e. battery). /// The performed action is implementation specific and not defined by the spec. /// It might result in the re-initialization of both volatile memory and non-volatile memory locations to predetermined values. - HardReset, + HardReset = Self::HARD_RESET, /// This `SubFunction` identifies a condition similar to the driver turning the ignition key off and back on. /// This reset condition should simulate a key-off-on sequence (i.e. interrupting the switched power supply). /// The performed action is implementation specific and not defined by this document. /// Typically the values of non-volatile mmemory locations are preserved; /// volatile memory will be initialized. - KeyOffOnReset, + KeyOffOnReset = Self::KEY_OFF_ON_RESET, /// This `SubFunction` identifies a "soft reset" condition, which causes the server to immediately restart the application program if applicable. /// The performed action is implementation specific and not defined by the spec. /// A typical action is to restart the application without reinitializing of previously applied configuration data, /// adaptive factors and other long-term adjustments. - SoftReset, + SoftReset = Self::SOFT_RESET, /// This `SubFunction` applies to ECUs which are not ignition powered but battery powered only. /// Therefore a shutdown forces the sleep mode rather than a power off. /// Sleep means power off but still ready for wake-up (battery powered). @@ -43,9 +44,9 @@ pub enum ResetType { /// the server shall send the positive response message prior to the start of the "rapid power shut down" function. /// The next occurrence of a "key on" or "ignition on" signal terminates the "rapid power shut down" function. /// **NOTE** This `SubFunction` is only applicable to a server supporting a stand-by-mode. - EnableRapidPowerShutDown, + EnableRapidPowerShutDown = Self::ENABLE_RAPID_POWER_SHUTDOWN, /// This `SubFunction` requests the server to disable the previously enabled "rapid power shut down" function. - DisableRapidPowerShutDown, + DisableRapidPowerShutDown = Self::DISABLE_RAPID_POWER_SHUTDOWN, /// Reserved for use by vehicle manufacturers #[cfg_attr(feature = "clap", clap(skip))] VehicleManufacturerSpecific(u8), @@ -54,16 +55,32 @@ pub enum ResetType { SystemSupplierSpecific(u8), } +impl ResetType { + pub const ISO_RESERVED: u8 = 0x00; + pub const HARD_RESET: u8 = 0x01; + pub const KEY_OFF_ON_RESET: u8 = 0x02; + pub const SOFT_RESET: u8 = 0x03; + pub const ENABLE_RAPID_POWER_SHUTDOWN: u8 = 0x04; + pub const DISABLE_RAPID_POWER_SHUTDOWN: u8 = 0x05; + pub const ISO_RESERVED_START: u8 = 0x06; + pub const ISO_RESERVED_END: u8 = 0x3F; + pub const VEHICLE_MANUFACTURER_START: u8 = 0x40; + pub const VEHICLE_MANUFACTURER_END: u8 = 0x5F; + pub const SYSTEM_SUPPLIER_START: u8 = 0x60; + pub const SYSTEM_SUPPLIER_END: u8 = 0x7E; + pub const ISO_RESERVED_EXTENSION: u8 = 0x7F; +} + impl From for u8 { #[allow(clippy::match_same_arms)] fn from(value: ResetType) -> Self { match value { ResetType::ISOSAEReserved(val) => val, - ResetType::HardReset => 0x01, - ResetType::KeyOffOnReset => 0x02, - ResetType::SoftReset => 0x03, - ResetType::EnableRapidPowerShutDown => 0x04, - ResetType::DisableRapidPowerShutDown => 0x05, + ResetType::HardReset => ResetType::HARD_RESET, + ResetType::KeyOffOnReset => ResetType::KEY_OFF_ON_RESET, + ResetType::SoftReset => ResetType::SOFT_RESET, + ResetType::EnableRapidPowerShutDown => ResetType::ENABLE_RAPID_POWER_SHUTDOWN, + ResetType::DisableRapidPowerShutDown => ResetType::DISABLE_RAPID_POWER_SHUTDOWN, ResetType::VehicleManufacturerSpecific(val) => val, ResetType::SystemSupplierSpecific(val) => val, } @@ -75,16 +92,20 @@ impl TryFrom for ResetType { #[allow(clippy::match_same_arms)] fn try_from(value: u8) -> Result { match value { - 0x00 => Ok(Self::ISOSAEReserved(0)), - 0x01 => Ok(Self::HardReset), - 0x02 => Ok(Self::KeyOffOnReset), - 0x03 => Ok(Self::SoftReset), - 0x04 => Ok(Self::EnableRapidPowerShutDown), - 0x05 => Ok(Self::DisableRapidPowerShutDown), - 0x06..=0x3F => Ok(Self::ISOSAEReserved(value)), - 0x40..=0x5F => Ok(Self::VehicleManufacturerSpecific(value)), - 0x60..=0x7E => Ok(Self::SystemSupplierSpecific(value)), - 0x7F => Ok(Self::ISOSAEReserved(value)), + Self::ISO_RESERVED => Ok(Self::ISOSAEReserved(value)), + Self::HARD_RESET => Ok(Self::HardReset), + Self::KEY_OFF_ON_RESET => Ok(Self::KeyOffOnReset), + Self::SOFT_RESET => Ok(Self::SoftReset), + Self::ENABLE_RAPID_POWER_SHUTDOWN => Ok(Self::EnableRapidPowerShutDown), + Self::DISABLE_RAPID_POWER_SHUTDOWN => Ok(Self::DisableRapidPowerShutDown), + Self::ISO_RESERVED_START..=Self::ISO_RESERVED_END => Ok(Self::ISOSAEReserved(value)), + Self::VEHICLE_MANUFACTURER_START..=Self::VEHICLE_MANUFACTURER_END => { + Ok(Self::VehicleManufacturerSpecific(value)) + } + Self::SYSTEM_SUPPLIER_START..=Self::SYSTEM_SUPPLIER_END => { + Ok(Self::SystemSupplierSpecific(value)) + } + Self::ISO_RESERVED_EXTENSION => Ok(Self::ISOSAEReserved(value)), _ => Err(Error::InvalidEcuResetType(value)), } } diff --git a/src/common/security_access_type.rs b/src/common/security_access_type.rs index c53bf29..254e0fd 100644 --- a/src/common/security_access_type.rs +++ b/src/common/security_access_type.rs @@ -12,6 +12,7 @@ use crate::Error; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum SecurityAccessType { /// This value is reserved for future definition ISOSAEReserved(u8), @@ -21,13 +22,28 @@ pub enum SecurityAccessType { SendKey(u8), /// `RequestSeed` with different levels of security defined for end of life /// activation of on-board pyrotechnic devices - ISO26021_2Values, + ISO26021_2Values = Self::ISO26021_2_VALUES, /// `SendKey` with different levels of security defined for end of life activation - ISO26021_2SendKeyValues, + ISO26021_2SendKeyValues = Self::ISO26021_2_SEND_KEY_VALUES, /// This range of values is reserved for system supplier specific use SystemSupplierSpecific(u8), } +impl SecurityAccessType { + pub const ISO_RESERVED: u8 = 0x00; + pub const REQUEST_SEED_MIN: u8 = 0x01; + pub const REQUEST_SEED_MAX: u8 = 0x41; + pub const SEND_KEY_MIN: u8 = 0x02; + pub const SEND_KEY_MAX: u8 = 0x42; + pub const ISO_RESERVED_RANGE_START: u8 = 0x43; + pub const ISO_RESERVED_RANGE_END: u8 = 0x5E; + pub const ISO26021_2_VALUES: u8 = 0x5F; + pub const ISO26021_2_SEND_KEY_VALUES: u8 = 0x60; + pub const SYSTEM_SUPPLIER_START: u8 = 0x61; + pub const SYSTEM_SUPPLIER_END: u8 = 0x7E; + pub const ISO_RESERVED_EXTENSION: u8 = 0x7F; +} + impl From for u8 { #[allow(clippy::match_same_arms)] fn from(value: SecurityAccessType) -> Self { @@ -35,8 +51,10 @@ impl From for u8 { SecurityAccessType::ISOSAEReserved(val) => val, SecurityAccessType::RequestSeed(val) => val, SecurityAccessType::SendKey(val) => val, - SecurityAccessType::ISO26021_2Values => 0x5F, - SecurityAccessType::ISO26021_2SendKeyValues => 0x60, + SecurityAccessType::ISO26021_2Values => SecurityAccessType::ISO26021_2_VALUES, + SecurityAccessType::ISO26021_2SendKeyValues => { + SecurityAccessType::ISO26021_2_SEND_KEY_VALUES + } SecurityAccessType::SystemSupplierSpecific(val) => val, } } @@ -46,19 +64,23 @@ impl TryFrom for SecurityAccessType { type Error = Error; fn try_from(value: u8) -> Result { match value { - 0x00 | 0x43..=0x5E | 0x7F => Ok(Self::ISOSAEReserved(value)), + Self::ISO_RESERVED + | Self::ISO_RESERVED_RANGE_START..=Self::ISO_RESERVED_RANGE_END + | Self::ISO_RESERVED_EXTENSION => Ok(Self::ISOSAEReserved(value)), // Security requests alternate, with odd numbers being seed requests, // and even numbers being send key requests - 0x01..=0x42 => { + Self::REQUEST_SEED_MIN..=Self::SEND_KEY_MAX => { if value % 2 == 1 { Ok(Self::RequestSeed(value)) } else { Ok(Self::SendKey(value)) } } - 0x5F => Ok(Self::ISO26021_2Values), - 0x60 => Ok(Self::ISO26021_2SendKeyValues), - 0x61..=0x7E => Ok(Self::SystemSupplierSpecific(value)), + Self::ISO26021_2_VALUES => Ok(Self::ISO26021_2Values), + Self::ISO26021_2_SEND_KEY_VALUES => Ok(Self::ISO26021_2SendKeyValues), + Self::SYSTEM_SUPPLIER_START..=Self::SYSTEM_SUPPLIER_END => { + Ok(Self::SystemSupplierSpecific(value)) + } _ => Err(Error::InvalidSecurityAccessType(value)), } } diff --git a/src/service.rs b/src/service.rs index 8cec1c3..093d2fa 100644 --- a/src/service.rs +++ b/src/service.rs @@ -4,6 +4,7 @@ // Without the non-exhaustive annotation, adding additional diagnostic commands would be a breaking semver change. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] +#[repr(u8)] pub enum UdsServiceType { // ======================================================================== // Diagnostics and Communications Management @@ -18,7 +19,7 @@ pub enum UdsServiceType { /// - 0x04 "Safety system diagnostic session" used to test all safety-critical diagnostic functions, such as airbag tests. /// /// In addition, there are reserved session identifiers that can be defined for vehicle manufacturers and vehicle suppliers specific use. - DiagnosticSessionControl, + DiagnosticSessionControl = Self::DIAGNOSTIC_SESSION_CONTROL, /// The service "ECU reset" is used to restart the control unit (ECU). /// Depending on the control unit hardware and implementation, different forms of reset can be used: /// @@ -27,49 +28,49 @@ pub enum UdsServiceType { /// - Soft Reset" allows the initialization of certain program units and their storage structures. /// /// Again, there are reserved values that can be defined for vehicle manufacturers and vehicle suppliers specific use. - EcuReset, + EcuReset = Self::ECU_RESET, /// Security check is available to enable the most security-critical uds. /// For this purpose a "Seed" is generated and sent to the client by the control unit. /// From this "Seed" the client has to compute a "Key" and send it back to the control unit to unlock the security-critical uds. - SecurityAccess, + SecurityAccess = Self::SECURITY_ACCESS, /// With this service, both the sending and receiving of messages can be turned off in the control unit. - CommunicationControl, + CommunicationControl = Self::COMMUNICATION_CONTROL, /// An update (2020) of the standard added this service to provide a standardized approach to more modern methods of authentication than are permitted by the Security Access (0x27) service, /// including bidirectional authentication with PKI-based Certificate Exchange. - Authentication, + Authentication = Self::AUTHENTICATION, /// If no communication is exchanged with the client for a long time, /// the control unit automatically exits the current session and returns to the "Default Session". /// It might even go to sleep mode. /// This service is to signal to the device that the client is still present. - TesterPresent, + TesterPresent = Self::TESTER_PRESENT, /// In the communication between the controllers and the client, /// certain timing must be preserved. /// If these timings are exceeded without a message being sent, /// it must be assumed that the connection was interrupted. /// These timings can be read and changed through this service. - AccessTimingParameters, - SecuredDataTransmission, + AccessTimingParameters = Self::ACCESS_TIMING_PARAMETERS, + SecuredDataTransmission = Self::SECURED_DATA_TRANSMISSION, /// Enable or disable the detection of any or all errors. /// This is important when diagnostic work is performed in the car, /// which can cause an anomalous behavior of individual devices. - ControlDTCSettings, - ResponseOnEvent, + ControlDTCSettings = Self::CONTROL_DTC_SETTINGS, + ResponseOnEvent = Self::RESPONSE_ON_EVENT, /// The Service Link Control is used to set the baud rate of the diagnostic access. /// It is usually implemented only at the central gateway. - LinkControl, + LinkControl = Self::LINK_CONTROL, // ======================================================================== // Data Transmission /// With this service, it is possible to retrieve one or more values of a control unit. /// This can be information of all kinds and of different lengths such as part numbers or the software version. - ReadDataByIdentifier, + ReadDataByIdentifier = Self::READ_DATA_BY_IDENTIFIER, /// Read data from the physical memory at the provided address. /// This function can be used by a testing tool to read the internal behavior of the software. - ReadMemoryByAddress, - ReadScalingDataByIdentifier, + ReadMemoryByAddress = Self::READ_MEMORY_BY_ADDRESS, + ReadScalingDataByIdentifier = Self::READ_SCALING_DATA_BY_IDENTIFIER, /// With this service, values are sent periodically by a ecu. /// The values to be sent must only use the "Dynamically Defined Data Identifier". - ReadDataByIdentifierPeriodic, + ReadDataByIdentifierPeriodic = Self::READ_DATA_BY_IDENTIFIER_PERIODIC, /// This service offers the possibility of a fix for a device specified Data Identifier (DID) pool to configure another Data Identifier. /// This is usually a combination of parts of different DIDs or simply a concatenation of complete DIDs. /// The requested data may be configured or grouped in the following manner: @@ -77,93 +78,170 @@ pub enum UdsServiceType { /// - Source DID, position, length (in bytes), Sub-Function Byte: defineByIdentifier /// - Memory address length (in bytes), Sub-Function Byte: defineByMemoryAddress /// - Combinations of the two above methods through multiple requests. - DynamicallyDefinedDataIdentifier, + DynamicallyDefinedDataIdentifier = Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER, /// Change the specified Data Identifier (DID) to the provided value - WriteDataByIdentifier, + WriteDataByIdentifier = Self::WRITE_DATA_BY_IDENTIFIER, /// Write information into the ECU at one or more contiguous memory locations. - WriteMemoryByAddress, + WriteMemoryByAddress = Self::WRITE_MEMORY_BY_ADDRESS, // ======================================================================== // Stored Data Transmission /// Delete all stored Diagnostic Trouble Codes (DTC) - ClearDiagnosticInfo, + ClearDiagnosticInfo = Self::CLEAR_DIAGNOSTIC_INFO, /// DTC stands for "Diagnostic Trouble Codes". /// Each DTC handled by the ECU is stored with its own code in the error memory. /// These DTCs can be read via this service. /// In addition to the errors themselves, /// additional diagnostic information is stored. - ReadDTCInfo, + ReadDTCInfo = Self::READ_DTC_INFO, // ======================================================================== // Input / Output Control - InputOutputControlByIdentifier, + InputOutputControlByIdentifier = Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER, // ======================================================================== // Remote Activation of Routine - RoutineControl, + RoutineControl = Self::ROUTINE_CONTROL, // ======================================================================== // Upload / Download /// Downloading new software or other data into the control unit is initiated using the "Request Download". /// Here, the location and size of the data is specified. /// In response, the controller specifies how large the data packets can be. - RequestDownload, + RequestDownload = Self::REQUEST_DOWNLOAD, /// Request the transfer of data from the ECU to the tester. /// The location and size must be specified. /// The size of the data blocks are specified by the tester. - RequestUpload, + RequestUpload = Self::REQUEST_UPLOAD, /// For the actual transmission of data, the service "Transfer Data" is used /// This service is used for both uploading and downloading data. /// The transfer direction is established in advance by the service "Request Download" or "Upload Request". /// This service should try to send packets at maximum length, as specified in previous uds. /// If the data set is larger than the maximum, the "Transfer Data" service must be used several times in succession until all data has arrived. - TransferData, + TransferData = Self::TRANSFER_DATA, /// A data transmission can be 'completed' when using the "Transfer Exit" service. /// This service is used for comparison between the control unit and the tester. /// When it is running, a control unit can answer negatively on this request to stop a data transfer request. /// This will be used when the amount of data (set in "Request Download" or "Upload Request") has not been transferred. - RequestTransferExit, + RequestTransferExit = Self::REQUEST_TRANSFER_EXIT, /// This service is used to initiate a file download from the client to the server or upload from the server to the client. /// Additionally information about the file system are available by this service. - RequestFileTransfer, + RequestFileTransfer = Self::REQUEST_FILE_TRANSFER, /// This response is given when a service request could not be performed, /// for example a request for an unsupported Data Identifier. /// for example a request for an unsupported Data Identifier. /// A Negative Response Code will be included. - NegativeResponse, + NegativeResponse = Self::NEGATIVE_RESPONSE, /// While additional uds may exist, only the above are supported by this library - UnsupportedDiagnosticService, + UnsupportedDiagnosticService = Self::UNSUPPORTED_DIAGNOSTIC_SERVICE, // ======================================================================== } impl UdsServiceType { + pub const DIAGNOSTIC_SESSION_CONTROL: u8 = 0x10; + pub const ECU_RESET: u8 = 0x11; + pub const SECURITY_ACCESS: u8 = 0x27; + pub const COMMUNICATION_CONTROL: u8 = 0x28; + pub const AUTHENTICATION: u8 = 0x29; + pub const TESTER_PRESENT: u8 = 0x3E; + pub const ACCESS_TIMING_PARAMETERS: u8 = 0x83; + pub const SECURED_DATA_TRANSMISSION: u8 = 0x84; + pub const CONTROL_DTC_SETTINGS: u8 = 0x85; + pub const RESPONSE_ON_EVENT: u8 = 0x86; + pub const LINK_CONTROL: u8 = 0x87; + pub const READ_DATA_BY_IDENTIFIER: u8 = 0x22; + pub const READ_MEMORY_BY_ADDRESS: u8 = 0x23; + pub const READ_SCALING_DATA_BY_IDENTIFIER: u8 = 0x24; + pub const READ_DATA_BY_IDENTIFIER_PERIODIC: u8 = 0x2A; + pub const DYNAMICALLY_DEFINED_DATA_IDENTIFIER: u8 = 0x2C; + pub const WRITE_DATA_BY_IDENTIFIER: u8 = 0x2E; + pub const WRITE_MEMORY_BY_ADDRESS: u8 = 0x3D; + pub const CLEAR_DIAGNOSTIC_INFO: u8 = 0x14; + pub const READ_DTC_INFO: u8 = 0x19; + pub const INPUT_OUTPUT_CONTROL_BY_IDENTIFIER: u8 = 0x2F; + pub const ROUTINE_CONTROL: u8 = 0x31; + pub const REQUEST_DOWNLOAD: u8 = 0x34; + pub const REQUEST_UPLOAD: u8 = 0x35; + pub const TRANSFER_DATA: u8 = 0x36; + pub const REQUEST_TRANSFER_EXIT: u8 = 0x37; + pub const REQUEST_FILE_TRANSFER: u8 = 0x38; + pub const NEGATIVE_RESPONSE: u8 = 0x7F; + pub const UNSUPPORTED_DIAGNOSTIC_SERVICE: u8 = 0xFF; + pub const POSITIVE_RESPONSE_OFFSET: u8 = 0x40; + + pub const DIAGNOSTIC_SESSION_CONTROL_RESPONSE: u8 = + Self::DIAGNOSTIC_SESSION_CONTROL + Self::POSITIVE_RESPONSE_OFFSET; + pub const ECU_RESET_RESPONSE: u8 = Self::ECU_RESET + Self::POSITIVE_RESPONSE_OFFSET; + pub const SECURITY_ACCESS_RESPONSE: u8 = Self::SECURITY_ACCESS + Self::POSITIVE_RESPONSE_OFFSET; + pub const COMMUNICATION_CONTROL_RESPONSE: u8 = + Self::COMMUNICATION_CONTROL + Self::POSITIVE_RESPONSE_OFFSET; + pub const AUTHENTICATION_RESPONSE: u8 = Self::AUTHENTICATION + Self::POSITIVE_RESPONSE_OFFSET; + pub const TESTER_PRESENT_RESPONSE: u8 = Self::TESTER_PRESENT + Self::POSITIVE_RESPONSE_OFFSET; + pub const ACCESS_TIMING_PARAMETERS_RESPONSE: u8 = + Self::ACCESS_TIMING_PARAMETERS + Self::POSITIVE_RESPONSE_OFFSET; + pub const SECURED_DATA_TRANSMISSION_RESPONSE: u8 = + Self::SECURED_DATA_TRANSMISSION + Self::POSITIVE_RESPONSE_OFFSET; + pub const CONTROL_DTC_SETTINGS_RESPONSE: u8 = + Self::CONTROL_DTC_SETTINGS + Self::POSITIVE_RESPONSE_OFFSET; + pub const RESPONSE_ON_EVENT_RESPONSE: u8 = + Self::RESPONSE_ON_EVENT + Self::POSITIVE_RESPONSE_OFFSET; + pub const LINK_CONTROL_RESPONSE: u8 = Self::LINK_CONTROL + Self::POSITIVE_RESPONSE_OFFSET; + pub const READ_DATA_BY_IDENTIFIER_RESPONSE: u8 = + Self::READ_DATA_BY_IDENTIFIER + Self::POSITIVE_RESPONSE_OFFSET; + pub const READ_MEMORY_BY_ADDRESS_RESPONSE: u8 = + Self::READ_MEMORY_BY_ADDRESS + Self::POSITIVE_RESPONSE_OFFSET; + pub const READ_SCALING_DATA_BY_IDENTIFIER_RESPONSE: u8 = + Self::READ_SCALING_DATA_BY_IDENTIFIER + Self::POSITIVE_RESPONSE_OFFSET; + pub const READ_DATA_BY_IDENTIFIER_PERIODIC_RESPONSE: u8 = + Self::READ_DATA_BY_IDENTIFIER_PERIODIC + Self::POSITIVE_RESPONSE_OFFSET; + pub const DYNAMICALLY_DEFINED_DATA_IDENTIFIER_RESPONSE: u8 = + Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER + Self::POSITIVE_RESPONSE_OFFSET; + pub const WRITE_DATA_BY_IDENTIFIER_RESPONSE: u8 = + Self::WRITE_DATA_BY_IDENTIFIER + Self::POSITIVE_RESPONSE_OFFSET; + pub const WRITE_MEMORY_BY_ADDRESS_RESPONSE: u8 = + Self::WRITE_MEMORY_BY_ADDRESS + Self::POSITIVE_RESPONSE_OFFSET; + pub const CLEAR_DIAGNOSTIC_INFO_RESPONSE: u8 = + Self::CLEAR_DIAGNOSTIC_INFO + Self::POSITIVE_RESPONSE_OFFSET; + pub const READ_DTC_INFO_RESPONSE: u8 = Self::READ_DTC_INFO + Self::POSITIVE_RESPONSE_OFFSET; + pub const INPUT_OUTPUT_CONTROL_BY_IDENTIFIER_RESPONSE: u8 = + Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER + Self::POSITIVE_RESPONSE_OFFSET; + pub const ROUTINE_CONTROL_RESPONSE: u8 = Self::ROUTINE_CONTROL + Self::POSITIVE_RESPONSE_OFFSET; + pub const REQUEST_DOWNLOAD_RESPONSE: u8 = + Self::REQUEST_DOWNLOAD + Self::POSITIVE_RESPONSE_OFFSET; + pub const REQUEST_UPLOAD_RESPONSE: u8 = Self::REQUEST_UPLOAD + Self::POSITIVE_RESPONSE_OFFSET; + pub const TRANSFER_DATA_RESPONSE: u8 = Self::TRANSFER_DATA + Self::POSITIVE_RESPONSE_OFFSET; + pub const REQUEST_TRANSFER_EXIT_RESPONSE: u8 = + Self::REQUEST_TRANSFER_EXIT + Self::POSITIVE_RESPONSE_OFFSET; + pub const REQUEST_FILE_TRANSFER_RESPONSE: u8 = + Self::REQUEST_FILE_TRANSFER + Self::POSITIVE_RESPONSE_OFFSET; + #[must_use] pub fn service_from_request_byte(value: u8) -> Self { match value { - 0x10 => Self::DiagnosticSessionControl, - 0x11 => Self::EcuReset, - 0x27 => Self::SecurityAccess, - 0x28 => Self::CommunicationControl, - 0x29 => Self::Authentication, - 0x3E => Self::TesterPresent, - 0x83 => Self::AccessTimingParameters, - 0x84 => Self::SecuredDataTransmission, - 0x85 => Self::ControlDTCSettings, - 0x86 => Self::ResponseOnEvent, - 0x87 => Self::LinkControl, - 0x22 => Self::ReadDataByIdentifier, - 0x23 => Self::ReadMemoryByAddress, - 0x24 => Self::ReadScalingDataByIdentifier, - 0x2A => Self::ReadDataByIdentifierPeriodic, - 0x2C => Self::DynamicallyDefinedDataIdentifier, - 0x2E => Self::WriteDataByIdentifier, - 0x3D => Self::WriteMemoryByAddress, - 0x14 => Self::ClearDiagnosticInfo, - 0x19 => Self::ReadDTCInfo, - 0x2F => Self::InputOutputControlByIdentifier, - 0x31 => Self::RoutineControl, - 0x34 => Self::RequestDownload, - 0x35 => Self::RequestUpload, - 0x36 => Self::TransferData, - 0x37 => Self::RequestTransferExit, - 0x38 => Self::RequestFileTransfer, + Self::DIAGNOSTIC_SESSION_CONTROL => Self::DiagnosticSessionControl, + Self::ECU_RESET => Self::EcuReset, + Self::SECURITY_ACCESS => Self::SecurityAccess, + Self::COMMUNICATION_CONTROL => Self::CommunicationControl, + Self::AUTHENTICATION => Self::Authentication, + Self::TESTER_PRESENT => Self::TesterPresent, + Self::ACCESS_TIMING_PARAMETERS => Self::AccessTimingParameters, + Self::SECURED_DATA_TRANSMISSION => Self::SecuredDataTransmission, + Self::CONTROL_DTC_SETTINGS => Self::ControlDTCSettings, + Self::RESPONSE_ON_EVENT => Self::ResponseOnEvent, + Self::LINK_CONTROL => Self::LinkControl, + Self::READ_DATA_BY_IDENTIFIER => Self::ReadDataByIdentifier, + Self::READ_MEMORY_BY_ADDRESS => Self::ReadMemoryByAddress, + Self::READ_SCALING_DATA_BY_IDENTIFIER => Self::ReadScalingDataByIdentifier, + Self::READ_DATA_BY_IDENTIFIER_PERIODIC => Self::ReadDataByIdentifierPeriodic, + Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER => Self::DynamicallyDefinedDataIdentifier, + Self::WRITE_DATA_BY_IDENTIFIER => Self::WriteDataByIdentifier, + Self::WRITE_MEMORY_BY_ADDRESS => Self::WriteMemoryByAddress, + Self::CLEAR_DIAGNOSTIC_INFO => Self::ClearDiagnosticInfo, + Self::READ_DTC_INFO => Self::ReadDTCInfo, + Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER => Self::InputOutputControlByIdentifier, + Self::ROUTINE_CONTROL => Self::RoutineControl, + Self::REQUEST_DOWNLOAD => Self::RequestDownload, + Self::REQUEST_UPLOAD => Self::RequestUpload, + Self::TRANSFER_DATA => Self::TransferData, + Self::REQUEST_TRANSFER_EXIT => Self::RequestTransferExit, + Self::REQUEST_FILE_TRANSFER => Self::RequestFileTransfer, _ => Self::UnsupportedDiagnosticService, } } @@ -171,67 +249,73 @@ impl UdsServiceType { #[must_use] pub fn request_service_to_byte(&self) -> u8 { match self { - Self::DiagnosticSessionControl => 0x10, - Self::EcuReset => 0x11, - Self::SecurityAccess => 0x27, - Self::CommunicationControl => 0x28, - Self::Authentication => 0x29, - Self::TesterPresent => 0x3E, - Self::AccessTimingParameters => 0x83, - Self::SecuredDataTransmission => 0x84, - Self::ControlDTCSettings => 0x85, - Self::ResponseOnEvent => 0x86, - Self::LinkControl => 0x87, - Self::ReadDataByIdentifier => 0x22, - Self::ReadMemoryByAddress => 0x23, - Self::ReadScalingDataByIdentifier => 0x24, - Self::ReadDataByIdentifierPeriodic => 0x2A, - Self::DynamicallyDefinedDataIdentifier => 0x2C, - Self::WriteDataByIdentifier => 0x2E, - Self::WriteMemoryByAddress => 0x3D, - Self::ClearDiagnosticInfo => 0x14, - Self::ReadDTCInfo => 0x19, - Self::InputOutputControlByIdentifier => 0x2F, - Self::RoutineControl => 0x31, - Self::RequestDownload => 0x34, - Self::RequestUpload => 0x35, - Self::TransferData => 0x36, - Self::RequestTransferExit => 0x37, - Self::RequestFileTransfer => 0x38, - _ => 0x7F, + Self::DiagnosticSessionControl => Self::DIAGNOSTIC_SESSION_CONTROL, + Self::EcuReset => Self::ECU_RESET, + Self::SecurityAccess => Self::SECURITY_ACCESS, + Self::CommunicationControl => Self::COMMUNICATION_CONTROL, + Self::Authentication => Self::AUTHENTICATION, + Self::TesterPresent => Self::TESTER_PRESENT, + Self::AccessTimingParameters => Self::ACCESS_TIMING_PARAMETERS, + Self::SecuredDataTransmission => Self::SECURED_DATA_TRANSMISSION, + Self::ControlDTCSettings => Self::CONTROL_DTC_SETTINGS, + Self::ResponseOnEvent => Self::RESPONSE_ON_EVENT, + Self::LinkControl => Self::LINK_CONTROL, + Self::ReadDataByIdentifier => Self::READ_DATA_BY_IDENTIFIER, + Self::ReadMemoryByAddress => Self::READ_MEMORY_BY_ADDRESS, + Self::ReadScalingDataByIdentifier => Self::READ_SCALING_DATA_BY_IDENTIFIER, + Self::ReadDataByIdentifierPeriodic => Self::READ_DATA_BY_IDENTIFIER_PERIODIC, + Self::DynamicallyDefinedDataIdentifier => Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER, + Self::WriteDataByIdentifier => Self::WRITE_DATA_BY_IDENTIFIER, + Self::WriteMemoryByAddress => Self::WRITE_MEMORY_BY_ADDRESS, + Self::ClearDiagnosticInfo => Self::CLEAR_DIAGNOSTIC_INFO, + Self::ReadDTCInfo => Self::READ_DTC_INFO, + Self::InputOutputControlByIdentifier => Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER, + Self::RoutineControl => Self::ROUTINE_CONTROL, + Self::RequestDownload => Self::REQUEST_DOWNLOAD, + Self::RequestUpload => Self::REQUEST_UPLOAD, + Self::TransferData => Self::TRANSFER_DATA, + Self::RequestTransferExit => Self::REQUEST_TRANSFER_EXIT, + Self::RequestFileTransfer => Self::REQUEST_FILE_TRANSFER, + Self::UnsupportedDiagnosticService => Self::UNSUPPORTED_DIAGNOSTIC_SERVICE, + _ => Self::NEGATIVE_RESPONSE, } } #[must_use] pub fn response_from_byte(value: u8) -> Self { match value { - 0x50 => Self::DiagnosticSessionControl, - 0x51 => Self::EcuReset, - 0x67 => Self::SecurityAccess, - 0x68 => Self::CommunicationControl, - 0x69 => Self::Authentication, - 0x7E => Self::TesterPresent, - 0xC3 => Self::AccessTimingParameters, - 0xC4 => Self::SecuredDataTransmission, - 0xC5 => Self::ControlDTCSettings, - 0xC6 => Self::ResponseOnEvent, - 0xC7 => Self::LinkControl, - 0x62 => Self::ReadDataByIdentifier, - 0x63 => Self::ReadMemoryByAddress, - 0x64 => Self::ReadScalingDataByIdentifier, - 0x6A => Self::ReadDataByIdentifierPeriodic, - 0x6C => Self::DynamicallyDefinedDataIdentifier, - 0x6E => Self::WriteDataByIdentifier, - 0x7D => Self::WriteMemoryByAddress, - 0x54 => Self::ClearDiagnosticInfo, - 0x59 => Self::ReadDTCInfo, - 0x6F => Self::InputOutputControlByIdentifier, - 0x71 => Self::RoutineControl, - 0x74 => Self::RequestDownload, - 0x75 => Self::RequestUpload, - 0x76 => Self::TransferData, - 0x77 => Self::RequestTransferExit, - 0x78 => Self::RequestFileTransfer, - 0x7F => Self::NegativeResponse, + Self::DIAGNOSTIC_SESSION_CONTROL_RESPONSE => Self::DiagnosticSessionControl, + Self::ECU_RESET_RESPONSE => Self::EcuReset, + Self::SECURITY_ACCESS_RESPONSE => Self::SecurityAccess, + Self::COMMUNICATION_CONTROL_RESPONSE => Self::CommunicationControl, + Self::AUTHENTICATION_RESPONSE => Self::Authentication, + Self::TESTER_PRESENT_RESPONSE => Self::TesterPresent, + Self::ACCESS_TIMING_PARAMETERS_RESPONSE => Self::AccessTimingParameters, + Self::SECURED_DATA_TRANSMISSION_RESPONSE => Self::SecuredDataTransmission, + Self::CONTROL_DTC_SETTINGS_RESPONSE => Self::ControlDTCSettings, + Self::RESPONSE_ON_EVENT_RESPONSE => Self::ResponseOnEvent, + Self::LINK_CONTROL_RESPONSE => Self::LinkControl, + Self::READ_DATA_BY_IDENTIFIER_RESPONSE => Self::ReadDataByIdentifier, + Self::READ_MEMORY_BY_ADDRESS_RESPONSE => Self::ReadMemoryByAddress, + Self::READ_SCALING_DATA_BY_IDENTIFIER_RESPONSE => Self::ReadScalingDataByIdentifier, + Self::READ_DATA_BY_IDENTIFIER_PERIODIC_RESPONSE => Self::ReadDataByIdentifierPeriodic, + Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER_RESPONSE => { + Self::DynamicallyDefinedDataIdentifier + } + Self::WRITE_DATA_BY_IDENTIFIER_RESPONSE => Self::WriteDataByIdentifier, + Self::WRITE_MEMORY_BY_ADDRESS_RESPONSE => Self::WriteMemoryByAddress, + Self::CLEAR_DIAGNOSTIC_INFO_RESPONSE => Self::ClearDiagnosticInfo, + Self::READ_DTC_INFO_RESPONSE => Self::ReadDTCInfo, + Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER_RESPONSE => { + Self::InputOutputControlByIdentifier + } + Self::ROUTINE_CONTROL_RESPONSE => Self::RoutineControl, + Self::REQUEST_DOWNLOAD_RESPONSE => Self::RequestDownload, + Self::REQUEST_UPLOAD_RESPONSE => Self::RequestUpload, + Self::TRANSFER_DATA_RESPONSE => Self::TransferData, + Self::REQUEST_TRANSFER_EXIT_RESPONSE => Self::RequestTransferExit, + Self::REQUEST_FILE_TRANSFER_RESPONSE => Self::RequestFileTransfer, + Self::NEGATIVE_RESPONSE => Self::NegativeResponse, + Self::UNSUPPORTED_DIAGNOSTIC_SERVICE => Self::UnsupportedDiagnosticService, _ => Self::UnsupportedDiagnosticService, } } @@ -239,34 +323,38 @@ impl UdsServiceType { #[must_use] pub fn response_to_byte(self) -> u8 { match self { - Self::DiagnosticSessionControl => 0x50, - Self::EcuReset => 0x51, - Self::SecurityAccess => 0x67, - Self::CommunicationControl => 0x68, - Self::Authentication => 0x69, - Self::TesterPresent => 0x7E, - Self::AccessTimingParameters => 0xC3, - Self::SecuredDataTransmission => 0xC4, - Self::ControlDTCSettings => 0xC5, - Self::ResponseOnEvent => 0xC6, - Self::LinkControl => 0xC7, - Self::ReadDataByIdentifier => 0x62, - Self::ReadMemoryByAddress => 0x63, - Self::ReadScalingDataByIdentifier => 0x64, - Self::ReadDataByIdentifierPeriodic => 0x6A, - Self::DynamicallyDefinedDataIdentifier => 0x6C, - Self::WriteDataByIdentifier => 0x6E, - Self::WriteMemoryByAddress => 0x7D, - Self::ClearDiagnosticInfo => 0x54, - Self::ReadDTCInfo => 0x59, - Self::InputOutputControlByIdentifier => 0x6F, - Self::RoutineControl => 0x71, - Self::RequestDownload => 0x74, - Self::RequestUpload => 0x75, - Self::TransferData => 0x76, - Self::RequestTransferExit => 0x77, - Self::RequestFileTransfer => 0x78, - _ => 0x7F, + Self::DiagnosticSessionControl => Self::DIAGNOSTIC_SESSION_CONTROL_RESPONSE, + Self::EcuReset => Self::ECU_RESET_RESPONSE, + Self::SecurityAccess => Self::SECURITY_ACCESS_RESPONSE, + Self::CommunicationControl => Self::COMMUNICATION_CONTROL_RESPONSE, + Self::Authentication => Self::AUTHENTICATION_RESPONSE, + Self::TesterPresent => Self::TESTER_PRESENT_RESPONSE, + Self::AccessTimingParameters => Self::ACCESS_TIMING_PARAMETERS_RESPONSE, + Self::SecuredDataTransmission => Self::SECURED_DATA_TRANSMISSION_RESPONSE, + Self::ControlDTCSettings => Self::CONTROL_DTC_SETTINGS_RESPONSE, + Self::ResponseOnEvent => Self::RESPONSE_ON_EVENT_RESPONSE, + Self::LinkControl => Self::LINK_CONTROL_RESPONSE, + Self::ReadDataByIdentifier => Self::READ_DATA_BY_IDENTIFIER_RESPONSE, + Self::ReadMemoryByAddress => Self::READ_MEMORY_BY_ADDRESS_RESPONSE, + Self::ReadScalingDataByIdentifier => Self::READ_SCALING_DATA_BY_IDENTIFIER_RESPONSE, + Self::ReadDataByIdentifierPeriodic => Self::READ_DATA_BY_IDENTIFIER_PERIODIC_RESPONSE, + Self::DynamicallyDefinedDataIdentifier => { + Self::DYNAMICALLY_DEFINED_DATA_IDENTIFIER_RESPONSE + } + Self::WriteDataByIdentifier => Self::WRITE_DATA_BY_IDENTIFIER_RESPONSE, + Self::WriteMemoryByAddress => Self::WRITE_MEMORY_BY_ADDRESS_RESPONSE, + Self::ClearDiagnosticInfo => Self::CLEAR_DIAGNOSTIC_INFO_RESPONSE, + Self::ReadDTCInfo => Self::READ_DTC_INFO_RESPONSE, + Self::InputOutputControlByIdentifier => { + Self::INPUT_OUTPUT_CONTROL_BY_IDENTIFIER_RESPONSE + } + Self::RoutineControl => Self::ROUTINE_CONTROL_RESPONSE, + Self::RequestDownload => Self::REQUEST_DOWNLOAD_RESPONSE, + Self::RequestUpload => Self::REQUEST_UPLOAD_RESPONSE, + Self::TransferData => Self::TRANSFER_DATA_RESPONSE, + Self::RequestTransferExit => Self::REQUEST_TRANSFER_EXIT_RESPONSE, + Self::RequestFileTransfer => Self::REQUEST_FILE_TRANSFER_RESPONSE, + _ => Self::NEGATIVE_RESPONSE, } } } diff --git a/src/services/read_dtc_information.rs b/src/services/read_dtc_information.rs index b660417..7c00c31 100644 --- a/src/services/read_dtc_information.rs +++ b/src/services/read_dtc_information.rs @@ -226,6 +226,7 @@ type DTCReadinessGroupIdentifier = u8; // RGID #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum ReadDTCInfoSubFunction { /// * Parameter: `DTCStatusMask` /// @@ -237,7 +238,7 @@ pub enum ReadDTCInfoSubFunction { ReportDTC_ByStatusMask(DTCStatusMask), /// 0x03 - ReportDTCSnapshotIdentification, + ReportDTCSnapshotIdentification = Self::REPORT_DTC_SNAPSHOT_IDENTIFICATION, /// Parameter: `DTCRecord` (3 bytes) /// Parameter DTCSnapshotRecordNumber(1) @@ -271,19 +272,19 @@ pub enum ReadDTCInfoSubFunction { ReportSeverityInfoOfDTC(DTCRecord), /// 0x0A - ReportSupportedDTC, + ReportSupportedDTC = Self::REPORT_SUPPORTED_DTC, /// 0x0B - ReportFirstTestFailedDTC, + ReportFirstTestFailedDTC = Self::REPORT_FIRST_TEST_FAILED_DTC, /// 0x0C - ReportFirstConfirmedDTC, + ReportFirstConfirmedDTC = Self::REPORT_FIRST_CONFIRMED_DTC, /// 0x0D - ReportMostRecentTestFailedDTC, + ReportMostRecentTestFailedDTC = Self::REPORT_MOST_RECENT_TEST_FAILED_DTC, /// 0x0E - ReportMostRecentConfirmedDTC, + ReportMostRecentConfirmedDTC = Self::REPORT_MOST_RECENT_CONFIRMED_DTC, /// 0x14 - ReportDTCFaultDetectionCounter, + ReportDTCFaultDetectionCounter = Self::REPORT_DTC_FAULT_DETECTION_COUNTER, /// 0x15 - ReportDTCWithPermanentStatus, + ReportDTCWithPermanentStatus = Self::REPORT_DTC_WITH_PERMANENT_STATUS, /// * Parameter: DTCExtDataRecordNumber(1) /// @@ -344,33 +345,82 @@ pub enum ReadDTCInfoSubFunction { } impl ReadDTCInfoSubFunction { + pub const REPORT_NUMBER_OF_DTC_BY_STATUS_MASK: u8 = 0x01; + pub const REPORT_DTC_BY_STATUS_MASK: u8 = 0x02; + pub const REPORT_DTC_SNAPSHOT_IDENTIFICATION: u8 = 0x03; + pub const REPORT_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER: u8 = 0x04; + pub const REPORT_DTC_STORED_DATA_BY_RECORD_NUMBER: u8 = 0x05; + pub const REPORT_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER: u8 = 0x06; + pub const REPORT_NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD: u8 = 0x07; + pub const REPORT_DTC_BY_SEVERITY_MASK_RECORD: u8 = 0x08; + pub const REPORT_SEVERITY_INFO_OF_DTC: u8 = 0x09; + pub const REPORT_SUPPORTED_DTC: u8 = 0x0A; + pub const REPORT_FIRST_TEST_FAILED_DTC: u8 = 0x0B; + pub const REPORT_FIRST_CONFIRMED_DTC: u8 = 0x0C; + pub const REPORT_MOST_RECENT_TEST_FAILED_DTC: u8 = 0x0D; + pub const REPORT_MOST_RECENT_CONFIRMED_DTC: u8 = 0x0E; + pub const REPORT_DTC_FAULT_DETECTION_COUNTER: u8 = 0x14; + pub const REPORT_DTC_WITH_PERMANENT_STATUS: u8 = 0x15; + pub const REPORT_DTC_EXT_DATA_RECORD_BY_RECORD_NUMBER: u8 = 0x16; + pub const REPORT_USER_DEF_MEMORY_DTC_BY_STATUS_MASK: u8 = 0x17; + pub const REPORT_USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER: u8 = 0x18; + pub const REPORT_USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER: u8 = 0x19; + pub const REPORT_SUPPORTED_DTC_EXT_DATA_RECORD: u8 = 0x1A; + pub const REPORT_WWH_OBD_DTC_BY_MASK_RECORD: u8 = 0x42; + pub const REPORT_WWH_OBD_DTC_WITH_PERMANENT_STATUS: u8 = 0x55; + pub const REPORT_DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER: u8 = 0x56; + pub const ISO_SAE_RESERVED_START: u8 = 0x43; + pub const ISO_SAE_RESERVED_BEFORE_PERMANENT_END: u8 = 0x54; + pub const ISO_SAE_RESERVED_AFTER_PERMANENT_START: u8 = 0x57; + pub const ISO_SAE_RESERVED_AFTER_PERMANENT_END: u8 = 0x7F; + #[must_use] pub fn value(&self) -> u8 { match self { - Self::ReportNumberOfDTC_ByStatusMask(_) => 0x01, - Self::ReportDTC_ByStatusMask(_) => 0x02, - Self::ReportDTCSnapshotIdentification => 0x03, - Self::ReportDTCSnapshotRecord_ByDTCNumber(_, _) => 0x04, - Self::ReportDTCStoredData_ByRecordNumber(_) => 0x05, - Self::ReportDTCExtDataRecord_ByDTCNumber(_, _) => 0x06, - Self::ReportNumberOfDTC_BySeverityMaskRecord(_, _) => 0x07, - Self::ReportDTC_BySeverityMaskRecord(_, _) => 0x08, - Self::ReportSeverityInfoOfDTC(_) => 0x09, - Self::ReportSupportedDTC => 0x0A, - Self::ReportFirstTestFailedDTC => 0x0B, - Self::ReportFirstConfirmedDTC => 0x0C, - Self::ReportMostRecentTestFailedDTC => 0x0D, - Self::ReportMostRecentConfirmedDTC => 0x0E, - Self::ReportDTCFaultDetectionCounter => 0x14, - Self::ReportDTCWithPermanentStatus => 0x15, - Self::ReportDTCExtDataRecord_ByRecordNumber(_) => 0x16, - Self::ReportUserDefMemoryDTC_ByStatusMask(_) => 0x17, - Self::ReportUserDefMemoryDTCSnapshotRecord_ByDTCNumber(_, _, _) => 0x18, - Self::ReportUserDefMemoryDTCExtDataRecord_ByDTCNumber(_, _, _) => 0x19, - Self::ReportSupportedDTCExtDataRecord(_) => 0x1A, - Self::ReportWWHOBDDTC_ByMaskRecord(_, _, _) => 0x42, - Self::ReportWWHOBDDTC_WithPermanentStatus(_) => 0x55, - Self::ReportDTCInformation_ByDTCReadinessGroupIdentifier(_, _) => 0x56, + Self::ReportNumberOfDTC_ByStatusMask(_) => Self::REPORT_NUMBER_OF_DTC_BY_STATUS_MASK, + Self::ReportDTC_ByStatusMask(_) => Self::REPORT_DTC_BY_STATUS_MASK, + Self::ReportDTCSnapshotIdentification => Self::REPORT_DTC_SNAPSHOT_IDENTIFICATION, + Self::ReportDTCSnapshotRecord_ByDTCNumber(_, _) => { + Self::REPORT_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER + } + Self::ReportDTCStoredData_ByRecordNumber(_) => { + Self::REPORT_DTC_STORED_DATA_BY_RECORD_NUMBER + } + Self::ReportDTCExtDataRecord_ByDTCNumber(_, _) => { + Self::REPORT_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER + } + Self::ReportNumberOfDTC_BySeverityMaskRecord(_, _) => { + Self::REPORT_NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD + } + Self::ReportDTC_BySeverityMaskRecord(_, _) => Self::REPORT_DTC_BY_SEVERITY_MASK_RECORD, + Self::ReportSeverityInfoOfDTC(_) => Self::REPORT_SEVERITY_INFO_OF_DTC, + Self::ReportSupportedDTC => Self::REPORT_SUPPORTED_DTC, + Self::ReportFirstTestFailedDTC => Self::REPORT_FIRST_TEST_FAILED_DTC, + Self::ReportFirstConfirmedDTC => Self::REPORT_FIRST_CONFIRMED_DTC, + Self::ReportMostRecentTestFailedDTC => Self::REPORT_MOST_RECENT_TEST_FAILED_DTC, + Self::ReportMostRecentConfirmedDTC => Self::REPORT_MOST_RECENT_CONFIRMED_DTC, + Self::ReportDTCFaultDetectionCounter => Self::REPORT_DTC_FAULT_DETECTION_COUNTER, + Self::ReportDTCWithPermanentStatus => Self::REPORT_DTC_WITH_PERMANENT_STATUS, + Self::ReportDTCExtDataRecord_ByRecordNumber(_) => { + Self::REPORT_DTC_EXT_DATA_RECORD_BY_RECORD_NUMBER + } + Self::ReportUserDefMemoryDTC_ByStatusMask(_) => { + Self::REPORT_USER_DEF_MEMORY_DTC_BY_STATUS_MASK + } + Self::ReportUserDefMemoryDTCSnapshotRecord_ByDTCNumber(_, _, _) => { + Self::REPORT_USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER + } + Self::ReportUserDefMemoryDTCExtDataRecord_ByDTCNumber(_, _, _) => { + Self::REPORT_USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER + } + Self::ReportSupportedDTCExtDataRecord(_) => Self::REPORT_SUPPORTED_DTC_EXT_DATA_RECORD, + Self::ReportWWHOBDDTC_ByMaskRecord(_, _, _) => Self::REPORT_WWH_OBD_DTC_BY_MASK_RECORD, + Self::ReportWWHOBDDTC_WithPermanentStatus(_) => { + Self::REPORT_WWH_OBD_DTC_WITH_PERMANENT_STATUS + } + Self::ReportDTCInformation_ByDTCReadinessGroupIdentifier(_, _) => { + Self::REPORT_DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER + } Self::ISOSAEReserved(value) => *value, } } @@ -382,77 +432,102 @@ impl WireFormat for ReadDTCInfoSubFunction { let report_type = reader.read_u8()?; let subfunction = match report_type { - 0x01 | 0x02 => { + Self::REPORT_NUMBER_OF_DTC_BY_STATUS_MASK | Self::REPORT_DTC_BY_STATUS_MASK => { let status = DTCStatusMask::from(reader.read_u8()?); match report_type { - 0x01 => Self::ReportNumberOfDTC_ByStatusMask(status), - 0x02 => Self::ReportDTC_ByStatusMask(status), + Self::REPORT_NUMBER_OF_DTC_BY_STATUS_MASK => { + Self::ReportNumberOfDTC_ByStatusMask(status) + } + Self::REPORT_DTC_BY_STATUS_MASK => Self::ReportDTC_ByStatusMask(status), _ => unreachable!(), } } - 0x03 => Self::ReportDTCSnapshotIdentification, - 0x04 => Self::ReportDTCSnapshotRecord_ByDTCNumber( - DTCRecord::decode_single_value(reader)?, - DTCSnapshotRecordNumber::decode_single_value(reader)?, - ), - 0x05 => Self::ReportDTCStoredData_ByRecordNumber( - DTCStoredDataRecordNumber::decode_single_value(reader)?, - ), + Self::REPORT_DTC_SNAPSHOT_IDENTIFICATION => Self::ReportDTCSnapshotIdentification, + Self::REPORT_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER => { + Self::ReportDTCSnapshotRecord_ByDTCNumber( + DTCRecord::decode_single_value(reader)?, + DTCSnapshotRecordNumber::decode_single_value(reader)?, + ) + } + Self::REPORT_DTC_STORED_DATA_BY_RECORD_NUMBER => { + Self::ReportDTCStoredData_ByRecordNumber( + DTCStoredDataRecordNumber::decode_single_value(reader)?, + ) + } // 0xFF for all records, 0xFE for all OBD records - 0x06 => Self::ReportDTCExtDataRecord_ByDTCNumber( - DTCRecord::decode_single_value(reader)?, - DTCExtDataRecordNumber::decode_single_value(reader)?, - ), - 0x07 => Self::ReportNumberOfDTC_BySeverityMaskRecord( - DTCSeverityMask::from(reader.read_u8()?), - DTCStatusMask::from(reader.read_u8()?), - ), - 0x08 => Self::ReportDTC_BySeverityMaskRecord( + Self::REPORT_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => { + Self::ReportDTCExtDataRecord_ByDTCNumber( + DTCRecord::decode_single_value(reader)?, + DTCExtDataRecordNumber::decode_single_value(reader)?, + ) + } + Self::REPORT_NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD => { + Self::ReportNumberOfDTC_BySeverityMaskRecord( + DTCSeverityMask::from(reader.read_u8()?), + DTCStatusMask::from(reader.read_u8()?), + ) + } + Self::REPORT_DTC_BY_SEVERITY_MASK_RECORD => Self::ReportDTC_BySeverityMaskRecord( DTCSeverityMask::from(reader.read_u8()?), DTCStatusMask::from(reader.read_u8()?), ), - 0x09 => Self::ReportSeverityInfoOfDTC(DTCRecord::decode_single_value(reader)?), - 0x0A => Self::ReportSupportedDTC, - 0x0B => Self::ReportFirstTestFailedDTC, - 0x0C => Self::ReportFirstConfirmedDTC, - 0x0D => Self::ReportMostRecentTestFailedDTC, - 0x0E => Self::ReportMostRecentConfirmedDTC, - 0x14 => Self::ReportDTCFaultDetectionCounter, - 0x15 => Self::ReportDTCWithPermanentStatus, - 0x16 => Self::ReportDTCExtDataRecord_ByRecordNumber( - DTCExtDataRecordNumber::decode_single_value(reader)?, - ), - 0x17 => { + Self::REPORT_SEVERITY_INFO_OF_DTC => { + Self::ReportSeverityInfoOfDTC(DTCRecord::decode_single_value(reader)?) + } + Self::REPORT_SUPPORTED_DTC => Self::ReportSupportedDTC, + Self::REPORT_FIRST_TEST_FAILED_DTC => Self::ReportFirstTestFailedDTC, + Self::REPORT_FIRST_CONFIRMED_DTC => Self::ReportFirstConfirmedDTC, + Self::REPORT_MOST_RECENT_TEST_FAILED_DTC => Self::ReportMostRecentTestFailedDTC, + Self::REPORT_MOST_RECENT_CONFIRMED_DTC => Self::ReportMostRecentConfirmedDTC, + Self::REPORT_DTC_FAULT_DETECTION_COUNTER => Self::ReportDTCFaultDetectionCounter, + Self::REPORT_DTC_WITH_PERMANENT_STATUS => Self::ReportDTCWithPermanentStatus, + Self::REPORT_DTC_EXT_DATA_RECORD_BY_RECORD_NUMBER => { + Self::ReportDTCExtDataRecord_ByRecordNumber( + DTCExtDataRecordNumber::decode_single_value(reader)?, + ) + } + Self::REPORT_USER_DEF_MEMORY_DTC_BY_STATUS_MASK => { Self::ReportUserDefMemoryDTC_ByStatusMask(DTCStatusMask::from(reader.read_u8()?)) } // 0xFF for all records - 0x18 => Self::ReportUserDefMemoryDTCSnapshotRecord_ByDTCNumber( - DTCRecord::decode_single_value(reader)?, - UserDefDTCSnapshotRecordNumber::decode_single_value(reader)?, - reader.read_u8()?, - ), - 0x19 => Self::ReportUserDefMemoryDTCExtDataRecord_ByDTCNumber( - DTCRecord::decode_single_value(reader)?, - DTCExtDataRecordNumber::decode_single_value(reader)?, - reader.read_u8()?, - ), - 0x1A => Self::ReportSupportedDTCExtDataRecord( + Self::REPORT_USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER => { + Self::ReportUserDefMemoryDTCSnapshotRecord_ByDTCNumber( + DTCRecord::decode_single_value(reader)?, + UserDefDTCSnapshotRecordNumber::decode_single_value(reader)?, + reader.read_u8()?, + ) + } + Self::REPORT_USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => { + Self::ReportUserDefMemoryDTCExtDataRecord_ByDTCNumber( + DTCRecord::decode_single_value(reader)?, + DTCExtDataRecordNumber::decode_single_value(reader)?, + reader.read_u8()?, + ) + } + Self::REPORT_SUPPORTED_DTC_EXT_DATA_RECORD => Self::ReportSupportedDTCExtDataRecord( DTCExtDataRecordNumber::decode_single_value(reader)?, ), - 0x42 => Self::ReportWWHOBDDTC_ByMaskRecord( + Self::REPORT_WWH_OBD_DTC_BY_MASK_RECORD => Self::ReportWWHOBDDTC_ByMaskRecord( FunctionalGroupIdentifier::from(reader.read_u8()?), DTCStatusMask::from(reader.read_u8()?), DTCSeverityMask::from(reader.read_u8()?), ), - 0x43..=0x54 => Self::ISOSAEReserved(report_type), - 0x55 => Self::ReportWWHOBDDTC_WithPermanentStatus(FunctionalGroupIdentifier::from( - reader.read_u8()?, - )), - 0x56 => Self::ReportDTCInformation_ByDTCReadinessGroupIdentifier( - FunctionalGroupIdentifier::from(reader.read_u8()?), - reader.read_u8()?, - ), - 0x57..=0x7F => Self::ISOSAEReserved(report_type), + Self::ISO_SAE_RESERVED_START..=Self::ISO_SAE_RESERVED_BEFORE_PERMANENT_END => { + Self::ISOSAEReserved(report_type) + } + Self::REPORT_WWH_OBD_DTC_WITH_PERMANENT_STATUS => { + Self::ReportWWHOBDDTC_WithPermanentStatus(FunctionalGroupIdentifier::from( + reader.read_u8()?, + )) + } + Self::REPORT_DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER => { + Self::ReportDTCInformation_ByDTCReadinessGroupIdentifier( + FunctionalGroupIdentifier::from(reader.read_u8()?), + reader.read_u8()?, + ) + } + Self::ISO_SAE_RESERVED_AFTER_PERMANENT_START + ..=Self::ISO_SAE_RESERVED_AFTER_PERMANENT_END => Self::ISOSAEReserved(report_type), _ => return Err(Error::InvalidDtcSubfunctionType(report_type)), }; Ok(Some(subfunction)) @@ -776,18 +851,92 @@ pub enum ReadDTCInfoResponse { DTCByReadinessGroupIdentifierList(DTCByReadinessGroupIdentifierRecord), } +impl ReadDTCInfoResponse { + pub const NUMBER_OF_DTC_BY_STATUS_MASK: u8 = + ReadDTCInfoSubFunction::REPORT_NUMBER_OF_DTC_BY_STATUS_MASK; + pub const NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD: u8 = + ReadDTCInfoSubFunction::REPORT_NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD; + pub const DTC_BY_STATUS_MASK: u8 = ReadDTCInfoSubFunction::REPORT_DTC_BY_STATUS_MASK; + pub const SUPPORTED_DTC: u8 = ReadDTCInfoSubFunction::REPORT_SUPPORTED_DTC; + pub const FIRST_TEST_FAILED_DTC: u8 = ReadDTCInfoSubFunction::REPORT_FIRST_TEST_FAILED_DTC; + pub const FIRST_CONFIRMED_DTC: u8 = ReadDTCInfoSubFunction::REPORT_FIRST_CONFIRMED_DTC; + pub const MOST_RECENT_TEST_FAILED_DTC: u8 = + ReadDTCInfoSubFunction::REPORT_MOST_RECENT_TEST_FAILED_DTC; + pub const MOST_RECENT_CONFIRMED_DTC: u8 = + ReadDTCInfoSubFunction::REPORT_MOST_RECENT_CONFIRMED_DTC; + pub const DTC_SEVERITY_MASK_RECORD: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_BY_SEVERITY_MASK_RECORD; + pub const SEVERITY_INFO_OF_DTC: u8 = ReadDTCInfoSubFunction::REPORT_SEVERITY_INFO_OF_DTC; + pub const DTC_SNAPSHOT_IDENTIFICATION: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_SNAPSHOT_IDENTIFICATION; + pub const DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER; + pub const DTC_STORED_DATA_BY_RECORD_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_STORED_DATA_BY_RECORD_NUMBER; + pub const DTC_EXT_DATA_RECORD_BY_DTC_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER; + pub const DTC_FAULT_DETECTION_COUNTER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_FAULT_DETECTION_COUNTER; + pub const DTC_WITH_PERMANENT_STATUS: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_WITH_PERMANENT_STATUS; + pub const DTC_EXT_DATA_RECORD_BY_RECORD_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_EXT_DATA_RECORD_BY_RECORD_NUMBER; + pub const USER_DEF_MEMORY_DTC_BY_STATUS_MASK: u8 = + ReadDTCInfoSubFunction::REPORT_USER_DEF_MEMORY_DTC_BY_STATUS_MASK; + pub const USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER; + pub const USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER: u8 = + ReadDTCInfoSubFunction::REPORT_USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER; + pub const SUPPORTED_DTC_EXT_DATA_RECORD: u8 = + ReadDTCInfoSubFunction::REPORT_SUPPORTED_DTC_EXT_DATA_RECORD; + pub const WWH_OBD_DTC_BY_MASK_RECORD: u8 = + ReadDTCInfoSubFunction::REPORT_WWH_OBD_DTC_BY_MASK_RECORD; + pub const WWH_OBD_DTC_WITH_PERMANENT_STATUS: u8 = + ReadDTCInfoSubFunction::REPORT_WWH_OBD_DTC_WITH_PERMANENT_STATUS; + pub const DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER: u8 = + ReadDTCInfoSubFunction::REPORT_DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER; + + pub fn response_id(&self) -> u8 { + match self { + Self::NumberOfDTCs(subfunction, ..) => *subfunction, + Self::DTCList(subfunction, ..) => *subfunction, + Self::DTCSnapshotList(..) => Self::DTC_SNAPSHOT_IDENTIFICATION, + Self::DTCSnapshotRecordList(..) => Self::DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER, + Self::DTCExtDataRecordList(..) => Self::DTC_EXT_DATA_RECORD_BY_DTC_NUMBER, + Self::DTCSeverityRecordList(subfunction, ..) => *subfunction, + Self::DTCFaultDetectionCounterRecordList(..) => Self::DTC_FAULT_DETECTION_COUNTER, + Self::UserDefMemoryDTCByStatusMaskList(..) => Self::USER_DEF_MEMORY_DTC_BY_STATUS_MASK, + Self::UserDefMemoryDTCSnapshotRecordByDTCNumberList(..) => { + Self::USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER + } + Self::SupportedDTCExtDataRecordList(..) => Self::SUPPORTED_DTC_EXT_DATA_RECORD, + Self::WWHOBDDTCByMaskRecordList(..) => Self::WWH_OBD_DTC_BY_MASK_RECORD, + Self::WWHOBDDTCWithPermanentStatusList(..) => Self::WWH_OBD_DTC_WITH_PERMANENT_STATUS, + Self::DTCByReadinessGroupIdentifierList(..) => { + Self::DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER + } + } + } +} + impl WireFormat for ReadDTCInfoResponse { #[allow(clippy::too_many_lines)] fn decode(reader: &mut T) -> Result, Error> { let subfunction_id = reader.read_u8()?; match subfunction_id { - 0x01 | 0x07 => { + Self::NUMBER_OF_DTC_BY_STATUS_MASK | Self::NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD => { let status = DTCStatusAvailabilityMask::from(reader.read_u8()?); let count = reader.read_u16::()?; Ok(Some(Self::NumberOfDTCs(subfunction_id, status, count))) } - 0x02 | 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x15 => { + Self::DTC_BY_STATUS_MASK + | Self::SUPPORTED_DTC + | Self::FIRST_TEST_FAILED_DTC + | Self::FIRST_CONFIRMED_DTC + | Self::MOST_RECENT_TEST_FAILED_DTC + | Self::MOST_RECENT_CONFIRMED_DTC + | Self::DTC_WITH_PERMANENT_STATUS => { let status = DTCStatusAvailabilityMask::from(reader.read_u8()?); let mut dtcs: Vec<(DTCRecord, DTCStatusMask)> = Vec::new(); @@ -801,7 +950,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::DTC_SNAPSHOT_IDENTIFICATION => { let mut dtcs: Vec<(DTCRecord, DTCSnapshotRecordNumber)> = Vec::new(); // Loop until we're done with the reader and fill the DTC list @@ -814,15 +963,15 @@ impl WireFormat for ReadDTCInfoResponse { + Self::DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER => { let snapshot_list = DTCSnapshotRecordList::decode(reader)?.unwrap(); Ok(Some(Self::DTCSnapshotRecordList(snapshot_list))) } - 0x06 => { + Self::DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => { let ext_data_list = DTCExtDataRecordList::decode(reader)?.unwrap(); Ok(Some(Self::DTCExtDataRecordList(ext_data_list))) } - 0x08 | 0x09 => { + Self::DTC_SEVERITY_MASK_RECORD | Self::SEVERITY_INFO_OF_DTC => { let status = DTCStatusAvailabilityMask::from(reader.read_u8()?); let mut dtcs = Vec::new(); @@ -843,7 +992,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::DTC_FAULT_DETECTION_COUNTER => { let mut dtcs = Vec::new(); for dtc_fault_record in DTCFaultDetectionCounterRecord::decode_iterable(reader) { match dtc_fault_record { @@ -857,7 +1006,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::USER_DEF_MEMORY_DTC_BY_STATUS_MASK => { let memory_selection = reader.read_u8()?; let status_availability_mask = DTCStatusMask::decode_single_value(reader)?; let mut record_data = Vec::new(); @@ -875,10 +1024,12 @@ impl WireFormat for ReadDTCInfoResponse Ok(Some(Self::UserDefMemoryDTCSnapshotRecordByDTCNumberList( - UserDefMemoryDTCSnapshotRecordByDTCNumRecord::decode(reader)?.unwrap(), - ))), - 0x1A => { + Self::USER_DEF_MEMORY_DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER => { + Ok(Some(Self::UserDefMemoryDTCSnapshotRecordByDTCNumberList( + UserDefMemoryDTCSnapshotRecordByDTCNumRecord::decode(reader)?.unwrap(), + ))) + } + Self::SUPPORTED_DTC_EXT_DATA_RECORD => { let status_availability_mask = DTCStatusAvailabilityMask::decode_single_value(reader)?; let mut dtc_and_status_records = Vec::new(); @@ -898,7 +1049,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::WWH_OBD_DTC_BY_MASK_RECORD => { let functional_group_identifier = FunctionalGroupIdentifier::from(reader.read_u8()?); let status_availability_mask = @@ -930,7 +1081,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::WWH_OBD_DTC_WITH_PERMANENT_STATUS => { let functional_group_identifier = FunctionalGroupIdentifier::from(reader.read_u8()?); let status_availability_mask = DTCStatusAvailabilityMask::decode(reader)?.unwrap(); @@ -959,7 +1110,7 @@ impl WireFormat for ReadDTCInfoResponse { + Self::DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER => { let functional_group_identifier = FunctionalGroupIdentifier::from(reader.read_u8()?); let status_availability_mask = @@ -983,7 +1134,11 @@ impl WireFormat for ReadDTCInfoResponse todo!(), // _ => Err(Error::InvalidDtcSubfunctionType(subfunction_id)), + ReadDTCInfoSubFunction::ISO_SAE_RESERVED_START + ..=ReadDTCInfoSubFunction::ISO_SAE_RESERVED_AFTER_PERMANENT_END => { + return Err(Error::InvalidDtcSubfunctionType(subfunction_id)); + } + _ => todo!(), } } @@ -1020,14 +1175,13 @@ impl WireFormat for ReadDTCInfoResponse(&self, writer: &mut T) -> Result { + writer.write_u8(self.response_id())?; match self { - Self::NumberOfDTCs(id, mask, count) => { - writer.write_u8(*id)?; + Self::NumberOfDTCs(_, mask, count) => { writer.write_u8(mask.bits())?; writer.write_u16::(*count)?; } - Self::DTCList(id, mask, list) => { - writer.write_u8(*id)?; + Self::DTCList(_, mask, list) => { writer.write_u8(mask.bits())?; for (record, status) in list { record.encode(writer)?; @@ -1035,35 +1189,29 @@ impl WireFormat for ReadDTCInfoResponse { - writer.write_u8(0x03)?; for (record, number) in list { record.encode(writer)?; number.encode(writer)?; } } Self::DTCSnapshotRecordList(list) => { - writer.write_u8(0x04)?; list.encode(writer)?; } Self::DTCExtDataRecordList(list) => { - writer.write_u8(0x06)?; list.encode(writer)?; } Self::DTCFaultDetectionCounterRecordList(list) => { - writer.write_u8(0x14)?; for fault_detection_counter in list { fault_detection_counter.encode(writer)?; } } - Self::DTCSeverityRecordList(id, status, list) => { - writer.write_u8(*id)?; + Self::DTCSeverityRecordList(_, status, list) => { status.encode(writer)?; for dtcs in list { dtcs.encode(writer)?; } } Self::UserDefMemoryDTCByStatusMaskList(data_record_struct) => { - writer.write_u8(0x17)?; writer.write_u8(data_record_struct.memory_selection)?; data_record_struct.status_availability_mask.encode(writer)?; for (data_record, status) in &data_record_struct.record_data { @@ -1073,11 +1221,9 @@ impl WireFormat for ReadDTCInfoResponse { - writer.write_u8(0x18)?; snapshot_struct.encode(writer)?; } Self::SupportedDTCExtDataRecordList(response_struct) => { - writer.write_u8(0x1A)?; response_struct.status_availability_mask.encode(writer)?; if let Some(record_number) = &response_struct.ext_data_record_number { record_number.encode(writer)?; @@ -1088,7 +1234,6 @@ impl WireFormat for ReadDTCInfoResponse { - writer.write_u8(0x42)?; writer.write_u8(response_struct.functional_group_identifier.value())?; response_struct.status_availability_mask.encode(writer)?; writer.write_u8(response_struct.severity_availability_mask.into())?; @@ -1100,7 +1245,6 @@ impl WireFormat for ReadDTCInfoResponse { - writer.write_u8(0x55)?; writer.write_u8(response_struct.functional_group_identifier.value())?; response_struct.status_availability_mask.encode(writer)?; writer.write_u8(response_struct.format_identifier.into())?; @@ -1110,7 +1254,6 @@ impl WireFormat for ReadDTCInfoResponse { - writer.write_u8(0x56)?; writer.write_u8(response_struct.functional_group_identifier.value())?; response_struct.status_availability_mask.encode(writer)?; writer.write_u8(response_struct.format_identifier.into())?; diff --git a/src/services/request_file_transfer.rs b/src/services/request_file_transfer.rs index add6995..ae63134 100644 --- a/src/services/request_file_transfer.rs +++ b/src/services/request_file_transfer.rs @@ -12,31 +12,43 @@ pub enum FileOperationMode { // 0x00, 0x07-0xFF Reserved for future definition by ISO ISOSAEReserved(u8), /// Add a file to the server - AddFile = 0x01, + AddFile = Self::ADD_FILE, /// Delete the specified file from the server - DeleteFile = 0x02, + DeleteFile = Self::DELETE_FILE, /// Replace the specified file on the server, if it does not exist, add it - ReplaceFile = 0x03, + ReplaceFile = Self::REPLACE_FILE, /// Read the specified file from the server (upload) - ReadFile = 0x04, + ReadFile = Self::READ_FILE, /// Read the directory from the server /// Implies that the request does not include a `fileName` - ReadDir = 0x05, + ReadDir = Self::READ_DIR, /// Resume a file transfer at the returned `filePosition` indicator /// The file must already exist in the ECU's filesystem - ResumeFile = 0x06, + ResumeFile = Self::RESUME_FILE, +} + +impl FileOperationMode { + pub const RESERVED: u8 = 0x00; + pub const ADD_FILE: u8 = 0x01; + pub const DELETE_FILE: u8 = 0x02; + pub const REPLACE_FILE: u8 = 0x03; + pub const READ_FILE: u8 = 0x04; + pub const READ_DIR: u8 = 0x05; + pub const RESUME_FILE: u8 = 0x06; + pub const RESERVED_START: u8 = 0x07; + pub const RESERVED_END: u8 = 0xFF; } impl From for u8 { fn from(value: FileOperationMode) -> Self { match value { FileOperationMode::ISOSAEReserved(value) => value, - FileOperationMode::AddFile => 0x01, - FileOperationMode::DeleteFile => 0x02, - FileOperationMode::ReplaceFile => 0x03, - FileOperationMode::ReadFile => 0x04, - FileOperationMode::ReadDir => 0x05, - FileOperationMode::ResumeFile => 0x06, + FileOperationMode::AddFile => FileOperationMode::ADD_FILE, + FileOperationMode::DeleteFile => FileOperationMode::DELETE_FILE, + FileOperationMode::ReplaceFile => FileOperationMode::REPLACE_FILE, + FileOperationMode::ReadFile => FileOperationMode::READ_FILE, + FileOperationMode::ReadDir => FileOperationMode::READ_DIR, + FileOperationMode::ResumeFile => FileOperationMode::RESUME_FILE, } } } @@ -46,13 +58,15 @@ impl TryFrom for FileOperationMode { fn try_from(value: u8) -> Result { match value { - 0x01 => Ok(Self::AddFile), - 0x02 => Ok(Self::DeleteFile), - 0x03 => Ok(Self::ReplaceFile), - 0x04 => Ok(Self::ReadFile), - 0x05 => Ok(Self::ReadDir), - 0x06 => Ok(Self::ResumeFile), - 0x00 | 0x07..=0xFF => Ok(Self::ISOSAEReserved(value)), + Self::ADD_FILE => Ok(Self::AddFile), + Self::DELETE_FILE => Ok(Self::DeleteFile), + Self::REPLACE_FILE => Ok(Self::ReplaceFile), + Self::READ_FILE => Ok(Self::ReadFile), + Self::READ_DIR => Ok(Self::ReadDir), + Self::RESUME_FILE => Ok(Self::ResumeFile), + Self::RESERVED | Self::RESERVED_START..=Self::RESERVED_END => { + Ok(Self::ISOSAEReserved(value)) + } } } } From ea9044ef361cfff5851bba037c1fe1fdab5f783d Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Fri, 17 Oct 2025 15:32:18 -0400 Subject: [PATCH 4/6] style(clippy): fix clippy pedantic suggestions Signed-off-by: Parth Patel --- src/service.rs | 2 ++ src/services/read_dtc_information.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/service.rs b/src/service.rs index 093d2fa..584871c 100644 --- a/src/service.rs +++ b/src/service.rs @@ -280,6 +280,8 @@ impl UdsServiceType { _ => Self::NEGATIVE_RESPONSE, } } + + #[allow(clippy::match_same_arms)] #[must_use] pub fn response_from_byte(value: u8) -> Self { match value { diff --git a/src/services/read_dtc_information.rs b/src/services/read_dtc_information.rs index 7c00c31..f9dd538 100644 --- a/src/services/read_dtc_information.rs +++ b/src/services/read_dtc_information.rs @@ -896,6 +896,8 @@ impl ReadDTCInfoResponse { pub const DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER: u8 = ReadDTCInfoSubFunction::REPORT_DTC_INFORMATION_BY_DTC_READINESS_GROUP_IDENTIFIER; + #[allow(clippy::match_same_arms)] + #[must_use] pub fn response_id(&self) -> u8 { match self { Self::NumberOfDTCs(subfunction, ..) => *subfunction, @@ -1136,7 +1138,7 @@ impl WireFormat for ReadDTCInfoResponse { - return Err(Error::InvalidDtcSubfunctionType(subfunction_id)); + Err(Error::InvalidDtcSubfunctionType(subfunction_id)) } _ => todo!(), } From 7d6ef40c49e6b222e8909b2c8c8068d0a759e807 Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Fri, 17 Oct 2025 17:50:27 -0400 Subject: [PATCH 5/6] style(fmt): sort derives in alphabetical order Signed-off-by: Parth Patel --- src/common/communication_type.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/communication_type.rs b/src/common/communication_type.rs index 89b7fdb..f4afb2e 100644 --- a/src/common/communication_type.rs +++ b/src/common/communication_type.rs @@ -12,7 +12,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)] #[num_enum(error_type(name = crate::Error, constructor = Error::InvalidCommunicationType))] #[repr(u8)] pub enum CommunicationType { diff --git a/src/lib.rs b/src/lib.rs index fc7b208..cec84d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ pub type ProtocolResponse = Response; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)] #[num_enum(error_type(name = crate::Error, constructor = Error::InvalidUDSMessageValue))] #[repr(u8)] pub enum RoutineControlSubFunction { @@ -100,7 +100,7 @@ impl IterableWireFormat for Vec {} #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)] #[num_enum(error_type(name = crate::Error, constructor = Error::InvalidUDSMessageValue))] #[repr(u8)] pub enum DtcSettings { From bcbec503e258210c789e3cbdfa9d02c66771565d Mon Sep 17 00:00:00 2001 From: Parth Patel Date: Mon, 20 Oct 2025 12:51:35 -0400 Subject: [PATCH 6/6] fix(spell): correct spelling mistake Signed-off-by: Parth Patel --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cec84d9..90837d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,13 +115,13 @@ mod tests { #[test] fn test_correct_discriminant() { - let raw_disciminant: u8 = 0x01; + let raw_discriminant: u8 = 0x01; let discriminant_from_id: u8 = RoutineControlSubFunction::StartRoutine.into(); let id_from_discriminant: RoutineControlSubFunction = - RoutineControlSubFunction::try_from(raw_disciminant).unwrap(); + RoutineControlSubFunction::try_from(raw_discriminant).unwrap(); - assert_eq!(discriminant_from_id, raw_disciminant); + assert_eq!(discriminant_from_id, raw_discriminant); assert_eq!( id_from_discriminant, RoutineControlSubFunction::StartRoutine @@ -130,16 +130,16 @@ mod tests { #[test] fn test_incorrect_discriminant() { - let raw_disciminant: u8 = 0x04; + let raw_discriminant: u8 = 0x04; - let id_from_discriminant = RoutineControlSubFunction::try_from(raw_disciminant) + let id_from_discriminant = RoutineControlSubFunction::try_from(raw_discriminant) .err() .unwrap() .to_string(); assert_eq!( id_from_discriminant, - Error::InvalidUDSMessageValue(raw_disciminant).to_string() + Error::InvalidUDSMessageValue(raw_discriminant).to_string() ); } }