### Install python-doipclient Source: https://github.com/jacobschaer/python-doipclient/blob/main/README.rst Install the library using pip. ```bash pip install doipclient ``` -------------------------------- ### DoIPClient Initialization Examples Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Demonstrates basic and custom initialization of the DoIPClient. The first example uses default activation, while the second specifies a custom TCP port and disables auto-activation. The third example shows usage with a context manager for automatic cleanup. ```python from doipclient import DoIPClient # Basic initialization with default activation client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0 ) ``` ```python # With custom TCP port and no auto-activation client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, tcp_port=3496, activation_type=None ) ``` ```python # Using context manager for automatic cleanup with DoIPClient("192.168.1.100", 0x00E0) as client: response = client.request_vehicle_identification() client.send_diagnostic(bytearray([0x22, 0xF1, 0x90])) ``` -------------------------------- ### Integration Example with udsoncan Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md A full example demonstrating the integration of DoIPClient with UDS communication using the udsoncan library. ```APIDOC ## Integration Example Full example showing DoIPClient with UDS communication via udsoncan: ```python import udsoncan from doipclient import DoIPClient from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import DiagnosticSessionControl, ECUReset from udsoncan.exceptions import NegativeResponseException # Setup logging udsoncan.setup_logging() # Create DoIP transport doip_client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0 ) # Create UDS connector conn = DoIPClientUDSConnector( doip_client, name="Engine_ECU", close_connection=False # We'll manage DoIP client lifetime ) try: # Use UDS client over DoIP with Client(conn, request_timeout=2) as uds_client: # Change to extended diagnostic session uds_client.change_session( DiagnosticSessionControl.Session.extendedDiagnosticSession ) print("Switched to extended session") # Perform diagnostics # ... UDS operations ... # ECU reset uds_client.ecu_reset(ECUReset.ResetType.hardReset) finally: # Cleanup doip_client.close() ``` ``` -------------------------------- ### Run tests from source Source: https://github.com/jacobschaer/python-doipclient/blob/main/README.rst Install test dependencies and execute the test suite. ```bash pip install pytest pytest-mock pytest ``` -------------------------------- ### Install python-uds fork Source: https://github.com/jacobschaer/python-doipclient/blob/main/README.rst Install the required fork of python-uds to enable DoIP support. ```bash git clone https://github.com/jacobschaer/python-uds git checkout doip cd python-uds pip install . ``` -------------------------------- ### Full Integration Example: DoIPClient with UDS Communication via udsoncan Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md A complete example showcasing DoIPClient with UDS communication using the udsoncan library. This snippet is useful for setting up a DoIP client, establishing a UDS connection, and performing diagnostic operations like changing sessions and resetting the ECU. ```python import udsoncan from doipclient import DoIPClient from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import DiagnosticSessionControl, ECUReset from udsoncan.exceptions import NegativeResponseException # Setup logging udsoncan.setup_logging() # Create DoIP transport doip_client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0 ) # Create UDS connector conn = DoIPClientUDSConnector( doip_client, name="Engine_ECU", close_connection=False # We'll manage DoIP client lifetime ) try: # Use UDS client over DoIP with Client(conn, request_timeout=2) as uds_client: # Change to extended diagnostic session uds_client.change_session( DiagnosticSessionControl.Session.extendedDiagnosticSession ) print("Switched to extended session") # Perform diagnostics # ... UDS operations ... # ECU reset uds_client.ecu_reset(ECUReset.ResetType.hardReset) finally: # Cleanup doip_client.close() ``` -------------------------------- ### RoutingActivationRequest Example Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/types.md Demonstrates initializing a DoIPClient with a specific activation type. Ensure the RoutingActivationRequest message type is imported. ```python from doipclient.messages import RoutingActivationRequest client = DoIPClient( "192.168.1.100", 0x00E0, activation_type=RoutingActivationRequest.ActivationType.Default ) ``` -------------------------------- ### Communicate with ECU using udsoncan Source: https://github.com/jacobschaer/python-doipclient/blob/main/README.rst Example demonstrating how to use DoIPClient as a transport layer for the udsoncan library. ```python import SomeLib.SomeCar.SomeModel as MyCar import udsoncan from doipclient import DoIPClient from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.exceptions import * from udsoncan.services import * udsoncan.setup_logging() ecu_ip = '127.0.0.1' ecu_logical_address = 0x00E0 doip_client = DoIPClient(ecu_ip, ecu_logical_address) conn = DoIPClientUDSConnector(doip_client) with Client(conn, request_timeout=2, config=MyCar.config) as client: try: client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession) # integer with value of 3 client.unlock_security_access(MyCar.debug_level) # Fictive security level. Integer coming from fictive lib, let's say its value is 5 client.write_data_by_identifier(udsoncan.DataIdentifier.VIN, 'ABC123456789') # Standard ID for VIN is 0xF190. Codec is set in the client configuration print('Vehicle Identification Number successfully changed.') client.ecu_reset(ECUReset.ResetType.hardReset) # HardReset = 0x01 except NegativeResponseException as e: print('Server refused our request for service %s with code "%s" (0x%02x)' % (e.response.service.get_name(), e.response.code_name, e.response.code)) except (InvalidResponseException, UnexpectedResponseException) as e: print('Server sent an invalid payload : %s' % e.response.original_payload) # Because we reset our UDS server, we must also reconnect/reactivate the DoIP socket # Alternatively, we could have used the auto_reconnect_tcp flag on the DoIPClient # Note: ECU's do not restart instantly, so you may need a sleep() before moving on doip_client.reconnect() client.tester_present() # Cleanup the DoIP Socket when we're done. Alternatively, we could have used the # close_connection flag on conn so that the udsoncan client would clean it up doip_client.close() ``` -------------------------------- ### Create and Send RoutingActivationRequest Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of creating a RoutingActivationRequest and sending it using the DoIP client. Ensure the client is initialized. ```python msg = RoutingActivationRequest( source_address=0x0E00, activation_type=RoutingActivationRequest.ActivationType.Default ) client.send_doip_message(msg) ``` -------------------------------- ### Communicate with ECU using python-uds Source: https://github.com/jacobschaer/python-doipclient/blob/main/README.rst Example showing how to use the python-uds library with DoIP transport. ```python from uds import Uds ecu = Uds(transportProtocol="DoIP", ecu_ip="192.168.1.1", ecu_logical_address=1) try: response = ecu.send([0x3E, 0x00]) print(response) # This should be [0x7E, 0x00] except: print("Send did not complete") ``` -------------------------------- ### Creating and Inspecting GenericDoIPNegativeAcknowledge Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of how to instantiate a GenericDoIPNegativeAcknowledge with a specific NACK code and access its properties. This is typically received, not created directly. ```python # This would typically be received via read_doip(), not created directly nack = GenericDoIPNegativeAcknowledge(GenericDoIPNegativeAcknowledge.NackCodes.UnknownPayloadType) print(f"NACK Code: {nack.nack_code}") ``` -------------------------------- ### Handle RoutingActivationResponse Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of requesting activation and checking the response code. Prints the ECU logical address on success or an error message on failure. ```python response = client.request_activation(RoutingActivationRequest.ActivationType.Default) if response.response_code == RoutingActivationResponse.ResponseCode.Success: print(f"ECU logical address: 0x{response.logical_address:04X}") else: print(f"Activation failed: {response.response_code}") ``` -------------------------------- ### Send AliveCheckRequest Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of creating and sending an AliveCheckRequest message using the DoIP client. ```python msg = AliveCheckRequest() client.send_doip_message(msg) ``` -------------------------------- ### Diagnostic Power Mode Check Example Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/types.md Checks if the ECU is ready for diagnostics. Prints a message indicating readiness based on the diagnostic power mode response. ```python response = client.request_diagnostic_power_mode() if response.diagnostic_power_mode == DiagnosticPowerModeResponse.DiagnosticPowerMode.Ready: print("Ready for diagnostics") ``` -------------------------------- ### Discover Vehicle with IPv6 Announcement Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This example demonstrates how to discover a vehicle using IPv6 announcements. It listens on a specified source interface for a limited time and prints the found ECU's address or a timeout message. ```python from doipclient import DoIPClient # Wait for IPv6 announcement on eth0 try: (ip, port), response = DoIPClient.await_vehicle_announcement( ipv6=True, source_interface="eth0", timeout=5.0 ) print(f"Found ECU at [{ip}]:{port}") except TimeoutError: print("No IPv6 announcement received") ``` -------------------------------- ### Handle DiagnosticPowerModeResponse Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of receiving and checking the diagnostic power mode status from a response. ```python response = client.request_diagnostic_power_mode() if response.diagnostic_power_mode == DiagnosticPowerModeResponse.DiagnosticPowerMode.Ready: print("ECU is ready for diagnostics") ``` -------------------------------- ### Configure TLS-Secured DoIP Communication Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This example demonstrates setting up a DoIP client for secure communication using TLS. It requires a specific TCP port and a custom SSL context for verification, including hostname checking and certificate validation. ```python import ssl from doipclient import DoIPClient # Create custom SSL context for verification ssl_context = ssl.create_default_context() ssl_context.check_hostname = True ssl_context.verify_mode = ssl.CERT_REQUIRED client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, tcp_port=3496, # TLS port use_secure=ssl_context # Pass custom SSL context ) ``` -------------------------------- ### Set and Get vm_specific Property Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md Use the vm_specific property to get or set OEM-specific fields. The setter includes validation for the input type and value range. It accepts an integer between 1 and 0xFFFFFFFF or None. ```python @property def vm_specific(self) -> Optional[int]: # Returns current value @vm_specific.setter def vm_specific(self, value: Optional[int]) -> None: # Sets new value with validation ``` ```python client.vm_specific = 0x12345678 # Set OEM value print(client.vm_specific) # Get value client.vm_specific = None # Clear value ``` -------------------------------- ### Routing Activation Response Check Example Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/types.md Checks the response code from a routing activation request. Prints success or failure based on the received response code. ```python response = client.request_activation(RoutingActivationRequest.ActivationType.Default) if response.response_code == RoutingActivationResponse.ResponseCode.Success: print("Activation successful") else: print(f"Activation failed: {response.response_code}") ``` -------------------------------- ### Send and Receive DiagnosticMessage Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of creating and sending a DiagnosticMessage with UDS data (Read VIN) and receiving a response. ```python msg = DiagnosticMessage( source_address=0x0E00, target_address=0x00E0, user_data=bytearray([0x22, 0xF1, 0x90]) # Read VIN ) client.send_doip_message(msg) response = client.receive_diagnostic() ``` -------------------------------- ### Request and Print AliveCheckResponse Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of requesting an alive check from the client and printing the source address of the active client from the response. ```python response = client.request_alive_check() print(f"Active client: 0x{response.source_address:04X}") ``` -------------------------------- ### Enable DoIP Debug Logging Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md Enable debug logging for the doipclient library to view detailed error information. This setup should be performed before initiating DoIP operations. ```python import logging # Enable DoIP debug logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger("doipclient") logger.setLevel(logging.DEBUG) # Now all DoIP operations are logged including errors ``` -------------------------------- ### Send DiagnosticPowerModeRequest Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of sending a DiagnosticPowerModeRequest using the DoIP client over UDP transport. ```python msg = DiagnosticPowerModeRequest() client.send_doip_message(msg, transport=DoIPClient.TransportType.TRANSPORT_UDP) ``` -------------------------------- ### Send DoipEntityStatusRequest via UDP Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of creating and sending a DoipEntityStatusRequest message using the DoIP client, specifying UDP as the transport protocol. ```python msg = DoipEntityStatusRequest() client.send_doip_message(msg, transport=DoIPClient.TransportType.TRANSPORT_UDP) ``` -------------------------------- ### Vehicle Identification Further Action Example Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/types.md Checks if routing activation is required based on the vehicle identification response. Prints a message if activation is needed. ```python ip, response = DoIPClient.get_entity() if response.further_action_required == VehicleIdentificationResponse.FurtherActionCodes.RoutingActivationRequired: print("Activation required") ``` -------------------------------- ### vm_specific Property Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Allows getting or setting an OEM-specific 4-byte integer value. The value must be within the range of 1 to 0xFFFFFFFF, or it can be set to None. ```APIDOC ## vm_specific ### Description Get or set the OEM-specific field value. This property accepts an optional 4-byte integer (1 <= value <= 0xFFFFFFFF) or None. ### Getter ```python @property def vm_specific(self) -> Optional[int] ``` ### Setter ```python @vm_specific.setter def vm_specific(self, value: Optional[int]) -> None ``` ### Returns - **value** (int) - An optional 4-byte integer value or None. ### Exceptions - **ValueError**: Raised when the provided value is out of the allowed range. ``` -------------------------------- ### Discover ECUs using Broadcast Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This snippet shows how to query all ECUs on the network using a broadcast address. It attempts to get entity information and prints the found ECU's IP and VIN, or a message if no ECU is found within the timeout. ```python from doipclient import DoIPClient # Query all ECUs on network try: (ip, port), response = DoIPClient.get_entity( ecu_ip_address="255.255.255.255", # Broadcast protocol_version=0x02 ) print(f"Found ECU at {ip}") print(f"VIN: {response.vin}") except TimeoutError: print("No ECU found on network") ``` -------------------------------- ### Check DoIP Vehicle Identification Response for Activation Requirement Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This example shows how to make a request for vehicle identification and check the response to determine if a routing activation is required. This is part of the activation type selection process for certain ECUs. ```python response = client.request_vehicle_identification() if response.further_action_required == VehicleIdentificationResponse.FurtherActionCodes.RoutingActivationRequired: # Must do activation pass ``` -------------------------------- ### Process Vehicle Identification Response Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of how to receive and process a vehicle identification response, typically obtained from get_entity() or await_vehicle_announcement(). It prints the VIN, logical address, and EID of the responding entity. ```python # Typically received from get_entity() or await_vehicle_announcement() ip, response = DoIPClient.get_entity() print(f"VIN: {response.vin}") print(f"Logical Address: 0x{response.logical_address:04X}") print(f"EID: {response.eid.hex()}") ``` -------------------------------- ### Request and Print Entity Status Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of requesting entity status from the client and printing details such as maximum concurrent sockets, currently open sockets, and maximum data size. ```python status = client.request_entity_status() print(f"Max sockets: {status.max_concurrent_sockets}") print(f"Open sockets: {status.currently_open_sockets}") print(f"Max data: {status.max_data_size} bytes") ``` -------------------------------- ### Handling TimeoutError during ECU Communication Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md This example demonstrates how to catch TimeoutError, which can occur if an ECU fails to respond within the expected time frame during various DoIP operations. ```python from doipclient import DoIPClient try: response = client.request_diagnostic_power_mode() except TimeoutError as e: print(f"ECU timeout: {e}") # Could be network issue or ECU unresponsive ``` -------------------------------- ### Initialize DoIP Client with Error Handling Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md Handles potential errors during client initialization, such as bad parameters, connection refusal, or timeouts. Use this pattern when establishing the initial connection to the ECU. ```python from doipclient import DoIPClient from doipclient.messages import RoutingActivationRequest try: client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, activation_type=RoutingActivationRequest.ActivationType.Default, tcp_port=13400 ) except ValueError as e: print(f"Bad parameters: {e}") exit(1) except ConnectionRefusedError as e: print(f"ECU rejected activation: {e}") # May need different activation type or ECU reset exit(1) except TimeoutError as e: print(f"Cannot reach ECU: {e}") exit(1) ``` -------------------------------- ### open Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Opens the connector, enabling communication. This method should be called after initializing the connector. ```APIDOC ## open ### Description Opens the connector, enabling communication. ### Method open ### Endpoint N/A (Instance Method) ### Parameters None ### Request Example ```python conn.open() ``` ### Response #### Success Response None ### Response Example None ``` -------------------------------- ### Handle DiagnosticMessageNegativeAcknowledgement Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Example of receiving a negative acknowledgement for a diagnostic message and printing the NACK code. Typically occurs when a diagnostic send fails. ```python # Typically received when diagnostic send fails try: response = client.read_doip() if isinstance(response, DiagnosticMessageNegativeAcknowledgement): print(f"NACK: {response.nack_code}") except IOError as e: print(f"Diagnostic rejected: {e}") ``` -------------------------------- ### Using DoIPClientUDSConnector with udsoncan Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Demonstrates how to create a DoIPClient and a DoIPClientUDSConnector, then use it with the udsoncan UDS client to perform a UDS service request, such as reading VIN. Ensure the DoIP client is closed after use. ```python from doipclient import DoIPClient from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import ReadDataByIdentifier # Create DoIP client and connector doip_client = DoIPClient("192.168.1.100", 0x00E0) conn = DoIPClientUDSConnector(doip_client, name="MyECU") # Use with udsoncan UDS client with Client(conn, request_timeout=2) as uds_client: # Read VIN via UDS service response = uds_client.send_request( ReadDataByIdentifier(0xF190) # VIN ) print(response) # Cleanup doip_client.close() ``` -------------------------------- ### Handling Connection Errors with DoIPClient Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Demonstrates how to handle potential connection errors when initializing a DoIPClient. Catches common exceptions like ConnectionRefusedError, TimeoutError, and ValueError. ```python try: client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, activation_type=RoutingActivationRequest.ActivationType.Default ) except (ConnectionRefusedError, TimeoutError, ValueError) as e: print(f"Connection failed: {e}") exit(1) ``` -------------------------------- ### DoIPClient Constructor Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Initializes the DoIPClient for communication with a target ECU. It allows configuration of various DoIP parameters, including IP addresses, ports, activation types, and security settings. ```APIDOC ## DoIPClient Constructor ### Description Initializes the DoIPClient for communication with a target ECU. It allows configuration of various DoIP parameters, including IP addresses, ports, activation types, and security settings. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Parameters - **ecu_ip_address** (str) - Required - IP address of the target ECU (IPv4 or IPv6 format, e.g., "192.168.1.1" or "2001:db8::") - **ecu_logical_address** (int) - Required - Logical address of target ECU; should be 0x0001 to 0x0DFF per ISO-13400 - **tcp_port** (int) - Optional - Default: 13400 - Destination TCP port for DoIP data communication (13400 for unsecured, 3496 for TLS) - **udp_port** (int) - Optional - Default: 13400 - UDP port for discovery communications - **activation_type** (RoutingActivationRequest.ActivationType) - Optional - Default: Default - Activation type for initial connection (Default=0x00, DiagnosticRequiredByRegulation=0x01, CentralSecurity=0xE1); set to None to disable - **protocol_version** (int) - Optional - Default: 0x02 - DoIP protocol version per ISO-13400 (0x02 for 2012, 0x03 for 2019) - **client_logical_address** (int) - Optional - Default: 0x0E00 - Logical address for this client (per spec should be 0x0E00 to 0x0FFF) - **client_ip_address** (str) - Optional - Default: None - Optional source IP for socket binding; useful for multi-adapter systems - **use_secure** (Union[bool, SSLContext]) - Optional - Default: False - Enable TLS; pass True for default context or provide custom ssl.SSLContext - **auto_reconnect_tcp** (bool) - Optional - Default: False - Automatically reconnect TCP sockets closed by peer - **vm_specific** (int) - Optional - Default: None - Optional 4-byte OEM-specific value (0 < value <= 0xFFFFFFFF) ### Raises - **ConnectionRefusedError** - Activation request fails during initialization - **ValueError** - ecu_ip_address is neither valid IPv4 nor IPv6 - **ValueError** - vm_specific is out of range ### Example ```python from doipclient import DoIPClient # Basic initialization with default activation client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0 ) # With custom TCP port and no auto-activation client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, tcp_port=3496, activation_type=None ) # Using context manager for automatic cleanup with DoIPClient("192.168.1.100", 0x00E0) as client: response = client.request_vehicle_identification() client.send_diagnostic(bytearray([0x22, 0xF1, 0x90])) ``` ``` -------------------------------- ### Check and Set System Socket Limits Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This snippet demonstrates how to check the current system limits for open files and optionally increase them. This is important when running multiple concurrent DoIP clients, as each client uses two sockets. ```python import socket import resource # Check system limits (on Unix) soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) print(f"Open files limit: {soft}/{hard}") # For multiple concurrent clients, may need to increase resource.setrlimit(resource.RLIMIT_NOFILE, (4096, hard)) ``` -------------------------------- ### Context Manager Protocol for DoIPClientUDSConnector Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Demonstrates the use of the context manager protocol for the DoIPClientUDSConnector, ensuring automatic cleanup. Use this when you need to manage the connector's lifecycle within a specific block of code. ```python def __enter__(self) -> DoIPClientUDSConnector: pass def __exit__(self, type, value, traceback) -> None: pass ``` ```python with DoIPClientUDSConnector(doip_client) as conn: # Use connector conn.specific_send(payload) response = conn.specific_wait_frame() # Connector automatically closed ``` -------------------------------- ### Configure DoIP Client for Multi-Adapter Systems Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md Use this configuration when your system has multiple network adapters. It allows you to specify the source IP address, ensuring the DoIP client binds to the correct network interface. ```python from doipclient import DoIPClient # Bind to specific source adapter client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, client_ip_address="192.168.1.50" # Specify source IP ) ``` -------------------------------- ### Open DoIP Connector Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Use the `open` method to establish communication through the connector. This method enables the underlying DoIP communication. ```python conn = DoIPClientUDSConnector(doip_client) conn.open() ``` -------------------------------- ### Get Entity Information Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Send a vehicle identification request without instantiating the DoIPClient. Useful for discovering ECUs on the network by IP address, VIN, or Entity ID. ```python from typing import Optional import socket from doipclient import DoIPClient from doipclient.responses import VehicleIdentificationResponse # Discover any ECU via broadcast ip, response = DoIPClient.get_entity() print(f"Found ECU at {ip[0]}: {response.vin}") # Discover specific VIN ip, response = DoIPClient.get_entity(vin="ABC123456789XYZ12") ``` -------------------------------- ### Project File Structure Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md This snippet outlines the directory structure of the Python DoIP client project, indicating the location of key modules and documentation files. ```text /workspace/home/output/ ├── README.md # This file ├── api-reference/ │ ├── doipclient.md # Main client class │ ├── messages.md # Protocol messages │ └── connectors.md # UDS integration ├── types.md # Enumerations and type definitions ├── errors.md # Exception reference └── configuration.md # Configuration parameters ``` -------------------------------- ### Catching ConnectionRefusedError during Client Initialization Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md Use this snippet to handle cases where the DoIP client activation request fails during initialization. It catches ConnectionRefusedError and prints a custom message. ```python from doipclient import DoIPClient try: client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, activation_type=RoutingActivationRequest.ActivationType.Default ) except ConnectionRefusedError as e: print(f"Activation failed: {e}") # e.args[0] contains the failure message with response code ``` -------------------------------- ### Configure OEM-Specific DoIP Parameters Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This snippet shows how to configure OEM-specific values for DoIP communication. You can set an initial OEM-specific value and also change it dynamically during runtime. ```python from doipclient import DoIPClient # Configure with OEM-specific value client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, vm_specific=0x87654321 # OEM-specific value ) # Change OEM value dynamically client.vm_specific = 0x12345678 ``` -------------------------------- ### Importing Core DoIP Client and Message Classes Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Import the main DoIPClient class for establishing connections and various message classes for DoIP communication. This is the primary import for using the library's core functionalities. ```python # Main client (primary import) from doipclient import DoIPClient # Message classes from doipclient.messages import ( RoutingActivationRequest, RoutingActivationResponse, VehicleIdentificationResponse, DiagnosticMessage, # ... other message types ) ``` -------------------------------- ### Basic Diagnostic Communication with DoIPClient Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Connect to an ECU, send a diagnostic request, and receive the response. Ensure to close the client connection after use. ```python from doipclient import DoIPClient # Connect to ECU client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0 ) # Send diagnostic request client.send_diagnostic(bytearray([0x22, 0xF1, 0x90])) # Receive response response = client.receive_diagnostic(timeout=2.0) print(f"Response: {response.hex()}") # Cleanup client.close() ``` -------------------------------- ### Vehicle Discovery with Timeout and Fallback Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md Demonstrates finding an ECU by first awaiting announcements and then falling back to a direct query if no announcement is received within the specified timeout. This pattern is used for discovering available ECUs on the network. ```python try: # Try to find ECU via announcement (ip, port), response = DoIPClient.await_vehicle_announcement( timeout=5.0 ) print(f"Found ECU at {ip}:{port} with VIN {response.vin}") except TimeoutError: # No announcement, try get_entity print("No announcement, trying query...") try: (ip, port), response = DoIPClient.get_entity() print(f"Found ECU at {ip}:{port}") except TimeoutError: print("Cannot find any ECU") ``` -------------------------------- ### Integrating DoIPClient with udsoncan for UDS Communication Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Set up DoIP transport and use the DoIPClientUDSConnector to enable UDS communication with an ECU via the udsoncan library. ```python from doipclient import DoIPClient from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import ReadDataByIdentifier # Setup DoIP transport doip_client = DoIPClient("192.168.1.100", 0x00E0) conn = DoIPClientUDSConnector(doip_client) # Use UDS over DoIP with Client(conn, request_timeout=2) as uds_client: response = uds_client.send_request(ReadDataByIdentifier(0xF190)) print(f"VIN: {response.data}") ``` -------------------------------- ### Vehicle Discovery using DoIPClient Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Discover ECUs on the network. This snippet shows two methods: awaiting an announcement or actively querying the network for entities. ```python from doipclient import DoIPClient # Method 1: Wait for announcement on startup try: (ip, port), response = DoIPClient.await_vehicle_announcement(timeout=5.0) print(f"ECU at {ip}:{port}, VIN: {response.vin}") except TimeoutError: print("No announcement received") # Method 2: Query network (ip, port), response = DoIPClient.get_entity( ecu_ip_address="255.255.255.255" ) print(f"Found ECU at {ip}, logical address: 0x{response.logical_address:04X}") ``` -------------------------------- ### Context Manager Support Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md The connector supports the Python context manager protocol, ensuring automatic cleanup of resources when exiting a `with` block. ```APIDOC ## Context Manager Support The connector supports Python context manager protocol for automatic cleanup. ```python def __enter__(self) -> DoIPClientUDSConnector def __exit__(self, type, value, traceback) -> None ``` **Example**: ```python with DoIPClientUDSConnector(doip_client) as conn: # Use connector conn.specific_send(payload) response = conn.specific_wait_frame() # Connector automatically closed ``` ``` -------------------------------- ### request_activation Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Requests routing activation from the ECU for the current connection. Supports different activation types and optional OEM-specific values, with options to disable retries. Returns a RoutingActivationResponse object. ```APIDOC ## request_activation ### Description Request routing activation from the ECU for this connection. ### Method POST (Assumed, as it initiates an activation request) ### Endpoint `/doip/activate` (Assumed, for activation requests) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **activation_type** (RoutingActivationRequest.ActivationType) - Required - Activation type (Default=0x00, DiagnosticRequiredByRegulation=0x01, CentralSecurity=0xE1) - **vm_specific** (int) - Optional - Optional 4-byte OEM-specific value - **disable_retry** (bool) - Optional - Disable automatic TCP reconnection retry (Default: False) ### Request Example ```python from doipclient.messages import RoutingActivationRequest response = client.request_activation( RoutingActivationRequest.ActivationType.Default ) if response.response_code == RoutingActivationResponse.ResponseCode.Success: print("Activation successful") else: print(f"Activation failed: {response.response_code}") ``` ### Response #### Success Response (200) - **response** (RoutingActivationResponse) - Response containing response code and ECU info #### Response Example ```json { "response": { "response_code": "Success", "ecu_info": "..." } } ``` ### Exceptions - **TimeoutError**: ECU fails to respond within timeout - **ValueError**: vm_specific is out of range ``` -------------------------------- ### Enable Encrypted Communication Source: https://github.com/jacobschaer/python-doipclient/blob/main/doc/source/index.md Configures the DoIPClient to use encryption by setting the use_secure parameter. ```python client = DoIPClient( ip, logical_address, use_secure=True, # Enable encryption tcp_port=3496, ) ``` -------------------------------- ### Empty RX/TX Queues Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Compatibility methods for the UDSonCAN library to clear the receive and transmit queues. ```python client.empty_rxqueue() ``` ```python client.empty_txqueue() ``` -------------------------------- ### Configure Long-lived DoIP Connection with Timeouts Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md Use this snippet for stable, long-lived diagnostic sessions. It configures the client with default activation, protocol version, and client address, enabling auto-reconnect for TCP. Timeouts can be extended for slow ECUs. ```python from doipclient import DoIPClient from doipclient.messages import RoutingActivationRequest # Configure for stable long-lived diagnostics client = DoIPClient( ecu_ip_address="192.168.1.100", ecu_logical_address=0x00E0, tcp_port=13400, activation_type=RoutingActivationRequest.ActivationType.Default, protocol_version=0x02, client_logical_address=0x0E00, auto_reconnect_tcp=True # Important for long sessions ) try: # Use longer timeouts for slow ECUs client.send_diagnostic(payload, timeout=5.0) response = client.receive_diagnostic(timeout=5.0) finally: client.close() ``` -------------------------------- ### Configure Custom SSL Context Source: https://github.com/jacobschaer/python-doipclient/blob/main/doc/source/index.md Provides a preconfigured SSL context to the client for advanced encryption settings, such as enforcing specific TLS versions. ```python import ssl # Enforce use of TLSv1.2 ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) client = DoIPClient( ip, logical_address, use_secure=ssl_context, tcp_port=3496, ) ``` -------------------------------- ### Connect and Request Entity Status Source: https://github.com/jacobschaer/python-doipclient/blob/main/doc/source/index.md Establishes a connection to a specific ECU using its IP and logical address to retrieve status information. ```python client = DoIPClient(ip, logical_address) print(client.request_entity_status()) ``` -------------------------------- ### Test DoIP Protocol Version Compatibility Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/configuration.md This code iterates through common DoIP protocol versions (0x02 and 0x03) to determine which one an ECU expects. It attempts to connect with each version and prints a success message for the working version. ```python # Test which version ECU expects for version in [0x02, 0x03]: try: client = DoIPClient( "192.168.1.100", 0x00E0, protocol_version=version ) print(f"Protocol version {version:02X} works") client.close() break except (TimeoutError, ConnectionRefusedError): continue ``` -------------------------------- ### Importing UDS Connector and Constants Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/README.md Import the DoIPClientUDSConnector for integrating with the UDS protocol and relevant constants for network communication and timeouts. These are used for advanced configurations and specific protocol implementations. ```python # UDS integration from doipclient.connectors import DoIPClientUDSConnector # Constants from doipclient.constants import ( A_PROCESSING_TIME, TCP_DATA_UNSECURED, UDP_DISCOVERY, # ... other constants ) ``` -------------------------------- ### is_open Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Checks if the connector is currently open and active. Returns a boolean value indicating the connection status. ```APIDOC ## is_open ### Description Checks if the connector is open. ### Method is_open ### Endpoint N/A (Instance Method) ### Parameters None ### Returns - **status** (bool) - True if the connector is open, False otherwise. ### Response Example ```python if conn.is_open(): print("Connector is active") ``` ``` -------------------------------- ### DoIPClient.await_vehicle_announcement Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Listens for and receives vehicle announcement messages from ECUs, typically sent during system startup. This static method can be called without instantiating the DoIPClient class. ```APIDOC ## DoIPClient.await_vehicle_announcement ### Description Receive vehicle announcement message from ECU (typically at startup). ### Method `@classmethod` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **udp_port** (int) - Optional - UDP port to listen on - **timeout** (float) - Optional - Maximum time to wait for announcement - **ipv6** (bool) - Optional - Use IPv6 socket instead of IPv4 - **source_interface** (str) - Optional - Interface name for IPv6 (e.g., "eth0") - **sock** (socket.socket) - Optional - Existing socket to use ### Returns - **result** (tuple) - ((ip: str, port: int), response: VehicleIdentificationResponse) ### Exception - **TimeoutError** - Vehicle announcement not received in time ### Request Example ```python # Wait for ECU to announce itself on startup try: (ip, port), response = DoIPClient.await_vehicle_announcement(timeout=5.0) print(f"ECU announced at {ip}:{port}") except TimeoutError: print("No announcement received") ``` ``` -------------------------------- ### RoutingActivationRequest Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Represents a request to activate routing services. It specifies the client's source address and the desired activation type. ```APIDOC ## RoutingActivationRequest ### Description Represents a request to activate routing services. It specifies the client's source address and the desired activation type. ### Class Definition ```python class RoutingActivationRequest(DoIPMessage): payload_type = 0x0005 class ActivationType(IntEnum): Default = 0x00 DiagnosticRequiredByRegulation = 0x01 CentralSecurity = 0xE1 def __init__(self, source_address: int, activation_type: int, reserved: int = 0, vm_specific: Optional[int] = None) ``` ### Parameters #### Constructor Parameters - **source_address** (int) - Yes - Client logical address (0x0E00-0x0FFF per spec) - **activation_type** (int) - Yes - Type of activation (0x00, 0x01, or 0xE1) - **reserved** (int) - No - Reserved field (should be 0x00000000) - **vm_specific** (int) - No - OEM-specific 4-byte value ### Properties - **source_address** (int) - Client DoIP entity address - **activation_type** (ActivationType) - Activation type enum - **reserved** (int) - Reserved value - **vm_specific** (int) - VM-specific field ### Example ```python msg = RoutingActivationRequest( source_address=0x0E00, activation_type=RoutingActivationRequest.ActivationType.Default ) client.send_doip_message(msg) ``` ``` -------------------------------- ### DoIPClientUDSConnector Constructor Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md Defines the constructor for the DoIPClientUDSConnector, which wraps a DoIPClient to provide DoIP as a transport for UDS protocol communication. It accepts the DoIPClient instance, an optional logger name suffix, and a flag to control connection closing. ```python class DoIPClientUDSConnector(BaseConnection): def __init__( self, doip_layer: DoIPClient, name: Optional[str] = None, close_connection: bool = False ) ``` -------------------------------- ### Request Routing Activation Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Requests routing activation from the ECU for the current connection. Use this to establish a diagnostic session. Various activation types are supported, and retries can be disabled. ```python from doipclient.messages import RoutingActivationRequest def request_activation( self, activation_type: RoutingActivationRequest.ActivationType, vm_specific: Optional[int] = None, disable_retry: bool = False ) -> RoutingActivationResponse: response = client.request_activation( RoutingActivationRequest.ActivationType.Default ) if response.response_code == RoutingActivationResponse.ResponseCode.Success: print("Activation successful") else: print(f"Activation failed: {response.response_code}") ``` -------------------------------- ### Reconnect DoIP Client Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Re-establishes the DoIP connection by closing and reconnecting sockets. Useful after an ECU reset, with an optional delay before closing. ```python # After ECU reset time.sleep(1) # Allow ECU to restart client.reconnect() ``` -------------------------------- ### Await Vehicle Announcement Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Receive a vehicle announcement message from an ECU, typically used during startup. This method listens on a specified UDP port and can be configured with a timeout and source interface for IPv6. ```python from typing import Optional import socket from doipclient import DoIPClient from doipclient.responses import VehicleIdentificationResponse # Wait for ECU to announce itself on startup try: (ip, port), response = DoIPClient.await_vehicle_announcement(timeout=5.0) print(f"ECU announced at {ip}:{port}") except TimeoutError: print("No announcement received") ``` -------------------------------- ### Check Connector Status Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/connectors.md The `is_open` method returns a boolean indicating whether the connector is currently active and communication is established. Use this to verify connection status before performing operations. ```python if conn.is_open(): print("Connector is active") ``` -------------------------------- ### RoutingActivationRequest Class Definition Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/messages.md Defines the structure for a routing activation request message. Includes an enum for activation types. ```python class RoutingActivationRequest(DoIPMessage): payload_type = 0x0005 class ActivationType(IntEnum): Default = 0x00 DiagnosticRequiredByRegulation = 0x01 CentralSecurity = 0xE1 def __init__( self, source_address: int, activation_type: int, reserved: int = 0, vm_specific: Optional[int] = None ) ``` -------------------------------- ### Perform UDS Diagnostic Communication Source: https://github.com/jacobschaer/python-doipclient/blob/main/doc/source/index.md Integrates with the udsoncan library to perform diagnostic services over the DoIP connection. ```python from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import * uds_connection = DoIPClientUDSConnector(client) with Client(uds_connection) as uds_client: client.ecu_reset(ECUReset.ResetType.hardReset) ``` -------------------------------- ### Parser Class Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/api-reference/doipclient.md Implements the state machine for parsing DoIP messages according to ISO-13400, maintaining buffer state across TCP reads. ```APIDOC ## Parser Class ### Description Manages the state machine for parsing DoIP messages as defined in ISO-13400, Table 16. It handles buffering of data received over TCP. ### Inner Class: ParserState Enum Enumerates the states of the DoIP message parsing state machine. - **READ_PROTOCOL_VERSION** (int) - **READ_INVERSE_PROTOCOL_VERSION** (int) - **READ_PAYLOAD_TYPE** (int) - **READ_PAYLOAD_SIZE** (int) - **READ_PAYLOAD** (int) ### Methods - **read_message(self, data_bytes: bytes) -> Optional[DoIPMessage]**: Reads message data from the provided bytes and returns a DoIPMessage if a complete message is parsed. - **reset(self) -> None**: Resets the parser to its initial state. - **push_bytes(self, data_bytes: bytes) -> None**: Pushes raw bytes into the parser's buffer for processing. ``` -------------------------------- ### Catching ValueError for Invalid IP Address Source: https://github.com/jacobschaer/python-doipclient/blob/main/_autodocs/errors.md Catch ValueError when initializing DoIPClient with an invalid ECU IP address. Ensure the IP address is a valid IPv4 or IPv6 format. ```python from doipclient import DoIPClient try: client = DoIPClient( ecu_ip_address="not-an-ip", ecu_logical_address=0x00E0 ) except ValueError as e: print(f"Invalid parameter: {e}") ```