diff --git a/examples/xml/component/application_component.py b/examples/xml/component/application_component.py index b97d49f..b296cb0 100644 --- a/examples/xml/component/application_component.py +++ b/examples/xml/component/application_component.py @@ -4,7 +4,6 @@ import os import autosar import autosar.xml.element as ar_element -import autosar.xml.enumeration as ar_enum def create_platform_types(packages: dict[str, ar_element.Package]): @@ -50,17 +49,6 @@ def create_platform_types(packages: dict[str, ar_element.Package]): packages["PlatformImplementationDataTypes"].append(uint32_impl_type) -# def create_implementation_data_types(packages: dict[str, ar_element.Package]): -# """ -# Creates non-platform implementation data types -# """ -# sw_data_def_props = ar_element.SwDataDefPropsConditional(base_type_ref="AUTOSAR_Platform/BaseTypes/uint8") -# inactive_active_t = ar_element.ImplementationDataType("InactiveActive_T", -# category="VALUE", -# sw_data_def_props=sw_data_def_props) -# packages["ImplementationDataTypes"].append(inactive_active_t) - - def create_sender_receiver_port_interfaces(packages: dict[str, ar_element.Package]): """ Create sender-receiver port interfaces used in example @@ -69,9 +57,6 @@ def create_sender_receiver_port_interfaces(packages: dict[str, ar_element.Packag port_interface = ar_element.SenderReceiverInterface("VehicleSpeed_I") port_interface.create_data_element("VehicleSpeed", type_ref=uint16_impl_t.ref()) packages["PortInterfaces"].append(port_interface) - port_interface = ar_element.SenderReceiverInterface("EngineSpeed_I") - port_interface.create_data_element("EngineSpeed", type_ref=uint16_impl_t.ref()) - packages["PortInterfaces"].append(port_interface) def create_client_server_interfaces(packages: dict[str, ar_element.Package]): @@ -90,19 +75,37 @@ def create_client_server_interfaces(packages: dict[str, ar_element.Package]): packages["PortInterfaces"].append(interface) +def create_application_component(packages: dict[str, ar_element.Package]): + """ + Creates application component with one sender-receiver port and one + client-server port + """ + timer_interface = packages["PortInterfaces"].find("FreeRunningTimer_I") + vehicle_speed_interface = packages["PortInterfaces"].find("VehicleSpeed_I") + swc = ar_element.ApplicationSoftwareComponentType("MyApplication") + swc.create_require_port("VehicleSpeed", vehicle_speed_interface, com_spec={"init_value": 65535, + 'alive_timeout': 0, + 'enable_update': False, + 'uses_end_to_end_protection': False, + 'handle_never_received': False + }) + swc.create_require_port("FreeRunningTimer", timer_interface) + packages["ComponentTypes"].append(swc) + + def save_xml_files(workspace: autosar.xml.Workspace): """ Saves workspace as XML documents """ interface_document_path = os.path.abspath(os.path.join(os.path.dirname( __file__), 'data', 'portinterfaces.arxml')) - datatype_document_path = os.path.abspath(os.path.join(os.path.dirname( - __file__), 'data', 'datatypes.arxml')) platform_document_path = os.path.abspath(os.path.join(os.path.dirname( __file__), 'data', 'platform.arxml')) + component_document_path = os.path.abspath(os.path.join(os.path.dirname( + __file__), 'data', 'MyApplication.arxml')) workspace.create_document(interface_document_path, packages="/PortInterfaces") - workspace.create_document(datatype_document_path, packages="/DataTypes") workspace.create_document(platform_document_path, packages="/AUTOSAR_Platform") + workspace.create_document(component_document_path, packages="/ComponentTypes") workspace.write_documents() @@ -116,16 +119,19 @@ def main(): "PlatformDataConstraints", "PlatformCompuMethods", "ImplementationDataTypes", - "PortInterfaces"], + "PortInterfaces", + "ComponentTypes"], workspace.make_packages("AUTOSAR_Platform/BaseTypes", "AUTOSAR_Platform/ImplementationDataTypes", "AUTOSAR_Platform/DataConstraints", "AUTOSAR_Platform/CompuMethods", "DataTypes/ImplementationDataTypes", - "PortInterfaces"))) + "PortInterfaces", + "ComponentTypes"))) create_platform_types(packages) create_sender_receiver_port_interfaces(packages) create_client_server_interfaces(packages) + create_application_component(packages) save_xml_files(workspace) diff --git a/examples/xml/component/data/MyApplication.arxml b/examples/xml/component/data/MyApplication.arxml new file mode 100644 index 0000000..3855af3 --- /dev/null +++ b/examples/xml/component/data/MyApplication.arxml @@ -0,0 +1,37 @@ + + + + + ComponentTypes + + + MyApplication + + + VehicleSpeed + + + /PortInterfaces/VehicleSpeed_I/VehicleSpeed + false + 0 + false + false + + + 65535 + + + + + /PortInterfaces/VehicleSpeed_I + + + FreeRunningTimer + /PortInterfaces/FreeRunningTimer_I + + + + + + + \ No newline at end of file diff --git a/examples/xml/component/data/platform.arxml b/examples/xml/component/data/platform.arxml new file mode 100644 index 0000000..72a93b4 --- /dev/null +++ b/examples/xml/component/data/platform.arxml @@ -0,0 +1,128 @@ + + + + + AUTOSAR_Platform + + + BaseTypes + + + boolean + 8 + BOOLEAN + + + uint8 + 8 + + + uint16 + 16 + + + uint32 + 32 + + + + + ImplementationDataTypes + + + boolean + VALUE + + + + /AUTOSAR_Platform/BaseTypes/uint8 + /AUTOSAR_Platform/CompuMethods/boolean_CompuMethod + /AUTOSAR_Platform/DataConstraints/boolean_DataConstr + + + + + + uint8 + VALUE + + + + /AUTOSAR_Platform/BaseTypes/uint8 + + + + + + uint16 + VALUE + + + + /AUTOSAR_Platform/BaseTypes/uint16 + + + + + + uint32 + VALUE + + + + /AUTOSAR_Platform/BaseTypes/uint32 + + + + + + + + DataConstraints + + + boolean_DataConstr + + + + 0 + 1 + + + + + + + + CompuMethods + + + boolean_CompuMethod + TEXTTABLE + + + + FALSE + 0 + 0 + + FALSE + + + + TRUE + 1 + 1 + + TRUE + + + + + + + + + + + \ No newline at end of file diff --git a/examples/xml/component/data/portinterfaces.arxml b/examples/xml/component/data/portinterfaces.arxml new file mode 100644 index 0000000..366b0e5 --- /dev/null +++ b/examples/xml/component/data/portinterfaces.arxml @@ -0,0 +1,54 @@ + + + + + PortInterfaces + + + VehicleSpeed_I + + + VehicleSpeed + /AUTOSAR_Platform/ImplementationDataTypes/uint16 + + + + + FreeRunningTimer_I + + + GetTime + + + value + /AUTOSAR_Platform/ImplementationDataTypes/uint32 + OUT + + + + + IsTimerElapsed + + + startTime + /AUTOSAR_Platform/ImplementationDataTypes/uint32 + IN + + + duration + /AUTOSAR_Platform/ImplementationDataTypes/uint32 + IN + + + result + /AUTOSAR_Platform/ImplementationDataTypes/boolean + OUT + + + + + + + + + \ No newline at end of file diff --git a/examples/xml/port_interface/client_server_interface.py b/examples/xml/port_interface/client_server_interface.py index 9aeba00..b5da46f 100644 --- a/examples/xml/port_interface/client_server_interface.py +++ b/examples/xml/port_interface/client_server_interface.py @@ -29,7 +29,7 @@ def create_platform_types(packages: dict[str, ar_element.Package]): def create_port_interfaces(packages: dict[str, ar_element.Package]): """ - Creates interface with one element + Creates client-server interface with one operation """ uint32_impl_type = packages["PlatformImplementationDataTypes"].find("uint32") interface = ar_element.ClientServerInterface("FreeRunningTimer_I", is_service=True) diff --git a/src/autosar/xml/element.py b/src/autosar/xml/element.py index 0afd477..84e12e6 100644 --- a/src/autosar/xml/element.py +++ b/src/autosar/xml/element.py @@ -20,13 +20,13 @@ # Type aliases -ValueSpeficationElement = Union["TextValueSpecification", - "NumericalValueSpecification", - "NotAvailableValueSpecification", - "ArrayValueSpecification", - "RecordValueSpecification", - "ApplicationValueSpecification", - "ConstantReference"] +ValueSpecificationElement = Union["TextValueSpecification", + "NumericalValueSpecification", + "NotAvailableValueSpecification", + "ArrayValueSpecification", + "RecordValueSpecification", + "ApplicationValueSpecification", + "ConstantReference"] PortPrototypeElement = Union["ProvidePortPrototype", "RequirePortPrototype", @@ -449,8 +449,9 @@ class CompuMethodRef(BaseRef): CompuMethod reference """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.COMPU_METHOD) + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.COMPU_METHOD) -> None: + super().__init__(value, dest) def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: """Acceptable values for dest""" @@ -2202,6 +2203,15 @@ def __init__(self, if ptr_target_props is not None: self._set_attr_with_strict_type('ptr_target_props', ptr_target_props, SwPointerTargetProps) + @property + def is_queued(self) -> bool: + """ + Returns True if impl_policy is set to QUEUED + """ + if self.impl_policy is not None and self.impl_policy == ar_enum.SwImplPolicy.QUEUED: + return True + return False + class SwDataDefProps(ARObject): """ @@ -2455,10 +2465,10 @@ class VariableDataPrototype(AutosarDataPrototype): def __init__(self, name: str, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE # .VARIATION-POINT not supported self._assign_optional_strict("init_value", init_value, ValueSpecification) @@ -2470,6 +2480,15 @@ def ref(self) -> VariableDataPrototypeRef | None: ref_str = self._calc_ref_string() return None if ref_str is None else VariableDataPrototypeRef(ref_str) + @property + def is_queued(self) -> bool: + """ + Returns True if internal sw_data_def_props has its impl_policy is set to QUEUED + """ + if self.sw_data_def_props is not None and len(self.sw_data_def_props.variants) > 0: + return self.sw_data_def_props.variants[0].is_queued + return False + class ParameterDataPrototype(AutosarDataPrototype): """ @@ -2480,10 +2499,10 @@ class ParameterDataPrototype(AutosarDataPrototype): def __init__(self, name: str, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE # .VARIATION-POINT not supported self._assign_optional_strict("init_value", init_value, ValueSpecification) @@ -2919,7 +2938,31 @@ def __init__(self, label: str | None = None) -> None: # .VARIATION-POINT not supported @classmethod - def make_value(cls, data: Any) -> ValueSpeficationElement: + def make_init_value(cls, + init_value: int | float | str | tuple | ValueSpecificationElement | None = None, # noqa E501 pylint: disable=C0301 + init_value_ref: Union[str, ConstantRef, "ConstantReference", None] = None + ) -> ValueSpecificationElement: + """ + Attempts to create an init value from either the init_value argument or init_value_ref. + Both cannot be set simultaneously + """ + if init_value is not None: + if init_value_ref is not None: + msg = "init_value and init_value_ref cannot be set at the same time. One of them must be None" + raise ValueError(msg) + if isinstance(init_value, ValueSpecification): + return init_value + else: + return cls.make_value(init_value) + elif init_value_ref is not None: + if isinstance(init_value_ref, ConstantReference): + return init_value_ref + elif isinstance(init_value_ref, (str, ConstantRef)): + return ConstantReference(init_value_ref) + return None + + @classmethod + def make_value(cls, data: Any) -> ValueSpecificationElement: """ Builds value specification based on Python data Format 1 - data is not a tuple: @@ -2961,7 +3004,7 @@ def make_value(cls, data: Any) -> ValueSpeficationElement: @classmethod def _make_from_args(cls, label: str | None, value: Any, - default_pattern: int | None = None) -> ValueSpeficationElement: + default_pattern: int | None = None) -> ValueSpecificationElement: if isinstance(value, (int, float)): return NumericalValueSpecification(label, value) elif isinstance(value, str): @@ -3047,10 +3090,10 @@ class ArrayValueSpecification(ValueSpecification): def __init__(self, label: str | None = None, - elements: list[ValueSpeficationElement] | None = None + elements: list[ValueSpecificationElement] | None = None ) -> None: super().__init__(label) - self.elements: list[ValueSpeficationElement] = [] + self.elements: list[ValueSpecificationElement] = [] if elements is not None: if isinstance(elements, ValueSpecification): self.append(elements) @@ -3058,7 +3101,7 @@ def __init__(self, for element in elements: self.append(element) - def append(self, element: ValueSpeficationElement): + def append(self, element: ValueSpecificationElement): """ Appends element to array specification """ @@ -3076,10 +3119,10 @@ class RecordValueSpecification(ValueSpecification): def __init__(self, label: str | None = None, - fields: list[ValueSpeficationElement] | None = None + fields: list[ValueSpecificationElement] | None = None ) -> None: super().__init__(label) - self.fields: list[ValueSpeficationElement] = [] + self.fields: list[ValueSpecificationElement] = [] if fields is not None: if isinstance(fields, ValueSpecification): self.append(fields) @@ -3087,7 +3130,7 @@ def __init__(self, for field in fields: self.append(field) - def append(self, field: ValueSpeficationElement): + def append(self, field: ValueSpecificationElement): """ Appends field to record specification """ @@ -3137,9 +3180,9 @@ class ConstantSpecification(ARElement): Tag Variants: 'CONSTANT-SPECIFICATION' """ - def __init__(self, name: str, value: ValueSpeficationElement | None = None, **kwargs) -> None: + def __init__(self, name: str, value: ValueSpecificationElement | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.value: ValueSpeficationElement = None # .VALUE-SPEC + self.value: ValueSpecificationElement = None # .VALUE-SPEC if value is not None: if isinstance(value, ValueSpecification): self.value = value @@ -3567,6 +3610,7 @@ def append_data_element(self, data_element: VariableDataPrototype): Appends data element to internal list of elements """ if isinstance(data_element, VariableDataPrototype): + data_element.parent = self self.data_elements.append(data_element) else: msg = f"data_element: Invalid type '{str(type(data_element))}'" @@ -3584,7 +3628,7 @@ def append_invalidation_policy(self, invalidation_policy: InvalidationPolicy): def create_data_element(self, name: str, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, **kwargs) -> VariableDataPrototype: """ Convenience method for adding a new data element to this port interface @@ -3657,7 +3701,7 @@ def append_data_element(self, nv_data: VariableDataPrototype): def create_data_element(self, name: str, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, **kwargs) -> VariableDataPrototype: """ Convenience method for adding a new data element to this port interface @@ -3712,7 +3756,7 @@ def append_parameter(self, parameter: ParameterDataPrototype): def create_parameter(self, name: str, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, **kwargs) -> ParameterDataPrototype: """ Convenience method for adding a new parameter to this port interface @@ -4156,6 +4200,43 @@ class ProvidePortComSpec(ARObject): Group AR:P-PORT-COM-SPEC """ + @classmethod + def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "ProvidePortComSpec": + """ + Convenience method for creating require-port com-specs for port-interfaces + with one data element + Special keys for non-queued SenderReceiverInterface: + * init_value_ref: str | ConstantRef | ConstantReference + Remaining keys are the same as the constructor of NonqueuedSenderComSpec + + Currently only supports SenderReceiverInterface + """ + if isinstance(port_interface, SenderReceiverInterface): + if len(port_interface.data_elements) == 0: + raise ValueError(f"{port_interface.name}: Port interface must have at least one element") + if len(port_interface.data_elements) == 1: + data_element: VariableDataPrototype = port_interface.data_elements[0] + if data_element.is_queued: + return QueuedSenderComSpec(data_element_ref=data_element.ref(), **kwargs) + else: + return cls.make_non_queued_sender_com_spec(data_element_ref=data_element.ref(), **kwargs) + else: + raise NotImplementedError("Multiple data elements not yet supported") + else: + raise NotImplementedError(str(type(port_interface))) + + @classmethod + def make_non_queued_sender_com_spec(cls, + init_value: int | float | str | tuple | ValueSpecificationElement | None = None, # noqa E501 pylint: disable=C0301 + init_value_ref: str | ConstantRef | ConstantReference | None = None, + **kwargs + ) -> "NonqueuedSenderComSpec": + """ + Convenience method for creating NonqueuedSenderComSpec + """ + init_value = ValueSpecification.make_init_value(init_value, init_value_ref) + return NonqueuedSenderComSpec(init_value=init_value, **kwargs) + class SenderComSpec(ProvidePortComSpec): """ @@ -4251,12 +4332,12 @@ class NonqueuedSenderComSpec(SenderComSpec): """ def __init__(self, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, data_filter: DataFilter | None = None, **kwargs) -> None: super().__init__(**kwargs) self.data_filter: DataFilter | None = None # .DATA-FILTER - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE self._assign_optional_strict("data_filter", data_filter, DataFilter) self._assign_optional_strict("init_value", init_value, ValueSpecification) @@ -4269,12 +4350,12 @@ class NvProvideComSpec(ProvidePortComSpec): def __init__(self, variable_ref: VariableDataPrototypeRef | None = None, - ram_block_init_value: ValueSpeficationElement | None = None, - rom_block_init_value: ValueSpeficationElement | None = None, + ram_block_init_value: ValueSpecificationElement | None = None, + rom_block_init_value: ValueSpecificationElement | None = None, ) -> None: super().__init__() - self.ram_block_init_value: ValueSpeficationElement | None = None # .RAM-BLOCK-INIT-VALUE - self.rom_block_init_value: ValueSpeficationElement | None = None # .RAM-BLOCK-INIT-VALUE + self.ram_block_init_value: ValueSpecificationElement | None = None # .RAM-BLOCK-INIT-VALUE + self.rom_block_init_value: ValueSpecificationElement | None = None # .RAM-BLOCK-INIT-VALUE self.variable_ref: VariableDataPrototypeRef | None = None # .VARIABLE-REF self._assign_optional_strict("ram_block_init_value", ram_block_init_value, ValueSpecification) self._assign_optional_strict("rom_block_init_value", rom_block_init_value, ValueSpecification) @@ -4289,10 +4370,10 @@ class ParameterProvideComSpec(ProvidePortComSpec): def __init__(self, parameter_ref: ParameterDataPrototypeRef | str | None = None, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, ) -> None: super().__init__() - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE self.parameter_ref: VariableDataPrototypeRef | None = None # .PARAMETER-REF self._assign_optional_strict("init_value", init_value, ValueSpecification) self._assign_optional("parameter_ref", parameter_ref, ParameterDataPrototypeRef) @@ -4369,6 +4450,43 @@ class RequirePortComSpec(ARObject): Group AR:R-PORT-COM-SPEC """ + @classmethod + def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "RequirePortComSpec": + """ + Convenience method for creating require-port com-specs for port-interfaces + with one data element + Special keys for non-queued SenderReceiverInterface: + * init_value_ref: str | ConstantRef | ConstantReference + Remaining keys are the same as the constructor of NonqueuedReceiverComSpec + + Currently only supports SenderReceiverInterface + """ + if isinstance(port_interface, SenderReceiverInterface): + if len(port_interface.data_elements) == 0: + raise ValueError(f"{port_interface.name}: Port interface must have at least one element") + if len(port_interface.data_elements) == 1: + data_element: VariableDataPrototype = port_interface.data_elements[0] + if data_element.is_queued: + return QueuedReceiverComSpec(data_element_ref=data_element.ref(), **kwargs) + else: + return cls.make_non_queued_receiver_com_spec(data_element_ref=data_element.ref(), **kwargs) + else: + raise NotImplementedError("Multiple data elements not yet supported") + else: + raise NotImplementedError(str(type(port_interface))) + + @classmethod + def make_non_queued_receiver_com_spec(cls, + init_value: int | float | str | tuple | ValueSpecificationElement | None = None, # noqa E501 pylint: disable=C0301 + init_value_ref: str | ConstantRef | ConstantReference | None = None, + **kwargs + ) -> "NonqueuedReceiverComSpec": + """ + Convenience method for creating NonqueuedReceiverComSpec + """ + init_value = ValueSpecification.make_init_value(init_value, init_value_ref) + return NonqueuedReceiverComSpec(init_value=init_value, **kwargs) + class ReceiverComSpec(RequirePortComSpec): """ @@ -4475,8 +4593,8 @@ def __init__(self, handle_data_status: bool | None = None, handle_never_received: bool | None = None, handle_timeout_type: ar_enum.HandleTimeout | None = None, - init_value: ValueSpeficationElement | None = None, - timeout_substitution_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, + timeout_substitution_value: ValueSpecificationElement | None = None, **kwargs) -> None: super().__init__(**kwargs) self.alive_timeout: int | float | None = None # .ALIVE-TIMEOUT @@ -4485,8 +4603,8 @@ def __init__(self, self.handle_data_status: bool | None = None # .HANDLE-DATA-STATUS self.handle_never_received: bool | None = None # .HANDLE-NEVER-RECEIVED self.handle_timeout_type: ar_enum.HandleTimeout | None = None # .HANDLE-TIMEOUT-TYPE - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE - self.timeout_substitution_value: ValueSpeficationElement | None = None # .TIMEOUT-SUBSTITUTION-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE + self.timeout_substitution_value: ValueSpecificationElement | None = None # .TIMEOUT-SUBSTITUTION-VALUE self._assign_optional("alive_timeout", alive_timeout, float) self._assign_optional("enable_update", enable_update, bool) self._assign_optional_strict("data_filter", data_filter, DataFilter) @@ -4505,10 +4623,10 @@ class NvRequireComSpec(RequirePortComSpec): def __init__(self, variable_ref: VariableDataPrototypeRef | None = None, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, ) -> None: super().__init__() - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE self.variable_ref: VariableDataPrototypeRef | None = None # .VARIABLE-REF self._assign_optional_strict("init_value", init_value, ValueSpecification) self._assign_optional("variable_ref", variable_ref, VariableDataPrototypeRef) @@ -4522,10 +4640,10 @@ class ParameterRequireComSpec(RequirePortComSpec): def __init__(self, parameter_ref: ParameterDataPrototypeRef | str | None = None, - init_value: ValueSpeficationElement | None = None, + init_value: ValueSpecificationElement | None = None, ) -> None: super().__init__() - self.init_value: ValueSpeficationElement | None = None # .INIT-VALUE + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE self.parameter_ref: VariableDataPrototypeRef | None = None # .PARAMETER-REF self._assign_optional_strict("init_value", init_value, ValueSpecification) self._assign_optional("parameter_ref", parameter_ref, ParameterDataPrototypeRef) @@ -4686,7 +4804,8 @@ def __init__(self, for com_spec_elem in com_spec: self.append_com_spec(com_spec_elem) else: - raise TypeError("com_spec must be of a type derived from RequirePortComSpec") + msg = "com_spec: Needs be of a type derived from RequirePortComSpec." + raise TypeError(msg + f" Got {str(type(com_spec))}") def ref(self) -> PortPrototypeRef | None: """ @@ -4798,6 +4917,7 @@ def append_port(self, port: PortPrototypeElement): Adds port to internal list of ports """ if isinstance(port, PortPrototype): + port.parent = self self.ports.append(port) else: msg = "port type must be one of: ProvidePortPrototype, RequirePortPrototype, PRPortPrototype." @@ -4866,6 +4986,51 @@ def ref(self) -> SwComponentTypeRef | None: return None return SwComponentTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE) + def create_require_port(self, + name: str, + port_interface: PortInterface, + com_spec: dict | list[dict] | RequirePortComSpec | list[RequirePortComSpec] | None = None, + allow_unconnected: bool | None = None, + **kwargs) -> RequirePortPrototype: + """ + Creates a new require port and adds it to the internal list of ports + """ + if com_spec is not None: + if isinstance(com_spec, dict): + com_spec = RequirePortComSpec.make_from_port_interface(port_interface, **com_spec) + assert com_spec is not None + port = RequirePortPrototype(name, port_interface.ref(), com_spec, allow_unconnected, **kwargs) + self.append_port(port) + return port + + def create_provide_port(self, + name: str, + port_interface: PortInterface | None = None, + com_spec: dict | list[dict] | ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + **kwargs) -> ProvidePortPrototype: + """ + Creates a new provide port and adds it to the internal list of ports + """ + if com_spec is not None: + if isinstance(com_spec, dict): + com_spec = ProvidePortComSpec.make_from_port_interface(port_interface, **com_spec) + assert com_spec is not None + port = ProvidePortPrototype(name, port_interface.ref(), com_spec, **kwargs) + self.append_port(port) + return port + + def create_pr_port(self, + name: str, + port_interface_ref: PortInterfaceRef | None = None, + com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, + **kwargs) -> PRPortPrototype: + """ + Creates a new pr-port and adds it to the internal list of ports + """ + port = PRPortPrototype(name, port_interface_ref, com_spec, **kwargs) + self.append_port(port) + return port + class SwComponentPrototype(Identifiable): """ diff --git a/src/autosar/xml/reader.py b/src/autosar/xml/reader.py index 0f78078..3166e3a 100644 --- a/src/autosar/xml/reader.py +++ b/src/autosar/xml/reader.py @@ -2651,7 +2651,7 @@ def _read_application_value_specification_group(self, def _read_value_specification_element(self, xml_element: ElementTree.Element - ) -> ar_element.ValueSpeficationElement: + ) -> ar_element.ValueSpecificationElement: """ Reads any ValueSpecificationElement """ diff --git a/src/autosar/xml/writer.py b/src/autosar/xml/writer.py index ac59e1a..28d9e5a 100644 --- a/src/autosar/xml/writer.py +++ b/src/autosar/xml/writer.py @@ -2303,7 +2303,7 @@ def _write_value_specification_group(self, elem: ar_element.ValueSpecification) if elem.label is not None: self._add_content("SHORT-LABEL", str(elem.label)) - def _write_value_specification_element(self, elem: ar_element.ValueSpeficationElement) -> None: + def _write_value_specification_element(self, elem: ar_element.ValueSpecificationElement) -> None: """ Switched writer for value specification elements """ diff --git a/tests/xml/test_software_component_builder.py b/tests/xml/test_software_component_builder.py new file mode 100644 index 0000000..39df6e9 --- /dev/null +++ b/tests/xml/test_software_component_builder.py @@ -0,0 +1,167 @@ +"""Unit tests for programmatically building components and save them as XML""" + +# pylint: disable=missing-class-docstring, missing-function-docstring +import os +import sys +import unittest +from typing import Any +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../src'))) +import autosar.xml.element as ar_element # noqa E402 +import autosar # noqa E402 + + +def create_packages(workspace: autosar.xml.workspace.Workspace) -> dict[str, ar_element.Package]: + """ + Creates the packages needed for unit tests + """ + packages = dict(zip(["PlatformBaseTypes", + "PlatformImplementationDataTypes", + "PlatformDataConstraints", + "PlatformCompuMethods", + "Constants", + "PortInterfaces", + "ComponentTypes"], + workspace.make_packages("AUTOSAR_Platform/BaseTypes", + "AUTOSAR_Platform/ImplementationDataTypes", + "AUTOSAR_Platform/DataConstraints", + "AUTOSAR_Platform/CompuMethods", + "Constants", + "PortInterfaces", + "ComponentTypes"))) + return packages + + +def create_platform_types(packages: dict[str, ar_element.Package]): + """ + Creates necessary platform types + """ + boolean_base_type = ar_element.SwBaseType('boolean', size=8, encoding="BOOLEAN") + packages["PlatformBaseTypes"].append(boolean_base_type) + uint8_base_type = ar_element.SwBaseType('uint8', size=8) + packages["PlatformBaseTypes"].append(uint8_base_type) + uint16_base_type = ar_element.SwBaseType('uint16', size=16) + packages["PlatformBaseTypes"].append(uint16_base_type) + uint32_base_type = ar_element.SwBaseType('uint32', size=32) + packages["PlatformBaseTypes"].append(uint32_base_type) + boolean_data_constr = ar_element.DataConstraint.make_internal("boolean_DataConstr", 0, 1) + packages["PlatformDataConstraints"].append(boolean_data_constr) + computation = ar_element.Computation.make_value_table(["FALSE", "TRUE"]) + boolean_compu_method = ar_element.CompuMethod(name="boolean_CompuMethod", + category="TEXTTABLE", + int_to_phys=computation) + packages["PlatformCompuMethods"].append(boolean_compu_method) + sw_data_def_props = ar_element.SwDataDefPropsConditional(base_type_ref=uint8_base_type.ref(), + data_constraint_ref=boolean_data_constr.ref(), + compu_method_ref=boolean_compu_method.ref()) + boolean_impl_type = ar_element.ImplementationDataType("boolean", + category="VALUE", + sw_data_def_props=sw_data_def_props) + packages["PlatformImplementationDataTypes"].append(boolean_impl_type) + sw_data_def_props = ar_element.SwDataDefPropsConditional(base_type_ref=uint8_base_type.ref()) + uint8_impl_type = ar_element.ImplementationDataType("uint8", + category="VALUE", + sw_data_def_props=sw_data_def_props) + packages["PlatformImplementationDataTypes"].append(uint8_impl_type) + sw_data_def_props = ar_element.SwDataDefPropsConditional(base_type_ref=uint16_base_type.ref()) + uint16_impl_type = ar_element.ImplementationDataType("uint16", + category="VALUE", + sw_data_def_props=sw_data_def_props) + packages["PlatformImplementationDataTypes"].append(uint16_impl_type) + sw_data_def_props = ar_element.SwDataDefPropsConditional(base_type_ref=uint32_base_type.ref()) + uint32_impl_type = ar_element.ImplementationDataType("uint32", + category="VALUE", + sw_data_def_props=sw_data_def_props) + packages["PlatformImplementationDataTypes"].append(uint32_impl_type) + + +def create_vehicle_speed_interface(packages: dict[str, ar_element.Package]) -> ar_element.SenderReceiverInterface: + """ + Create sender-receiver port interfaces used in example + """ + uint16_impl_t = packages["PlatformImplementationDataTypes"].find("uint16") + port_interface = ar_element.SenderReceiverInterface("VehicleSpeed_I") + port_interface.create_data_element("VehicleSpeed", type_ref=uint16_impl_t.ref()) + packages["PortInterfaces"].append(port_interface) + return port_interface + + +def create_init_value(packages, name: str, value: Any) -> ar_element.ConstantSpecification: + """ + Creates VehicleSpeed init value + """ + constant = ar_element.ConstantSpecification.make_constant(name, value) + packages["Constants"].append(constant) + return constant + + +def create_application_swc(packages): + """ + Creates application SW component + """ + swc = ar_element.ApplicationSoftwareComponentType("MyApplication") + packages["ComponentTypes"].append(swc) + return swc + + +class TestSenderPort(unittest.TestCase): + + def test_init_value_ref(self): + workspace = autosar.xml.Workspace() + packages = create_packages(workspace) + create_platform_types(packages) + port_interface = create_vehicle_speed_interface(packages) + init_value = create_init_value(packages, "VehicleSpeed_IV", 65535) + swc = create_application_swc(packages) + port = swc.create_provide_port("VehicleSpeed", port_interface, com_spec={'init_value_ref': init_value.ref()}) + self.assertIsInstance(port, ar_element.ProvidePortPrototype) + com_spec: ar_element.NonqueuedSenderComSpec = port.com_spec[0] + self.assertIsInstance(com_spec, ar_element.NonqueuedSenderComSpec) + self.assertIsInstance(com_spec.init_value, ar_element.ConstantReference) + self.assertEqual(str(com_spec.init_value.constant_ref), "/Constants/VehicleSpeed_IV") + + def test_numerical_init_value(self): + workspace = autosar.xml.Workspace() + packages = create_packages(workspace) + create_platform_types(packages) + port_interface = create_vehicle_speed_interface(packages) + swc = create_application_swc(packages) + port = swc.create_provide_port("VehicleSpeed", port_interface, com_spec={'init_value': 65535}) + self.assertIsInstance(port, ar_element.ProvidePortPrototype) + com_spec: ar_element.NonqueuedSenderComSpec = port.com_spec[0] + self.assertIsInstance(com_spec, ar_element.NonqueuedSenderComSpec) + self.assertIsInstance(com_spec.init_value, ar_element.NumericalValueSpecification) + self.assertEqual(com_spec.init_value.value, 65535) + + +class TestReceiverPort(unittest.TestCase): + + def test_init_value_ref(self): + workspace = autosar.xml.Workspace() + packages = create_packages(workspace) + create_platform_types(packages) + port_interface = create_vehicle_speed_interface(packages) + init_value = create_init_value(packages, "VehicleSpeed_IV", 65535) + swc = create_application_swc(packages) + port = swc.create_require_port("VehicleSpeed", port_interface, com_spec={'init_value_ref': init_value.ref()}) + self.assertIsInstance(port, ar_element.RequirePortPrototype) + com_spec: ar_element.NonqueuedReceiverComSpec = port.com_spec[0] + self.assertIsInstance(com_spec, ar_element.NonqueuedReceiverComSpec) + self.assertIsInstance(com_spec.init_value, ar_element.ConstantReference) + self.assertEqual(str(com_spec.init_value.constant_ref), "/Constants/VehicleSpeed_IV") + + def test_numerical_init_value(self): + workspace = autosar.xml.Workspace() + packages = create_packages(workspace) + create_platform_types(packages) + port_interface = create_vehicle_speed_interface(packages) + swc = create_application_swc(packages) + port = swc.create_require_port("VehicleSpeed", port_interface, com_spec={'init_value': 65535}) + self.assertIsInstance(port, ar_element.RequirePortPrototype) + com_spec: ar_element.NonqueuedReceiverComSpec = port.com_spec[0] + self.assertIsInstance(com_spec, ar_element.NonqueuedReceiverComSpec) + self.assertIsInstance(com_spec.init_value, ar_element.NumericalValueSpecification) + self.assertEqual(com_spec.init_value.value, 65535) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/xml/test_software_component.py b/tests/xml/test_software_component_elements.py similarity index 99% rename from tests/xml/test_software_component.py rename to tests/xml/test_software_component_elements.py index 01ee576..39d5cf1 100644 --- a/tests/xml/test_software_component.py +++ b/tests/xml/test_software_component_elements.py @@ -1,4 +1,4 @@ -"""Unit tests for software components""" +"""Unit tests for reading/writing software component elements""" # pylint: disable=missing-class-docstring, missing-function-docstring import os