Skip to main content

uds_protocol/
lib.rs

1#![warn(clippy::pedantic)]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
3mod common;
4pub use common::*;
5
6mod error;
7pub use error::Error;
8
9// Export the Identifier derive macro
10pub use uds_protocol_derive::Identifier;
11
12mod protocol_definitions;
13pub use protocol_definitions::{ProtocolIdentifier, ProtocolPayload};
14
15mod request;
16pub use request::Request;
17
18mod response;
19pub use response::{Response, UdsResponse};
20
21mod service;
22pub use service::UdsServiceType;
23
24mod services;
25pub use services::*;
26
27mod traits;
28pub use traits::{
29    DiagnosticDefinition, Identifier, IterableWireFormat, RoutineIdentifier, SingleValueWireFormat,
30    WireFormat,
31};
32
33pub const SUCCESS: u8 = 0x80;
34pub const PENDING: u8 = 0x78;
35
36/// Basic UDS implementation of the [`DiagnosticDefinition`] trait.
37///
38/// This is an example of a simple data spec that can be used with UDS requests and responses.
39/// It should **not** be used directly in production code, but rather as a base for more complex data specifiers.
40#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
41#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
43pub struct UdsSpec;
44impl DiagnosticDefinition for UdsSpec {
45    type RID = UDSRoutineIdentifier;
46    type DID = ProtocolIdentifier;
47    type RoutinePayload = ProtocolPayload;
48    type DiagnosticPayload = ProtocolPayload;
49}
50
51/// Type alias for a UDS Request type that only implements the messages explicitly defined by the UDS specification.
52pub type ProtocolRequest = Request<UdsSpec>;
53
54/// Type alias for a UDS Response type that only implements the messages explicitly defined by the UDS specification.
55pub type ProtocolResponse = Response<UdsSpec>;
56
57/// What type of routine control to perform for a [`RoutineControlRequest`].
58#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
59#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
60#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
61#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub enum RoutineControlSubFunction {
63    /// Routine will be started sometime between completion of the `StartRoutine` request and the completion of the 1st response message
64    /// which indicates that the routine has already been performed, or is in progress
65    ///
66    /// It might be necessary to switch the server to a specific Diagnostic Session via [`DiagnosticSessionControlRequest`] before starting the routine,
67    /// or unlock the server using [`SecurityAccessRequest`] before starting the routine.
68    StartRoutine,
69
70    /// 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
71    /// which indicates that the routine has already been stopped, or is in progress
72    StopRoutine,
73
74    /// Request results for the specified routineIdentifier
75    RequestRoutineResults,
76}
77
78impl From<RoutineControlSubFunction> for u8 {
79    fn from(value: RoutineControlSubFunction) -> Self {
80        match value {
81            RoutineControlSubFunction::StartRoutine => 0x01,
82            RoutineControlSubFunction::StopRoutine => 0x02,
83            RoutineControlSubFunction::RequestRoutineResults => 0x03,
84        }
85    }
86}
87
88impl From<u8> for RoutineControlSubFunction {
89    fn from(value: u8) -> Self {
90        match value {
91            0x01 => RoutineControlSubFunction::StartRoutine,
92            0x02 => RoutineControlSubFunction::StopRoutine,
93            0x03 => RoutineControlSubFunction::RequestRoutineResults,
94            _ => panic!("Invalid routine control subfunction: {value}"),
95        }
96    }
97}
98
99impl WireFormat for Vec<u8> {
100    fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
101        let mut data = Vec::new();
102        reader.read_to_end(&mut data)?;
103        Ok(Some(data))
104    }
105
106    fn required_size(&self) -> usize {
107        self.len()
108    }
109
110    fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
111        writer.write_all(self)?;
112        Ok(self.len())
113    }
114}
115
116impl SingleValueWireFormat for Vec<u8> {}
117impl IterableWireFormat for Vec<u8> {}
118
119#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
120#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
121#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123pub enum DtcSettings {
124    On,
125    Off,
126}
127
128impl From<DtcSettings> for u8 {
129    fn from(value: DtcSettings) -> Self {
130        match value {
131            DtcSettings::On => 0x01,
132            DtcSettings::Off => 0x02,
133        }
134    }
135}
136
137impl From<u8> for DtcSettings {
138    fn from(value: u8) -> Self {
139        match value {
140            0x01 => Self::On,
141            0x02 => Self::Off,
142            _ => panic!("Invalid DTC setting: {value}"),
143        }
144    }
145}