Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/pages/knowledge_base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ understanding of the UDS protocol itself.
knowledge_base/osi_model.rst
knowledge_base/client_server_model.rst
knowledge_base/addressing.rst
knowledge_base/states.rst
knowledge_base/service.rst
knowledge_base/diagnostic_message.rst
knowledge_base/packet.rst
Expand Down
70 changes: 70 additions & 0 deletions docs/source/pages/knowledge_base/states.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.. _knowledge-base-states:

States
======
In UDS, the behavior of a server (ECU) depends on its current operating state. Many diagnostic services are
only available when specific conditions are satisfied. For example, a service may only be supported in
Extended Diagnostic Session, require an unlocked security level (to protect from unwanted access),
or be available only when the engine is stopped from safety reasons.

The current state of the ECU therefore determines whether a diagnostic request is accepted or rejected.

Typical diagnostic states include:

* `Diagnostic Session`_
* `Security Access`_
* `Authentication`_

In addition to these diagnostic states, many ECUs also consider vehicle-specific conditions, such as:

* whether the ignition (KL15) is ON
* whether the engine is running
* vehicle speed
* battery voltage
* gear selector position
* parking brake status

Manufacturers may define additional ECU-specific states depending on the functionality being protected.


.. _knowledge-base-state-session:

Diagnostic Session
------------------
The Diagnostic Session defines the current operating mode of the ECU. It is controlled through the
:ref:`DiagnosticSessionControl <knowledge-base-service-diagnostic-session-control>` service.

Only one diagnostic session can be active at any given time.
After an ECU reset or power-up, the server enters the **Default Session**.
A client may request a different session, such as Programming Session or Extended Diagnostic Session,
to gain access to additional diagnostic features.


.. _knowledge-base-state-security-access:

Security Access
---------------
Security Access protects diagnostic functionality that should not be available to every client.
It is controlled through the :ref:`SecurityAccess <knowledge-base-service-security-access>` service.

The server starts in a **locked** state. A client may unlock one or more security levels by
successfully completing the Security Access sequence (`requestSeed` → `sendKey`).

The unlocked security level shall be cleared whenever the diagnostic session changes or the ECU is reset.


.. _knowledge-base-state-authentication:

Authentication
--------------
Authentication provides an identity-based mechanism for authorizing diagnostic communication.
It is controlled through the :ref:`Authentication <knowledge-base-service-authentication>` service.

Unlike `Security Access`_, which is based on a challenge-response algorithm using a seed and key,
Authentication establishes the identity of the communicating parties, typically using cryptographic credentials.

Authentication may be performed in either direction.
Depending on the ECU implementation and requested SubFunction, the client may authenticate the server,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
the server may authenticate the client, or both parties may authenticate each other (bi-directional authentication).

Some diagnostic services may only be available after successful authentication.
1 change: 1 addition & 0 deletions docs/source/pages/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ for getting started.
user_guide/addressing.rst
user_guide/client.rst
user_guide/message_translation.rst
user_guide/diagnostic_configuration.rst
user_guide/logging.rst
user_guide/can.rst
user_guide/custom.rst
141 changes: 141 additions & 0 deletions docs/source/pages/user_guide/diagnostic_configuration.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
.. _implementation-ecu-diagnostic-configuration:

Diagnostic Configuration
========================
The Diagnostic Configuration module provides a mechanism for describing the conditions under which an ECU supports
diagnostic messages. It allows applications to model ECU operating states and define the availability of
diagnostic functions depending on the current state.

The implementation is located in the :mod:`uds.diagnostic_configuration` package and consists of
the following components:

- `State`_
- `States Definitions`_
- `ECU Diagnostic Configuration`_


State
-----
The :class:`~uds.diagnostic_configuration.state.State` class represents a single
:ref:`ECU state <knowledge-base-states>` that may affect the availability of diagnostic functions.
A state has a name, a predefined set of allowed values, and a current value representing the ECU's current operating
condition.

Attributes:

- :attr:`~uds.diagnostic_configuration.state.State.name` - name of a state
- :attr:`~uds.diagnostic_configuration.state.State.possible_values` - collection of all values the state can assume
- :attr:`~uds.diagnostic_configuration.state.State.current_value` - current value of the state

**Example code:**

.. code-block:: python

import uds

# create an example state describing the active diagnostic session
session = uds.diagnostic_configuration.State(name="Diagnostic Session",
possible_values={"Default", "Programming", "Extended"})

# change the current session
session.current_value = "Default"

# mark the current session as undefined
session.current_value = None


States Definitions
------------------
The :mod:`uds.diagnostic_configuration.state_definitions` module provides predefined
:class:`~uds.diagnostic_configuration.state.State` objects representing the most common ECU states used in
UDS diagnostic communication. These definitions can be used directly or serve as a starting point for creating custom
diagnostic configurations.

The following state definitions are provided:

- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_DIAGNOSTIC_SESSION_STATE`
- current diagnostic session
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_SECURITY_ACCESS_STATE`
- currently unlocked security access level
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_AUTHENTICATION_STATE`
- current authentication state
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_IGNITION_STATE`
- current ignition status
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_ENGINE_STATE`
- current engine state
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_SECURED_TRANSMISSION_STATE`
– indicates whether secured data transmission is active
- :obj:`~uds.diagnostic_configuration.state_definitions.DEFAULT_ADDRESSING_TYPE_STATE`
– current addressing type (physical or functional)


ECU Diagnostic Configuration
----------------------------
The :class:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration` class is the central
component of the Diagnostic Configuration module. It stores the ECU states relevant for diagnostic communication
together with the restrictions that determine when diagnostic services, sub-functions, DID and RID are available.

Restrictions can be defined at multiple levels of specificity:

- Service Identifier (SID)
- Sub-function (for a given SID)
- Data Identifier (DID, for a given SID)
- Routine Identifier (RID, for a given SID)

More specific restrictions complement or override the restrictions defined at higher levels.

Attributes:

- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.states`
- configured ECU states
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.states_names`
- names of all configured states
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.states_mapping`
- mapping from state name to :class:`~uds.diagnostic_configuration.state.State` object
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.sid_restrictions`
- restrictions defined for diagnostic services (SIDs)
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.subfunction_restrictions`
- restrictions defined for service sub-functions
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.did_restrictions`
- restrictions defined for Data Identifiers (DIDs)
- :attr:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.rid_restrictions`
- restrictions defined for Routine Identifiers (RIDs)

Methods:

- :meth:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.combine_restrictions`
- combines multiple restriction definitions into a single effective restriction
- :meth:`~uds.diagnostic_configuration.ecu_configuration.EcuDiagnosticConfiguration.get_restrictions`
- returns the effective restrictions for a diagnostic message


**Example code:**

.. code-block:: python

import uds

# create an example (simplified) ECU Configuration
ecu_config = uds.diagnostic_configuration.EcuDiagnosticConfiguration(
states=(uds.diagnostic_configuration.DEFAULT_DIAGNOSTIC_SESSION_STATE,
uds.diagnostic_configuration.DEFAULT_SECURITY_ACCESS_STATE,
uds.diagnostic_configuration.DEFAULT_ADDRESSING_TYPE_STATE),
sid_restrictions={
0x22: {
"Session": {0x03},
}},
did_restrictions={
0x22: {
0xF190: {
"Session": {0x03},
"SecurityAccess": {0x01},
"AddressingType": {uds.addressing.AddressingType.PHYSICAL}}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}},
rid_restrictions={},
subfunction_restrictions={})

# Restrictions for ReadDataByIdentifier (0x22)
ecu_config.sid_restrictions[0x22]

# Restrictions for 22 (ReadDataByIdentifier) F1 90 (DID 0xF190) message
ecu_config.get_restrictions([0x22, 0xF1, 0x90])
1 change: 1 addition & 0 deletions uds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"can",
"client",
"translator",
"diagnostic_configuration",
"message",
"packet",
"segmentation",
Expand Down
1 change: 1 addition & 0 deletions uds/diagnostic_configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
DEFAULT_AUTHENTICATION_STATE,
DEFAULT_DIAGNOSTIC_SESSION_STATE,
DEFAULT_ENGINE_STATE,
DEFAULT_IGNITION_STATE,
DEFAULT_SECURED_TRANSMISSION_STATE,
DEFAULT_SECURITY_ACCESS_STATE,
)
4 changes: 2 additions & 2 deletions uds/diagnostic_configuration/ecu_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ def __getitem__(self, item: str) -> State:

@property
def states(self) -> Set[State]:
"""Get ECU states that are relevant for diagnostic communication."""
"""Get :ref:`ECU states <knowledge-base-states>` relevant for diagnostic communication."""
return self.__states

@states.setter
def states(self, states: Collection[State]) -> None:
"""
Set ECU states relevant for diagnostic communication.
Set :ref:`ECU states <knowledge-base-states>` relevant for diagnostic communication.

:param states: ECU states relevant for diagnostic communication.
"""
Expand Down
2 changes: 1 addition & 1 deletion uds/diagnostic_configuration/state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Implementation for diagnostic communication state."""
"""Implementation for :ref:`diagnostic communication state <knowledge-base-states>`."""

__all__ = ["State"]

Expand Down
31 changes: 24 additions & 7 deletions uds/diagnostic_configuration/state_definitions.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
"""Definitions of typical diagnostic communication states."""
"""Predefined State objects representing common :ref:`diagnostic communication states <knowledge-base-states>`."""

__all__ = ["DEFAULT_DIAGNOSTIC_SESSION_STATE",
"DEFAULT_SECURITY_ACCESS_STATE",
"DEFAULT_AUTHENTICATION_STATE",
"DEFAULT_SECURED_TRANSMISSION_STATE",
"DEFAULT_IGNITION_STATE",
"DEFAULT_ENGINE_STATE",
"DEFAULT_SECURED_TRANSMISSION_STATE",
"DEFAULT_ADDRESSING_TYPE_STATE"]
Comment thread
coderabbitai[bot] marked this conversation as resolved.

from uds.addressing import AddressingType
from uds.utilities import OFF_ON_MAPPING

from .state import State

DEFAULT_DIAGNOSTIC_SESSION_STATE = State(name="Session",
possible_values=range(0x80))
DEFAULT_SECURITY_ACCESS_STATE = State(name="Unlocked SecurityAccess level",
"""State representing the current :ref:`Diagnostic Session <knowledge-base-state-session>`."""

DEFAULT_SECURITY_ACCESS_STATE = State(name="SecurityAccess",
possible_values={"Locked", *range(1, 0x80, 2)})
DEFAULT_AUTHENTICATION_STATE = State(name="Authentication state",
"""State representing the currently unlocked :ref:`Security Access <knowledge-base-state-security-access>` level."""

DEFAULT_AUTHENTICATION_STATE = State(name="Authentication",
possible_values={"noone authenticated",
"Client authenticated",
"Server authenticated",
"Client and server authenticated"})
DEFAULT_SECURED_TRANSMISSION_STATE = State(name="Secured Transmission",
"""State representing the current :ref:`Authentication <knowledge-base-state-authentication>` status."""

DEFAULT_IGNITION_STATE = State(name="Ignition",
possible_values=OFF_ON_MAPPING.values())
"""State indicating whether the vehicle ignition is ON or OFF."""

DEFAULT_ENGINE_STATE = State(name="Engine",
possible_values=OFF_ON_MAPPING.values())
"""State indicating whether the engine is running."""
Comment thread
coderabbitai[bot] marked this conversation as resolved.

DEFAULT_SECURED_TRANSMISSION_STATE = State(name="SecuredTransmission",
possible_values={"yes", "no"})
DEFAULT_ENGINE_STATE = State(name="Engine state",
possible_values={"ON", "OFF"})
"""State indicating whether secured data transmission is active."""

DEFAULT_ADDRESSING_TYPE_STATE = State(name="AddressingType",
possible_values=set(AddressingType))
"""State representing the current :class:`~uds.addressing.AddressingType`."""
1 change: 1 addition & 0 deletions uds/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
NETWORKS_MAPPING,
NO_YES_MAPPING,
NODE_IDENTIFICATION_NUMBER_MAPPING,
OFF_ON_MAPPING,
PERIODIC_DID_BIT_LENGTH,
PERIODIC_DID_OFFSET,
POWER_DOWN_TIME_MAPPING,
Expand Down
1 change: 1 addition & 0 deletions uds/utilities/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
NETWORKS_MAPPING,
NO_YES_MAPPING,
NODE_IDENTIFICATION_NUMBER_MAPPING,
OFF_ON_MAPPING,
POWER_DOWN_TIME_MAPPING,
REPEATED_DATA_RECORDS_NUMBER,
SCALING_BYTE_TYPE_MAPPING,
Expand Down
5 changes: 4 additions & 1 deletion uds/utilities/constants/other.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__all__ = [
# Shared
"REPEATED_DATA_RECORDS_NUMBER",
"NO_YES_MAPPING",
"NO_YES_MAPPING", "OFF_ON_MAPPING",
"COMPRESSION_METHOD_MAPPING", "ENCRYPTION_METHOD_MAPPING",
# SID 0x11
"POWER_DOWN_TIME_MAPPING",
Expand Down Expand Up @@ -44,6 +44,9 @@
NO_YES_MAPPING: Dict[int, str] = {0: "no", 1: "yes"}
"""Generic `no` and `yes` values mapping."""

OFF_ON_MAPPING: Dict[int, str] = {0: "OFF", 1: "ON"}
"""Generic `OFF` and `ON` values mapping."""

Comment thread
coderabbitai[bot] marked this conversation as resolved.
COMPRESSION_METHOD_MAPPING: Dict[int, str] = ({0: "no compression"}
| {value: f"compression #{value}" for value in range(1, 0x10)})
"""Values mapping for compressionMethod Data Record that is part of messages for multiple services."""
Expand Down
Loading