python-udsoncan
repository·master·Indexed 20 days ago
https://github.com/pylessard/python-udsoncanA Python 3 implementation of the Unified Diagnostic Services (UDS) protocol as defined by ISO-14229. It provides tools to interact with vehicle ECUs via transport layers like ISO-TP, allowing developers to build and interpret UDS payloads, manage diagnostic sessions, and detect malformed messages. The library includes a synchronous Client for handling request/response cycles, support for custom security algorithms, and configurable codecs for Data Identifiers (DID) and Input/Output Control (IOC).
What's inside python-udsoncan
- python-udsoncan is a Python 3 implementation of the Unified Diagnostic Services (UDS) protocol as defined by the ISO-14229 standard. It provides tools to interact with UDS servers by building and interpreting UDS payloads and detecting malformed messages. It is designed for developing tester units, debugging server code, searching for security flaws, or general automotive diagnostic tasks.
Understand Unified Diagnostic Services (UDS) concepts
masterUnified Diagnostic Services (UDS), defined by the ISO-14229 standard, is an application protocol interface used for diagnostics, debugging, and configuration of Electronic Control Units (ECUs) in road vehicles.
Key roles in a UDS communication:
- UDS Client: Typically a tester unit connected to a vehicle diagnostic port.
- UDS Server: An ECU within the vehicle connected to the CAN bus.
UDS defines message formatting and the interface for services, but the specific implementation of how a server responds to a request is left to the ECU manufacturer.
Use python-udsoncan with non-CAN transport protocols
masterDespite the namepython-udsoncan, the library is not limited to CAN bus. The library abstracts the transport protocol through theConnectionclass. You can implement or use connections for other transport layers as long as they satisfy theConnectioninterface.How the UDS security algorithm handshake works
masterWhile UDS does not define the specific mathematical algorithm used for security, it defines the protocol for the key exchange. The process follows a request/response pattern consisting of two main exchanges:
- Request Seed: The client requests a seed for a specific security level (identified by a number). The seed acts as a nonce to prevent replay attacks.
- Compute Key: The client receives the seed and computes a key using a manufacturer-defined algorithm.
- Send Key: The client sends the computed key to the server. If the server verifies the key, the security level is unlocked and a positive response is sent.
How UDS sessions and security levels work
masterUDS communication involves managing both the current session and the current security level.
Sessions
When a client connects, the server typically assigns it a default session. In this session, only a limited set of services (like reading DTCs) are available.
- A client can switch to other sessions using the
DiagnosticSessionControlservice. - The ECU manufacturer can define up to 32 additional sessions beyond the default.
- Switching sessions is a way to change the available service set, not a security mechanism itself.
Security Levels
A security level is a status that grants access to restricted features (services, subfunctions, or specific values) by providing a security key.
- There can be up to 64 security levels.
- Unlocking process: You cannot unlock security levels in the default session. You must first switch to a non-default session that enables the
SecurityAccessservice. - Expiration: Security privileges often expire after a short period. To maintain an active session and keep security levels unlocked, the client must send keepalive messages using the
TesterPresentservice.
- A client can switch to other sessions using the
How the UDS Client works
masterThe
udsoncan.client.Clientis a synchronous client designed to handle a single request/response cycle at a time. It simplifies interaction with the Services object by automating repetitive tasks and providing error handling.When you request a service, the client automatically performs the following sequence:
- Builds the request payload.
- Calls the connection's
empty_rxqueuemethod to clear stale messages. - Sends the request.
- Waits for a response (respecting the configured timeout).
- Interprets and validates the response data.
- Returns the response object.
This abstraction allows the client to detect usage errors and malformed server responses automatically.
Work with DTC (Diagnostic Trouble Codes) and its sub-components
masterThe
udsoncan.Dtcclass and its associated components are used to manage Diagnostic Trouble Codes.Key sub-components include:
udsoncan.Dtc.Status: Represents the status of a DTC.udsoncan.Dtc.DtcClass: Represents the class of a DTC.udsoncan.Dtc.Severity: Represents the severity level of a DTC.udsoncan.Dtc.Format: Handles the formatting of DTCs.udsoncan.Dtc.FunctionalGroupIdentifiers: Manages functional group identifiers related to DTCs.
Understand the four layers of UDS interaction
masterThe
python-udsoncanlibrary allows you to interact with UDS (Unified Diagnostic Services) at different levels of abstraction, ranging from raw byte manipulation to high-level client methods:- Raw Connection: Manually sending and receiving binary payloads via a connection object.
- Request and Responses: Using
RequestandResponseobjects to wrap payloads, providing basic service and code identification. - Services: Using service-specific objects (e.g.,
services.RoutineControl) to generate requests and interpret responses, including automatic parsing of service-specific data (likecontrol_type_echo). - Client: Using the high-level
Clientclass, which provides named methods (e.g.,client.start_routine()) and handles validation of echoed data automatically.
# Level 4: High-level Client usage try: response = client.start_routine(routine_id=0x1234) print('Success!') except Exception: print('Start of routine 0x1234 failed')How Connections work in python-udsoncan
masterSince UDS is an application layer protocol, it requires a data transport protocol (like ISO-TP over CAN) to function.
python-udsoncandoes not implement the underlying communication protocols itself, but instead provides a standardConnectioninterface to interact with them.Users interact with the underlying protocol through a
Connectionobject. This abstraction allows theClientobject to remain agnostic of whether you are using a CAN bus, a socket, or a custom transport layer.How UDS services work: Crafting and Parsing requests/responses
masterEach UDS service is represented by a class extending
BaseService. Services follow a two-step pattern for communication:- Crafting a request: Use the service's
make_requestmethod. This returns aRequestinstance containing the payload. You then send this payload via yourConnectionobject. - Parsing a response: After receiving a payload from the connection, wrap it in a
Responseobject usingResponse.from_payload(payload). Then, call the service'sinterpret_responsemethod. This parses the rawresponse.dataand populates theresponse.service_dataproperty with an instance of the service's nestedResponseDataclass.
This pattern ensures that raw byte payloads are converted into structured, typed Python objects.
# Crafting a request req = SomeService.make_request(param1, param2) my_connection.send(req.get_payload()) # Parsing a response payload = my_connection.wait_frame(timeout=1) response = Response.from_payload(payload) print('Raw data : %s' % response.data) SomeService.interpret_response(response, param1, param2) print('Interpreted data : field1 : %s, field2 : %s' % (response.service_data.field1, response.service_data.field2))- Crafting a request: Use the service's
How UDS services and subfunctions work
masterFunctionality in UDS is organized into services. A service is a type of request that includes specific parameters.
Common examples of services include:
- Reading Diagnostic Trouble Codes (DTCs)
- Writing Data By Identifier (setting vehicle-specific configuration)
- Input/Output Control By Identifier (overriding IOs)
- ECU Reset
Subfunctions: Many services include subfunctions, which are identified by the first byte of the service payload. For example, the
ECUResetservice uses a subfunction to specify the type of reset requested, such as a 'hard reset' (power cycle) or a 'soft reset' (firmware restart).Implement a custom security algorithm for SecurityAccess
masterTo use the
SecurityAccessservice, you must provide asecurity_algocallable in the client configuration. This function implements the specific security logic required by your ECU.Signature Requirements: Starting from v1.12, parameters are passed by name. The function must accept:
level(int): The requested security level.seed(bytes): The seed provided by the server.params(any): The value provided via thesecurity_algo_paramsconfiguration key.
Returns:
bytes: The calculated security key.
Example configuration:
config = { 'security_algo': my_algorithm_function, 'security_algo_params': {'key': 'some_value'} }