@@ -145,10 +145,10 @@ class DoIPClient:
145145 :param use_secure: Enables TLS. If set to True, a default SSL context is used. For more control, a preconfigured
146146 SSL context can be passed directly. Untested. Should be combined with changing tcp_port to 3496.
147147 :type use_secure: Union[bool,ssl.SSLContext]
148- :param log_level: Logging level
149- :type log_level: int
150148 :param auto_reconnect_tcp: Attempt to automatically reconnect TCP sockets that were closed by peer
151149 :type auto_reconnect_tcp: bool
150+ :param vm_specific: Optional 4 byte long int
151+ :type vm_specific: int, optional
152152
153153 :raises ConnectionRefusedError: If the activation request fails
154154 :raises ValueError: If the IPAddress is neither an IPv4 nor an IPv6 address
@@ -166,6 +166,7 @@ def __init__(
166166 client_ip_address = None ,
167167 use_secure = False ,
168168 auto_reconnect_tcp = False ,
169+ vm_specific = None
169170 ):
170171 self ._ecu_logical_address = ecu_logical_address
171172 self ._client_logical_address = client_logical_address
@@ -180,6 +181,7 @@ def __init__(
180181 self ._protocol_version = protocol_version
181182 self ._auto_reconnect_tcp = auto_reconnect_tcp
182183 self ._tcp_close_detected = False
184+ self .vm_specific = vm_specific
183185
184186 # Check the ECU IP type to determine socket family
185187 # Will raise ValueError if neither a valid IPv4, nor IPv6 address
@@ -587,16 +589,19 @@ def request_activation(
587589 :type disable_retry: bool, optional
588590 :return: The resulting activation response object
589591 :rtype: RoutingActivationResponse
592+ :raises ValueError: vm_specific is invalid or out of range
590593 """
591594 message = RoutingActivationRequest (
592- self ._client_logical_address , activation_type , vm_specific = vm_specific
595+ self ._client_logical_address ,
596+ activation_type ,
597+ vm_specific = self ._validate_vm_specific_value (vm_specific ) if vm_specific else self .vm_specific ,
593598 )
594599 self .send_doip_message (message , disable_retry = disable_retry )
595600 while True :
596601 result = self .read_doip ()
597- if type (result ) == RoutingActivationResponse :
602+ if isinstance (result , RoutingActivationResponse ) :
598603 return result
599- elif result :
604+ if result :
600605 logger .warning (
601606 "Received unexpected DoIP message type {}. Ignoring" .format (
602607 type (result )
@@ -824,3 +829,39 @@ def reconnect(self, close_delay=A_PROCESSING_TIME):
824829 raise ConnectionRefusedError (
825830 f"Activation Request failed with code { result .response_code } "
826831 )
832+
833+ @staticmethod
834+ def _validate_vm_specific_value (value ):
835+ """Validate the VM specific value (must be > 0 and <= 0xffffffff) or None.
836+ If the conditions are not fulfilled, raises an exception.
837+
838+ :param value: The value to check.
839+ :type value: int, optional
840+ :return: The input value if valid.
841+ :rtype: int or None
842+ :raises ValueError: If the value is invalid or out of range.
843+ """
844+ if not isinstance (value , int ) and value is not None :
845+ raise ValueError ("Invalid vm_specific type must be int or None" )
846+ if isinstance (value , int ) and (value < 0 or value > 0xffffffff ):
847+ raise ValueError ("Invalid vm_specific value must be > 0 and <= 0xffffffff" )
848+ return value
849+
850+ @property
851+ def vm_specific (self ):
852+ """Get the optional OEM specific field value if set.
853+
854+ :return: vm_specific value
855+ :rtype: int, optional
856+ """
857+ return self ._vm_specific
858+
859+ @vm_specific .setter
860+ def vm_specific (self , value ):
861+ """Set the optional OEM specific field value. If you do not need to send this item, set it to None.
862+
863+ :param value: The vm_specific value (must be > 0 and <= 0xffffffff) or None
864+ :type value: int, optional
865+ :raises ValueError: Value is invalid or out of range
866+ """
867+ self ._vm_specific = self ._validate_vm_specific_value (value )
0 commit comments