def make_request(cls, memory_location, data): """ Generate a request for ReadMemoryByAddress :param memory_location: The address and the size of the memory block to write. :type memory_location: :ref:`MemoryLocation <HelperClass_MemoryLocation>` :param data: The data to write into memory. :type data: bytes :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request, MemoryLocation if not isinstance(memory_location, MemoryLocation): raise ValueError('Given memory location must be an instance of MemoryLocation') if not isinstance(data, bytes): raise ValueError('data must be a bytes object') request = Request(service=cls) request.data = b'' request.data += memory_location.alfid.get_byte() # AddressAndLengthFormatIdentifier request.data += memory_location.get_address_bytes() request.data += memory_location.get_memorysize_bytes() request.data += data return request
def make_request(cls, control_type, communication_type): """ Generate a request for CommunicationControl :param control_type: Service subfunction. Allowed values are from 0 to 0x7F :type control_type: int :param communication_type: The communication type requested. :type communication_type: :ref:`CommunicationType <CommunicationType>` :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request ServiceHelper.validate_int(control_type, min=0, max=0x7F, name='Control type') communication_type = cls.normalize_communication_type( communication_type) request = Request(service=cls, subfunction=control_type) request.data = communication_type.get_byte() return request
def make_request(cls, level, mode, key=None): u""" Generates a request for SecurityAccess :param level: Service subfunction. The security level to unlock. Value ranging from 0 to 7F For mode=``RequestSeed`` (0), level must be an even value. For mode=``SendKey`` (1), level must be an odd value. If the even/odd constraint is not respected, the level value will be corrected to properly set the LSB. :type level: int :param mode: Type of request to perform. ``SecurityAccess.Mode.RequestSeed`` or ``SecurityAccess.Mode.SendKey`` :type mode: SecurityAccess.Mode, int :param key: When mode=``SendKey``, this value must be provided. :type key: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request cls.validate_mode(mode) ServiceHelper.validate_int(level, min=0, max=0x7F, name=u'Security level') req = Request(service=cls, subfunction=cls.normalize_level(mode=mode, level=level)) if mode == cls.Mode.SendKey: if not isinstance(key, str): raise ValueError(u'key must be a valid bytes object') req.data = key return req
def make_request(cls, level, mode, data=bytes()): """ Generates a request for SecurityAccess :param level: Service subfunction. The security level to unlock. Value ranging from 0 to 7F For mode=``RequestSeed`` (0), level must be an even value. For mode=``SendKey`` (1), level must be an odd value. If the even/odd constraint is not respected, the level value will be corrected to properly set the LSB. :type level: int :param mode: Type of request to perform. ``SecurityAccess.Mode.RequestSeed`` or ``SecurityAccess.Mode.SendKey`` :type mode: SecurityAccess.Mode, int :param data: securityAccessDataRecord (optional) for the get seed, securityKey (required) for the send key :type data: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request cls.validate_mode(mode) ServiceHelper.validate_int(level, min=0, max=0x7F, name='Security level') req = Request(service=cls, subfunction=cls.normalize_level(mode=mode, level=level)) if not isinstance(data, bytes): raise ValueError('key must be a valid bytes object') req.data = data return req
def make_request(cls, did, value, didconfig): """ Generates a request for WriteDataByIdentifier :param did: The data identifier to write :type did: int :param value: Value given to the :ref:`DidCodec <DidCodec>`.encode method. If involved codec is defined with a pack string (default codec), multiple values may be passed with a tuple. :type value: object :param didconfig: Definition of DID codecs. Dictionary mapping a DID (int) to a valid :ref:`DidCodec <DidCodec>` class or pack/unpack string :type didconfig: dict[int] = :ref:`DidCodec <DidCodec>` :raises ValueError: If parameters are out of range, missing or wrong type :raises ConfigError: If ``didlist`` contains a DID not defined in ``didconfig`` """ from udsoncan import Request, DidCodec ServiceHelper.validate_int(did, min=0, max=0xFFFF, name='Data Identifier') req = Request(cls) didconfig = ServiceHelper.check_did_config( did, didconfig=didconfig ) # Make sure all DIDs are correctly defined in client config req.data = struct.pack('>H', did) # encode DID number codec = DidCodec.from_config(didconfig[did]) if codec.__class__ == DidCodec and isinstance(value, tuple): req.data += codec.encode(*value) # Fixes issue #29 else: req.data += codec.encode(value) return req
def make_request(cls, memory_location, dfi=None): """ Generate a request for RequestDownload :param memory_location: The address and the size of the memory block to be written. :type memory_location: :ref:`MemoryLocation <HelperClass_MemoryLocation>` :param dfi: Optional dataFormatIdentifier defining the compression and encryption scheme of the data. If not specified, the default value of 00 will be used, specifying no encryption and no compression :type dfi: :ref:`DataFormatIdentifier <HelperClass_DataFormatIdentifier>` :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request, MemoryLocation dfi = cls.normalize_data_format_identifier(dfi) if not isinstance(memory_location, MemoryLocation): raise ValueError('memory_location must be an instance of MemoryLocation') request = Request(service=cls) request.data=b"" request.data += dfi.get_byte() # Data Format Identifier request.data += memory_location.alfid.get_byte() # AddressAndLengthFormatIdentifier request.data += memory_location.get_address_bytes() request.data += memory_location.get_memorysize_bytes() return request
def make_request(cls, did, value, didconfig): """ Generate a request for WriteDataByIdentifier :param did: The data identifier to write :type did: int :param value: Value given to the :ref:`DidCodec <HelperClass_DidCodec>`.encode method :type value: object :param didconfig: Definition of DID codecs. Dictionary mapping a DID (int) to a valid :ref:`DidCodec <HelperClass_DidCodec>` class or pack/unpack string :type didconfig: dict[int] = :ref:`DidCodec <HelperClass_DidCodec>` :raises ValueError: If parameters are out of range or missing :raises ConfigError: If didlist contains a DID not defined in didconfig """ from udsoncan import Request, DidCodec ServiceHelper.validate_int(did, min=0, max=0xFFFF, name='Data Identifier') req = Request(cls) didconfig = ServiceHelper.check_did_config(did, didconfig=didconfig) # Make sure all DID are correctly defined in client config req.data = struct.pack('>H', did) # encode DID number codec = DidCodec.from_config(didconfig[did]) req.data += codec.encode(value) return req
def make_request(cls, routine_id, control_type, data=None): u""" Generates a request for RoutineControl :param routine_id: The routine ID. Value should be between 0 and 0xFFFF :type routine_id: int :param control_type: Service subfunction. Allowed values are from 0 to 0x7F :type control_type: bytes :param data: Optional additional data to provide to the server :type data: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request ServiceHelper.validate_int(routine_id, min=0, max=0xFFFF, name=u'Routine ID') ServiceHelper.validate_int(control_type, min=0, max=0x7F, name=u'Routine control type') if data is not None: if not isinstance(data, str): raise ValueError(u'data must be a valid bytes object') request = Request(service=cls, subfunction=control_type) request.data = struct.pack(u'>H', routine_id) if data is not None: request.data += data return request
def make_request(cls, sequence_number, data=None): """ Generates a request for TransferData :param sequence_number: Corresponds to an 8bit counter that should increment for each new block transferred. Allowed values are from 0 to 0xFF :type sequence_number: int :param data: Optional additional data to send to the server :type data: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request, MemoryLocation ServiceHelper.validate_int( sequence_number, min=0, max=0xFF, name='Block sequence counter') # Not a subfunction! if data is not None and not isinstance(data, bytes): raise ValueError('data must be a bytes object') request = Request(service=cls) request.data = struct.pack('B', sequence_number) if data is not None: request.data += data return request
def test_from_input_param(self): with self.assertRaises(ValueError): req = Request("a string") with self.assertRaises(ValueError): req = Request(DummyServiceNormal, "string") with self.assertRaises(ValueError): req = Request(DummyServiceNormal(), data=123)
def __getSeed(self): req = Request(SecurityAccess, subfunction=self.ACCESS_LEVEL) self.client.send(req.get_payload()) payload = self.client.wait_frame(timeout=self.timeout) response = Response.from_payload(payload) if response.service == SecurityAccess and response.code == Response.Code.PositiveResponse: return response.data[1:] else: return None
def make_request(cls, control_type, baudrate=None): u""" Generates a request for LinkControl :param control_type: Service subfunction. Allowed values are from 0 to 0x7F :type control_type: int :param baudrate: Required baudrate value when ``control_type`` is either ``verifyBaudrateTransitionWithFixedBaudrate`` (1) or ``verifyBaudrateTransitionWithSpecificBaudrate`` (2) :type baudrate: :ref:`Baudrate <Baudrate>` :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request, Baudrate ServiceHelper.validate_int(control_type, min=0, max=0x7F, name=u'Control type') if control_type in [ cls.ControlType.verifyBaudrateTransitionWithSpecificBaudrate, cls.ControlType.verifyBaudrateTransitionWithFixedBaudrate ]: if baudrate is None: raise ValueError( u'A Baudrate must be provided with control type : "verifyBaudrateTransitionWithSpecificBaudrate" (0x%02x) or "verifyBaudrateTransitionWithFixedBaudrate" (0x%02x)' % (cls.ControlType. verifyBaudrateTransitionWithSpecificBaudrate, cls. ControlType.verifyBaudrateTransitionWithFixedBaudrate)) if not isinstance(baudrate, Baudrate): raise ValueError( u'Given baudrate must be an instance of the Baudrate class' ) else: if baudrate is not None: raise ValueError( u'The baudrate parameter is only needed when control type is "verifyBaudrateTransitionWithSpecificBaudrate" (0x%02x) or "verifyBaudrateTransitionWithFixedBaudrate" (0x%02x)' % (cls.ControlType. verifyBaudrateTransitionWithSpecificBaudrate, cls. ControlType.verifyBaudrateTransitionWithFixedBaudrate)) if control_type == cls.ControlType.verifyBaudrateTransitionWithSpecificBaudrate: baudrate = baudrate.make_new_type(Baudrate.Type.Specific) if control_type == cls.ControlType.verifyBaudrateTransitionWithFixedBaudrate and baudrate.baudtype == Baudrate.Type.Specific: baudrate = baudrate.make_new_type(Baudrate.Type.Fixed) request = Request(service=cls, subfunction=control_type) if baudrate is not None: request.data = baudrate.get_bytes() return request
def __sendKeyAndMesureTime(self, keyLevel, data): req = Request(SecurityAccess, subfunction=keyLevel, data=data) self.client.send(req.get_payload()) startTime = time.time() payload = self.client.wait_frame(timeout=self.timeout) endTime = time.time() progressTime = endTime - startTime response = Response.from_payload(payload) return response, progressTime
def make_request(cls, didlist, didconfig): """ Generates a request for ReadDataByIdentifier :param didlist: List of data identifier to read. :type didlist: list[int] :param didconfig: Definition of DID codecs. Dictionary mapping a DID (int) to a valid :ref:`DidCodec<DidCodec>` class or pack/unpack string :type didconfig: dict[int] = :ref:`DidCodec<DidCodec>` :raises ValueError: If parameters are out of range, missing or wrong type :raises ConfigError: If didlist contains a DID not defined in didconfig """ from udsoncan import Request from udsoncan import DidCodec didlist = cls.validate_didlist_input(didlist) req = Request(cls) ServiceHelper.check_did_config(didlist, didconfig) did_reading_all_data = None for did in didlist: if did not in didconfig: # Already checked in check_did_config. Paranoid check raise ConfigError( key=did, msg= 'Actual data identifier configuration contains no definition for data identifier 0x%04x' % did) codec = DidCodec.from_config(didconfig[did]) try: length = len(codec) if did_reading_all_data is not None: raise ValueError( 'Did 0x%04X is configured to read the rest of the payload (__len__ raisong ReadAllRemainingData), but a subsequent DID is requested (0x%04x)' % (did_reading_all_data, did)) except DidCodec.ReadAllRemainingData: if did_reading_all_data is not None: raise ValueError( 'It is impossible to read 2 DIDs configured to read the rest of the payload (__len__ raising ReadAllRemainingData). Dids are : 0x%04X and 0x%04X' % (did_reading_all_data, did)) did_reading_all_data = did req.data = struct.pack('>' + 'H' * len(didlist), *didlist) #Encode list of DID return req
def _test_p2_star_timeout_overrided_by_diagnostic_session_control(self): req = Request(service=services.TesterPresent, subfunction=0) self.udsclient.set_configs({ 'request_timeout': 5, 'p2_timeout': 0.5, 'p2_star_timeout': 1 }) self.udsclient.change_session(1) timeout = 2 try: t1 = time.time() response = self.udsclient.send_request(req) raise Exception('Request did not raise a TimeoutException') except TimeoutException as e: self.assertIsNotNone( self.udsclient.last_response, 'Client never received the PendingResponse message') self.completed = True diff = time.time() - t1 self.assertGreater( diff, timeout, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertLess( diff, timeout + 0.5, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout))
def _test_p2_star_timeout(self): req = Request(service=services.TesterPresent, subfunction=0) timeout = 2 self.udsclient.set_configs({ u'request_timeout': 5, u'p2_timeout': 0.5, u'p2_star_timeout': timeout }) try: t1 = time.time() response = self.udsclient.send_request(req) raise Exception(u'Request did not raise a TimeoutException') except TimeoutException, e: self.assertIsNotNone( self.udsclient.last_response, u'Client never received the PendingResponse message') self.completed = True diff = time.time() - t1 self.assertGreater( diff, timeout, u'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertLess( diff, timeout + 0.5, u'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout))
def make_request(cls, access_type, timing_param_record=None): """ Generates a request for AccessTimingParameter :param access_type: Service subfunction. Allowed values are from 0 to 0x7F :type access_type: int :param timing_param_record: Data associated with request. Must be present only when access_type=``AccessType.setTimingParametersToGivenValues`` (4) :type timing_param_record: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request ServiceHelper.validate_int(access_type, min=0, max=0x7F, name='Access type') if timing_param_record is not None and access_type != cls.AccessType.setTimingParametersToGivenValues : raise ValueError('timing_param_record can only be set when access_type is setTimingParametersToGivenValues"') if timing_param_record is None and access_type == cls.AccessType.setTimingParametersToGivenValues : raise ValueError('A timing_param_record must be provided when access_type is "setTimingParametersToGivenValues"') request = Request(service=cls, subfunction=access_type) if timing_param_record is not None: if not isinstance(timing_param_record, bytes): raise ValueError("timing_param_record must be a valid bytes objects") request.data += timing_param_record return request
def make_request(cls, sequence_number, data=None): """ Generate a request for AccessTimingParameter :param sequence_number: Service subfunction. Correspond to an 8bits counter that should increment for each new block transfered. Allowed values are from 0 to 0xFF :type sequence_number: int :param data: Optional additional data to send to the server :type data: bytes :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request, MemoryLocation ServiceHelper.validate_int(sequence_number, min=0, max=0xFF, name='Block sequence counter') if data is not None and not isinstance(data, bytes): raise ValueError('data must be a bytes object') request = Request(service=cls, subfunction=sequence_number, data=data) return request
def _test_payload_override_func(self): def func(payload): return b'\x99\x88\x77\x66' req = Request(service=services.TesterPresent, subfunction=0) with self.udsclient.payload_override(func): response = self.udsclient.send_request(req) self.assertEqual(response.original_payload, b'\x7E\x00')
def make_request(cls, group=0xFFFFFF): """ Generate a request for ClearDiagnosticInformation :param group: DTC mask ranging from 0 to 0xFFFFFF. 0xFFFFFF means all DTCs :type group: int :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request ServiceHelper.validate_int(group, min=0, max=0xFFFFFF, name='Group of DTC') request = Request(service=cls) hb = (group >> 16) & 0xFF mb = (group >> 8) & 0xFF lb = (group >> 0) & 0xFF request.data = struct.pack("BBB", hb,mb,lb) return request
def _test_timeout(self): req = Request(service = services.TesterPresent, subfunction=0) timeout = 0.5 try: t1 = time.time() response = self.udsclient.send_request(req, timeout=timeout) raise Exception('Request did not raise a TimeoutException') except TimeoutException as e: diff = time.time() - t1 self.assertGreater(diff, timeout, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertLess(diff, timeout+0.5, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout))
def make_request(cls, memory_location): """ Generates a request for ReadMemoryByAddress :param memory_location: The address and the size of the memory block to read. :type memory_location: :ref:`MemoryLocation <MemoryLocation>` :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request, MemoryLocation if not isinstance(memory_location, MemoryLocation): raise ValueError('Given memory location must be an instance of MemoryLocation') request = Request(service=cls) request.data = b'' request.data += memory_location.alfid.get_byte() # AddressAndLengthFormatIdentifier request.data += memory_location.get_address_bytes() request.data += memory_location.get_memorysize_bytes() return request
def make_request(cls, reset_type): """ Generate a request for ECUReset :param reset_type: Service subfunction. Allowed values are from 0 to 0xFF :type reset_type: int :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request ServiceHelper.validate_int(reset_type, min=0, max=0xFF, name='Reset type') return Request(service=cls, subfunction=reset_type)
def make_request(cls, didlist, didconfig): """ Generate a request for ReadDataByIdentifier :param didlist: List of data identifier to read. :type didlist: list[int] :param didconfig: Definition of DID codecs. Dictionary mapping a DID (int) to a valid :ref:`DidCodec<DidCodec>` class or pack/unpack string :type didconfig: dict[int] = :ref:`DidCodec<DidCodec>` :raises ValueError: If parameters are out of range, missing or wrong type :raises ConfigError: If didlist contains a DID not defined in didconfig """ from udsoncan import Request didlist = cls.validate_didlist_input(didlist) req = Request(cls) ServiceHelper.check_did_config(didlist, didconfig) req.data = struct.pack('>'+'H'*len(didlist), *didlist) #Encode list of DID return req
def make_request(cls, session): """ Generates a request for DiagnosticSessionControl service :param session: Service subfunction. Allowed values are from 0 to 0x7F :type session: int :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request ServiceHelper.validate_int(session, min=0, max=0x7F, name='Session number') return Request(service=cls, subfunction=session)
def _test_timeout_pending_response(self): req = Request(service = services.TesterPresent, subfunction=0) timeout = 0.5 try: t1 = time.time() response = self.udsclient.send_request(req, timeout=timeout) raise Exception('Request did not raise a TimeoutException') except TimeoutException as e: self.assertIsNotNone(self.udsclient.last_response, 'Client never received the PendingResponse message') self.completed = True diff = time.time() - t1 self.assertGreater(diff, timeout, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertLess(diff, timeout+0.5, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout))
def make_request(cls, data=None): """ Generate a request for RequestTransferExit :param data: Additional optional data to send to the server :type data: bytes :raises ValueError: If parameters are out of range or missing """ from udsoncan import Request, MemoryLocation if data is not None and not isinstance(data, bytes): raise ValueError('data must be a bytes object') request = Request(service=cls, data=data) return request
def test_suppress_positive_response_override(self): req = Request(DummyServiceNormal, subfunction=0x44, suppress_positive_response=False) payload = req.get_payload(suppress_positive_response=True) self.assertEqual(b"\x13\xC4", payload) # Subfunction bit 7 is set req = Request(DummyServiceNormal, subfunction=0x44, suppress_positive_response=True) payload = req.get_payload(suppress_positive_response=False) self.assertEqual(b"\x13\x44", payload) # Subfunction bit 7 is cleared
def RCRRP_responses_check(self, respect_overall_timeout): req = Request(service=services.TesterPresent, subfunction=0) overall_timeout = 2.0 if not respect_overall_timeout: overall_timeout = None p2_star_timeout = 1.0 self.udsclient.set_configs({ 'request_timeout': overall_timeout, 'p2_timeout': 0.5, 'p2_star_timeout': p2_star_timeout }) # Record our expectation on how long the timeout wlil be if respect_overall_timeout: timeout = overall_timeout else: # Server is going to send RCRRP for 4s. Then the client will wait for P2* timeout = 4.0 + p2_star_timeout t1 = time.time() try: response = self.udsclient.send_request(req) except TimeoutException as e: if respect_overall_timeout: diff = time.time() - t1 self.assertGreater( diff, timeout, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertLess( diff, timeout + 0.5, 'Timeout raised after %.3f seconds when it should be %.3f sec' % (diff, timeout)) self.assertIsNotNone( self.udsclient.last_response, 'Client never received the PendingResponse message') else: raise Exception('Request raised a TimeoutException') if not respect_overall_timeout: self.assertEqual(self.udsclient.last_response.code, Response.Code.PositiveResponse, 'Client never received the Positive Response')
def make_request(cls, setting_type, data = None): """ Generate a request for ControlDTCSetting :param setting_type: Service subfunction. Allowed values are from 0 to 0x7F :type setting_type: int :param data: Optional additional data sent with the request called `DTCSettingControlOptionRecord` :type data: bytes :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request ServiceHelper.validate_int(setting_type, min=0, max=0x7F, name='Setting type') if data is not None: if not isinstance(data, bytes): raise ValueError('data must be a valid bytes object') return Request(service=cls, subfunction=setting_type, data=data)