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, 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, 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, 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, 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, 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, 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, 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 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, 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 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 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 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, 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, subfunction, status_mask=None, severity_mask=None, dtc=None, snapshot_record_number=None, extended_data_record_number=None): u""" Generates a request for ReadDTCInformation. Each subfunction uses a subset of parameters. :param subfunction: The service subfunction. Values are defined in :class:`ReadDTCInformation.Subfunction<ReadDTCInformation.Subfunction>` :type subfunction: int :param status_mask: A DTC status mask used to filter DTC :type status_mask: int or :ref:`Dtc.Status <DTC_Status>` :param severity_mask: A severity mask used to filter DTC :type severity_mask: int or :ref:`Dtc.Severity <DTC_Severity>` :param dtc: A DTC mask used to filter DTC :type dtc: int or :ref:`Dtc <DTC>` :param snapshot_record_number: Snapshot record number :type snapshot_record_number: int :param extended_data_record_number: Extended data record number :type extended_data_record_number: int :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request, Dtc # Request grouping for subfunctions that have the same request format request_subfn_no_param = [ ReadDTCInformation.Subfunction.reportSupportedDTCs, ReadDTCInformation.Subfunction.reportFirstTestFailedDTC, ReadDTCInformation.Subfunction.reportFirstConfirmedDTC, ReadDTCInformation.Subfunction.reportMostRecentTestFailedDTC, ReadDTCInformation.Subfunction.reportMostRecentConfirmedDTC, ReadDTCInformation.Subfunction.reportDTCFaultDetectionCounter, ReadDTCInformation.Subfunction.reportDTCWithPermanentStatus, # Documentation is confusing about reportDTCSnapshotIdentification subfunction. # It is presented with reportDTCSnapshotRecordByDTCNumber (2 params) but a footnote says that these 2 parameters # are not to be provided for reportDTCSnapshotIdentification. Therefore, it is the same as other no-params subfn ReadDTCInformation.Subfunction.reportDTCSnapshotIdentification ] request_subfn_status_mask = [ ReadDTCInformation.Subfunction.reportNumberOfDTCByStatusMask, ReadDTCInformation.Subfunction.reportDTCByStatusMask, ReadDTCInformation.Subfunction.reportMirrorMemoryDTCByStatusMask, ReadDTCInformation.Subfunction. reportNumberOfMirrorMemoryDTCByStatusMask, ReadDTCInformation. Subfunction.reportNumberOfEmissionsRelatedOBDDTCByStatusMask, ReadDTCInformation.Subfunction. reportEmissionsRelatedOBDDTCByStatusMask ] request_subfn_mask_record_plus_snapshot_record_number = [ ReadDTCInformation.Subfunction.reportDTCSnapshotRecordByDTCNumber ] request_subfn_snapshot_record_number = [ ReadDTCInformation.Subfunction. reportDTCSnapshotRecordByRecordNumber ] request_subfn_mask_record_plus_extdata_record_number = [ ReadDTCInformation.Subfunction. reportDTCExtendedDataRecordByDTCNumber, ReadDTCInformation. Subfunction.reportMirrorMemoryDTCExtendedDataRecordByDTCNumber ] request_subfn_severity_plus_status_mask = [ ReadDTCInformation.Subfunction. reportNumberOfDTCBySeverityMaskRecord, ReadDTCInformation.Subfunction.reportDTCBySeverityMaskRecord ] request_subfn_mask_record = [ ReadDTCInformation.Subfunction.reportSeverityInformationOfDTC ] ServiceHelper.validate_int(subfunction, min=1, max=0x15, name=u'Subfunction') if status_mask is not None and isinstance(status_mask, Dtc.Status): status_mask = status_mask.get_byte_as_int() if severity_mask is not None and isinstance(severity_mask, Dtc.Severity): severity_mask = severity_mask.get_byte_as_int() if dtc is not None and isinstance(dtc, Dtc): dtc = dtc.id req = Request(service=cls, subfunction=subfunction) if subfunction in request_subfn_no_param: # Service ID + Subfunction pass elif subfunction in request_subfn_status_mask: cls.assert_status_mask(status_mask, subfunction) req.data = struct.pack(u'B', status_mask) elif subfunction in request_subfn_mask_record_plus_snapshot_record_number: cls.assert_dtc(dtc, subfunction) cls.assert_snapshot_record_number(snapshot_record_number, subfunction) req.data = cls.pack_dtc(dtc) + struct.pack(u'B', snapshot_record_number) elif subfunction in request_subfn_snapshot_record_number: cls.assert_snapshot_record_number(snapshot_record_number, subfunction) req.data = struct.pack(u'B', snapshot_record_number) elif subfunction in request_subfn_mask_record_plus_extdata_record_number: cls.assert_dtc(dtc, subfunction) cls.assert_extended_data_record_number(extended_data_record_number, subfunction) req.data = cls.pack_dtc(dtc) + struct.pack( u'B', extended_data_record_number) elif subfunction in request_subfn_severity_plus_status_mask: cls.assert_status_mask(status_mask, subfunction) cls.assert_severity_mask(severity_mask, subfunction) req.data = struct.pack(u'BB', severity_mask, status_mask) elif subfunction in request_subfn_mask_record: cls.assert_dtc(dtc, subfunction) req.data = cls.pack_dtc(dtc) return req
def test_make_payload_custom_data_no_subfunction(self): req = Request(DummyServiceNoSubunction, subfunction=0x44) req.data = b"\x12\x34\x56\x78" payload = req.get_payload() self.assertEqual(b"\x13\x12\x34\x56\x78", payload)
def make_request(cls, subfunction, did=None, diddef=None): """ Generates a request for DynamicallyDefineDataIdentifier :param subfunction: Service subfunction. Allowed values are from 1 to 3 :type subfunction: int :param did: The Data Identifier to define. Values from 0x0000 to 0xFFFF :type did: int :param diddef: Definition of the DID. Either by source DID or memory address. This parameter is only needed with subfunctions defineByIdentifie (1)` and defineByMemoryAddress (2) :type diddef: :ref:`DynamicDidDefinition<DynamicDidDefinition>` :raises ValueError: If parameters are out of range, missing or wrong type """ from udsoncan import Request, DynamicDidDefinition ServiceHelper.validate_int(subfunction, min=1, max=3, name='Subfunction') req = Request(service=cls, subfunction=subfunction) if subfunction in [ cls.Subfunction.defineByIdentifier, cls.Subfunction.defineByMemoryAddress ]: if not isinstance(diddef, DynamicDidDefinition): raise ValueError( 'A DynamicDidDefinition must be given to define a dynamic did with subfunction %d' % (subfunction)) if did is None: raise ValueError( 'A DID number must be given with subfunction %d' % (subfunction)) if did is not None: ServiceHelper.validate_int(did, min=0, max=0xFFFF, name='DID number') if subfunction in [ cls.Subfunction.defineByIdentifier, cls.Subfunction.defineByMemoryAddress ]: if diddef is None: raise ValueError( 'DynamicDidDefinition must be given for this subfunction') diddef_entries = diddef.get() if len(diddef_entries) == 0: raise ValueError( 'DynamicDidDefinition object must have at least one DID specification' ) req.data = struct.pack('>H', did) if subfunction == cls.Subfunction.defineByIdentifier: if not diddef.is_by_source_did(): raise ValueError( "DynamicDidDefinition must be defined by source DID when used with subfunction 'defineByIdentifier'" ) for entry in diddef_entries: req.data += struct.pack('>HBB', entry.source_did, entry.position, entry.memorysize) elif subfunction == cls.Subfunction.defineByMemoryAddress: if not diddef.is_by_memory_address(): raise ValueError( "DynamicDidDefinition must be defined by memory address when used with subfunction 'defineByMemoryAddress'" ) req.data += diddef.get_alfid().get_byte() for entry in diddef_entries: req.data += entry.memloc.get_address_bytes() req.data += entry.memloc.get_memorysize_bytes() elif subfunction == cls.Subfunction.clearDynamicallyDefinedDataIdentifier: if did is not None: req.data = struct.pack('>H', did) return req
def make_request(cls, did, control_param=None, values=None, masks=None, ioconfig=None): """ Generate a request for InputOutputControlByIdentifier :param did: Data identifier to read :type did: int :param control_param: Optional parameter that can be a value from InputOutputControlByIdentifier.ControlParam :type control_param: int :param values: Optional values to send to the server. This parameter will be given to :ref:`DidCodec<HelperClass_DidCodec>`.encode() method. It can be: - A list for positional arguments - A dict for named arguments - An instance of :ref:`IOValues<HelperClass_IOValues>` for mixed arguments :type values: list, dict, :ref:`IOValues<HelperClass_IOValues>` :param masks: Optional mask record for composite values. The mask definition must be included in ioconfig It can be: - A list naming the bit mask to set - A dict with the mask name as a key and a boolean setting or clearing the mask as the value - An instance of :ref:`IOMask<HelperClass_IOMask>` - A boolean value to set all mask to the same value. :type masks: list, dict, :ref:`IOMask<HelperClass_IOMask>`, bool :param ioconfig: Definition of DID codecs. Dictionary mapping a DID (int) to a valid :ref:`DidCodec<HelperClass_DidCodec>` class or pack/unpack string. It is possible to use composite :ref:`DidCodec<HelperClass_DidCodec>` by specifying a dict with entries : codec, mask, mask_size. :type ioconfig: dict[int] = :ref:`DidCodec<HelperClass_DidCodec>`, dict :raises ValueError: If parameters are out of range or missing :raises ConfigError: If given did is not defined within ioconfig """ from udsoncan import Request, IOMasks, IOValues, DidCodec ServiceHelper.validate_int(did, min=0, max=0xffff, name='DID') if control_param is not None: if not isinstance(control_param, int): raise ValueError("control_param must be a valid integer") if control_param < 0 or control_param > 3: raise ValueError('control_param must either be returnControlToECU(0), resetToDefault(1), freezeCurrentState(2), shortTermAdjustment(3). %d given.' % control_param) if values is not None: if isinstance(values, list): values = IOValues(*values) if isinstance(values, dict): values = IOValues(**values) if not isinstance(values, IOValues): raise ValueError("values must be an instance of IOValues") if masks is not None: if isinstance(masks, list): masks = IOMasks(*masks) if isinstance(masks, dict): masks = IOMasks(**masks) if not isinstance(masks, IOMasks) and not isinstance(masks, bool): raise ValueError("masks must be an instance of IOMask or a boolean value") if values is None and masks is not None: raise ValueError('An IOValue must be given if a IOMask is provided.') request = Request(service=cls) request.data = b'' ioconfig = ServiceHelper.check_io_config(did, ioconfig) # IO dids are defined in client config. request.data += struct.pack('>H', did) # This parameters is optional according to standard if control_param is not None: request.data += struct.pack('B', control_param) codec = DidCodec.from_config(ioconfig[did]) # Get IO codec from config if values is not None: request.data += codec.encode(*values.args, **values.kwargs) if masks is not None: # Skip the masks byte if none is given. if isinstance(masks, bool): byte = b'\xFF' if masks == True else b'\x00' if 'mask_size' in ioconfig[did]: request.data += (byte * ioconfig[did]['mask_size']) else: raise ConfigError('mask_size', msg='Given mask is boolean value, indicating that all mask should be set to same value, but no mask_size is defined in configuration. Cannot guess how many bits to set.') elif isinstance(masks, IOMasks): if 'mask' not in ioconfig[did]: raise ConfigError('mask', msg='Cannot apply given mask. Input/Output configuration does not define their position (and size).') masks_config = ioconfig[did]['mask'] given_masks = masks.get_dict() numeric_val = 0 for mask_name in given_masks: if mask_name not in masks_config: raise ConfigError('mask_size', msg='Cannot set mask bit for mask %s. The configuration does not define its position' % (mask_name)) if given_masks[mask_name] == True: numeric_val |= masks_config[mask_name] minsize = math.ceil(math.log(numeric_val+1, 2)/8.0) size = minsize if 'mask_size' not in ioconfig[did] else ioconfig[did]['mask_size'] request.data += numeric_val.to_bytes(size, 'big') return request
def test_make_payload_custom_data(self): req = Request(DummyServiceNormal, subfunction=0x44) req.data = "\x12\x34\x56\x78" payload = req.get_payload() self.assertEqual("\x13\x44\x12\x34\x56\x78", payload)