diff --git a/CHANGELOG.md b/CHANGELOG.md index c1dc896..c57efa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,57 @@ Non-collectable elements are various sub-elements to collectable elements. ## [Unreleased] +### Added + +#### XML - Software component elements + +* PModeGroupInAtomicSwcInstanceRef | P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF +* POperationInAtomicSwcInstanceRef | P-OPERATION-IN-ATOMIC-SWC-INSTANCE-REF +* PTriggerInAtomicSwcTypeInstanceRef | P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF +* RModeInAtomicSwcInstanceRef | R-MODE-IN-ATOMIC-SWC-INSTANCE-REF +* RTriggerInAtomicSwcInstanceRef | R-TRIGGER-IN-ATOMIC-SWC-INSTANCE-REF +* RVariableInAtomicSwcInstanceRef | R-VARIABLE-IN-ATOMIC-SWC-INSTANCE-REF + +#### XML - SWC internal behavior elements + +* AsynchronousServerCallReturnsEvent | ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT +* BackgroundEvent | BACKGROUND-EVENT +* DataReceivedEvent | DATA-RECEIVED-EVENT +* DataReceiveErrorEvent | DATA-RECEIVE-ERROR-EVENT +* DataSendCompletedEvent | DATA-SEND-COMPLETED-EVENT +* DataWriteCompletedEvent | DATA-WRITE-COMPLETED-EVENT +* ExclusiveAreaRefConditional | EXCLUSIVE-AREA-REF-CONDITIONAL +* ExecutableEntityActivationReason | EXECUTABLE-ENTITY-ACTIVATION-REASON +* ExternalTriggerOccurredEvent | EXTERNAL-TRIGGER-OCCURRED-EVENT +* InitEvent | INIT-EVENT +* InternalTriggerOccurredEvent | INTERNAL-TRIGGER-OCCURRED-EVENT +* ModeSwitchedAckEvent | MODE-SWITCHED-ACK-EVENT +* OperationInvokedEvent | OPERATION-INVOKED-EVENT +* RunnableEntity | RUNNABLE-ENTITY +* SwcInternalBehavior | SWC-INTERNAL-BEHAVIOR (Partly implemented) + * events + * runnables +* SwcModeManagerErrorEvent | SWC-MODE-MANAGER-ERROR-EVENT +* SwcModeSwitchEvent | SWC-MODE-SWITCH-EVENT +* TimingEvent | TIMING-EVENT +* TransformerHardErrorEvent | TRANSFORMER-HARD-ERROR-EVENT + +#### XML - Reference elements + +* AbstractProvidedPortPrototypeRef +* AbstractRequiredPortPrototypeRef +* AsynchronousServerCallResultPointRef +* ExclusiveAreaNestingOrderRef +* ExclusiveAreaRef +* InternalTriggeringPointRef +* ModeSwitchPointRef +* RunnableEntityRef +* SwcImplementationRef +* SwcInternalBehaviorRef +* TriggerRef +* VariableAccessRef + + ### Fixed * Fixed parsing error on elements containing `ADMIN-DATA`. @@ -68,6 +119,7 @@ Non-collectable elements are various sub-elements to collectable elements. * AutosarVariableRef | AUTOSAR-VARIABLE-REF * VariableAccess | VARIABLE-ACCESS * VariableInAtomicSWCTypeInstanceRef | VARIABLE-IN-ATOMIC-SWC-TYPE-INSTANCE-REF +* SwcImplementation | SWC-IMPLEMENTATION #### XML - Reference elements diff --git a/README.md b/README.md index f7c2df5..cf61615 100644 --- a/README.md +++ b/README.md @@ -211,11 +211,23 @@ List of convenience-methods: * `ProvidePortComSpec.make_non_queued_sender_com_spec` * `ProvidePortComSpec.make_from_port_interface` * `RequirePortComSpec.make_non_queued_receiver_com_spec` -* `SwComponentType.create_provide_port` -* `SwComponentType.create_require_port` +* `AtomicSoftwareComponentType.create_internal_behavior` +* `SwComponentType.create_p_port` +* `SwComponentType.create_r_port` * `SwComponentType.create_pr_port` * `CompositionSwComponentType.create_component_prototype` * `CompositionSwComponentType.create_connector` +* `SwcInternalBehavior.create_runnable` +* `SwcInternalBehavior.create_background_event` +* `SwcInternalBehavior.create_data_receive_error_event` +* `SwcInternalBehavior.create_data_received_event` +* `SwcInternalBehavior.create_data_send_completed_event` +* `SwcInternalBehavior.create_data_write_completed_event` +* `SwcInternalBehavior.create_init_event` +* `SwcInternalBehavior.create_operation_invoked_event` +* `SwcInternalBehavior.create_swc_mode_manager_error_event` +* `SwcInternalBehavior.create_swc_mode_mode_switch_event` +* `SwcInternalBehavior.create_timing_event` ## Python Module Hierachy @@ -247,14 +259,21 @@ Below is a rough roadmap of planned releases. **v0.5.4:** SwcInternalBehavior - basics * Runnables -* Basic event support (Init, Periodic, ModeSwitch) +* Events **v0.5.5** SwcInternalBehavior - ports * Port-access * Port-API options -**v0.5.6** Add some missing elements and functions that wasn't prioritized before. +**v0.5.6** Fixes and refactoring + +* Fix some early design mistakes +* Harmonize some member names to better match "qualified name" from XSD (BREAKING CHANGE) + * For the most part this means that several class members will have its "_ref" suffix stripped from its name. +* Attempt to break apart large Python files into smaller ones. + +**v0.5.7** Add some missing elements and functions that wasn't prioritized before. **v0.6.0:** Stable version, publish to PyPI. diff --git a/examples/generator/data_types/READMe.md b/examples/generator/data_types/READMe.md new file mode 100644 index 0000000..8cb3b21 --- /dev/null +++ b/examples/generator/data_types/READMe.md @@ -0,0 +1,9 @@ +# RTE generator examples + +Proof of concept examples for generating type definitions using the RTE generator. + +Examples: + +- Single ImplementationDataType (scalar) +- Array of ImplementationDataTypes (array) +- Struct with ImplementationDataTypes members (record) diff --git a/examples/template/README.md b/examples/template/README.md new file mode 100644 index 0000000..904cc9e --- /dev/null +++ b/examples/template/README.md @@ -0,0 +1,76 @@ +# Template Example + +Demonstrates how to apply template objects in a workspace. + +## Template objects + +Template objects enables developers to describe how ARXML elements should be created without specifying its final location. +Think of it like recipes for ARXML elements. +Most importantly it allows us to describe the dependencies between elements. This helps greatly when working in large scale projects with multiple developers. + +To assist with their creation, a template factory (see [factory.py](demo_system/factory.py)) needs to be written. New template objects are then declared by calling on the various factory methods. For example, a relatively complex data type can now be declared using a single line of Python code (see [datatype.py](demo_system/datatype.py)). + +## Namespaces + +Before applying template objects we first need to declare one or more namespaces in our workspace. + +A namespace is a mapping that decides in what package each new element should be placed. Data types goes into one package, port-interfaces into another and so on. + +In short, namespaces handles the creation of packages while templates handles the creation of ARXML elements in those packages. + +### Applying templates + +Templates are applied in a workspace using the `Workspace.apply` method. +In general, applying template objects requires 4 steps. + +1. Create an empty workspace. +2. In the workspace, create one or more namespaces (a default is fine). +3. Call the `Workspace.apply` method with the template object as argument. +4. Save the workspace as ARXML + +During step 3, Python AUTOSAR not only creates the element itself, it automatically creates all elements +that it depends on (data types, port interfaces, modes etc.). + +In the two Python scripts found in this directory you will see examples how an entire ARXML project is generated from a single line of code: + +```python +workspace.apply(component.CompositionComponent) +``` + +This will create all ARXML elements that the compositin SWC depends on such as: + +- Data types +- Port interfaces +- Constants +- Mode declarations +- inner (or child) SWCs + +If you look closely in the examples you will notice that it handles the platform types differently. Normally, unused elements are skipped but +this special step forces them to be generated in the project even if they are unused/unreferenced. This is used as to not confuse the toolchain that will read the ARXML files later. + +## Generation with config + +The recomended way is to use a config file which are loaded into the workspace during its creation. See [config.toml](config.toml) for an example. + +With a config file you can create both namespaces as well as the destination ARXML file names. This greatly helps with steps 2 and 4 above. +For a full example, see [generate_xml_using_config.py](generate_xml_using_config.py). + +## Generation without config + +It's possible to accomplish the same result without using a config file. It requires a bit more code setting up the workspace. +See [generate_xml_without_config.py](generate_xml_without_config.py) for a full example of that. + +## Advantages and disadvantages using template objects + +It's recommended to use template objects in medium to large projects that has multiple team members. + +Advantages: + +- Possible to track dependencies between elements. +- Prevents generating duplicate elements. +- The generated ARXML files will generate exactly what's currently in use (No unused elements). +- Easy to resolve merge conflicts when Python files are changed by different developers. + +Disadantages: + +- It takes a lot of time to setup. The hardest part is to to write and maintain the factory layer (see [factory.py](demo_system/factory.py)). diff --git a/examples/template/config.toml b/examples/template/config.toml index 3d7eb26..2fb392c 100644 --- a/examples/template/config.toml +++ b/examples/template/config.toml @@ -33,3 +33,13 @@ element_types = "SwComponentType" suffix_filters = ["_Implementation"] +[behavior] + background_event_prefix = "BT_" + data_receive_error_event_prefix = "DRET_" + data_receive_event_prefix = "DRT_" + init_event_prefix = "IT_" + operation_invoked_event_prefix = "OIT_" + swc_mode_manager_error_event_prefix = "MMET_" + swc_mode_switch_event_prefix = "MST_" + timing_event_prefix = "TMT_" + diff --git a/examples/template/demo_system/README.md b/examples/template/demo_system/README.md new file mode 100644 index 0000000..b52219c --- /dev/null +++ b/examples/template/demo_system/README.md @@ -0,0 +1,24 @@ +# Demo System Example + +This folder contains an example which demonstrates how the template mechanism is intended to be used. + +## Software layers + +This example uses 3 layers. At the bottom we have the Python AUTOSAR XML API (This git repo). +The [Factory](factory.py) layer enables an easy way to create commonly used elements such as data types and port-interfaces. +It acts like an abstraction layer, hiding most of the low-level details seen in the Python AUTOSAR XML API. + +1. Template element layer +2. Factory layer +3. Python AUTOSAR XML layer + +## components + +The file [component.py](component.py) contains 3 example SWCs: + +- ReceiverComponent (ApplicationSoftwareComponentType) +- TimerComponent (ApplicationSoftwareComponentType) +- CompositionComponent (CompositionSwComponentType) + +The composition "CompositionComponent" wraps the two application SWCs and create some connectors between them. +The component TimerComponent provides a timer API (Client-server-interface) that the ReceiverComponent uses. diff --git a/examples/template/demo_system/component.py b/examples/template/demo_system/component.py index ba7601e..c2457cc 100644 --- a/examples/template/demo_system/component.py +++ b/examples/template/demo_system/component.py @@ -5,25 +5,35 @@ import autosar.xml.element as ar_element +import autosar.xml.enumeration as ar_enum import autosar.xml.workspace as ar_workspace from . import factory, portinterface, constants NAMESPACE = "Default" -def create_ReceiverComponent(_0: ar_element.Package, +def create_ReceiverComponent(package: ar_element.Package, workspace: ar_workspace.Workspace, deps: dict[str, ar_element.ARElement] | None, **_1) -> ar_element.ApplicationSoftwareComponentType: """ - Create Receiver component type + Receiver ports: + - EngineSpeed + - VehicleSpeed + Client ports: + - FreeRunningTimer """ timer_interface = deps[portinterface.FreeRunningTimer_I.ref(workspace)] vehicle_speed_interface = deps[portinterface.VehicleSpeed_I.ref(workspace)] engine_speed_interface = deps[portinterface.EngineSpeed_I.ref(workspace)] + ecu_mode_interface = deps[portinterface.EcuM_CurrentMode_I.ref(workspace)] engine_speed_init = deps[constants.EngineSpeed_IV.ref(workspace)] vehicle_speed_init = deps[constants.VehicleSpeed_IV.ref(workspace)] - swc = ar_element.ApplicationSoftwareComponentType("ReceiverComponent") + swc_name = "ReceiverComponent" + swc = ar_element.ApplicationSoftwareComponentType(swc_name) + package.append(swc) + swc.create_require_port("EcuM_CurrentMode", ecu_mode_interface, com_spec={"enhanced_mode_api": False, + "supports_async": False}) swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={"init_value": engine_speed_init.ref(), "alive_timeout": 0, "enable_update": False, @@ -37,30 +47,48 @@ def create_ReceiverComponent(_0: ar_element.Package, "handle_never_received": False }) swc.create_require_port("FreeRunningTimer", timer_interface) - swc.create_internal_behavior() + init_runnable_name = swc_name + '_Init' + periodic_runnable_name = swc_name + '_Run' + behavior = swc.create_internal_behavior() + behavior.create_runnable(init_runnable_name) + behavior.create_runnable(periodic_runnable_name) + behavior.create_swc_mode_mode_switch_event(init_runnable_name, + "EcuM_CurrentMode/RUN", + ar_enum.ModeActivationKind.ON_ENTRY) + behavior.create_timing_event(periodic_runnable_name, 20.0 / 1000) return swc -def create_TimerComponent(_0: ar_element.Package, +def create_TimerComponent(package: ar_element.Package, workspace: ar_workspace.Workspace, deps: dict[str, ar_element.ARElement] | None, - **_1) -> ar_element.ApplicationSoftwareComponentType: + **_0) -> ar_element.ApplicationSoftwareComponentType: """ Create TimerComponent component type """ timer_interface = deps[portinterface.FreeRunningTimer_I.ref(workspace)] swc = ar_element.ApplicationSoftwareComponentType("TimerComponent") + package.append(swc) swc.create_provide_port("FreeRunningTimer", timer_interface, com_spec={"GetTime": {"queue_length": 1}, "IsTimerElapsed": {"queue_length": 1} }) - swc.create_internal_behavior() + behavior = swc.create_internal_behavior() + init_runnable_name = swc.name + "_Init" + get_time_runnable_name = swc.name + "_GetTime" + timer_elapsed_runnable_name = swc.name + "_IsTimerElapsed" + behavior.create_runnable(init_runnable_name) + behavior.create_runnable(get_time_runnable_name, reentrancy_level=ar_enum.ReentrancyLevel.NON_REENTRANT) + behavior.create_runnable(timer_elapsed_runnable_name, reentrancy_level=ar_enum.ReentrancyLevel.NON_REENTRANT) + behavior.create_init_event(init_runnable_name) + behavior.create_operation_invoked_event(get_time_runnable_name, "FreeRunningTimer/GetTime") + behavior.create_operation_invoked_event(timer_elapsed_runnable_name, "FreeRunningTimer/IsTimerElapsed") return swc def create_composition_component(package: ar_element.Package, workspace: ar_workspace.Workspace, deps: dict[str, ar_element.ARElement] | None, - **_1) -> ar_element.ApplicationSoftwareComponentType: + **_0) -> ar_element.ApplicationSoftwareComponentType: """ Creates a composition component The created swc must be manually added to the package, otherwise the @@ -77,6 +105,7 @@ def create_composition_component(package: ar_element.Package, assert isinstance(receiver_component, ar_element.ApplicationSoftwareComponentType) assert isinstance(timer_component, ar_element.ApplicationSoftwareComponentType) swc = ar_element.CompositionSwComponentType("CompositionComponent") + package.append(swc) swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={"init_value": engine_speed_init.ref(), "uses_end_to_end_protection": False}) swc.create_require_port("VehicleSpeed", vehicle_speed_interface, com_spec={"init_value": vehicle_speed_init.ref(), @@ -84,8 +113,6 @@ def create_composition_component(package: ar_element.Package, swc.create_component_prototype(receiver_component) swc.create_component_prototype(timer_component) - # Element must be added to workspace before connectors can be created - package.append(swc) swc.create_connector("TimerComponent/FreeRunningTimer", "ReceiverComponent/FreeRunningTimer", workspace) swc.create_connector("VehicleSpeed", "ReceiverComponent/VehicleSpeed", workspace) swc.create_connector("EngineSpeed", "ReceiverComponent/EngineSpeed", workspace) @@ -95,7 +122,8 @@ def create_composition_component(package: ar_element.Package, ReceiverComponent = factory.GenericComponentTypeTemplate("ReceiverComponent", NAMESPACE, create_ReceiverComponent, - depends=[portinterface.EngineSpeed_I, + depends=[portinterface.EcuM_CurrentMode_I, + portinterface.EngineSpeed_I, portinterface.VehicleSpeed_I, portinterface.FreeRunningTimer_I, constants.EngineSpeed_IV, @@ -118,5 +146,4 @@ def create_composition_component(package: ar_element.Package, constants.EngineSpeed_IV, constants.VehicleSpeed_IV, ReceiverComponent_Implementation, - TimerComponent_Implementation], - append_to_package=False) + TimerComponent_Implementation]) diff --git a/examples/template/demo_system/datatype.py b/examples/template/demo_system/datatype.py index c60a115..69153a4 100644 --- a/examples/template/demo_system/datatype.py +++ b/examples/template/demo_system/datatype.py @@ -8,4 +8,4 @@ NAMESPACE = "Default" -InactiveActive_T = factory.ImplementationEnumDataTypeTemplate("InactiveActive_T", "Default", platform.BaseTypes.uint8, ["InactiveActive_Inactive", "InactiveActive_Active"]) +InactiveActive_T = factory.ImplementationEnumDataTypeTemplate("InactiveActive_T", NAMESPACE, platform.BaseTypes.uint8, ["InactiveActive_Inactive", "InactiveActive_Active"]) diff --git a/examples/template/demo_system/factory.py b/examples/template/demo_system/factory.py index e76d5aa..ffab03f 100644 --- a/examples/template/demo_system/factory.py +++ b/examples/template/demo_system/factory.py @@ -362,7 +362,7 @@ def __init__(self, namespace_name: str, create_func: CreateFuncType, depends: list[TemplateBase] | None = None, - append_to_package: bool = True) -> None: + append_to_package: bool = False) -> None: super().__init__(element_name, namespace_name, ar_enum.PackageRole.COMPONENT_TYPE, depends, append_to_package) self.create_func = create_func diff --git a/examples/template/demo_system/portinterface.py b/examples/template/demo_system/portinterface.py index 5107c65..8d9dc62 100644 --- a/examples/template/demo_system/portinterface.py +++ b/examples/template/demo_system/portinterface.py @@ -44,7 +44,7 @@ def create_free_running_timer_interface(_0: str, operation.create_out_argument("result", type_ref=boolean_impl_type.ref()) return port_interface -EcuM_CurrentMode = factory.ModeSwitchInterfaceTemplate("EcuM_CurrentMode", NAMESPACE, mode.EcuM_Mode, "currentMode", is_service=True) +EcuM_CurrentMode_I = factory.ModeSwitchInterfaceTemplate("EcuM_CurrentMode_I", NAMESPACE, mode.EcuM_Mode, "currentMode", is_service=True) NvMService_I = factory.GenericPortInterfaceTemplate("NvMService_I", NAMESPACE, create_NvMService_interface) FreeRunningTimer_I = factory.GenericPortInterfaceTemplate("FreeRunningTimer_I", NAMESPACE, diff --git a/examples/template/generate_xml_without_config.py b/examples/template/generate_xml_without_config.py index 84f3ac8..ac7f6b2 100644 --- a/examples/template/generate_xml_without_config.py +++ b/examples/template/generate_xml_without_config.py @@ -32,6 +32,21 @@ def create_namespaces(workspace: ar_workspace.Workspace): base_ref="/") +def create_behavior_settings(workspace: ar_workspace.Workspace): + """ + Define default event name prefixess + """ + workspace.behavior_settings.update({ + "background_event_prefix": "BT_", + "data_receive_error_event_prefix": "DRET_", + "data_receive_event_prefix": "DRT_", + "init_event_prefix": "IT_", + "operation_invoked_event_prefix": "OIT_", + "swc_mode_manager_error_event_prefix": "MMET_", + "swc_mode_switch_event_prefix": "MST_", + "timing_event_prefix": "TMT_"}) + + def create_documents(workspace: ar_workspace.Workspace) -> None: """ Creates documents @@ -65,12 +80,13 @@ def apply_component_types(workspace: ar_workspace.Workspace): def main(): """Main""" - workspace = ar_workspace.Workspace(document_root="generated") + document_root = os.path.join(os.path.dirname(__file__), "generated") + workspace = ar_workspace.Workspace(document_root=document_root) create_namespaces(workspace) + create_behavior_settings(workspace) create_documents(workspace) apply_platform_types(workspace) apply_component_types(workspace) - workspace.set_document_root(os.path.join(os.path.dirname(__file__), "generated")) workspace.write_documents() print("Done") diff --git a/examples/template/generated/PortInterfaces.arxml b/examples/template/generated/PortInterfaces.arxml index de8d0a3..ec96e2b 100644 --- a/examples/template/generated/PortInterfaces.arxml +++ b/examples/template/generated/PortInterfaces.arxml @@ -1,6 +1,35 @@ + + ModeDclrGroups + + + EcuM_Mode + /ModeDclrGroups/EcuM_Mode/STARTUP + + + STARTUP + + + RUN + + + POST_RUN + + + SLEEP + + + WAKEUP + + + SHUTDOWN + + + + + PortInterfaces @@ -22,6 +51,14 @@ + + EcuM_CurrentMode_I + true + + currentMode + /ModeDclrGroups/EcuM_Mode + + FreeRunningTimer_I diff --git a/examples/template/generated/ReceiverComponent.arxml b/examples/template/generated/ReceiverComponent.arxml index 3ee7794..af8925a 100644 --- a/examples/template/generated/ReceiverComponent.arxml +++ b/examples/template/generated/ReceiverComponent.arxml @@ -7,6 +7,17 @@ ReceiverComponent + + EcuM_CurrentMode + + + false + /PortInterfaces/EcuM_CurrentMode_I/currentMode + false + + + /PortInterfaces/EcuM_CurrentMode_I + EngineSpeed @@ -51,6 +62,33 @@ ReceiverComponent_InternalBehavior + + + MST_ReceiverComponent_Init + /ComponentTypes/ReceiverComponent/ReceiverComponent_InternalBehavior/ReceiverComponent_Init + ON-ENTRY + + + /ComponentTypes/ReceiverComponent/EcuM_CurrentMode + /PortInterfaces/EcuM_CurrentMode_I/currentMode + /ModeDclrGroups/EcuM_Mode/RUN + + + + + TMT_ReceiverComponent_Run + /ComponentTypes/ReceiverComponent/ReceiverComponent_InternalBehavior/ReceiverComponent_Run + 0.02 + + + + + ReceiverComponent_Init + + + ReceiverComponent_Run + + diff --git a/examples/template/generated/TimerComponent.arxml b/examples/template/generated/TimerComponent.arxml index e6599fb..fe7ee6a 100644 --- a/examples/template/generated/TimerComponent.arxml +++ b/examples/template/generated/TimerComponent.arxml @@ -25,6 +25,41 @@ TimerComponent_InternalBehavior + + + IT_TimerComponent_Init + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_Init + + + OIT_TimerComponent_GetTime_FreeRunningTimer_GetTime + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_GetTime + + /ComponentTypes/TimerComponent/FreeRunningTimer + /PortInterfaces/FreeRunningTimer_I/GetTime + + + + OIT_TimerComponent_IsTimerElapsed_FreeRunningTimer_IsTimerElapsed + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_IsTimerElapsed + + /ComponentTypes/TimerComponent/FreeRunningTimer + /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed + + + + + + TimerComponent_Init + + + TimerComponent_GetTime + NON-REENTRANT + + + TimerComponent_IsTimerElapsed + NON-REENTRANT + + diff --git a/examples/xml/component/README.md b/examples/xml/component/README.md new file mode 100644 index 0000000..f78a385 --- /dev/null +++ b/examples/xml/component/README.md @@ -0,0 +1,8 @@ +# Component Examples + +Demonstrates how to create software components (SWCs) and store them as ARXML files. + +Currently only two kinds of SWCs are supported: + +- ApplicationSoftwareComponentType +- CompositionSwComponentType \ No newline at end of file diff --git a/examples/xml/component/application_component.py b/examples/xml/component/application_component.py index bd1336f..0e968f1 100644 --- a/examples/xml/component/application_component.py +++ b/examples/xml/component/application_component.py @@ -4,6 +4,35 @@ import os import autosar import autosar.xml.element as ar_element +import autosar.xml.workspace as ar_workspace + + +def create_package_map(workspace: ar_workspace.Workspace): + """ + Creates package map in workspace + """ + workspace.create_package_map({"PlatformBaseTypes": "AUTOSAR_Platform/BaseTypes", + "PlatformImplementationDataTypes": "AUTOSAR_Platform/ImplementationDataTypes", + "PlatformDataConstraints": "AUTOSAR_Platform/DataConstraints", + "PlatformCompuMethods": "AUTOSAR_Platform/CompuMethods", + "Constants": "Constants", + "PortInterfaces": "PortInterfaces", + "ComponentTypes": "ComponentTypes"}) + + +def create_behavior_settings(workspace: ar_workspace.Workspace): + """ + Define default event name prefixess + """ + workspace.behavior_settings.update({ + "background_event_prefix": "BT_", + "data_receive_error_event_prefix": "DRET_", + "data_receive_event_prefix": "DRT_", + "init_event_prefix": "IT_", + "operation_invoked_event_prefix": "OIT_", + "swc_mode_manager_error_event_prefix": "MMET_", + "swc_mode_switch_event_prefix": "MST_", + "timing_event_prefix": "TMT_"}) def create_platform_types(workspace: autosar.xml.Workspace): @@ -97,14 +126,21 @@ def create_application_component(workspace: autosar.xml.Workspace): vehicle_speed_interface = workspace.find_element("PortInterfaces", "VehicleSpeed_I") vehicle_speed_init = workspace.find_element("Constants", "VehicleSpeed_IV") swc = ar_element.ApplicationSoftwareComponentType("SenderComponent") + workspace.add_element("ComponentTypes", swc) swc.create_provide_port("EngineSpeed", engine_speed_interface, com_spec={"init_value": engine_speed_init.ref(), "uses_end_to_end_protection": False, }) swc.create_provide_port("VehicleSpeed", vehicle_speed_interface, com_spec={"init_value": vehicle_speed_init.ref(), "uses_end_to_end_protection": False, }) - swc.create_internal_behavior() - workspace.add_element("ComponentTypes", swc) + init_runnable_name = swc.name + '_Init' + periodic_runnable_name = swc.name + '_Run' + behavior = swc.create_internal_behavior() + behavior.create_runnable(init_runnable_name) + behavior.create_runnable(periodic_runnable_name) + behavior.create_init_event(init_runnable_name) + behavior.create_timing_event(periodic_runnable_name, 0.1) + impl = ar_element.SwcImplementation("SenderComponent_Implementation", behavior_ref=swc.internal_behavior.ref()) workspace.add_element("ComponentTypes", impl) @@ -128,13 +164,8 @@ def main(): Main """ workspace = autosar.xml.Workspace() - workspace.create_package_map({"PlatformBaseTypes": "AUTOSAR_Platform/BaseTypes", - "PlatformImplementationDataTypes": "AUTOSAR_Platform/ImplementationDataTypes", - "PlatformDataConstraints": "AUTOSAR_Platform/DataConstraints", - "PlatformCompuMethods": "AUTOSAR_Platform/CompuMethods", - "Constants": "Constants", - "PortInterfaces": "PortInterfaces", - "ComponentTypes": "ComponentTypes"}) + create_package_map(workspace) + create_behavior_settings(workspace) create_platform_types(workspace) create_sender_receiver_port_interfaces(workspace) create_client_server_interfaces(workspace) diff --git a/examples/xml/component/composition_component.py b/examples/xml/component/composition_component.py index 475c397..4fbd8bb 100644 --- a/examples/xml/component/composition_component.py +++ b/examples/xml/component/composition_component.py @@ -4,6 +4,35 @@ import os import autosar import autosar.xml.element as ar_element +import autosar.xml.workspace as ar_workspace + + +def create_package_map(workspace: ar_workspace.Workspace): + """ + Creates package map in workspace + """ + workspace.create_package_map({"PlatformBaseTypes": "AUTOSAR_Platform/BaseTypes", + "PlatformImplementationDataTypes": "AUTOSAR_Platform/ImplementationDataTypes", + "PlatformDataConstraints": "AUTOSAR_Platform/DataConstraints", + "PlatformCompuMethods": "AUTOSAR_Platform/CompuMethods", + "Constants": "Constants", + "PortInterfaces": "PortInterfaces", + "ComponentTypes": "ComponentTypes"}) + + +def create_behavior_settings(workspace: ar_workspace.Workspace): + """ + Define default event name prefixess + """ + workspace.behavior_settings.update({ + "background_event_prefix": "BT_", + "data_receive_error_event_prefix": "DRET_", + "data_receive_event_prefix": "DRT_", + "init_event_prefix": "IT_", + "operation_invoked_event_prefix": "OIT_", + "swc_mode_manager_error_event_prefix": "MMET_", + "swc_mode_switch_event_prefix": "MST_", + "timing_event_prefix": "TMT_"}) def create_platform_types(workspace: autosar.xml.Workspace): @@ -98,6 +127,7 @@ def create_receiver_component(workspace: autosar.xml.Workspace): vehicle_speed_interface = workspace.find_element("PortInterfaces", "VehicleSpeed_I") vehicle_speed_init = workspace.find_element("Constants", "VehicleSpeed_IV") swc = ar_element.ApplicationSoftwareComponentType("ReceiverComponent") + workspace.add_element("ComponentTypes", swc) swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={"init_value": engine_speed_init.ref(), "alive_timeout": 0, "enable_update": False, @@ -111,9 +141,15 @@ def create_receiver_component(workspace: autosar.xml.Workspace): "handle_never_received": False }) swc.create_require_port("FreeRunningTimer", timer_interface, com_spec={"GetTime": {}, "IsTimerElapsed": {}}) - swc.create_internal_behavior() - workspace.add_element("ComponentTypes", swc) - impl = ar_element.SwcImplementation("ReceiverComponent_Implementation", behavior_ref=swc.internal_behavior.ref()) + + init_runnable_name = swc.name + '_Init' + periodic_runnable_name = swc.name + '_Run' + behavior = swc.create_internal_behavior() + behavior.create_runnable(init_runnable_name) + behavior.create_runnable(periodic_runnable_name) + behavior.create_init_event(init_runnable_name) + behavior.create_timing_event(periodic_runnable_name, 0.1) + impl = ar_element.SwcImplementation("ReceiverComponent_Implementation", behavior_ref=behavior.ref()) workspace.add_element("ComponentTypes", impl) @@ -123,12 +159,21 @@ def create_server_component(workspace: autosar.xml.Workspace): """ timer_interface = workspace.find_element("PortInterfaces", "FreeRunningTimer_I") swc = ar_element.ApplicationSoftwareComponentType("TimerComponent") + workspace.add_element("ComponentTypes", swc) swc.create_provide_port("FreeRunningTimer", timer_interface, com_spec={"GetTime": {"queue_length": 1}, "IsTimerElapsed": {"queue_length": 1} }) - swc.create_internal_behavior() - workspace.add_element("ComponentTypes", swc) - impl = ar_element.SwcImplementation("TimerComponent_Implementation", behavior_ref=swc.internal_behavior.ref()) + init_runnable_name = swc.name + '_Init' + get_time_runnable_name = "TimerComponent_FreeRunningTimer_GetTime" + is_timer_elapsed_runnable_name = "TimerComponent_FreeRunningTimer_IsTimerElapsed" + behavior = swc.create_internal_behavior() + behavior.create_runnable(init_runnable_name) + behavior.create_runnable(get_time_runnable_name) + behavior.create_runnable(is_timer_elapsed_runnable_name) + behavior.create_init_event(init_runnable_name) + behavior.create_operation_invoked_event(get_time_runnable_name, "FreeRunningTimer/GetTime") + behavior.create_operation_invoked_event(is_timer_elapsed_runnable_name, "FreeRunningTimer/IsTimerElapsed") + impl = ar_element.SwcImplementation("TimerComponent_Implementation", behavior_ref=behavior.ref()) workspace.add_element("ComponentTypes", impl) @@ -173,13 +218,8 @@ def main(): Main """ workspace = autosar.xml.Workspace() - workspace.create_package_map({"PlatformBaseTypes": "AUTOSAR_Platform/BaseTypes", - "PlatformImplementationDataTypes": "AUTOSAR_Platform/ImplementationDataTypes", - "PlatformDataConstraints": "AUTOSAR_Platform/DataConstraints", - "PlatformCompuMethods": "AUTOSAR_Platform/CompuMethods", - "Constants": "Constants", - "PortInterfaces": "PortInterfaces", - "ComponentTypes": "ComponentTypes"}) + create_package_map(workspace) + create_behavior_settings(workspace) create_platform_types(workspace) create_sender_receiver_port_interfaces(workspace) create_client_server_interfaces(workspace) diff --git a/examples/xml/component/data/ReceiverComponent.arxml b/examples/xml/component/data/ReceiverComponent.arxml index 4be205b..607735b 100644 --- a/examples/xml/component/data/ReceiverComponent.arxml +++ b/examples/xml/component/data/ReceiverComponent.arxml @@ -59,6 +59,25 @@ ReceiverComponent_InternalBehavior + + + IT_ReceiverComponent_Init + /ComponentTypes/ReceiverComponent/ReceiverComponent_InternalBehavior/ReceiverComponent_Init + + + TMT_ReceiverComponent_Run + /ComponentTypes/ReceiverComponent/ReceiverComponent_InternalBehavior/ReceiverComponent_Run + 0.1 + + + + + ReceiverComponent_Init + + + ReceiverComponent_Run + + diff --git a/examples/xml/component/data/SenderComponent.arxml b/examples/xml/component/data/SenderComponent.arxml index 1de0398..d11e6c2 100644 --- a/examples/xml/component/data/SenderComponent.arxml +++ b/examples/xml/component/data/SenderComponent.arxml @@ -41,6 +41,25 @@ SenderComponent_InternalBehavior + + + IT_SenderComponent_Init + /ComponentTypes/SenderComponent/SenderComponent_InternalBehavior/SenderComponent_Init + + + TMT_SenderComponent_Run + /ComponentTypes/SenderComponent/SenderComponent_InternalBehavior/SenderComponent_Run + 0.1 + + + + + SenderComponent_Init + + + SenderComponent_Run + + diff --git a/examples/xml/component/data/TimerComponent.arxml b/examples/xml/component/data/TimerComponent.arxml index e6599fb..0b4dfaa 100644 --- a/examples/xml/component/data/TimerComponent.arxml +++ b/examples/xml/component/data/TimerComponent.arxml @@ -25,6 +25,39 @@ TimerComponent_InternalBehavior + + + IT_TimerComponent_Init + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_Init + + + OIT_TimerComponent_FreeRunningTimer_GetTime_FreeRunningTimer_GetTime + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_FreeRunningTimer_GetTime + + /ComponentTypes/TimerComponent/FreeRunningTimer + /PortInterfaces/FreeRunningTimer_I/GetTime + + + + OIT_TimerComponent_FreeRunningTimer_IsTimerElapsed_FreeRunningTimer_IsTimerElapsed + /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior/TimerComponent_FreeRunningTimer_IsTimerElapsed + + /ComponentTypes/TimerComponent/FreeRunningTimer + /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed + + + + + + TimerComponent_Init + + + TimerComponent_FreeRunningTimer_GetTime + + + TimerComponent_FreeRunningTimer_IsTimerElapsed + + diff --git a/examples/xml/constant/README.md b/examples/xml/constant/README.md new file mode 100644 index 0000000..cd5629e --- /dev/null +++ b/examples/xml/constant/README.md @@ -0,0 +1,3 @@ +# Constant examples + +Demonstrates how to create constants using the ConstantSpecification.make_constant function. diff --git a/examples/xml/constant/create_constants.py b/examples/xml/constant/create_constants.py index f993195..be10aa0 100644 --- a/examples/xml/constant/create_constants.py +++ b/examples/xml/constant/create_constants.py @@ -1,5 +1,5 @@ """ -Demonstrates how you can easily turn plain Python data into ARXML constants objects +Demonstrates how to create ARXML constants """ import os import autosar.xml diff --git a/examples/xml/data_types/README.md b/examples/xml/data_types/README.md new file mode 100644 index 0000000..a5409ee --- /dev/null +++ b/examples/xml/data_types/README.md @@ -0,0 +1,18 @@ +# DataType Examples + +Demonstrates how to create data types and compu-methods in ARXML. + +DataType examples: + +- ApplicationPrimitiveDataType +- ImplementationDataType +- SwBaseType + +CompuMethod examples: + +- CompuMethod with Linear Computation (category="LINEAR") +- CompuMethod with ValueTable Computation (category="TEXTTABLE") + +Other examples: + +- SwAddrMethod diff --git a/examples/xml/port_interface/README.md b/examples/xml/port_interface/README.md new file mode 100644 index 0000000..48b8371 --- /dev/null +++ b/examples/xml/port_interface/README.md @@ -0,0 +1,11 @@ +# Portinterface examples + +Demonstrates how to create port interfaces in ARXML. + +Implemented Examples: + +- ClientServerInterface +- ModeSwitchInterface +- NvDataInterface +- ParameterInterface +- SenderReceiverInterface diff --git a/examples/xml/port_interface/data/mode_declarations.arxml b/examples/xml/port_interface/data/mode_declarations.arxml index 4bfd39e..def741d 100644 --- a/examples/xml/port_interface/data/mode_declarations.arxml +++ b/examples/xml/port_interface/data/mode_declarations.arxml @@ -12,14 +12,17 @@ OFF - ACCESSORY + PARKING - RUNNING + ACCESSORY CRANKING + + RUNNING + diff --git a/examples/xml/port_interface/mode_switch_interface.py b/examples/xml/port_interface/mode_switch_interface.py index 254abc7..dc0acf5 100644 --- a/examples/xml/port_interface/mode_switch_interface.py +++ b/examples/xml/port_interface/mode_switch_interface.py @@ -11,9 +11,10 @@ def create_mode_declaration_groups(workspace: autosar.xml.Workspace): Creates mode declarations """ vehicle_mode = ar_element.ModeDeclarationGroup("VehicleMode", ["OFF", + "PARKING", "ACCESSORY", - "RUNNING", - "CRANKING"]) + "CRANKING", + "RUNNING"]) workspace.add_element("ModeDeclarations", vehicle_mode) vehicle_mode.initial_mode_ref = vehicle_mode.find("OFF").ref() diff --git a/examples/xml/reader/README.md b/examples/xml/reader/README.md new file mode 100644 index 0000000..cbf9d85 --- /dev/null +++ b/examples/xml/reader/README.md @@ -0,0 +1,6 @@ +# Reader Examples + +Demonstrates behaviour when XML reader is handed invalid ARXML files. + +- Invalid data in XML elements +- Elements with duplicated SHORT-NAME diff --git a/examples/xml/reader/print_errors.py b/examples/xml/reader/print_errors.py index 71101f8..61b0144 100644 --- a/examples/xml/reader/print_errors.py +++ b/examples/xml/reader/print_errors.py @@ -1,5 +1,5 @@ """ -SwAddrMethod example +Demonstrates how the XML parser resumes when an error is encountered """ import os import autosar.xml diff --git a/examples/xml/reference/README.md b/examples/xml/reference/README.md new file mode 100644 index 0000000..25f2701 --- /dev/null +++ b/examples/xml/reference/README.md @@ -0,0 +1,3 @@ +# Reference examples + +Demonstrates how to create reference objects and how to convert them back to strings. diff --git a/examples/xml/reference/reference_example.py b/examples/xml/reference/reference_example.py new file mode 100644 index 0000000..f21e82a --- /dev/null +++ b/examples/xml/reference/reference_example.py @@ -0,0 +1,7 @@ +""" +Reference example +""" +import autosar.xml.element as ar_element + +ref = ar_element.ExclusiveAreaRef("/Areas/Area1") +print(str(ref)) diff --git a/examples/xml/unit/README.md b/examples/xml/unit/README.md new file mode 100644 index 0000000..0c227d6 --- /dev/null +++ b/examples/xml/unit/README.md @@ -0,0 +1,3 @@ +# Unit Examples + +Demonstrates how to create unit elements in ARMXL. diff --git a/pyproject.toml b/pyproject.toml index c3673e4..58581c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "autosar" -version = "0.5.4a2" +version = "0.5.4b1" description = "A set of Python modules for working with AUTOSAR XML files" readme = "README.md" requires-python = ">=3.10" diff --git a/run_examples.sh b/run_examples.sh new file mode 100644 index 0000000..5132c5a --- /dev/null +++ b/run_examples.sh @@ -0,0 +1,21 @@ +python examples/xml/data_types/application_data_type.py +python examples/xml/data_types/compu_method_rational.py +python examples/xml/data_types/compu_method_value_table.py +python examples/xml/data_types/implementation_data_type.py +python examples/xml/data_types/sw_addr_method.py +python examples/xml/data_types/sw_base_type.py +python examples/xml/constant/create_constants.py +python examples/xml/unit/unit.py +python examples/xml/port_interface/nv_data_interface.py +python examples/xml/port_interface/parameter_interface.py +python examples/xml/port_interface/sender_receiver_interface.py +python examples/xml/port_interface/client_server_interface.py +python examples/xml/port_interface/mode_switch_interface.py +python examples/xml/component/application_component.py +python examples/xml/component/composition_component.py +python examples/xml/reader/print_errors.py +python examples/template/generate_xml_using_config.py +python examples/template/generate_xml_without_config.py +python examples/generator/data_types/gen_type_defs_scalar.py +python examples/generator/data_types/gen_type_defs_array.py +python examples/generator/data_types/gen_type_defs_record.py \ No newline at end of file diff --git a/run_flake.sh b/run_flake.sh new file mode 100644 index 0000000..0584399 --- /dev/null +++ b/run_flake.sh @@ -0,0 +1,3 @@ +flake8 --max-line-length=120 --ignore=D107,D200,D205,D400,D401 src +flake8 --max-line-length=120 --ignore=D101,D102,D107,D200,D205,D400,D401,E402 tests +flake8 --max-line-length=120 --ignore=D107,D200,D205,D400,D401 examples \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh new file mode 100644 index 0000000..cc2826b --- /dev/null +++ b/run_tests.sh @@ -0,0 +1 @@ +python -m unittest discover -v tests test_*.py \ No newline at end of file diff --git a/src/autosar/base.py b/src/autosar/base.py index d7df89a..5471a6c 100644 --- a/src/autosar/base.py +++ b/src/autosar/base.py @@ -6,12 +6,25 @@ def split_ref(ref: str) -> list[str] | None: - """Splits an autosar reference string into a list of strings""" + """Splits a string separated with slashes and automatially removes leading slash""" + sep = "/" if isinstance(ref, str): - return ref[1:].split('/') if ref[0] == '/' else ref.split('/') + return ref[1:].split(sep) if ref[0] == sep else ref.split(sep) return None +def split_ref_strict(ref: str) -> list[str] | None: + """Splits a strings separated with slashes but throws an error if the string starts with a slash""" + sep = "/" + if not isinstance(ref, str): + raise TypeError("ref: Must be a string") + if len(ref) == 0: + raise ValueError("String cannot be empty") + if ref[0] == sep: + raise ValueError("ref: String cannot start with '/'") + return ref.split(sep) + + class Searchable(abc.ABC): """ Searchable interface diff --git a/src/autosar/xml/base.py b/src/autosar/xml/base.py new file mode 100644 index 0000000..06d67fe --- /dev/null +++ b/src/autosar/xml/base.py @@ -0,0 +1,199 @@ +""" +AUTOSAR XML base classes +""" + +import abc +import re +from typing import Any, Type +from enum import Enum +import autosar.xml.enumeration as ar_enum + + +class ARObject: + """ + Base class for all AUTOSAR objects + """ + + @property + def is_empty(self) -> bool: + """ + True if no value has been set (everything is None) + """ + for value in vars(self).values(): + if isinstance(value, list): + if len(value) > 0: + return False + else: + if value is not None: + return False + return True + + def is_empty_with_ignore(self, ignore_set: set) -> bool: + """ + Same as is_empty but the caller can give + a list of property names to ignore during + check + """ + for key in vars(self).keys(): + if key not in ignore_set: + value = getattr(self, key) + if isinstance(value, list): + if len(value) > 0: + return False + else: + if value is not None: + return False + return True + + def _assign_optional(self, attr_name: str, value: Any, type_name: type) -> None: + """ + Same as _assign but with a None-check + """ + if value is not None: + self._assign(attr_name, value, type_name) + + def _assign(self, attr_name: str, value: Any, type_name: type) -> None: + """ + Assign single value to attribute with type check. + """ + if issubclass(type_name, Enum): + self._set_attr_with_strict_type(attr_name, value, type_name) + elif issubclass(type_name, BaseRef): + self._check_and_set_reference(attr_name, value, type_name) + else: + self._set_attr_with_type_cast(attr_name, value, type_name) + + def _assign_int_or_str_pattern_optional(self, attr_name: str, value: int | str | None, pattern: re.Pattern) -> None: + """ + Same as _assign_int_or_str_pattern but with a None-check + """ + if value is not None: + self._assign_int_or_str_pattern(attr_name, value, pattern) + + def _assign_int_or_str_pattern(self, attr_name: str, value: int | str, pattern: re.Pattern) -> None: + """ + Special assignment-function for values that can be either int or conforms + to a specific regular expression + """ + if isinstance(value, int): + pass + elif isinstance(value, str): + match = pattern.match(value) + if match is None: + raise ValueError(f"Invalid parameter '{value}' for '{attr_name}'") + else: + raise TypeError(f"{attr_name}: Invalid type. Expected (int, str), got '{str(type(value))}'") + setattr(self, attr_name, value) + + def _assign_optional_strict(self, attr_name: str, value: Any, type_name: type) -> None: + """ + Sets object attribute with strict type check + """ + if value is not None: + self._set_attr_with_strict_type(attr_name, value, type_name) + + def _assign_optional_positive_int(self, attr_name, value: int) -> None: + """ + Checks that the optional value is a positive integer before assignment + """ + if value is not None: + self._set_attr_positive_int(attr_name, value) + + def _set_attr_with_strict_type(self, attr_name: str, value: Any, type_class: type) -> None: + """ + Sets object attribute only if the value is matches given type-class + """ + if isinstance(value, type_class): + setattr(self, attr_name, value) + else: + raise TypeError( + f"Invalid type for parameter '{attr_name}'. Expected type {str(type_class)}, got {str(type(value))}") + + def _check_and_set_reference(self, attr_name: str, value: Any, ref_type: Type["BaseRef"]): + """ + Checks reference type compatibility and on success updates the value + """ + accepted_sub_types: set = ref_type.accepted_sub_types() + if (len(accepted_sub_types) == 0) or not isinstance(accepted_sub_types, set): + msg = f"Error in reference type '{str(type(ref_type))}', it doesn't seem to have a valid set of sub-types." + raise RuntimeError(msg) + if isinstance(value, str): + if len(accepted_sub_types) == 1: + new_value = ref_type(value, list(accepted_sub_types)[0]) + else: + raise TypeError("Ambigious value for DEST. Unable to create reference directly from string") + elif isinstance(value, BaseRef): + if type(value) is ref_type or value.dest in accepted_sub_types: # pylint: disable=C0123 + new_value = ref_type(value.value, value.dest) + else: + raise TypeError(f"'{attr_name}': Reference type {str(type(value))}" + f"is incombatible with {str(ref_type)}") + else: + raise TypeError(f"'{attr_name}': Invalid type. " + f"Expected one of (str, {str(ref_type)}), got '{str(type(value))}'") + setattr(self, attr_name, new_value) + + def _set_attr_with_type_cast(self, attr_name: str, value: Any, type_class: type) -> None: + """ + Sets object attribute only if it can be converted to given type. + """ + if type_class in {bool, int, str, float}: + new_value = type_class(value) + else: + raise NotImplementedError(type_class) + setattr(self, attr_name, new_value) + + def _set_attr_positive_int(self, attr_name: str, value: int) -> None: + """ + Checks that value is non-negative before updating attribute + """ + if not isinstance(value, int): + raise TypeError(f"Invalid type for '{attr_name}'. Expected int, got '{str(type(value))}'") + if value < 0: + raise ValueError(f"Positive integer expected: {value}") + setattr(self, attr_name, value) + + def _find_by_name(self, elements: list, name: str): + """ + Iterates through list of elements and return the first whose + name matches the name argument + """ + for elem in elements: + if elem.name == name: + return elem + return None + + +class BaseRef(ARObject, abc.ABC): + """ + Base type for all reference classes + """ + + def __init__(self, + value: str, + dest: ar_enum.IdentifiableSubTypes = None) -> None: + self.value = value + self.dest: ar_enum.IdentifiableSubTypes = None + if dest is None: + if len(self.accepted_sub_types()) == 1: + dest = list(self.accepted_sub_types())[0] + else: + msg_part1 = "Value of dest cannot be None. Accepted values are: " + msg_part2 = ",".join([str(x) for x in sorted(list(self.accepted_sub_types()))]) + raise ValueError(msg_part1 + msg_part2) + if dest in self.accepted_sub_types(): + self.dest = dest + else: + raise ValueError(f"{str(dest)} is not a valid sub-type for {str(type(self))}") + + @classmethod + @abc.abstractmethod + def accepted_sub_types(cls) -> list[ar_enum.IdentifiableSubTypes]: + """ + Subset of ar_enum.IdentifiableSubTypes defining + which enum values are acceptable for dest + """ + + def __str__(self) -> str: + """Returns reference as string""" + return self.value diff --git a/src/autosar/xml/element.py b/src/autosar/xml/element.py index ba36d1a..a375947 100644 --- a/src/autosar/xml/element.py +++ b/src/autosar/xml/element.py @@ -1,16 +1,58 @@ """ -Classes related to AUTOSAR Elements - +Classes related to AUTOSAR XML Elements """ import re from collections.abc import Iterable, Iterator from typing import Any, Union -from enum import Enum -import abc -from autosar.base import split_ref, Searchable + + +from autosar.base import split_ref, split_ref_strict, Searchable +from autosar.xml.base import ARObject, BaseRef import autosar.xml.enumeration as ar_enum import autosar.xml.exception as ar_except +from autosar.xml.reference import (SwBaseTypeRef, # noqa F401 + PackageRef, + CompuMethodRef, + FunctionPtrSignatureRef, + ImplementationDataTypeRef, + SwAddrMethodRef, + DataConstraintRef, + PhysicalDimensionRef, + UnitRef, + IndexDataTypeRef, + ApplicationDataTypeRef, + ApplicationCompositeElementDataPrototypeRef, + AutosarDataTypeRef, + ConstantRef, + VariableDataPrototypeRef, + ParameterDataPrototypeRef, + ApplicationErrorRef, + ModeDeclarationRef, + ModeDeclarationGroupRef, + ModeDeclarationGroupPrototypeRef, + AutosarDataPrototypeRef, + E2EProfileCompatibilityPropsRef, + ClientServerOperationRef, + PortPrototypeRef, + AbstractImplementationDataTypeElementRef, + DataPrototypeRef, + PortInterfaceRef, + SwComponentTypeRef, + SwComponentPrototypeRef, + SwcInternalBehaviorRef, + SwcImplementationRef, + ExclusiveAreaRef, + ExclusiveAreaNestingOrderRef, + AbstractRequiredPortPrototypeRef, + AbstractProvidedPortPrototypeRef, + RunnableEntityRef, + VariableAccessRef, + ModeSwitchPointRef, + AsynchronousServerCallResultPointRef, + TriggerRef, + InternalTriggeringPointRef, + ) alignment_type_re = re.compile( @@ -21,6 +63,8 @@ # Type aliases +BaseReference = BaseRef # This line is simply here to suppress an unused import warning + ValueSpecificationElement = Union["TextValueSpecification", "NumericalValueSpecification", "NotAvailableValueSpecification", @@ -123,150 +167,6 @@ def _validate_value(self, value: int | str) -> int: # Base classes -class ARObject: - """ - Base class for all AUTOSAR objects - """ - - @property - def is_empty(self) -> bool: - """ - True if no value has been set (everything is None) - """ - for value in vars(self).values(): - if isinstance(value, list): - if len(value) > 0: - return False - else: - if value is not None: - return False - return True - - def is_empty_with_ignore(self, ignore_set: set) -> bool: - """ - Same as is_empty but the caller can give - a list of property names to ignore during - check - """ - for key in vars(self).keys(): - if key not in ignore_set: - value = getattr(self, key) - if isinstance(value, list): - if len(value) > 0: - return False - else: - if value is not None: - return False - return True - - def _assign_optional(self, attr_name: str, value: Any, type_name: type) -> None: - """ - Same as _assign but with a None-check - """ - if value is not None: - self._assign(attr_name, value, type_name) - - def _assign(self, attr_name: str, value: Any, type_name: type) -> None: - """ - Assign single value to attribute with type check. - """ - if issubclass(type_name, Enum): - self._set_attr_with_strict_type(attr_name, value, type_name) - elif issubclass(type_name, BaseRef): - self._set_attr_from_str_or_direct(attr_name, value, type_name) - else: - self._set_attr_with_type_cast(attr_name, value, type_name) - - def _assign_int_or_str_pattern_optional(self, attr_name: str, value: int | str | None, pattern: re.Pattern) -> None: - """ - Same as _assign_int_or_str_pattern but with a None-check - """ - if value is not None: - self._assign_int_or_str_pattern(attr_name, value, pattern) - - def _assign_int_or_str_pattern(self, attr_name: str, value: int | str, pattern: re.Pattern) -> None: - """ - Special assignment-function for values that can be either int or conforms - to a specific regular expression - """ - if isinstance(value, int): - pass - elif isinstance(value, str): - match = pattern.match(value) - if match is None: - raise ValueError(f"Invalid parameter '{value}' for '{attr_name}'") - else: - raise TypeError(f"{attr_name}: Invalid type. Expected (int, str), got '{str(type(value))}'") - setattr(self, attr_name, value) - - def _assign_optional_strict(self, attr_name: str, value: Any, type_name: type) -> None: - """ - Sets object attribute with strict type check - """ - if value is not None: - self._set_attr_with_strict_type(attr_name, value, type_name) - - def _assign_optional_positive_int(self, attr_name, value: int) -> None: - """ - Checks that the optional value is a positive integer before assignment - """ - if value is not None: - self._set_attr_positive_int(attr_name, value) - - def _set_attr_with_strict_type(self, attr_name: str, value: Any, type_class: type) -> None: - """ - Sets object attribute only if the value is matches given type-class - """ - if isinstance(value, type_class): - setattr(self, attr_name, value) - else: - raise TypeError( - f"Invalid type for parameter '{attr_name}'. Expected type {str(type_class)}, got {str(type(value))}") - - def _set_attr_from_str_or_direct(self, attr_name: str, value: Any, type_name: type): - """ - Can create new objects from str if necessary - """ - if isinstance(value, str): - new_value = type_name(value) - elif isinstance(value, type_name): - new_value = value - else: - raise TypeError(f"Invalid type for '{attr_name}'" - f". Expected one of (str, {type_name}), got '{str(type(value))}'") - setattr(self, attr_name, new_value) - - def _set_attr_with_type_cast(self, attr_name: str, value: Any, type_class: type) -> None: - """ - Sets object attribute only if it can be converted to given type. - """ - if type_class in {bool, int, str, float}: - new_value = type_class(value) - else: - raise NotImplementedError(type_class) - setattr(self, attr_name, new_value) - - def _set_attr_positive_int(self, attr_name: str, value: int) -> None: - """ - Checks that value is non-negative before updating attribute - """ - if not isinstance(value, int): - raise TypeError(f"Invalid type for '{attr_name}'. Expected int, got '{str(type(value))}'") - if value < 0: - raise ValueError(f"Positive integer expected: {value}") - setattr(self, attr_name, value) - - def _find_by_name(self, elements: list, name: str): - """ - Iterates through list of elements and return the first whose - name matches the name argument - """ - for elem in elements: - if elem.name == name: - return elem - return None - - class Referrable(ARObject): """ Group AR:REFERRABLE @@ -275,15 +175,28 @@ class Referrable(ARObject): def __init__(self, name: str) -> None: self.name: str = name # .SHORT-NAME - self.parent: 'CollectableElement' = None + self.parent: Union["CollectableElement", "PackageCollection", None] = None @property def short_name(self) -> str: """ - Alias for .name + Alias for "name" """ return self.name + def root_collection(self) -> Union["PackageCollection", None]: + """ + Returns the root package collection object or None if it can't be found. + A package collection can be either a Workspace or a Document object depending + on how the packages/elements was created initially. + """ + elem = self + while elem.parent is not None: + elem = elem.parent + if isinstance(elem, PackageCollection): + return elem + return None + class MultiLanguageReferrable(Referrable): """ @@ -518,2607 +431,2119 @@ def append_code_descriptor(self, code_descriptors: Code) -> None: else: raise TypeError("code_descriptors must be of type Code") -# --- Reference elements - - -class BaseRef(ARObject, abc.ABC): - """ - Base type for all reference classes - Complex type AR:REF - Type: Abstract - """ - - def __init__(self, - value: str, - dest: ar_enum.IdentifiableSubTypes) -> None: - self.value = value - self.dest: ar_enum.IdentifiableSubTypes = None - if dest in self._accepted_subtypes(): - self.dest = dest - else: - raise ValueError(f"{str(dest)} is not a valid sub-type for {str(type(self))}") - - @abc.abstractmethod - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """ - Subset of ar_enum.IdentifiableSubTypes defining - which enum values are acceptable for dest - """ - def __str__(self) -> str: - """Returns reference as string""" - return self.value +# --- Documentation Elements -class PackageRef(BaseRef): - """ - References to AR-PACKAGE--SUBTYPES-ENUM +class Break(ARObject): """ + Complex type AR:BR + Type: Concrete + Tag variants: BR - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.AR_PACKAGE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.AR_PACKAGE} - + Same function as the html element. -class CompuMethodRef(BaseRef): """ - CompuMethod reference - """ - - 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""" - return {ar_enum.IdentifiableSubTypes.COMPU_METHOD} - -class FunctionPtrSignatureRef(BaseRef): - """ - Function pointer signature reference +class EmphasisText(ARObject): """ + Complex type AR:EMPHASIS-TEXT + Type: Concrete + Tag variants: E - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.BSW_MODULE_ENTRY) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.BSW_MODULE_ENTRY} + Emphasized text + Limitations: No support for child-elements. Type for argument elements must be string. -class ImplementationDataTypeRef(BaseRef): - """ - ImplementationDataType reference """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE} + def __init__(self, + elements: None | list | str = None, + color: str = None, + font: ar_enum.EmphasisFont = None, + type: ar_enum.EmphasisType = None) -> None: # pylint: disable=redefined-builtin + self.elements = [] + self.color = color # Attribute @COLOR + self.font = font # Attribute @FONT + self.type = type # Attribute @TYPE + if elements is not None: + if isinstance(elements, str): + self.elements.append(elements) + else: + raise NotImplementedError("List of elements not yet supported") -class SwAddrMethodRef(BaseRef): - """ - SwAddrMethod reference +class IndexEntry(ARObject): """ + Complex type AR:INDEX-ENTRY + Type: Concrete + Tag variants: IE - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD} - + Index Entry -class SwBaseTypeRef(BaseRef): - """ - SwBaseType reference + Limitations: Doesn't support sub-elements as seen in XML schema. """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.SW_BASE_TYPE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.SW_BASE_TYPE} + def __init__(self, text: str) -> None: + self.text = text # Text content -class DataConstraintRef(BaseRef): - """ - DataConstraint reference +class TechnicalTerm(ARObject): """ + Complex type AR:TT + Type: Concrete + Tag variants: TT - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.DATA_CONSTR) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.DATA_CONSTR} - + Technical Term -class PhysicalDimensionRef(BaseRef): """ - PhysicalDimension reference - """ - - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.PHYSICAL_DIMENSION) - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.PHYSICAL_DIMENSION} + def __init__(self, + text: str, + tex_render: str = None, + type: str = None) -> None: # pylint: disable=redefined-builtin + self.tex_render = tex_render # attribute @TEX-RENDER + self.type = type # attribute @TYPE + self.text = text # Text content -class UnitRef(BaseRef): - """ - DataConstraint reference +class Subscript(ARObject): """ + Complex type AR:SUPSCRIPT + Type: Concrete + Tag variants: SUB - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.UNIT) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.UNIT} - + Subscript is based on the same Complex type -class IndexDataTypeRef(BaseRef): - """ - IndexDataType reference """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE} + def __init__(self, text: str) -> None: + self.text = text # Simple content -class ApplicationDataTypeRef(BaseRef): - """ - Application data type reference +class Superscript(ARObject): """ + Complex type AR:SUPSCRIPT + Type: Concrete + Tag variants: SUP - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_DEFERRED_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE} - - -class ApplicationCompositeElementDataPrototypeRef(BaseRef): - """ - References to APPLICATION-COMPOSITE-ELEMENT-DATA-PROTOTYPE--SUBTYPES-ENUM + Superscript """ - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_ELEMENT, - ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_ELEMENT_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT, - } - - -class AutosarDataTypeRef(BaseRef): - """ - References to AR:AUTOSAR-DATA-TYPE--SUBTYPES-ENUM - """ + def __init__(self, text: str) -> None: + self.text = text # Simple content - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.ABSTRACT_IMPLEMENTATION_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_DEFERRED_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE, - ar_enum.IdentifiableSubTypes.AUTOSAR_DATA_TYPE, - ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE} + def __str__(self) -> str: + """ + Convert to basic string + """ + return "^" + self.text -class ConstantRef(BaseRef): +class LanguageSpecific(ARObject): """ - Reference to ConstantSpecification + Complex type AR:LANGUAGE-SPECIFIC + Type: Abstract """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.CONSTANT_SPECIFICATION) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.CONSTANT_SPECIFICATION} + def __init__(self, language: ar_enum.Language) -> None: + assert isinstance(language, ar_enum.Language) + self.language = language # Attribute @L -class VariableDataPrototypeRef(BaseRef): +class MixedContentForLongName(LanguageSpecific): """ - Reference to VariableDataPrototype + Group AR:MIXED-CONTENT-FOR-LONG-NAME + Type: Abstract """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE) + def __init__(self, language: ar_enum.Language) -> None: + super().__init__(language) + self.parts = [] # Unbounded list of str | TT | E | SUP | SUB | IE - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE} + def append(self, part: str | TechnicalTerm | EmphasisText | Subscript | Subscript): + """ + Checks type validity before adding element to elements + """ + if isinstance(part, (str, TechnicalTerm, EmphasisText, Subscript, Subscript, IndexEntry)): + self.parts.append(part) + else: + raise TypeError('Unsupported element type: ' + str(type(part))) -class ParameterDataPrototypeRef(BaseRef): +class MixedContentForOverviewParagraph(LanguageSpecific): """ - Reference to ParameterDataPrototype + Group AR:MIXED-CONTENT-FOR-OVERVIEW-PARAGRAPH + Type: Abstract """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE) + def __init__(self, language: ar_enum.Language) -> None: + super().__init__(language) + self.parts = [] # Unbounded list of str | TT | E | SUP | SUB | IE + # Unsupported elements: + # FT : AR:SL-OVERVIEW-PARAGRAPH + # TRACE-REF: Complex type + # XREF: AR:-XREF-TARGET - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE} + def append(self, part: str | TechnicalTerm | EmphasisText | Subscript | Subscript): + """ + Checks type validity before adding element to elements + """ + if isinstance(part, (str, TechnicalTerm, EmphasisText, Subscript, Subscript, IndexEntry)): + self.parts.append(part) + else: + raise TypeError('Unsupported element type: ' + str(type(part))) -class ApplicationErrorRef(BaseRef): - """ - Reference to ApplicationError - tag variants: 'POSSIBLE-ERROR-REF' +class LanguageLongName(MixedContentForLongName): """ + Complex type AR:L-LONG-NAME + Type: Concrete + Tag: L-4 - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.APPLICATION_ERROR) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_ERROR} - + Longname for a specific language. -class ModeDeclarationRef(BaseRef): - """ - Reference to ModeDeclaration - tag variants: 'TARGET-MODE-DECLARATION-REF' | 'INITIAL-MODE-REF' | - 'FIRST-MODE-REF' | 'SECOND-MODE-REF' | 'MODE-DECLARATION-REF' | - 'DEFAULT-MODE-REF' | 'TARGET-MODE-REF' | 'ENTERED-MODE-REF' | - 'EXITED-MODE-REF' | 'ENTRY-MODE-DECLARATION-REF' | 'EXIT-MODE-DECLARATION-REF' + The parts parameter can be a single string or a list of mixed types. + Accepted mixed types: + * strings + * TechnicalTerm + * EmphasisText + * Subscript + * Subscript """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.MODE_DECLARATION) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION} + def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: + super().__init__(language) + if parts is not None: + if isinstance(parts, str): + self.append(parts) + else: + for part in parts: + self.append(part) -class ModeDeclarationGroupRef(BaseRef): +class MultilanguageLongName(ARObject): """ - Reference to ModeDeclarationGroup - Tag variants: 'MODE-DECLARATION-GROUP-REF' | 'TYPE-TREF' | 'MODE-GROUP-REF' + Complex type AR:MULTILANGUAGE-LONG-NAME + Type: Concrete + Tag variants: 'LABEL' | 'LONG-NAME' """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP} - - -class ModeDeclarationGroupPrototypeRef(BaseRef): - """ - Reference to ModeDeclarationGroupPrototype - Tag variants: 'MODE-GROUP-REF' | 'REQUIRED-MODE-GROUP-REF' | 'FIRST-MODE-GROUP-REF' | - 'SECOND-MODE-GROUP-REF' | 'MODE-DECLARATION-GROUP-PROTOTYPE-REF' - (and more) - """ - - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP_PROTOTYPE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP_PROTOTYPE} - - -class AutosarDataPrototypeRef(BaseRef): - """ - Reference to elements that derives from AutosarDataPrototype - """ + def __init__(self, + long_name: None | tuple[ar_enum.Language, + str] | LanguageLongName = None) -> None: + self.elements: list[LanguageLongName] = [] + if long_name is not None: + if isinstance(long_name, LanguageLongName): + self.append(long_name) + elif isinstance(long_name, tuple): + self.append(LanguageLongName(long_name[0], long_name[1])) + else: + raise TypeError('Invalid type for long_name. ' + f'Expected tuple[ar_enum.Language,str] or LanguageLongName,' + f' got "{str(type(long_name))}"') - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE} + def append(self, long_name: LanguageLongName) -> None: + """ + Adds long_name to its inner list with type-check + """ + assert isinstance(long_name, LanguageLongName) + self.elements.append(long_name) -class E2EProfileCompatibilityPropsRef(BaseRef): - """ - Reference to E2EProfileCompatibilityProps +class LanguageOverviewParagraph(MixedContentForOverviewParagraph): """ + Complex type AR:L-OVERVIEW-PARAGRAPH + Type: Concrete + Tag variants: 'L-2' - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS} + Overview paragraph for specific language + The parts parameter can be a single string or a list of mixed types. -class ClientServerOperationRef(BaseRef): - """ - Reference to ClientServerOperation + Accepted mixed types: + * strings + * TechnicalTerm + * EmphasisText + * Subscript + * Subscript """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.CLIENT_SERVER_OPERATION) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.CLIENT_SERVER_OPERATION} + def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: + super().__init__(language) + if parts is not None: + if isinstance(parts, str): + self.append(parts) + else: + for part in parts: + self.append(part) -class PortPrototypeRef(BaseRef): +class MultiLanguageOverviewParagraph(ARObject): """ - Reference to port prototype elements + Complex type AR:MULTI-LANGUAGE-OVERVIEW-PARAGRAPH + Type: Concrete + Tag variants: 'DESC' | 'ITEM-LABEL' | 'CHANGE' | 'REASON' """ - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.ABSTRACT_PROVIDED_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.ABSTRACT_REQUIRED_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE, - } + def __init__(self, + paragraph: None | tuple[ar_enum.Language, + str] | LanguageOverviewParagraph = None) -> None: + self.elements: list[LanguageOverviewParagraph] = [] + if paragraph is not None: + if isinstance(paragraph, LanguageOverviewParagraph): + self.append(paragraph) + elif isinstance(paragraph, tuple) and len(paragraph) == 2: + self.append(LanguageOverviewParagraph(*paragraph)) + else: + raise TypeError('Invalid type for paragraph. ' + f'Expected tuple[ar_enum.Language,str] or LanguageOverviewParagraph,' + f' got "{str(type(paragraph))}"') - @property - def is_provide_port_ref(self) -> bool: + def append(self, paragraph: LanguageOverviewParagraph) -> None: """ - True if destination of port reference is a P-PORT + Adds long_name to its inner list with type-check """ - p_port_values = {ar_enum.IdentifiableSubTypes.ABSTRACT_PROVIDED_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE} - return self.dest in p_port_values + assert isinstance(paragraph, LanguageOverviewParagraph) + self.elements.append(paragraph) - @property - def is_require_port_ref(self) -> bool: + @classmethod + def make(cls, language: ar_enum.Language, paragraph: str): """ - True if destination of port reference is an R-PORT + #convenience-method + + Simplified creation method that uses a simple string as paragraph text """ - r_port_values = {ar_enum.IdentifiableSubTypes.ABSTRACT_REQUIRED_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE, - ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE} - return self.dest in r_port_values + return cls(LanguageOverviewParagraph(language, paragraph)) -class AbstractImplementationDataTypeElementRef(BaseRef): +class DocumentViewSelectable(ARObject): """ - Reference to abstract or specific data-type elements + Group AR:DOCUMENT-VIEW-SELECTABLE + Type: Abstract """ - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.ABSTRACT_IMPLEMENTATION_DATA_TYPE_ELEMENT, - ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE_ELEMENT} + def __init__(self, + semantic_information: None | str = None, + view: None | str = None) -> None: + self.semantic_information = semantic_information # Attribute 'SI' + self.view = view # Attribute 'VIEW' + if semantic_information is not None and (not isinstance(semantic_information, str)): + raise TypeError( + f"semantic_information: Expected type 'str', got '{str(type(semantic_information))}'") + if view is not None and (not isinstance(view, str)): + raise TypeError( + f"view: Expected type 'str', got '{str(type(view))}'") -class DataPrototypeRef(BaseRef): +class Paginateable(DocumentViewSelectable): """ - References to DATA-PROTOTYPE--SUBTYPES-ENUM + Group AR:PAGINATEABLE + Type: Abstract + + Experiment with named attributes for this class while keeping + Unknown parent attributes hidden in kwargs """ - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_ELEMENT, - ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_ELEMENT_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT, - ar_enum.IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.AUTOSAR_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE, - ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE, - } + def __init__(self, + page_break: None | ar_enum.PageBreak = None, + keep_with_previous: None | ar_enum.KeepWithPrevious = None, + **kwargs) -> None: + super().__init__(**kwargs) + self.page_break = page_break # Attribute 'BREAK' + self.keep_with_previous = keep_with_previous # Attribute 'KEEP-WITH-PREVIOUS' + if (page_break is not None) and (not isinstance(page_break, ar_enum.PageBreak)): + raise TypeError( + f"page_break: Expected type 'PageBreak', got '{str(type(page_break))}'") + if (keep_with_previous is not None) and (not isinstance(keep_with_previous, ar_enum.KeepWithPrevious)): + raise TypeError( + f"page_break: Expected type 'PageBreak', got '{str(type(keep_with_previous))}'") -class PortInterfaceRef(BaseRef): +class MixedContentForParagraph(LanguageSpecific): """ - References to PORT-INTERFACE--SUBTYPES-ENUM - - Only a small piece of the enum is currently implemented + Group AR:MIXED-CONTENT-FOR-PARAGRAPH + Type: Abstract """ - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.CLIENT_SERVER_INTERFACE, - ar_enum.IdentifiableSubTypes.MODE_SWITCH_INTERFACE, - ar_enum.IdentifiableSubTypes.NV_DATA_INTERFACE, - ar_enum.IdentifiableSubTypes.PARAMETER_INTERFACE, - ar_enum.IdentifiableSubTypes.SENDER_RECEIVER_INTERFACE, - } + def __init__(self, language: ar_enum.Language) -> None: + super().__init__(language) + self.parts = [] # Unbounded list of str | BR | E | IE | SUB | SUP | TT + # Unsupported elements: + # FT : AR:SL-OVERVIEW-PARAGRAPH + # STD: AR:STD + # TRACE-REF : Specialization of AR:REF + # XDOC: AR:XDOC + # XFILE: AR:XFILE + # XREF: AR:XREF + # XREF-TARGET: AR:-XREF-TARGET + def append(self, + part: str | Break | EmphasisText | IndexEntry | Subscript | Subscript | TechnicalTerm): + """ + Checks type validity before adding element to elements + """ + if isinstance(part, (str, Break, EmphasisText, IndexEntry, Subscript, Subscript, TechnicalTerm)): + self.parts.append(part) + else: + raise TypeError('Unsupported element type: ' + str(type(part))) -class SwComponentTypeRef(BaseRef): - """ - References to SW-COMPONENT-TYPE--SUBTYPES-ENUM - Only a small piece of the enum is currently implemented +class LanguageParagraph(MixedContentForParagraph): """ + Complex type AR:L-PARAGRAPH + Type: Concrete + Tag variants: 'L-1' - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE, - ar_enum.IdentifiableSubTypes.COMPOSITION_SW_COMPONENT_TYPE, - } + Paragraph for specific language + The parts parameter can be a single string or a list of mixed types. -class SwComponentPrototypeRef(BaseRef): - """ - Reference to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM + Accepted mixed types: + * strings + * Break + * EmphasisText + * TechnicalTerm + * Subscript + * Subscript """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.SW_COMPONENT_PROTOTYPE) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.SW_COMPONENT_PROTOTYPE} + def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: + super().__init__(language) + if parts is not None: + if isinstance(parts, str): + self.append(parts) + else: + for part in parts: + self.append(part) -class SwcInternalBehaviorRef(BaseRef): +class MultiLanguageParagraph(Paginateable): """ - Reference to AR:SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM + Complex type AR:MULTI-LANGUAGE-PARAGRAPH + Type: Concrete + Tag variants: 'P' """ - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.SWC_INTERNAL_BEHAVIOR) + def __init__(self, + paragraph: None | tuple[ar_enum.Language, + str] | LanguageParagraph = None, + help_entry: None | str = None, + **kwargs) -> None: + super().__init__(**kwargs) + self.help_entry = help_entry # Attribute 'HELP-ENTRY' + self.elements: list[LanguageParagraph] = [] + if paragraph is not None: + if isinstance(paragraph, LanguageParagraph): + self.append(paragraph) + elif isinstance(paragraph, tuple): + self.append(LanguageParagraph(paragraph[0], paragraph[1])) + else: + raise TypeError('Invalid type for paragraph. ' + f'Expected tuple[ar_enum.Language,str] or LanguageParagraph,' + f' got "{str(type(paragraph))}"') - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.SWC_INTERNAL_BEHAVIOR} + def append(self, paragraph: LanguageParagraph) -> None: + """ + Adds long_name to its inner list with type-check + """ + assert isinstance(paragraph, LanguageParagraph) + self.elements.append(paragraph) -class SwcImplementationRef(BaseRef): - """ - Reference to SwcImplementation +class MixedContentForVerbatim(LanguageSpecific): """ + Group AR:MIXED-CONTENT-FOR-VERBATIM + Type: Abstract - def __init__(self, value: str) -> None: - super().__init__(value, ar_enum.IdentifiableSubTypes.SWC_IMPLEMENTATION) - - def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: - """Acceptable values for dest""" - return {ar_enum.IdentifiableSubTypes.SWC_IMPLEMENTATION} - -# --- Documentation Elements - - -class Break(ARObject): + This includes AR:WHITESPACE-CONTROLLED as it + does not have any attributes or elements of its + own. """ - Complex type AR:BR - Type: Concrete - Tag variants: BR - Same function as the html element. + def __init__(self, language: ar_enum.Language) -> None: + super().__init__(language) + self.parts = [] # Unbounded list of str | BR | E | TT + # Unsupported elements: + # XREF: AR:XREF - """ + def append(self, + part: str | Break | EmphasisText | TechnicalTerm): + """ + Checks type validity before adding element to elements + """ + if isinstance(part, (str, Break, EmphasisText, TechnicalTerm)): + self.parts.append(part) + else: + raise TypeError('Unsupported element type: ' + str(type(part))) -class EmphasisText(ARObject): +class LanguageVerbatim(MixedContentForVerbatim): """ - Complex type AR:EMPHASIS-TEXT + Complex type AR:L-VERBATIM Type: Concrete - Tag variants: E - - Emphasized text - - Limitations: No support for child-elements. Type for argument elements must be string. - + Tag variants: 'L-5' """ - def __init__(self, - elements: None | list | str = None, - color: str = None, - font: ar_enum.EmphasisFont = None, - type: ar_enum.EmphasisType = None) -> None: # pylint: disable=redefined-builtin - self.elements = [] - self.color = color # Attribute @COLOR - self.font = font # Attribute @FONT - self.type = type # Attribute @TYPE - if elements is not None: - if isinstance(elements, str): - self.elements.append(elements) + def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: + super().__init__(language) + if parts is not None: + if isinstance(parts, str): + self.append(parts) else: - raise NotImplementedError("List of elements not yet supported") + for part in parts: + self.append(part) -class IndexEntry(ARObject): +class MultiLanguageVerbatim(Paginateable): """ - Complex type AR:INDEX-ENTRY + Complex type AR:MULTI-LANGUAGE-VERBATIM Type: Concrete - Tag variants: IE - - Index Entry - - Limitations: Doesn't support sub-elements as seen in XML schema. - """ - - def __init__(self, text: str) -> None: - self.text = text # Text content - - -class TechnicalTerm(ARObject): - """ - Complex type AR:TT - Type: Concrete - Tag variants: TT - - Technical Term - - """ + Tag variants: 'VERBATIM' + """ def __init__(self, - text: str, - tex_render: str = None, - type: str = None) -> None: # pylint: disable=redefined-builtin - self.tex_render = tex_render # attribute @TEX-RENDER - self.type = type # attribute @TYPE - self.text = text # Text content - - -class Subscript(ARObject): - """ - Complex type AR:SUPSCRIPT - Type: Concrete - Tag variants: SUB - - Subscript is based on the same Complex type - - """ - - def __init__(self, text: str) -> None: - self.text = text # Simple content - - -class Superscript(ARObject): - """ - Complex type AR:SUPSCRIPT - Type: Concrete - Tag variants: SUP - - Superscript - """ - - def __init__(self, text: str) -> None: - self.text = text # Simple content - - def __str__(self) -> str: - """ - Convert to basic string - """ - return "^" + self.text - - -class LanguageSpecific(ARObject): - """ - Complex type AR:LANGUAGE-SPECIFIC - Type: Abstract - """ - - def __init__(self, language: ar_enum.Language) -> None: - assert isinstance(language, ar_enum.Language) - self.language = language # Attribute @L - - -class MixedContentForLongName(LanguageSpecific): - """ - Group AR:MIXED-CONTENT-FOR-LONG-NAME - Type: Abstract - """ - - def __init__(self, language: ar_enum.Language) -> None: - super().__init__(language) - self.parts = [] # Unbounded list of str | TT | E | SUP | SUB | IE + element: None | tuple[ar_enum.Language, + str] | LanguageVerbatim = None, + allow_break: None | str = None, + float: None | ar_enum.Float = None, # pylint: disable=redefined-builtin + page_wide: None | ar_enum.PageWide = None, + help_entry: None | str = None, + **kwargs) -> None: + super().__init__(**kwargs) + self.allow_break = allow_break # Attribute 'ALLOW-BREAK' + self.float = float # Attribte 'FLOAT' + self.page_wide = page_wide # Attribute 'PGWIDE' + self.help_entry = help_entry # Attribute 'HELP-ENTRY' + self.elements: list[LanguageVerbatim] = [] + if element is not None: + if isinstance(element, LanguageVerbatim): + self.append(element) + elif isinstance(element, tuple): + self.append(LanguageVerbatim(element[0], element[1])) + else: + raise TypeError('Invalid type for element. ' + f'Expected tuple[ar_enum.Language,str] or LanguageVerbatim,' + f' got "{str(type(element))}"') - def append(self, part: str | TechnicalTerm | EmphasisText | Subscript | Subscript): + def append(self, paragraph: LanguageVerbatim) -> None: """ - Checks type validity before adding element to elements + Adds long_name to its inner list with type-check """ - if isinstance(part, (str, TechnicalTerm, EmphasisText, Subscript, Subscript, IndexEntry)): - self.parts.append(part) - else: - raise TypeError('Unsupported element type: ' + str(type(part))) + assert isinstance(paragraph, LanguageVerbatim) + self.elements.append(paragraph) -class MixedContentForOverviewParagraph(LanguageSpecific): +class MixedContentForUnitNames(ARObject): """ - Group AR:MIXED-CONTENT-FOR-OVERVIEW-PARAGRAPH + Group MIXED-CONTENT-FOR-UNIT-NAMES Type: Abstract """ - def __init__(self, language: ar_enum.Language) -> None: - super().__init__(language) - self.parts = [] # Unbounded list of str | TT | E | SUP | SUB | IE - # Unsupported elements: - # FT : AR:SL-OVERVIEW-PARAGRAPH - # TRACE-REF: Complex type - # XREF: AR:-XREF-TARGET + def __init__(self) -> None: + self.parts = [] # Unbounded list of str | SUB | SUP - def append(self, part: str | TechnicalTerm | EmphasisText | Subscript | Subscript): + def append(self, + part: str | Break | EmphasisText | TechnicalTerm): """ Checks type validity before adding element to elements """ - if isinstance(part, (str, TechnicalTerm, EmphasisText, Subscript, Subscript, IndexEntry)): + if isinstance(part, (str, Subscript, Superscript)): self.parts.append(part) else: raise TypeError('Unsupported element type: ' + str(type(part))) -class LanguageLongName(MixedContentForLongName): +class SingleLanguageUnitNames(MixedContentForUnitNames): """ - Complex type AR:L-LONG-NAME + Complex type AR:SINGLE-LANGUAGE-UNIT-NAMES Type: Concrete - Tag: L-4 - - Longname for a specific language. - - The parts parameter can be a single string or a list of mixed types. - - Accepted mixed types: - * strings - * TechnicalTerm - * EmphasisText - * Subscript - * Subscript + Tag variants: 'PRM-UNIT' | 'UNIT-DISPLAY-NAME' | 'UNIT-DISPLAY-NAME' | 'DISPLAY-NAME' """ - def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: - super().__init__(language) + def __init__(self, parts: str | list | None = None) -> None: + super().__init__() if parts is not None: - if isinstance(parts, str): - self.append(parts) - else: + if isinstance(parts, Iterable): for part in parts: self.append(part) + else: + self.append(parts) + + def __str__(self) -> str: + """ + Convert to string if the unit name has simple + type (at most one part of type str). + """ + result = [] + for part in self.parts: + if isinstance(part, str): + result.append(part) + elif isinstance(part, Superscript): + result.append(str(part)) + else: + raise ValueError("Unable to convert to string from multiple parts") + return "".join(result) -class MultilanguageLongName(ARObject): +class DocumentationBlock(ARObject): """ - Complex type AR:MULTILANGUAGE-LONG-NAME + Complex type AR:DOCUMENTATION-BLOCK Type: Concrete - Tag variants: 'LABEL' | 'LONG-NAME' + Tag Variants: 'INTRODUCTION', 'DEF', 'VALUE', 'ANNOTATION-TEXT', 'REMARK' + 'COND', 'DESCRICPTION', 'RATIONALE', 'DEPENDENCIES', 'USE-CASE', + 'CONFLICTS', 'SUPPORTING-MATERIAL', 'SW-GENERIC-AXIS-DESC' """ def __init__(self, - long_name: None | tuple[ar_enum.Language, - str] | LanguageLongName = None) -> None: - self.elements: list[LanguageLongName] = [] - if long_name is not None: - if isinstance(long_name, LanguageLongName): - self.append(long_name) - elif isinstance(long_name, tuple): - self.append(LanguageLongName(long_name[0], long_name[1])) + element: MultiLanguageParagraph | MultiLanguageVerbatim | list[Any] | None = None) -> None: + self.elements: list[MultiLanguageParagraph | MultiLanguageVerbatim] = [] + if element is not None: + if isinstance(element, Iterable): + for elem in element: + self.append(elem) else: - raise TypeError('Invalid type for long_name. ' - f'Expected tuple[ar_enum.Language,str] or LanguageLongName,' - f' got "{str(type(long_name))}"') + self.append(element) - def append(self, long_name: LanguageLongName) -> None: + def append(self, element: MultiLanguageParagraph | MultiLanguageVerbatim) -> None: """ - Adds long_name to its inner list with type-check + Appends new element with type check """ - assert isinstance(long_name, LanguageLongName) - self.elements.append(long_name) + assert isinstance(element, + (MultiLanguageParagraph, + MultiLanguageVerbatim)) + self.elements.append(element) -class LanguageOverviewParagraph(MixedContentForOverviewParagraph): +class GeneralAnnotation(ARObject): + """ + Group AR:GENERAL-ANNOTATION + Type: Abstract """ - Complex type AR:L-OVERVIEW-PARAGRAPH - Type: Concrete - Tag variants: 'L-2' - Overview paragraph for specific language + def __init__(self, + label: MultilanguageLongName | None = None, + origin: str | None = None, + text: DocumentationBlock | None = None) -> None: + super().__init__() + self.label = label # .LABEL + self.origin = origin # .ANNOTATION-ORIGIN + self.text = text # .ANNOTATION-TEXT - The parts parameter can be a single string or a list of mixed types. - Accepted mixed types: - * strings - * TechnicalTerm - * EmphasisText - * Subscript - * Subscript +class Annotation(GeneralAnnotation): + """ + Complex type AR:ANNOTATION + Type: Concrete """ - def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: - super().__init__(language) - if parts is not None: - if isinstance(parts, str): - self.append(parts) - else: - for part in parts: - self.append(part) + def __init__(self, # pylint: disable=useless-parent-delegation + label: MultilanguageLongName | None = None, + origin: str | None = None, + text: DocumentationBlock | None = None) -> None: + super().__init__(label, origin, text) -class MultiLanguageOverviewParagraph(ARObject): +class Describable(ARObject): """ - Complex type AR:MULTI-LANGUAGE-OVERVIEW-PARAGRAPH - Type: Concrete - Tag variants: 'DESC' | 'ITEM-LABEL' | 'CHANGE' | 'REASON' + Group AR:DESCRIBABLE """ def __init__(self, - paragraph: None | tuple[ar_enum.Language, - str] | LanguageOverviewParagraph = None) -> None: - self.elements: list[LanguageOverviewParagraph] = [] - if paragraph is not None: - if isinstance(paragraph, LanguageOverviewParagraph): - self.append(paragraph) - elif isinstance(paragraph, tuple) and len(paragraph) == 2: - self.append(LanguageOverviewParagraph(*paragraph)) + desc: Union["MultiLanguageOverviewParagraph", tuple[ar_enum.Language, str], str, None] = None, + category: str | None = None, + introduction: DocumentationBlock | None = None, + admin_data: AdminData | None = None + ) -> None: + super().__init__() + self.desc: MultiLanguageOverviewParagraph | None = None # .DESC + self.category: str | None = None # .CATEGORY + self.introduction: DocumentationBlock | None = None # .INTRODUCTION + self.admin_data: AdminData | None = None # .ADMIN-DATA + if desc is not None: + if isinstance(desc, MultiLanguageOverviewParagraph): + self.desc = desc + elif isinstance(desc, str): + self.desc = MultiLanguageOverviewParagraph.make(ar_enum.Language.FOR_ALL, desc) + elif isinstance(desc, tuple) and len(desc) == 2: + self.desc = MultiLanguageOverviewParagraph.make(*desc) else: - raise TypeError('Invalid type for paragraph. ' - f'Expected tuple[ar_enum.Language,str] or LanguageOverviewParagraph,' - f' got "{str(type(paragraph))}"') - - def append(self, paragraph: LanguageOverviewParagraph) -> None: - """ - Adds long_name to its inner list with type-check - """ - assert isinstance(paragraph, LanguageOverviewParagraph) - self.elements.append(paragraph) + raise TypeError(f"Invalid type for argument 'desc': {str(type(desc))}") + self._assign_optional('category', category, str) + self._assign_optional_strict('introduction', introduction, DocumentationBlock) + self._assign_optional_strict('admin_data', admin_data, AdminData) - @classmethod - def make(cls, language: ar_enum.Language, paragraph: str): - """ - #convenience-method - Simplified creation method that uses a simple string as paragraph text - """ - return cls(LanguageOverviewParagraph(language, paragraph)) +# --- Computation method elements -class DocumentViewSelectable(ARObject): +class CompuRational(ARObject): """ - Group AR:DOCUMENT-VIEW-SELECTABLE - Type: Abstract + AR:COMPU-RATIONAL-COEFFS + Type: Concrete + Tag variants: 'COMPU-RATIONAL-COEFFS' """ def __init__(self, - semantic_information: None | str = None, - view: None | str = None) -> None: - self.semantic_information = semantic_information # Attribute 'SI' - self.view = view # Attribute 'VIEW' - if semantic_information is not None and (not isinstance(semantic_information, str)): - raise TypeError( - f"semantic_information: Expected type 'str', got '{str(type(semantic_information))}'") - if view is not None and (not isinstance(view, str)): - raise TypeError( - f"view: Expected type 'str', got '{str(type(view))}'") + numerator: tuple[int | float] | list[int | float] | None, + denominator: tuple[int | float] | list[int | float] | None = None) -> None: + if numerator is not None: + if not isinstance(numerator, (tuple, list)): + raise TypeError("Parameter for 'numerator' must be either a list or a tuple") + self.numerator = tuple(numerator) + else: + self.numerator = None + if denominator is not None: + if not isinstance(denominator, (tuple, list)): + raise TypeError("Parameter for 'denominator' must be either a list or a tuple") + self.denominator = tuple(denominator) + else: + self.denominator = None -class Paginateable(DocumentViewSelectable): +class CompuConst(ARObject): """ - Group AR:PAGINATEABLE - Type: Abstract + AR:COMPU-CONST + Type: Concrete - Experiment with named attributes for this class while keeping - Unknown parent attributes hidden in kwargs + Handles AR:COMPU-CONST-NUMERIC-CONTENT + and AR:COMPU-CONST-TEXT-CONTENT dynamically """ - def __init__(self, - page_break: None | ar_enum.PageBreak = None, - keep_with_previous: None | ar_enum.KeepWithPrevious = None, - **kwargs) -> None: - super().__init__(**kwargs) - self.page_break = page_break # Attribute 'BREAK' - self.keep_with_previous = keep_with_previous # Attribute 'KEEP-WITH-PREVIOUS' - if (page_break is not None) and (not isinstance(page_break, ar_enum.PageBreak)): - raise TypeError( - f"page_break: Expected type 'PageBreak', got '{str(type(page_break))}'") - if (keep_with_previous is not None) and (not isinstance(keep_with_previous, ar_enum.KeepWithPrevious)): - raise TypeError( - f"page_break: Expected type 'PageBreak', got '{str(type(keep_with_previous))}'") + def __init__(self, value: int | float | str): + self.value = value -class MixedContentForParagraph(LanguageSpecific): +class CompuScale(ARObject): """ - Group AR:MIXED-CONTENT-FOR-PARAGRAPH - Type: Abstract + AR:COMPU-SCALE + Type: Concrete + Tag variants: 'COMPU-SCALE' """ - def __init__(self, language: ar_enum.Language) -> None: - super().__init__(language) - self.parts = [] # Unbounded list of str | BR | E | IE | SUB | SUP | TT - # Unsupported elements: - # FT : AR:SL-OVERVIEW-PARAGRAPH - # STD: AR:STD - # TRACE-REF : Specialization of AR:REF - # XDOC: AR:XDOC - # XFILE: AR:XFILE - # XREF: AR:XREF - # XREF-TARGET: AR:-XREF-TARGET + def __init__(self, + content: CompuConst | CompuRational | None = None, + lower_limit: int | float | str | None = None, + upper_limit: int | float | str | None = None, + label: str | None = None, + symbol: str | None = None, + desc: MultiLanguageOverviewParagraph | None = None, + mask: int | None = None, + inverse_value: CompuConst | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + self.content = content # CHOICE(COMPU-SCALE-CONSTANT-CONTENTS, COMPU-SCALE-RATIONAL-FORMULA) # noqa E501 pylint: disable=C0301 + self.lower_limit = lower_limit # .LOWER-LIMIT + self.upper_limit = upper_limit # .UPPER-LIMIT + self.label = label # .SHORT-LABEL + self.symbol = symbol # .SYMBOL + self.desc = desc # .DESC + self.mask = mask # .MASK + self.inverse_value: CompuConst | None = None # .COMPU-INVERSE-VALUE + if inverse_value is not None: + if isinstance(inverse_value, CompuConst): + self.inverse_value = inverse_value + elif isinstance(inverse_value, (int, float, str)): + self.inverse_value = CompuConst(inverse_value) + else: + raise TypeError(f"Invalid type for 'inverse_value': {str(type(inverse_value))}") + self.lower_limit_type = lower_limit_type # .LOWER-LIMIT@INTERVAL-TYPE + self.upper_limit_type = upper_limit_type # .UPPER-LIMIT@INTERVAL-TYPE + # .VARIATION-POINT not supported - def append(self, - part: str | Break | EmphasisText | IndexEntry | Subscript | Subscript | TechnicalTerm): + @property + def content_type(self) -> ar_enum.CompuScaleContent: """ - Checks type validity before adding element to elements + What kind of content does this CompuScale have? """ - if isinstance(part, (str, Break, EmphasisText, IndexEntry, Subscript, Subscript, TechnicalTerm)): - self.parts.append(part) + if isinstance(self.content, CompuConst): + return ar_enum.CompuScaleContent.CONSTANT + elif isinstance(self.content, CompuRational): + return ar_enum.CompuScaleContent.RATIONAL else: - raise TypeError('Unsupported element type: ' + str(type(part))) - - -class LanguageParagraph(MixedContentForParagraph): - """ - Complex type AR:L-PARAGRAPH - Type: Concrete - Tag variants: 'L-1' - - Paragraph for specific language - - The parts parameter can be a single string or a list of mixed types. - - Accepted mixed types: - * strings - * Break - * EmphasisText - * TechnicalTerm - * Subscript - * Subscript - """ - - def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: - super().__init__(language) - if parts is not None: - if isinstance(parts, str): - self.append(parts) - else: - for part in parts: - self.append(part) + return ar_enum.CompuScaleContent.NONE -class MultiLanguageParagraph(Paginateable): +class Computation(ARObject): """ - Complex type AR:MULTI-LANGUAGE-PARAGRAPH + AR:COMPU Type: Concrete - Tag variants: 'P' + Tag variants: 'COMPU-INTERNAL-TO-PHYS' | 'COMPU-PHYS-TO-INTERNAL' """ def __init__(self, - paragraph: None | tuple[ar_enum.Language, - str] | LanguageParagraph = None, - help_entry: None | str = None, - **kwargs) -> None: - super().__init__(**kwargs) - self.help_entry = help_entry # Attribute 'HELP-ENTRY' - self.elements: list[LanguageParagraph] = [] - if paragraph is not None: - if isinstance(paragraph, LanguageParagraph): - self.append(paragraph) - elif isinstance(paragraph, tuple): - self.append(LanguageParagraph(paragraph[0], paragraph[1])) - else: - raise TypeError('Invalid type for paragraph. ' - f'Expected tuple[ar_enum.Language,str] or LanguageParagraph,' - f' got "{str(type(paragraph))}"') + compu_scales: list[CompuScale] | None = None, + default_value: CompuConst | int | float | str | None = None) -> None: - def append(self, paragraph: LanguageParagraph) -> None: - """ - Adds long_name to its inner list with type-check + self.compu_scales = compu_scales + self.default_value: CompuConst | int | float | str | None = None # .COMPU-DEFAULT-VALUE + if isinstance(default_value, CompuConst): + self.default_value = default_value + elif isinstance(default_value, (int, float, str)): + self.default_value = CompuConst(default_value) + + @classmethod + def make_value_table(cls: "Computation", + elements: list[Any], + default_value: CompuConst | int | float | str | None = None, + auto_label: bool = True): """ - assert isinstance(paragraph, LanguageParagraph) - self.elements.append(paragraph) + #convenience-method + Creates new CompuConst-based computation using values from a list. -class MixedContentForVerbatim(LanguageSpecific): - """ - Group AR:MIXED-CONTENT-FOR-VERBATIM - Type: Abstract + When elements is a list of strings: + Creates one CompuScale per list item and automatically calculates lower and upper limits. + Enumeration starts counting from zero and increments by one until the end of the list. - This includes AR:WHITESPACE-CONTROLLED as it - does not have any attributes or elements of its - own. - """ + When elements is a list of tuples: + If 2-tuple: First element is both lower_limit and upper_limit, second element is text value. + If 3-tuple: First element is lower_limit, second element is upper_limit, third element is text value. - def __init__(self, language: ar_enum.Language) -> None: - super().__init__(language) - self.parts = [] # Unbounded list of str | BR | E | TT - # Unsupported elements: - # XREF: AR:XREF + auto_label: automatically creates a based on the text value. - def append(self, - part: str | Break | EmphasisText | TechnicalTerm): - """ - Checks type validity before adding element to elements """ - if isinstance(part, (str, Break, EmphasisText, TechnicalTerm)): - self.parts.append(part) - else: - raise TypeError('Unsupported element type: ' + str(type(part))) + compu_scales = [] + for i, elem in enumerate(elements): + label = None + if isinstance(elem, str): + lower_limit, upper_limit, value = i, i, elem + elif isinstance(elem, tuple): + if len(elem) == 2: + lower_limit, upper_limit, value = (elem[0], elem[0], elem[1]) + elif len(elem) == 3: + lower_limit, upper_limit, value = elem + else: + raise ValueError(f"Invalid length of tuple: {len(elem)}") + else: + raise TypeError(f"Invalid type of element: {str(type(elem))}") + if auto_label and isinstance(value, str): + label = value + compu_scales.append(CompuScale(CompuConst(value), lower_limit, upper_limit, label)) + return cls(compu_scales, default_value) + @classmethod + def make_rational(cls: "Computation", + scaling_factor: int | float = 1, + offset: int | float = 0, + lower_limit: int | float | str | None = None, + upper_limit: int | float | str | None = None, + default_value: CompuConst | int | float | str | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + """ + #convenience-method -class LanguageVerbatim(MixedContentForVerbatim): - """ - Complex type AR:L-VERBATIM - Type: Concrete - Tag variants: 'L-5' - """ + Creates a new Computation instance with one COMPU-SCALE containing numerator + and denominator. - def __init__(self, language: ar_enum.Language, parts: None | str | list[Any] = None) -> None: - super().__init__(language) - if parts is not None: - if isinstance(parts, str): - self.append(parts) - else: - for part in parts: - self.append(part) + """ + numerator = [offset, float(scaling_factor)] + denominator = [1] + compu_scales = [CompuScale(CompuRational(numerator, denominator), + lower_limit, + upper_limit, + lower_limit_type=lower_limit_type, + upper_limit_type=upper_limit_type)] + return cls(compu_scales, default_value) -class MultiLanguageVerbatim(Paginateable): +class CompuMethod(ARElement): """ - Complex type AR:MULTI-LANGUAGE-VERBATIM + AR:COMPU-METHOD Type: Concrete - Tag variants: 'VERBATIM' + Tag Variants: 'COMPU-METHOD' """ - def __init__(self, - element: None | tuple[ar_enum.Language, - str] | LanguageVerbatim = None, - allow_break: None | str = None, - float: None | ar_enum.Float = None, # pylint: disable=redefined-builtin - page_wide: None | ar_enum.PageWide = None, - help_entry: None | str = None, + def __init__(self, name: str, + int_to_phys: Computation | None = None, + phys_to_int: Computation | None = None, + unit_ref: UnitRef | None = None, + display_format: str | None = None, **kwargs) -> None: - super().__init__(**kwargs) - self.allow_break = allow_break # Attribute 'ALLOW-BREAK' - self.float = float # Attribte 'FLOAT' - self.page_wide = page_wide # Attribute 'PGWIDE' - self.help_entry = help_entry # Attribute 'HELP-ENTRY' - self.elements: list[LanguageVerbatim] = [] - if element is not None: - if isinstance(element, LanguageVerbatim): - self.append(element) - elif isinstance(element, tuple): - self.append(LanguageVerbatim(element[0], element[1])) - else: - raise TypeError('Invalid type for element. ' - f'Expected tuple[ar_enum.Language,str] or LanguageVerbatim,' - f' got "{str(type(element))}"') + super().__init__(name, **kwargs) + self.int_to_phys = int_to_phys # .COMPU-INTERNAL-TO-PHYS + self.phys_to_int = phys_to_int # .COMPU-PHYS-TO-INTERNAL + self.unit_ref = unit_ref # .UNIT-REF + self.display_format = display_format # .DISPLAY-FORMAT - def append(self, paragraph: LanguageVerbatim) -> None: + def ref(self) -> CompuMethodRef | None: """ - Adds long_name to its inner list with type-check + Returns a reference to this element or + None if the element is not yet part of a package """ - assert isinstance(paragraph, LanguageVerbatim) - self.elements.append(paragraph) + ref_str = self._calc_ref_string() + return None if ref_str is None else CompuMethodRef(ref_str) -class MixedContentForUnitNames(ARObject): +# Constraint elements + + +class LimitObject(ARObject): """ - Group MIXED-CONTENT-FOR-UNIT-NAMES + Base class for elements that has + upper and lower limits Type: Abstract """ - def __init__(self) -> None: - self.parts = [] # Unbounded list of str | SUB | SUP - - def append(self, - part: str | Break | EmphasisText | TechnicalTerm): - """ - Checks type validity before adding element to elements - """ - if isinstance(part, (str, Subscript, Superscript)): - self.parts.append(part) - else: - raise TypeError('Unsupported element type: ' + str(type(part))) - + def __init__(self, + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: -class SingleLanguageUnitNames(MixedContentForUnitNames): - """ - Complex type AR:SINGLE-LANGUAGE-UNIT-NAMES - Type: Concrete - Tag variants: 'PRM-UNIT' | 'UNIT-DISPLAY-NAME' | 'UNIT-DISPLAY-NAME' | 'DISPLAY-NAME' - """ + self.lower_limit = lower_limit # .LOWER-LIMIT + self.upper_limit = upper_limit # .UPPER-LIMIT + self.lower_limit_type = lower_limit_type # .LOWER-LIMIT@INTERVAL-TYPE + self.upper_limit_type = upper_limit_type # .UPPER-LIMIT@INTERVAL-TYPE - def __init__(self, parts: str | list | None = None) -> None: - super().__init__() - if parts is not None: - if isinstance(parts, Iterable): - for part in parts: - self.append(part) - else: - self.append(parts) + @property + def is_empty(self) -> bool: + """Overrides is_empty from base class""" + return self.is_empty_with_ignore({"lower_limit_type", "upper_limit_type"}) - def __str__(self) -> str: + def check_value(self, value: int | float) -> bool: """ - Convert to string if the unit name has simple - type (at most one part of type str). + Checks if given value is inside the constraint limits """ - result = [] - for part in self.parts: - if isinstance(part, str): - result.append(part) - elif isinstance(part, Superscript): - result.append(str(part)) - else: - raise ValueError("Unable to convert to string from multiple parts") - return "".join(result) + if self.lower_limit_type == ar_enum.IntervalType.CLOSED: + if value < self.lower_limit: + return False + elif value <= self.lower_limit: + return False + if self.upper_limit_type == ar_enum.IntervalType.CLOSED: + if value > self.upper_limit: + return False + elif value >= self.upper_limit: + return False + return True -class DocumentationBlock(ARObject): +class ScaleConstraint(LimitObject): """ - Complex type AR:DOCUMENTATION-BLOCK + AR:SCALE-CONSTR Type: Concrete - Tag Variants: 'INTRODUCTION', 'DEF', 'VALUE', 'ANNOTATION-TEXT', 'REMARK' - 'COND', 'DESCRICPTION', 'RATIONALE', 'DEPENDENCIES', 'USE-CASE', - 'CONFLICTS', 'SUPPORTING-MATERIAL', 'SW-GENERIC-AXIS-DESC' + Tag variants: 'SCALE-CONSTR' """ def __init__(self, - element: MultiLanguageParagraph | MultiLanguageVerbatim | list[Any] | None = None) -> None: - self.elements: list[MultiLanguageParagraph | MultiLanguageVerbatim] = [] - if element is not None: - if isinstance(element, Iterable): - for elem in element: - self.append(elem) - else: - self.append(element) - - def append(self, element: MultiLanguageParagraph | MultiLanguageVerbatim) -> None: - """ - Appends new element with type check - """ - assert isinstance(element, - (MultiLanguageParagraph, - MultiLanguageVerbatim)) - self.elements.append(element) + label: str | None = None, + desc: MultiLanguageOverviewParagraph | None = None, + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + validity: ar_enum.ScaleConstraintValidity | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + super().__init__(lower_limit, upper_limit, lower_limit_type, upper_limit_type) + self.label = label + self.desc = desc + self.validity = validity -class GeneralAnnotation(ARObject): +class ConstraintBase(LimitObject): """ - Group AR:GENERAL-ANNOTATION + Base class data constraint rules Type: Abstract """ def __init__(self, - label: MultilanguageLongName | None = None, - origin: str | None = None, - text: DocumentationBlock | None = None) -> None: - super().__init__() - self.label = label # .LABEL - self.origin = origin # .ANNOTATION-ORIGIN - self.text = text # .ANNOTATION-TEXT + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + scale_constrs: list[ScaleConstraint] | None = None, + max_gradient: int | float | None = None, + max_diff: int | float | None = None, + monotony: ar_enum.Monotony | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + super().__init__(lower_limit, upper_limit, lower_limit_type, upper_limit_type) + self.scale_constrs = list(scale_constrs) if scale_constrs else [] + self.max_gradient = max_gradient + self.max_diff = max_diff + self.monotony = monotony -class Annotation(GeneralAnnotation): +class InternalConstraint(ConstraintBase): """ - Complex type AR:ANNOTATION + AR:INTERNAL-CONSTRS Type: Concrete - """ - - def __init__(self, # pylint: disable=useless-parent-delegation - label: MultilanguageLongName | None = None, - origin: str | None = None, - text: DocumentationBlock | None = None) -> None: - super().__init__(label, origin, text) - - -class Describable(ARObject): - """ - Group AR:DESCRIBABLE + Tag variants: 'INTERNAL-CONSTRS' """ def __init__(self, - desc: Union["MultiLanguageOverviewParagraph", tuple[ar_enum.Language, str], str, None] = None, - category: str | None = None, - introduction: DocumentationBlock | None = None, - admin_data: AdminData | None = None - ) -> None: - super().__init__() - self.desc: MultiLanguageOverviewParagraph | None = None # .DESC - self.category: str | None = None # .CATEGORY - self.introduction: DocumentationBlock | None = None # .INTRODUCTION - self.admin_data: AdminData | None = None # .ADMIN-DATA - if desc is not None: - if isinstance(desc, MultiLanguageOverviewParagraph): - self.desc = desc - elif isinstance(desc, str): - self.desc = MultiLanguageOverviewParagraph.make(ar_enum.Language.FOR_ALL, desc) - elif isinstance(desc, tuple) and len(desc) == 2: - self.desc = MultiLanguageOverviewParagraph.make(*desc) - else: - raise TypeError(f"Invalid type for argument 'desc': {str(type(desc))}") - self._assign_optional('category', category, str) - self._assign_optional_strict('introduction', introduction, DocumentationBlock) - self._assign_optional_strict('admin_data', admin_data, AdminData) - - -# --- Computation method elements + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + scale_constr: list[ScaleConstraint] | None = None, + max_gradient: int | float | None = None, + max_diff: int | float | None = None, + monotony: ar_enum.Monotony | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + super().__init__(lower_limit, + upper_limit, + scale_constr, + max_gradient, + max_diff, + monotony, + lower_limit_type, + upper_limit_type) -class CompuRational(ARObject): +class PhysicalConstraint(ConstraintBase): """ - AR:COMPU-RATIONAL-COEFFS + AR:PHYS-CONSTRS Type: Concrete - Tag variants: 'COMPU-RATIONAL-COEFFS' + Tag variants: 'PHYS-CONSTRS' """ def __init__(self, - numerator: tuple[int | float] | list[int | float] | None, - denominator: tuple[int | float] | list[int | float] | None = None) -> None: - if numerator is not None: - if not isinstance(numerator, (tuple, list)): - raise TypeError("Parameter for 'numerator' must be either a list or a tuple") - self.numerator = tuple(numerator) - else: - self.numerator = None - if denominator is not None: - if not isinstance(denominator, (tuple, list)): - raise TypeError("Parameter for 'denominator' must be either a list or a tuple") - self.denominator = tuple(denominator) - else: - self.denominator = None + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + scale_constr: list[ScaleConstraint] | None = None, + max_gradient: int | float | None = None, + max_diff: int | float | None = None, + monotony: ar_enum.Monotony | None = None, + unit_ref: UnitRef | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + super().__init__(lower_limit, + upper_limit, + scale_constr, + max_gradient, + max_diff, + monotony, + lower_limit_type, + upper_limit_type) + self.unit_ref = unit_ref -class CompuConst(ARObject): +class DataConstraintRule(ARObject): """ - AR:COMPU-CONST + AR:DATA-CONSTR-RULE Type: Concrete - - Handles AR:COMPU-CONST-NUMERIC-CONTENT - and AR:COMPU-CONST-TEXT-CONTENT dynamically + Tag variants: 'DATA-CONSTR-RULE' """ - def __init__(self, value: int | float | str): - self.value = value + def __init__(self, + internal: InternalConstraint | None = None, + physical: PhysicalConstraint | None = None, + level: int | None = None) -> None: + self.internal = internal # .INTERNAL-CONSTRS + self.physical = physical # .PHYS-CONSTRS + self.level = level # .CONSTR-LEVEL -class CompuScale(ARObject): +class DataConstraint(ARElement): """ - AR:COMPU-SCALE + AR:DATA-CONSTR Type: Concrete - Tag variants: 'COMPU-SCALE' + Tag variants: 'DATA-CONSTR' """ - def __init__(self, - content: CompuConst | CompuRational | None = None, - lower_limit: int | float | str | None = None, - upper_limit: int | float | str | None = None, - label: str | None = None, - symbol: str | None = None, - desc: MultiLanguageOverviewParagraph | None = None, - mask: int | None = None, - inverse_value: CompuConst | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: - self.content = content # CHOICE(COMPU-SCALE-CONSTANT-CONTENTS, COMPU-SCALE-RATIONAL-FORMULA) # noqa E501 pylint: disable=C0301 - self.lower_limit = lower_limit # .LOWER-LIMIT - self.upper_limit = upper_limit # .UPPER-LIMIT - self.label = label # .SHORT-LABEL - self.symbol = symbol # .SYMBOL - self.desc = desc # .DESC - self.mask = mask # .MASK - self.inverse_value: CompuConst | None = None # .COMPU-INVERSE-VALUE - if inverse_value is not None: - if isinstance(inverse_value, CompuConst): - self.inverse_value = inverse_value - elif isinstance(inverse_value, (int, float, str)): - self.inverse_value = CompuConst(inverse_value) - else: - raise TypeError(f"Invalid type for 'inverse_value': {str(type(inverse_value))}") - self.lower_limit_type = lower_limit_type # .LOWER-LIMIT@INTERVAL-TYPE - self.upper_limit_type = upper_limit_type # .UPPER-LIMIT@INTERVAL-TYPE - # .VARIATION-POINT not supported + def __init__(self, name: str, + rules: list[DataConstraintRule] | None = None, + **kwargs: dict) -> None: + super().__init__(name, **kwargs) + self.rules = [] + if rules is not None: + for rule in rules: + assert isinstance(rule, DataConstraintRule) + self.rules.extend(rules) - @property - def content_type(self) -> ar_enum.CompuScaleContent: + def ref(self) -> DataConstraintRef: """ - What kind of content does this CompuScale have? + Returns a reference to this element or None if the element + is not yet part of a package """ - if isinstance(self.content, CompuConst): - return ar_enum.CompuScaleContent.CONSTANT - elif isinstance(self.content, CompuRational): - return ar_enum.CompuScaleContent.RATIONAL - else: - return ar_enum.CompuScaleContent.NONE - - -class Computation(ARObject): - """ - AR:COMPU - Type: Concrete - Tag variants: 'COMPU-INTERNAL-TO-PHYS' | 'COMPU-PHYS-TO-INTERNAL' - """ - - def __init__(self, - compu_scales: list[CompuScale] | None = None, - default_value: CompuConst | int | float | str | None = None) -> None: - - self.compu_scales = compu_scales - self.default_value: CompuConst | int | float | str | None = None # .COMPU-DEFAULT-VALUE - if isinstance(default_value, CompuConst): - self.default_value = default_value - elif isinstance(default_value, (int, float, str)): - self.default_value = CompuConst(default_value) + ref_str = self._calc_ref_string() + return None if ref_str is None else DataConstraintRef(ref_str) @classmethod - def make_value_table(cls: "Computation", - elements: list[Any], - default_value: CompuConst | int | float | str | None = None, - auto_label: bool = True): + def make_physical(cls: "DataConstraint", + name: str, + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + scale_constr: list[ScaleConstraint] | None = None, + max_gradient: int | float | None = None, + max_diff: int | float | None = None, + monotony: ar_enum.Monotony | None = None, + unit_ref: UnitRef | None = None, + lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + **kwargs) -> "DataConstraint": """ #convenience-method - Creates new CompuConst-based computation using values from a list. - - When elements is a list of strings: - Creates one CompuScale per list item and automatically calculates lower and upper limits. - Enumeration starts counting from zero and increments by one until the end of the list. - - When elements is a list of tuples: - If 2-tuple: First element is both lower_limit and upper_limit, second element is text value. - If 3-tuple: First element is lower_limit, second element is upper_limit, third element is text value. - - auto_label: automatically creates a based on the text value. - + Creates a DataConstraint which contains a single physical constraint. """ - compu_scales = [] - for i, elem in enumerate(elements): - label = None - if isinstance(elem, str): - lower_limit, upper_limit, value = i, i, elem - elif isinstance(elem, tuple): - if len(elem) == 2: - lower_limit, upper_limit, value = (elem[0], elem[0], elem[1]) - elif len(elem) == 3: - lower_limit, upper_limit, value = elem - else: - raise ValueError(f"Invalid length of tuple: {len(elem)}") - else: - raise TypeError(f"Invalid type of element: {str(type(elem))}") - if auto_label and isinstance(value, str): - label = value - compu_scales.append(CompuScale(CompuConst(value), lower_limit, upper_limit, label)) - return cls(compu_scales, default_value) + rule = DataConstraintRule(physical=PhysicalConstraint(lower_limit, + upper_limit, + scale_constr, + max_gradient, + max_diff, + monotony, + unit_ref, + lower_limit_type, + upper_limit_type)) + return cls(name, [rule], **kwargs) @classmethod - def make_rational(cls: "Computation", - scaling_factor: int | float = 1, - offset: int | float = 0, - lower_limit: int | float | str | None = None, - upper_limit: int | float | str | None = None, - default_value: CompuConst | int | float | str | None = None, + def make_internal(cls: "DataConstraint", + name: str, + lower_limit: int | float | None = None, + upper_limit: int | float | None = None, + scale_constr: list[ScaleConstraint] | None = None, + max_gradient: int | float | None = None, + max_diff: int | float | None = None, + monotony: ar_enum.Monotony | None = None, lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, + **kwargs) -> "DataConstraint": """ #convenience-method - Creates a new Computation instance with one COMPU-SCALE containing numerator - and denominator. - + Creates a DataConstraint that contains a single internal constraint. """ - numerator = [offset, float(scaling_factor)] - denominator = [1] - compu_scales = [CompuScale(CompuRational(numerator, denominator), - lower_limit, - upper_limit, - lower_limit_type=lower_limit_type, - upper_limit_type=upper_limit_type)] - return cls(compu_scales, default_value) + rule = DataConstraintRule(internal=InternalConstraint(lower_limit, + upper_limit, + scale_constr, + max_gradient, + max_diff, + monotony, + lower_limit_type, + upper_limit_type)) + return cls(name, [rule], **kwargs) +# Unit elements -class CompuMethod(ARElement): + +class Unit(ARElement): """ - AR:COMPU-METHOD + Complex type AR:UNIT Type: Concrete - Tag Variants: 'COMPU-METHOD' + Tag variants: 'UNIT' """ def __init__(self, name: str, - int_to_phys: Computation | None = None, - phys_to_int: Computation | None = None, - unit_ref: UnitRef | None = None, - display_format: str | None = None, - **kwargs) -> None: + display_name: str | SingleLanguageUnitNames | None = None, + factor: float | None = None, + offset: float | None = None, + physical_dimension_ref: str | PhysicalDimensionRef | None = None, + **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.int_to_phys = int_to_phys # .COMPU-INTERNAL-TO-PHYS - self.phys_to_int = phys_to_int # .COMPU-PHYS-TO-INTERNAL - self.unit_ref = unit_ref # .UNIT-REF - self.display_format = display_format # .DISPLAY-FORMAT + self.display_name: SingleLanguageUnitNames | None = None # .DISPLAY-NAME + self.physical_dimension_ref: PhysicalDimensionRef | None = None # .PHYSICAL-DIMENSION-REF + self.factor: float | None = None # .FACTOR-SI-TO-UNIT + self.offset: float | None = None # .OFFSET-SI-TO-UNIT + if display_name is not None: + if isinstance(display_name, str): + self.display_name = SingleLanguageUnitNames(display_name) + elif isinstance(display_name, SingleLanguageUnitNames): + self.display_name = display_name + else: + raise TypeError(f"display_name: Invalid type '{str(type(display_name))}'") + if physical_dimension_ref is not None: + if isinstance(physical_dimension_ref, str): + self.physical_dimension_ref = PhysicalDimensionRef(display_name) + elif isinstance(physical_dimension_ref, PhysicalDimensionRef): + self.physical_dimension_ref = physical_dimension_ref + else: + raise TypeError(f"physical_dimension_ref: Invalid type '{str(type(physical_dimension_ref))}'") + self._assign_optional('factor', factor, float) + self._assign_optional('offset', offset, float) - def ref(self) -> CompuMethodRef | None: + def ref(self) -> UnitRef: """ - Returns a reference to this element or - None if the element is not yet part of a package + Returns a reference to this element or None if the element + is not yet part of a package """ ref_str = self._calc_ref_string() - return None if ref_str is None else CompuMethodRef(ref_str) + return None if ref_str is None else UnitRef(ref_str) -# Constraint elements +# DataDictionary and DataType elements -class LimitObject(ARObject): +class BaseType(ARElement): """ - Base class for elements that has - upper and lower limits + Merge of Complex types AR:BASE-TYPE, AR:BASE-TYPE-DEFINITION, + AR:BASE-TYPE-DIRECT-DEFINITION Type: Abstract """ - def __init__(self, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: + def __init__(self, name: str, **kwargs: dict) -> None: + super().__init__(name, **kwargs) + self.size: int | None = None # .BASE-TYPE-SIZE + self.max_size: int | None = None # .MAX-BASE-TYPE-SIZE + self.encoding: str | None = None # .BASE-TYPE-ENCODING + self.alignment: int | None = None # .MEM-ALIGNMENT + self.byte_order: ar_enum.ByteOrder | None = None # .BYTE-ORDER + self.native_declaration: str | None = None # .NATIVE-DECLARATION - self.lower_limit = lower_limit # .LOWER-LIMIT - self.upper_limit = upper_limit # .UPPER-LIMIT - self.lower_limit_type = lower_limit_type # .LOWER-LIMIT@INTERVAL-TYPE - self.upper_limit_type = upper_limit_type # .UPPER-LIMIT@INTERVAL-TYPE - @property - def is_empty(self) -> bool: - """Overrides is_empty from base class""" - return self.is_empty_with_ignore({"lower_limit_type", "upper_limit_type"}) +class SwBaseType(BaseType): + """ + Complex type AR:SW-BASE-TYPE + Type: Concrete + Tag variants: SW-BASE-TYPE + """ - def check_value(self, value: int | float) -> bool: + def __init__(self, + name: str, + size: int | None = None, + max_size: int | None = None, + encoding: str | None = None, + alignment: int | None = None, + byte_order: ar_enum.ByteOrder | None = None, + native_declaration: str | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.size = size + self.max_size = max_size + self.encoding = encoding + self.alignment = alignment + self.byte_order = byte_order + self.native_declaration = native_declaration + + def ref(self) -> SwBaseTypeRef | None: """ - Checks if given value is inside the constraint limits + Returns a reference to this element or None if the element + is not yet part of a package """ - if self.lower_limit_type == ar_enum.IntervalType.CLOSED: - if value < self.lower_limit: - return False - elif value <= self.lower_limit: - return False - if self.upper_limit_type == ar_enum.IntervalType.CLOSED: - if value > self.upper_limit: - return False - elif value >= self.upper_limit: - return False - return True + ref_str = self._calc_ref_string() + return None if ref_str is None else SwBaseTypeRef(ref_str) -class ScaleConstraint(LimitObject): +class SwBitRepresentation(ARObject): """ - AR:SCALE-CONSTR + SW-BIT-REPRESENTATION Type: Concrete - Tag variants: 'SCALE-CONSTR' """ def __init__(self, - label: str | None = None, - desc: MultiLanguageOverviewParagraph | None = None, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - validity: ar_enum.ScaleConstraintValidity | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: - super().__init__(lower_limit, upper_limit, lower_limit_type, upper_limit_type) - self.label = label - self.desc = desc - self.validity = validity + position: int | None = None, + num_bits: int | None = None) -> None: + super().__init__() + self.position: int | None = None + self.num_bits: int | None = None + self._assign_optional('position', position, int) + self._assign_optional('num_bits', num_bits, int) -class ConstraintBase(LimitObject): +class SwTextProps(ARObject): """ - Base class data constraint rules - Type: Abstract + Complex type AR:SW-TEXT-PROPS + Type: Concrete + Tag Variants: 'SW-TEXT-PROPS' """ def __init__(self, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - scale_constrs: list[ScaleConstraint] | None = None, - max_gradient: int | float | None = None, - max_diff: int | float | None = None, - monotony: ar_enum.Monotony | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: - super().__init__(lower_limit, upper_limit, lower_limit_type, upper_limit_type) - self.scale_constrs = list(scale_constrs) if scale_constrs else [] - self.max_gradient = max_gradient - self.max_diff = max_diff - self.monotony = monotony + array_size_semantics: ar_enum.ArraySizeSemantics | None = None, + max_text_size: int | None = None, + base_type_ref: SwBaseTypeRef | str | None = None, + fill_char: int | None = None, + ): + self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS + self.max_text_size: int | None = None # .SW-MAX-TEXT-SIZE + self.base_type_ref: SwBaseTypeRef | str | None = None # .BASE-TYPE-REF + self.fill_char: int | None = None # .FILL-CHAR + self._assign_optional('array_size_semantics', array_size_semantics, ar_enum.ArraySizeSemantics) + self._assign_optional('max_text_size', max_text_size, int) + self._assign_optional('base_type_ref', base_type_ref, SwBaseTypeRef) + self._assign_optional('fill_char', fill_char, int) -class InternalConstraint(ConstraintBase): +class SwPointerTargetProps(ARObject): """ - AR:INTERNAL-CONSTRS + Complex type AR:SW-POINTER-TARGET-PROPS Type: Concrete - Tag variants: 'INTERNAL-CONSTRS' + Tag Variants: 'SW-POINTER-TARGET-PROPS' """ def __init__(self, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - scale_constr: list[ScaleConstraint] | None = None, - max_gradient: int | float | None = None, - max_diff: int | float | None = None, - monotony: ar_enum.Monotony | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: - super().__init__(lower_limit, - upper_limit, - scale_constr, - max_gradient, - max_diff, - monotony, - lower_limit_type, - upper_limit_type) + target_category: str | None = None, + sw_data_def_props: Union["SwDataDefProps", "SwDataDefPropsConditional", None] = None, + function_ptr_signature_ref: FunctionPtrSignatureRef | None = None + ) -> None: + self.target_category: str | None = None # .TARGET-CATEGORY + self.sw_data_def_props: Union["SwDataDefProps", None] = None # .SW-DATA-DEF-PROPS + self.function_ptr_signature_ref: FunctionPtrSignatureRef | None = None # .FUNCTION-POINTER-SIGNATURE-REF + self._assign_optional("target_category", target_category, str) + self._assign_optional("function_ptr_signature_ref", function_ptr_signature_ref, FunctionPtrSignatureRef) + if sw_data_def_props is not None: + if isinstance(sw_data_def_props, SwDataDefProps): + self.sw_data_def_props = sw_data_def_props + elif isinstance(sw_data_def_props, SwDataDefPropsConditional): + self.sw_data_def_props = SwDataDefProps(sw_data_def_props) + else: + raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") -class PhysicalConstraint(ConstraintBase): +class SwDataDefPropsConditional(ARObject): """ - AR:PHYS-CONSTRS + Merge of Complex types AR:SW-DATA-DEF-PROPS-CONDITIONAL and + AR:SW-DATA-DEF-PROPS-CONTENT Type: Concrete - Tag variants: 'PHYS-CONSTRS' + Tag Variants: SW-DATA-DEF-PROPS-CONDITIONAL """ def __init__(self, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - scale_constr: list[ScaleConstraint] | None = None, - max_gradient: int | float | None = None, - max_diff: int | float | None = None, - monotony: ar_enum.Monotony | None = None, - unit_ref: UnitRef | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED) -> None: - super().__init__(lower_limit, - upper_limit, - scale_constr, - max_gradient, - max_diff, - monotony, - lower_limit_type, - upper_limit_type) - self.unit_ref = unit_ref - - -class DataConstraintRule(ARObject): - """ - AR:DATA-CONSTR-RULE - Type: Concrete - Tag variants: 'DATA-CONSTR-RULE' - """ + display_presentation: ar_enum.DisplayPresentation | None = None, + step_size: float | None = None, + annotations: Annotation | list[Annotation] | None = None, + sw_addr_method_ref: str | SwAddrMethodRef | None = None, + base_type_ref: SwBaseTypeRef | None = None, + compu_method_ref: str | CompuMethodRef | None = None, + data_constraint_ref: str | DataConstraintRef | None = None, + impl_data_type_ref: str | ImplementationDataTypeRef | None = None, + unit_ref: str | UnitRef | None = None, + alignment: int | float | None = None, + bit_representation: SwBitRepresentation | None = None, + calibration_access: ar_enum.SwCalibrationAccess | None = None, + text_props: SwTextProps | None = None, + display_format: str | None = None, + impl_policy: ar_enum.SwImplPolicy | None = None, + additional_native_type_qualifier: str | None = None, + intended_resolution: int | float | None = None, + interpolation_method: str | None = None, + is_virtual: bool | None = None, + ptr_target_props: SwPointerTargetProps | None = None + ) -> None: + # .DISPLAY-PRESENTATION + self.display_presentation: ar_enum.DisplayPresentation | None = None + self.step_size: float | None = None # .STEP-SIZE : AR:FLOAT + # .SW-VALUE-BLOCK-SIZE-MULTS not supported. + self.annotations: list[Annotation] = [] # .ANNOTATIONS + self.sw_addr_method_ref: SwAddrMethodRef | None = None # .SW-ADDR-METHOD-REF + self.alignment: int | str | None = None # .SW-ALIGNMENT + self.base_type_ref: SwBaseTypeRef | None = None # .BASE-TYPE-REF + self.bit_representation: SwBitRepresentation | None = None # .SW-BIT-REPRESENTATION + self.calibration_access: ar_enum.SwCalibrationAccess | None = None # .SW-CALIBRATION-ACCESS + # .SW-VALUE-BLOCK-SIZE not supported. + # .SW-CALPRM-AXIS-SET not yet supported. Low on priority list. + self.text_props: SwTextProps | None = None # .SW-TEXT-PROPS + # .SW-COMPARISON-VARIABLES not yet supported. Low on priority list. + self.compu_method_ref: CompuMethodRef | None = None + self.data_constraint_ref: DataConstraintRef | None = None + # .SW-DATA-DEPENDENCY not yet supported. Low on priority list. + self.display_format: str | None = None # .DISPLAY-FORMAT + self.impl_data_type_ref: ImplementationDataTypeRef | None = None # .IMPLEMENTATION-DATA-TYPE-REF + # .SW-HOST-VARIABLE not yet supported. Low on priority list. + self.impl_policy: ar_enum.SwImplPolicy | None = None # .SW-IMPL-POLICY + self.additional_native_type_qualifier: str | None = None # .ADDITIONAL-NATIVE-TYPE-QUALIFIER + self.intended_resolution: int | float | None = None # .SW-INTENDED-RESOLUTION + self.interpolation_method: str | None = None # .SW-INTERPOLATION-METHOD + # .INVALID-VALUE not yet supported. + # .MC-FUNCTION not yet supported. Low on priority list. + self.is_virtual: bool | None = None # .IS-VIRTUAL + self.ptr_target_props: SwPointerTargetProps | None = None # .SW-POINTER-TARGET-PROPS + # .SW-RECORD-LAYOUT-REF not yet supported. Low on priority list. + # .SW-REFRESH-TIMING not yet supported. Low on priority list. + self.unit_ref = None # .UNIT-REF + # .VALUE-AXIS-DATA-TYPE-REF not yet supported. Low on priority list. - def __init__(self, - internal: InternalConstraint | None = None, - physical: PhysicalConstraint | None = None, - level: int | None = None) -> None: - self.internal = internal # .INTERNAL-CONSTRS - self.physical = physical # .PHYS-CONSTRS - self.level = level # .CONSTR-LEVEL + self._assign_optional('display_presentation', display_presentation, ar_enum.DisplayPresentation) + self._assign_optional('step_size', step_size, float) + if annotations is not None: + if isinstance(annotations, Annotation): + self.annotations.append(annotations) + elif isinstance(annotations, Iterable): + for annotation in annotations: + if not isinstance(annotation, Annotation): + raise TypeError( + f"Param annotations: Expected type 'Annotation', got '{str(type(annotation))}'") + self.annotations.append(annotation) + else: + raise TypeError( + "Param annotations: " + f"Expected type 'Annotation' or list[Annotation], got '{str(type(annotations))}'") + self._assign_optional('sw_addr_method_ref', sw_addr_method_ref, SwAddrMethodRef) + self._assign_int_or_str_pattern_optional('alignment', alignment, alignment_type_re) + self._assign_optional('base_type_ref', base_type_ref, SwBaseTypeRef) + if bit_representation is not None: + if not isinstance(bit_representation, SwBitRepresentation): + raise TypeError(f"bit_representation: Invalid type '{str(type(bit_representation))}'." + " Expected 'SwBitRepresentation'") + self.bit_representation = bit_representation + self._assign_optional('calibration_access', calibration_access, ar_enum.SwCalibrationAccess) + if text_props is not None: + if not isinstance(text_props, SwTextProps): + raise TypeError(f"text_props: Invalid type '{str(type(text_props))}'." + " Expected 'SwTextProps'") + self.text_props = text_props + self._assign_optional('compu_method_ref', compu_method_ref, CompuMethodRef) + self._assign_optional('data_constraint_ref', data_constraint_ref, DataConstraintRef) + self._assign_optional('impl_data_type_ref', impl_data_type_ref, ImplementationDataTypeRef) + self._assign_optional('unit_ref', unit_ref, UnitRef) + self._assign_int_or_str_pattern_optional('display_format', display_format, display_format_str_re) + self._assign_optional('impl_policy', impl_policy, ar_enum.SwImplPolicy) + self._assign_optional('additional_native_type_qualifier', + additional_native_type_qualifier, str) + if intended_resolution is not None: + if isinstance(intended_resolution, (int, float)): + self.intended_resolution = intended_resolution + else: + raise TypeError(f"Invalid type '{str(type(intended_resolution))}' for paramater 'intended_resolution'") + self._assign_optional('interpolation_method', interpolation_method, str) + self._assign_optional('is_virtual', is_virtual, bool) + 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 DataConstraint(ARElement): +class SwDataDefProps(ARObject): """ - AR:DATA-CONSTR - Type: Concrete - Tag variants: 'DATA-CONSTR' + Complex type AR:SW-DATA-DEF-PROPS + Tag variants: 'SW-DATA-DEF-PROPS' | 'NETWORK-REPRESENTATION' | + 'NETWORK-REPRESENTATION-PROPS' | 'PHYSICAL-PROPS' """ - def __init__(self, name: str, - rules: list[DataConstraintRule] | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.rules = [] - if rules is not None: - for rule in rules: - assert isinstance(rule, DataConstraintRule) - self.rules.extend(rules) + def __init__(self, variants: SwDataDefPropsConditional | list[SwDataDefPropsConditional] | None = None) -> None: + super().__init__() + self.variants: list[SwDataDefPropsConditional] = [] # .SW-DATA-DEF-PROPS-VARIANTS + if variants is not None: + if isinstance(variants, list): + for variant in variants: + self.append(variant) + elif isinstance(variants, SwDataDefPropsConditional): + self.append(variants) + else: + raise TypeError("variant must be one of (SwDataDefPropsConditional, list[SwDataDefPropsConditional])") - def ref(self) -> DataConstraintRef: + def __getitem__(self, index: int) -> SwDataDefPropsConditional: """ - Returns a reference to this element or None if the element - is not yet part of a package + Accessor of variants list """ - ref_str = self._calc_ref_string() - return None if ref_str is None else DataConstraintRef(ref_str) + return self.variants[index] - @classmethod - def make_physical(cls: "DataConstraint", - name: str, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - scale_constr: list[ScaleConstraint] | None = None, - max_gradient: int | float | None = None, - max_diff: int | float | None = None, - monotony: ar_enum.Monotony | None = None, - unit_ref: UnitRef | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - **kwargs) -> "DataConstraint": + def __len__(self) -> int: """ - #convenience-method - - Creates a DataConstraint which contains a single physical constraint. + Length of variants list """ - rule = DataConstraintRule(physical=PhysicalConstraint(lower_limit, - upper_limit, - scale_constr, - max_gradient, - max_diff, - monotony, - unit_ref, - lower_limit_type, - upper_limit_type)) - return cls(name, [rule], **kwargs) + return len(self.variants) - @classmethod - def make_internal(cls: "DataConstraint", - name: str, - lower_limit: int | float | None = None, - upper_limit: int | float | None = None, - scale_constr: list[ScaleConstraint] | None = None, - max_gradient: int | float | None = None, - max_diff: int | float | None = None, - monotony: ar_enum.Monotony | None = None, - lower_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - upper_limit_type: ar_enum.IntervalType = ar_enum.IntervalType.CLOSED, - **kwargs) -> "DataConstraint": + def __iter__(self): """ - #convenience-method - - Creates a DataConstraint that contains a single internal constraint. + Iterator of variants list """ - rule = DataConstraintRule(internal=InternalConstraint(lower_limit, - upper_limit, - scale_constr, - max_gradient, - max_diff, - monotony, - lower_limit_type, - upper_limit_type)) - return cls(name, [rule], **kwargs) + return iter(self.variants) -# Unit elements + def append(self, variant: SwDataDefPropsConditional): + """ + Appends SW-DATA-DEF-PROPS-CONDITIONAL to variants list + """ + if isinstance(variant, SwDataDefPropsConditional): + self.variants.append(variant) + else: + raise TypeError("variant must be of type SwDataDefPropsConditional") -class Unit(ARElement): +class AutosarDataType(ARElement): """ - Complex type AR:UNIT - Type: Concrete - Tag variants: 'UNIT' + Element AUTOSAR-DATA-TYPE + Type: Abstract """ - def __init__(self, name: str, - display_name: str | SingleLanguageUnitNames | None = None, - factor: float | None = None, - offset: float | None = None, - physical_dimension_ref: str | PhysicalDimensionRef | None = None, + def __init__(self, + name: str, + sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.display_name: SingleLanguageUnitNames | None = None # .DISPLAY-NAME - self.physical_dimension_ref: PhysicalDimensionRef | None = None # .PHYSICAL-DIMENSION-REF - self.factor: float | None = None # .FACTOR-SI-TO-UNIT - self.offset: float | None = None # .OFFSET-SI-TO-UNIT - if display_name is not None: - if isinstance(display_name, str): - self.display_name = SingleLanguageUnitNames(display_name) - elif isinstance(display_name, SingleLanguageUnitNames): - self.display_name = display_name + self.sw_data_def_props: SwDataDefProps | None = None + if sw_data_def_props is not None: + if isinstance(sw_data_def_props, SwDataDefProps): + self.sw_data_def_props = sw_data_def_props + elif isinstance(sw_data_def_props, SwDataDefPropsConditional): + self.sw_data_def_props = SwDataDefProps(sw_data_def_props) else: - raise TypeError(f"display_name: Invalid type '{str(type(display_name))}'") - if physical_dimension_ref is not None: - if isinstance(physical_dimension_ref, str): - self.physical_dimension_ref = PhysicalDimensionRef(display_name) - elif isinstance(physical_dimension_ref, PhysicalDimensionRef): - self.physical_dimension_ref = physical_dimension_ref - else: - raise TypeError(f"physical_dimension_ref: Invalid type '{str(type(physical_dimension_ref))}'") - self._assign_optional('factor', factor, float) - self._assign_optional('offset', offset, float) + raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") - def ref(self) -> UnitRef: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - return None if ref_str is None else UnitRef(ref_str) +class ImplementationProps(Referrable): + """ + Group AR:IMPLEMENTATION-PROPS + """ -# DataDictionary and DataType elements + def __init__(self, + name: str, + symbol: str | None = None) -> None: + super().__init__(name) + self.symbol: str | None = None + self._assign_optional('symbol', symbol, str) -class BaseType(ARElement): +class SymbolProps(ImplementationProps): """ - Merge of Complex types AR:BASE-TYPE, AR:BASE-TYPE-DEFINITION, - AR:BASE-TYPE-DIRECT-DEFINITION - Type: Abstract + Complex type AR:SYMBOL-PROPS + Type: Concrete + Tag Variants: 'SYMBOL-PROPS', 'EVENT-SYMBOL-PROPS' """ - def __init__(self, name: str, **kwargs: dict) -> None: + +class ImplementationDataTypeElement(Identifiable): + """ + Complex type AR:IMPLEMENTATION-DATA-TYPE-ELEMENT + Type: Concrete + Tag variants: 'IMPLEMENTATION-DATA-TYPE-ELEMENT' + """ + + def __init__(self, + name: str, + sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, + array_size: int | None = None, + array_impl_policy: ar_enum.ArrayImplPolicy | None = None, + array_size_handling: ar_enum.ArraySizeHandling | None = None, + array_size_semantics: ar_enum.ArraySizeSemantics | None = None, + sub_elements: list["ImplementationDataTypeElement"] | None = None, + is_optional: bool | None = None, + **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.size: int | None = None # .BASE-TYPE-SIZE - self.max_size: int | None = None # .MAX-BASE-TYPE-SIZE - self.encoding: str | None = None # .BASE-TYPE-ENCODING - self.alignment: int | None = None # .MEM-ALIGNMENT - self.byte_order: ar_enum.ByteOrder | None = None # .BYTE-ORDER - self.native_declaration: str | None = None # .NATIVE-DECLARATION + self.array_size: int | None = None # .ARRAY-SIZE + self.array_impl_policy: ar_enum.ArrayImplPolicy | None = None # .ARRAY-IMPL-POLICY + self.array_size_handling: ar_enum.ArraySizeHandling | None = None # .ARRAY-SIZE-HANDLING + self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS + self.is_optional: bool | None = None # .IS-OPTIONAL + self.sub_elements: list["ImplementationDataTypeElement"] | None = [] # .SUB-ELEMENTS + self.sw_data_def_props: SwDataDefProps | None = None # .SW-DATA-DEF-PROPS + self._assign_optional_positive_int("array_size", array_size) + self._assign_optional("array_impl_policy", array_impl_policy, ar_enum.ArrayImplPolicy) + self._assign_optional("array_size_handling", array_size_handling, ar_enum.ArraySizeHandling) + self._assign_optional("array_size_semantics", array_size_semantics, ar_enum.ArraySizeSemantics) + self._assign_optional("is_optional", is_optional, bool) + if sub_elements is not None: + for elem in sub_elements: + self.append(elem) + if sw_data_def_props is not None: + if isinstance(sw_data_def_props, SwDataDefProps): + self.sw_data_def_props = sw_data_def_props + elif isinstance(sw_data_def_props, SwDataDefPropsConditional): + self.sw_data_def_props = SwDataDefProps(sw_data_def_props) + else: + raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") + + def append(self, elem: "ImplementationDataTypeElement") -> None: + """ + Appends elem to sub_element list + """ + if isinstance(elem, ImplementationDataTypeElement): + self.sub_elements.append(elem) + else: + raise TypeError("'elem' must be of type ImplementationDataTypeElement") -class SwBaseType(BaseType): +class ImplementationDataType(AutosarDataType): """ - Complex type AR:SW-BASE-TYPE + AR: IMPLEMENTATION-DATA-TYPE Type: Concrete - Tag variants: SW-BASE-TYPE + Tag Variants: 'IMPLEMENTATION-DATA-TYPE' """ def __init__(self, name: str, - size: int | None = None, - max_size: int | None = None, - encoding: str | None = None, - alignment: int | None = None, - byte_order: ar_enum.ByteOrder | None = None, - native_declaration: str | None = None, - **kwargs) -> None: + dynamic_array_size_profile: str | None = None, + is_struct_with_optional_element: bool | None = None, + sub_elements: list[ImplementationDataTypeElement] | None = None, + symbol_props: SymbolProps | None = None, + type_emitter: str | None = None, + **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.size = size - self.max_size = max_size - self.encoding = encoding - self.alignment = alignment - self.byte_order = byte_order - self.native_declaration = native_declaration + self.dynamic_array_size_profile: str | None = None # .DYNAMIC-ARRAY-SIZE-PROFILE + self.is_struct_with_optional_element: bool | None = None # .IS-STRUCT-WITH-OPTIONAL-ELEMENT + self.sub_elements: list[ImplementationDataTypeElement] = [] # .SUB-ELEMENTS + self.symbol_props: SymbolProps | None = None # .SYMBOL-PROPS + self.type_emitter: str | None = None # .TYPE-EMITTER + self._assign_optional('dynamic_array_size_profile', dynamic_array_size_profile, str) + self._assign_optional('is_struct_with_optional_element', is_struct_with_optional_element, bool) + self._assign_optional('type_emitter', type_emitter, str) + if sub_elements is not None: + for elem in sub_elements: + self.append(elem) + if symbol_props is not None: + if isinstance(symbol_props, SymbolProps): + self.symbol_props = symbol_props + else: + raise TypeError("'symbol_props' must be of type SymbolProps") - def ref(self) -> SwBaseTypeRef | None: + def append(self, elem: ImplementationDataTypeElement) -> None: + """ + Appends elem to sub_element list + """ + if isinstance(elem, ImplementationDataTypeElement): + self.sub_elements.append(elem) + else: + raise TypeError("'elem' must be of type ImplementationDataTypeElement") + + def ref(self) -> ImplementationDataTypeRef | None: """ Returns a reference to this element or None if the element is not yet part of a package """ ref_str = self._calc_ref_string() - return None if ref_str is None else SwBaseTypeRef(ref_str) + return None if ref_str is None else ImplementationDataTypeRef(ref_str) + + def find(self, ref: str) -> Any: + """ + Finds item by reference + """ + assert "/" not in ref + return self._find_by_name(self.sub_elements, ref) -class SwBitRepresentation(ARObject): +class DataPrototype(Identifiable): """ - SW-BIT-REPRESENTATION - Type: Concrete + Group AR:DATA-PROTOTYPE + Type: Abstract """ def __init__(self, - position: int | None = None, - num_bits: int | None = None) -> None: - super().__init__() - self.position: int | None = None - self.num_bits: int | None = None - self._assign_optional('position', position, int) - self._assign_optional('num_bits', num_bits, int) + name: str, + sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, + **kwargs: dict) -> None: + super().__init__(name, **kwargs) + self.sw_data_def_props: SwDataDefProps | None = None # .SW-DATA-DEF-PROPS + if sw_data_def_props is not None: + if isinstance(sw_data_def_props, SwDataDefProps): + self.sw_data_def_props = sw_data_def_props + elif isinstance(sw_data_def_props, SwDataDefPropsConditional): + self.sw_data_def_props = SwDataDefProps(sw_data_def_props) + else: + raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") -class SwTextProps(ARObject): +class AutosarDataPrototype(DataPrototype): """ - Complex type AR:SW-TEXT-PROPS - Type: Concrete - Tag Variants: 'SW-TEXT-PROPS' + Group AR:AUTOSAR-DATA-PROTOTYPE + Type: Abstract """ def __init__(self, - array_size_semantics: ar_enum.ArraySizeSemantics | None = None, - max_text_size: int | None = None, - base_type_ref: SwBaseTypeRef | str | None = None, - fill_char: int | None = None, - ): - self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS - self.max_text_size: int | None = None # .SW-MAX-TEXT-SIZE - self.base_type_ref: SwBaseTypeRef | str | None = None # .BASE-TYPE-REF - self.fill_char: int | None = None # .FILL-CHAR - self._assign_optional('array_size_semantics', array_size_semantics, ar_enum.ArraySizeSemantics) - self._assign_optional('max_text_size', max_text_size, int) - self._assign_optional('base_type_ref', base_type_ref, SwBaseTypeRef) - self._assign_optional('fill_char', fill_char, int) + name: str, + type_ref: AutosarDataTypeRef | None = None, + **kwargs: dict) -> None: + super().__init__(name, **kwargs) + self.type_ref: AutosarDataTypeRef | None = None # .TYPE-TREF + if type_ref is not None: + self._assign_optional("type_ref", type_ref, AutosarDataTypeRef) -class SwPointerTargetProps(ARObject): +class VariableDataPrototype(AutosarDataPrototype): """ - Complex type AR:SW-POINTER-TARGET-PROPS + Complex type AR:VARIABLE-DATA-PROTOTYPE Type: Concrete - Tag Variants: 'SW-POINTER-TARGET-PROPS' + Tag variants: 'VARIABLE-DATA-PROTOTYPE' | 'BULK-NV-BLOCK' | 'RAM-BLOCK' """ def __init__(self, - target_category: str | None = None, - sw_data_def_props: Union["SwDataDefProps", "SwDataDefPropsConditional", None] = None, - function_ptr_signature_ref: FunctionPtrSignatureRef | None = None - ) -> None: - self.target_category: str | None = None # .TARGET-CATEGORY - self.sw_data_def_props: Union["SwDataDefProps", None] = None # .SW-DATA-DEF-PROPS - self.function_ptr_signature_ref: FunctionPtrSignatureRef | None = None # .FUNCTION-POINTER-SIGNATURE-REF - self._assign_optional("target_category", target_category, str) - self._assign_optional("function_ptr_signature_ref", function_ptr_signature_ref, FunctionPtrSignatureRef) - if sw_data_def_props is not None: - if isinstance(sw_data_def_props, SwDataDefProps): - self.sw_data_def_props = sw_data_def_props - elif isinstance(sw_data_def_props, SwDataDefPropsConditional): - self.sw_data_def_props = SwDataDefProps(sw_data_def_props) - else: - raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") + name: str, + init_value: ValueSpecificationElement | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE + # .VARIATION-POINT not supported + self._assign_optional_strict("init_value", init_value, ValueSpecification) + def ref(self) -> VariableDataPrototypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + return None if ref_str is None else VariableDataPrototypeRef(ref_str) -class SwDataDefPropsConditional(ARObject): + @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): """ - Merge of Complex types AR:SW-DATA-DEF-PROPS-CONDITIONAL and - AR:SW-DATA-DEF-PROPS-CONTENT + Complex type AR:PARAMETER-DATA-PROTOTYPE Type: Concrete - Tag Variants: SW-DATA-DEF-PROPS-CONDITIONAL + Tag variants: 'PARAMETER-DATA-PROTOTYPE' | 'ROM-BLOCK' """ def __init__(self, - display_presentation: ar_enum.DisplayPresentation | None = None, - step_size: float | None = None, - annotations: Annotation | list[Annotation] | None = None, - sw_addr_method_ref: str | SwAddrMethodRef | None = None, - base_type_ref: SwBaseTypeRef | None = None, - compu_method_ref: str | CompuMethodRef | None = None, - data_constraint_ref: str | DataConstraintRef | None = None, - impl_data_type_ref: str | ImplementationDataTypeRef | None = None, - unit_ref: str | UnitRef | None = None, - alignment: int | float | None = None, - bit_representation: SwBitRepresentation | None = None, - calibration_access: ar_enum.SwCalibrationAccess | None = None, - text_props: SwTextProps | None = None, - display_format: str | None = None, - impl_policy: ar_enum.SwImplPolicy | None = None, - additional_native_type_qualifier: str | None = None, - intended_resolution: int | float | None = None, - interpolation_method: str | None = None, - is_virtual: bool | None = None, - ptr_target_props: SwPointerTargetProps | None = None - ) -> None: - # .DISPLAY-PRESENTATION - self.display_presentation: ar_enum.DisplayPresentation | None = None - self.step_size: float | None = None # .STEP-SIZE : AR:FLOAT - # .SW-VALUE-BLOCK-SIZE-MULTS not supported. - self.annotations: list[Annotation] = [] # .ANNOTATIONS - self.sw_addr_method_ref: SwAddrMethodRef | None = None # .SW-ADDR-METHOD-REF - self.alignment: int | str | None = None # .SW-ALIGNMENT - self.base_type_ref: SwBaseTypeRef | None = None # .BASE-TYPE-REF - self.bit_representation: SwBitRepresentation | None = None # .SW-BIT-REPRESENTATION - self.calibration_access: ar_enum.SwCalibrationAccess | None = None # .SW-CALIBRATION-ACCESS - # .SW-VALUE-BLOCK-SIZE not supported. - # .SW-CALPRM-AXIS-SET not yet supported. Low on priority list. - self.text_props: SwTextProps | None = None # .SW-TEXT-PROPS - # .SW-COMPARISON-VARIABLES not yet supported. Low on priority list. - self.compu_method_ref: CompuMethodRef | None = None - self.data_constraint_ref: DataConstraintRef | None = None - # .SW-DATA-DEPENDENCY not yet supported. Low on priority list. - self.display_format: str | None = None # .DISPLAY-FORMAT - self.impl_data_type_ref: ImplementationDataTypeRef | None = None # .IMPLEMENTATION-DATA-TYPE-REF - # .SW-HOST-VARIABLE not yet supported. Low on priority list. - self.impl_policy: ar_enum.SwImplPolicy | None = None # .SW-IMPL-POLICY - self.additional_native_type_qualifier: str | None = None # .ADDITIONAL-NATIVE-TYPE-QUALIFIER - self.intended_resolution: int | float | None = None # .SW-INTENDED-RESOLUTION - self.interpolation_method: str | None = None # .SW-INTERPOLATION-METHOD - # .INVALID-VALUE not yet supported. - # .MC-FUNCTION not yet supported. Low on priority list. - self.is_virtual: bool | None = None # .IS-VIRTUAL - self.ptr_target_props: SwPointerTargetProps | None = None # .SW-POINTER-TARGET-PROPS - # .SW-RECORD-LAYOUT-REF not yet supported. Low on priority list. - # .SW-REFRESH-TIMING not yet supported. Low on priority list. - self.unit_ref = None # .UNIT-REF - # .VALUE-AXIS-DATA-TYPE-REF not yet supported. Low on priority list. - - self._assign_optional('display_presentation', display_presentation, ar_enum.DisplayPresentation) - self._assign_optional('step_size', step_size, float) - if annotations is not None: - if isinstance(annotations, Annotation): - self.annotations.append(annotations) - elif isinstance(annotations, Iterable): - for annotation in annotations: - if not isinstance(annotation, Annotation): - raise TypeError( - f"Param annotations: Expected type 'Annotation', got '{str(type(annotation))}'") - self.annotations.append(annotation) - else: - raise TypeError( - "Param annotations: " - f"Expected type 'Annotation' or list[Annotation], got '{str(type(annotations))}'") - self._assign_optional('sw_addr_method_ref', sw_addr_method_ref, SwAddrMethodRef) - self._assign_int_or_str_pattern_optional('alignment', alignment, alignment_type_re) - self._assign_optional('base_type_ref', base_type_ref, SwBaseTypeRef) - if bit_representation is not None: - if not isinstance(bit_representation, SwBitRepresentation): - raise TypeError(f"bit_representation: Invalid type '{str(type(bit_representation))}'." - " Expected 'SwBitRepresentation'") - self.bit_representation = bit_representation - self._assign_optional('calibration_access', calibration_access, ar_enum.SwCalibrationAccess) - if text_props is not None: - if not isinstance(text_props, SwTextProps): - raise TypeError(f"text_props: Invalid type '{str(type(text_props))}'." - " Expected 'SwTextProps'") - self.text_props = text_props - self._assign_optional('compu_method_ref', compu_method_ref, CompuMethodRef) - self._assign_optional('data_constraint_ref', data_constraint_ref, DataConstraintRef) - self._assign_optional('impl_data_type_ref', impl_data_type_ref, ImplementationDataTypeRef) - self._assign_optional('unit_ref', unit_ref, UnitRef) - self._assign_int_or_str_pattern_optional('display_format', display_format, display_format_str_re) - self._assign_optional('impl_policy', impl_policy, ar_enum.SwImplPolicy) - self._assign_optional('additional_native_type_qualifier', - additional_native_type_qualifier, str) - if intended_resolution is not None: - if isinstance(intended_resolution, (int, float)): - self.intended_resolution = intended_resolution - else: - raise TypeError(f"Invalid type '{str(type(intended_resolution))}' for paramater 'intended_resolution'") - self._assign_optional('interpolation_method', interpolation_method, str) - self._assign_optional('is_virtual', is_virtual, bool) - if ptr_target_props is not None: - self._set_attr_with_strict_type('ptr_target_props', ptr_target_props, SwPointerTargetProps) + name: str, + init_value: ValueSpecificationElement | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE + # .VARIATION-POINT not supported + self._assign_optional_strict("init_value", init_value, ValueSpecification) - @property - def is_queued(self) -> bool: + def ref(self) -> ParameterDataPrototypeRef | None: """ - Returns True if impl_policy is set to QUEUED + Returns a reference to this element or None if the element + is not yet part of a package """ - if self.impl_policy is not None and self.impl_policy == ar_enum.SwImplPolicy.QUEUED: - return True - return False + ref_str = self._calc_ref_string() + return None if ref_str is None else ParameterDataPrototypeRef(ref_str) -class SwDataDefProps(ARObject): +class ArgumentDataPrototype(AutosarDataPrototype): """ - Complex type AR:SW-DATA-DEF-PROPS - Tag variants: 'SW-DATA-DEF-PROPS' | 'NETWORK-REPRESENTATION' | - 'NETWORK-REPRESENTATION-PROPS' | 'PHYSICAL-PROPS' + Complex type AR:ARGUMENT-DATA-PROTOTYPE + Type: Concrete + Tag variants: 'ARGUMENT-DATA-PROTOTYPE' """ - def __init__(self, variants: SwDataDefPropsConditional | list[SwDataDefPropsConditional] | None = None) -> None: - super().__init__() - self.variants: list[SwDataDefPropsConditional] = [] # .SW-DATA-DEF-PROPS-VARIANTS - if variants is not None: - if isinstance(variants, list): - for variant in variants: - self.append(variant) - elif isinstance(variants, SwDataDefPropsConditional): - self.append(variants) - else: - raise TypeError("variant must be one of (SwDataDefPropsConditional, list[SwDataDefPropsConditional])") + def __init__(self, + name: str, + direction: ar_enum.ArgumentDirection | None = None, + server_arg_impl_policy: ar_enum.ServerArgImplPolicy | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.direction: ar_enum.ArgumentDirection | None = None # .DIRECTION + self.server_arg_impl_policy: ar_enum.ServerArgImplPolicy | None = None # .SERVER-ARGUMENT-IMPL-POLICY + # .TYPE-BLUEPRINTS not supported + # .VARIATION-POINT not supported + self._assign_optional("direction", direction, ar_enum.ArgumentDirection) + self._assign_optional("server_arg_impl_policy", server_arg_impl_policy, ar_enum.ServerArgImplPolicy) - def __getitem__(self, index: int) -> SwDataDefPropsConditional: - """ - Accessor of variants list - """ - return self.variants[index] - def __len__(self) -> int: - """ - Length of variants list - """ - return len(self.variants) +class ApplicationDataType(AutosarDataType): + """ + Group AR:APPLICATION-DATA-TYPE + Type: Abstract + """ - def __iter__(self): - """ - Iterator of variants list - """ - return iter(self.variants) - def append(self, variant: SwDataDefPropsConditional): +class ApplicationCompositeDataType(ApplicationDataType): + """ + Group AR:APPLICATION-COMPOSITE-DATA-TYPE + Type: Abstract + """ + + @property + def is_composite(self): + """Is this a composite data type?""" + return True + + +class ApplicationPrimitiveDataType(ApplicationDataType): + """ + Complex type AR:APPLICATION-PRIMITIVE-DATA-TYPE + Type: Concrete + Tag variants: 'APPLICATION-PRIMITIVE-DATA-TYPE' + """ + + @property + def is_composite(self): + """Is this a composite data type?""" + return False + + def ref(self) -> ApplicationDataTypeRef | None: """ - Appends SW-DATA-DEF-PROPS-CONDITIONAL to variants list + Returns a reference to this element or + None if the element is not yet part of a package """ - if isinstance(variant, SwDataDefPropsConditional): - self.variants.append(variant) - else: - raise TypeError("variant must be of type SwDataDefPropsConditional") + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE) -class AutosarDataType(ARElement): +class ApplicationCompositeElementDataPrototype(DataPrototype): """ - Element AUTOSAR-DATA-TYPE + Group AR:APPLICATION-COMPOSITE-ELEMENT-DATA-PROTOTYPE Type: Abstract """ def __init__(self, name: str, - sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, + type_ref: ApplicationDataTypeRef | None = None, **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.sw_data_def_props: SwDataDefProps | None = None - if sw_data_def_props is not None: - if isinstance(sw_data_def_props, SwDataDefProps): - self.sw_data_def_props = sw_data_def_props - elif isinstance(sw_data_def_props, SwDataDefPropsConditional): - self.sw_data_def_props = SwDataDefProps(sw_data_def_props) - else: - raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") + self.type_ref: ApplicationDataTypeRef | None = None # .TYPE-TREF + self._assign_optional_strict('type_ref', type_ref, ApplicationDataTypeRef) -class ImplementationProps(Referrable): +class ApplicationArrayElement(ApplicationCompositeElementDataPrototype): """ - Complex type AR:IMPLEMENTATION-PROPS - Type: Abstract + Complex type AR:APPLICATION-ARRAY-ELEMENT + Type: Concrete + Tag variants: 'ELEMENT' """ def __init__(self, name: str, - symbol: str | None = None) -> None: - super().__init__(name) - self.symbol: str | None = None - self._assign_optional('symbol', symbol, str) - - -class SymbolProps(ImplementationProps): - """ - Complex type AR:SYMBOL-PROPS - Type: Concrete - Tag Variants: 'SYMBOL-PROPS', 'EVENT-SYMBOL-PROPS' - """ + max_number_of_elements: int | None = None, + array_size_handling: ar_enum.ArraySizeHandling | None = None, + array_size_semantics: ar_enum.ArraySizeSemantics | None = None, + index_data_type_ref: IndexDataTypeRef | None = None, + **kwargs: dict) -> None: + super().__init__(name, **kwargs) + self.array_size_handling: ar_enum.ArraySizeHandling | None = None # .ARRAY-SIZE-HANDLING + self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS + self.max_number_of_elements: int | None = None # ."MAX-NUMBER-OF-ELEMENTS + self.index_data_type_ref: IndexDataTypeRef | None = None # .INDEX-DATA-TYPE-REF + self._assign_optional("array_size_handling", array_size_handling, ar_enum.ArraySizeHandling) + self._assign_optional("array_size_semantics", array_size_semantics, ar_enum.ArraySizeSemantics) + self._assign_optional_positive_int("max_number_of_elements", max_number_of_elements) + self._assign_optional("index_data_type_ref", index_data_type_ref, IndexDataTypeRef) -class ImplementationDataTypeElement(Identifiable): +class ApplicationArrayDataType(ApplicationCompositeDataType): """ - Complex type AR:IMPLEMENTATION-DATA-TYPE-ELEMENT + Complex type AR:APPLICATION-ARRAY-DATA-TYPE Type: Concrete - Tag variants: 'IMPLEMENTATION-DATA-TYPE-ELEMENT' + Tag variants: 'APPLICATION-ARRAY-DATA-TYPE' """ def __init__(self, name: str, - sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, - array_size: int | None = None, - array_impl_policy: ar_enum.ArrayImplPolicy | None = None, - array_size_handling: ar_enum.ArraySizeHandling | None = None, - array_size_semantics: ar_enum.ArraySizeSemantics | None = None, - sub_elements: list["ImplementationDataTypeElement"] | None = None, - is_optional: bool | None = None, + dynamic_array_size_profile: str | None = None, + element: ApplicationArrayElement | None = None, **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.array_size: int | None = None # .ARRAY-SIZE - self.array_impl_policy: ar_enum.ArrayImplPolicy | None = None # .ARRAY-IMPL-POLICY - self.array_size_handling: ar_enum.ArraySizeHandling | None = None # .ARRAY-SIZE-HANDLING - self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS - self.is_optional: bool | None = None # .IS-OPTIONAL - self.sub_elements: list["ImplementationDataTypeElement"] | None = [] # .SUB-ELEMENTS - self.sw_data_def_props: SwDataDefProps | None = None # .SW-DATA-DEF-PROPS - self._assign_optional_positive_int("array_size", array_size) - self._assign_optional("array_impl_policy", array_impl_policy, ar_enum.ArrayImplPolicy) - self._assign_optional("array_size_handling", array_size_handling, ar_enum.ArraySizeHandling) - self._assign_optional("array_size_semantics", array_size_semantics, ar_enum.ArraySizeSemantics) - self._assign_optional("is_optional", is_optional, bool) - if sub_elements is not None: - for elem in sub_elements: - self.append(elem) - if sw_data_def_props is not None: - if isinstance(sw_data_def_props, SwDataDefProps): - self.sw_data_def_props = sw_data_def_props - elif isinstance(sw_data_def_props, SwDataDefPropsConditional): - self.sw_data_def_props = SwDataDefProps(sw_data_def_props) - else: - raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") + self.dynamic_array_size_profile: str | None = None # .DYNAMIC-ARRAY-SIZE-PROFILE + self.element: ApplicationArrayElement | None = None # .ELEMENT + self._assign_optional('dynamic_array_size_profile', dynamic_array_size_profile, str) + self._assign_optional_strict('element', element, ApplicationArrayElement) - def append(self, elem: "ImplementationDataTypeElement") -> None: + def ref(self) -> ApplicationDataTypeRef | None: """ - Appends elem to sub_element list + Returns a reference to this element or + None if the element is not yet part of a package """ - if isinstance(elem, ImplementationDataTypeElement): - self.sub_elements.append(elem) - else: - raise TypeError("'elem' must be of type ImplementationDataTypeElement") + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE) -class ImplementationDataType(AutosarDataType): +class ApplicationRecordElement(ApplicationCompositeElementDataPrototype): """ - AR: IMPLEMENTATION-DATA-TYPE + Complex type AR:APPLICATION-RECORD-ELEMENT Type: Concrete - Tag Variants: 'IMPLEMENTATION-DATA-TYPE' + Tag variants: 'APPLICATION-RECORD-ELEMENT' """ def __init__(self, name: str, - dynamic_array_size_profile: str | None = None, - is_struct_with_optional_element: bool | None = None, - sub_elements: list[ImplementationDataTypeElement] | None = None, - symbol_props: SymbolProps | None = None, - type_emitter: str | None = None, + is_optional: bool | None = None, **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.dynamic_array_size_profile: str | None = None # .DYNAMIC-ARRAY-SIZE-PROFILE - self.is_struct_with_optional_element: bool | None = None # .IS-STRUCT-WITH-OPTIONAL-ELEMENT - self.sub_elements: list[ImplementationDataTypeElement] = [] # .SUB-ELEMENTS - self.symbol_props: SymbolProps | None = None # .SYMBOL-PROPS - self.type_emitter: str | None = None # .TYPE-EMITTER - self._assign_optional('dynamic_array_size_profile', dynamic_array_size_profile, str) - self._assign_optional('is_struct_with_optional_element', is_struct_with_optional_element, bool) - self._assign_optional('type_emitter', type_emitter, str) - if sub_elements is not None: - for elem in sub_elements: - self.append(elem) - if symbol_props is not None: - if isinstance(symbol_props, SymbolProps): - self.symbol_props = symbol_props - else: - raise TypeError("'symbol_props' must be of type SymbolProps") + self.is_optional: bool | None = None # .IS-OPTIONAL + self._assign_optional('is_optional', is_optional, bool) - def append(self, elem: ImplementationDataTypeElement) -> None: + +class ApplicationRecordDataType(ApplicationCompositeDataType): + """ + Complex type AR:APPLICATION-RECORD-DATA-TYPE + Type: Concrete + Tag variants: 'APPLICATION-RECORD-DATA-TYPE' + """ + + def __init__(self, + name: str, + elements: ApplicationRecordElement | list[ApplicationRecordElement] | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.elements: list[ApplicationRecordElement] = [] + if elements is not None: + if isinstance(elements, ApplicationRecordElement): + self.append(elements) + elif isinstance(elements, list): + self.extend(elements) + + def append(self, element: ApplicationRecordElement) -> None: """ - Appends elem to sub_element list + Appends element to elements list """ - if isinstance(elem, ImplementationDataTypeElement): - self.sub_elements.append(elem) + if isinstance(element, ApplicationRecordElement): + self.elements.append(element) else: - raise TypeError("'elem' must be of type ImplementationDataTypeElement") + raise TypeError("'element' must be of type ApplicationRecordElement") - def ref(self) -> ImplementationDataTypeRef | None: + def extend(self, elements: list[ApplicationRecordElement]) -> None: """ - Returns a reference to this element or None if the element - is not yet part of a package + Extends elements to elements list """ - ref_str = self._calc_ref_string() - return None if ref_str is None else ImplementationDataTypeRef(ref_str) + for element in elements: # We want to type-check each element before adding to internal list + self.append(element) - def find(self, ref: str) -> Any: + def ref(self) -> ApplicationDataTypeRef | None: """ - Finds item by reference + Returns a reference to this element or + None if the element is not yet part of a package """ - assert "/" not in ref - return self._find_by_name(self.sub_elements, ref) + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE) -class DataPrototype(Identifiable): +class DataTypeMap(ARObject): """ - Group AR:DATA-PROTOTYPE - Type: Abstract + Complex type AR:DATA-TYPE-MAP + Type: Concrete + Tag variants: 'DATA-TYPE-MAP' """ def __init__(self, - name: str, - sw_data_def_props: SwDataDefProps | SwDataDefPropsConditional | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.sw_data_def_props: SwDataDefProps | None = None # .SW-DATA-DEF-PROPS - if sw_data_def_props is not None: - if isinstance(sw_data_def_props, SwDataDefProps): - self.sw_data_def_props = sw_data_def_props - elif isinstance(sw_data_def_props, SwDataDefPropsConditional): - self.sw_data_def_props = SwDataDefProps(sw_data_def_props) - else: - raise TypeError("'sw_data_def_props' must be one of (SwDataDefProps, SwDataDefPropsConditional)") + appl_data_type_ref: ApplicationDataTypeRef | None = None, + impl_data_type_ref: ImplementationDataTypeRef | None = None, + ) -> None: + self.appl_data_type_ref = appl_data_type_ref # .APPLICATION-DATA-TYPE-REF + self.impl_data_type_ref = impl_data_type_ref # .IMPLEMENTATION-DATA-TYPE-REF -class AutosarDataPrototype(DataPrototype): +class DataTypeMappingSet(ARElement): """ - Group AR:AUTOSAR-DATA-PROTOTYPE - Type: Abstract + Complex type AR:DATA-TYPE-MAPPING-SET + Type: Concrete + Tag variants: 'DATA-TYPE-MAPPING-SET' """ def __init__(self, name: str, - type_ref: AutosarDataTypeRef | ImplementationDataTypeRef | None = None, + data_type_maps: DataTypeMap | list[DataTypeMap] | None = None, **kwargs: dict) -> None: super().__init__(name, **kwargs) - self.type_ref: AutosarDataTypeRef | None = None # .TYPE-TREF - if type_ref is not None: - if isinstance(type_ref, AutosarDataTypeRef): - pass - elif isinstance(type_ref, ImplementationDataTypeRef): - type_ref = AutosarDataTypeRef(type_ref.value, ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE) + self.data_type_maps: list[DataTypeMap] = [] # .DATA-TYPE-MAPS + self.mode_request_type_maps = [] # .MODE-REQUEST-TYPE-MAPS (Not yet implemented) + if data_type_maps is not None: + if isinstance(data_type_maps, DataTypeMap): + self.append(data_type_maps) + elif isinstance(data_type_maps, list): + for data_type_map in data_type_maps: + self.append(data_type_map) else: - msg = f"type_ref: Invalid type '{str(type(type_ref))}'." - raise TypeError(msg + " Expected type 'AutosarDataTypeRef' or 'ImplementationDataTypeRef'") - self._set_attr_with_strict_type("type_ref", type_ref, AutosarDataTypeRef) + raise TypeError(f'data_type_maps: Invalid type "{str(type(data_type_maps))}"') + + def append(self, element: DataTypeMap) -> None: + """ + Appends element to one of the inner lists based on parameter type + Currently, appending to mode_request_type_maps isn't + implemented. + """ + if isinstance(element, DataTypeMap): + self.data_type_maps.append(element) + else: + raise TypeError(f'Unexpected type: "{str(type(element))}"') -class VariableDataPrototype(AutosarDataPrototype): +class ValueList(ARObject): """ - Complex type AR:VARIABLE-DATA-PROTOTYPE + Complex type AR:VALUE-LIST Type: Concrete - Tag variants: 'VARIABLE-DATA-PROTOTYPE' | 'BULK-NV-BLOCK' | 'RAM-BLOCK' + Tag variants: 'SW-ARRAYSIZE' """ - def __init__(self, - name: str, - init_value: ValueSpecificationElement | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE - # .VARIATION-POINT not supported - self._assign_optional_strict("init_value", init_value, ValueSpecification) + def __init__(self, values: list[int | float | NumericalValue] | None = None) -> None: + self.values = [] + if values is not None: + if isinstance(values, (int, float)): + self.append(values) + else: + for value in values: + self.append(value) - def ref(self) -> VariableDataPrototypeRef | None: + def append(self, value: int | float | NumericalValue) -> None: """ - Returns a reference to this element or None if the element - is not yet part of a package + Adds value to list of values """ - ref_str = self._calc_ref_string() - return None if ref_str is None else VariableDataPrototypeRef(ref_str) + if isinstance(value, (int, float, NumericalValue)): + self.values.append(value) + else: + raise TypeError(f"Invalid type for value: {str(type(value))}") - @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 +# Software address method (partly implemented) -class ParameterDataPrototype(AutosarDataPrototype): + +class SwAddrMethod(ARElement): """ - Complex type AR:PARAMETER-DATA-PROTOTYPE + Complex type AR:SW-ADDR-METHOD Type: Concrete - Tag variants: 'PARAMETER-DATA-PROTOTYPE' | 'ROM-BLOCK' + Tag Variants: 'SW-ADDR-METHOD' """ - def __init__(self, - name: str, - init_value: ValueSpecificationElement | None = None, - **kwargs) -> None: + def __init__(self, name: str, **kwargs) -> None: super().__init__(name, **kwargs) - self.init_value: ValueSpecificationElement | None = None # .INIT-VALUE - # .VARIATION-POINT not supported - self._assign_optional_strict("init_value", init_value, ValueSpecification) + self.memory_allocation_keyword_policy = None # .MEMORY-ALLOCATION-KEYWORD-POLICY + self.options = [] # .OPTIONS + self.section_initialization_policy = None # .SECTION-INITIALIZATION-POLICY + self.section_type = None # .SECTION-TYPE - def ref(self) -> ParameterDataPrototypeRef | None: + def ref(self) -> SwAddrMethodRef | None: """ Returns a reference to this element or None if the element is not yet part of a package """ ref_str = self._calc_ref_string() - return None if ref_str is None else ParameterDataPrototypeRef(ref_str) + return None if ref_str is None else SwAddrMethodRef(ref_str) +# --- Calibration data elements -class ArgumentDataPrototype(AutosarDataPrototype): + +SwValueElement = Union[int, float, str, NumericalValue, "ValueGroup"] # Type alias + + +class SwValues(ARObject): """ - Complex type AR:ARGUMENT-DATA-PROTOTYPE + Complex type AR:SW-VALUES Type: Concrete - Tag variants: 'ARGUMENT-DATA-PROTOTYPE' + Tag variants: SW-VALUES-PHYS """ def __init__(self, - name: str, - direction: ar_enum.ArgumentDirection | None = None, - server_arg_impl_policy: ar_enum.ServerArgImplPolicy | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.direction: ar_enum.ArgumentDirection | None = None # .DIRECTION - self.server_arg_impl_policy: ar_enum.ServerArgImplPolicy | None = None # .SERVER-ARGUMENT-IMPL-POLICY - # .TYPE-BLUEPRINTS not supported - # .VARIATION-POINT not supported - self._assign_optional("direction", direction, ar_enum.ArgumentDirection) - self._assign_optional("server_arg_impl_policy", server_arg_impl_policy, ar_enum.ServerArgImplPolicy) - - -class ApplicationDataType(AutosarDataType): - """ - Group AR:APPLICATION-DATA-TYPE - Type: Abstract - """ - - -class ApplicationCompositeDataType(ApplicationDataType): - """ - Group AR:APPLICATION-COMPOSITE-DATA-TYPE - Type: Abstract - """ - - @property - def is_composite(self): - """Is this a composite data type?""" - return True - - -class ApplicationPrimitiveDataType(ApplicationDataType): - """ - Complex type AR:APPLICATION-PRIMITIVE-DATA-TYPE - Type: Concrete - Tag variants: 'APPLICATION-PRIMITIVE-DATA-TYPE' - """ - - @property - def is_composite(self): - """Is this a composite data type?""" - return False + values: list[SwValueElement] | None = None) -> None: + self.values = [] + if values is not None: + if isinstance(values, (int, float, str, NumericalValue, ValueGroup)): + self.append(values) + elif isinstance(values, list): + for value in values: + self.append(value) - def ref(self) -> ApplicationDataTypeRef | None: + def append(self, value: SwValueElement) -> None: """ - Returns a reference to this element or - None if the element is not yet part of a package + Appends value to list of values + XML elements not supported: + + - VTF + - VF """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE) + if isinstance(value, (int, float, str, NumericalValue, ValueGroup)): + self.values.append(value) + else: + raise TypeError(f"Invalid value type: {str(type(value))}") -class ApplicationCompositeElementDataPrototype(DataPrototype): +class ValueGroup(SwValues): """ - Group AR:APPLICATION-COMPOSITE-ELEMENT-DATA-PROTOTYPE - Type: Abstract + Complex type AR:VALUE-GROUP + Type: Concrete + Tag variants: VG """ def __init__(self, - name: str, - type_ref: ApplicationDataTypeRef | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.type_ref: ApplicationDataTypeRef | None = None # .TYPE-TREF - self._assign_optional_strict('type_ref', type_ref, ApplicationDataTypeRef) + label: str | MultilanguageLongName | tuple[ar_enum.Language, str] | LanguageLongName | None = None, + values: SwValues | None = None) -> None: + self.label: MultilanguageLongName | None = None + super().__init__(values) + if label is not None: + if isinstance(label, MultilanguageLongName): + self.label = label + elif isinstance(label, (tuple, LanguageLongName)): + self.label = MultilanguageLongName(label) + else: + raise TypeError(f"Invalid type for 'label': {str(type(label))}") -class ApplicationArrayElement(ApplicationCompositeElementDataPrototype): +class SwAxisCont(ARObject): """ - Complex type AR:APPLICATION-ARRAY-ELEMENT + Complex type AR:SW-AXIS-CONT Type: Concrete - Tag variants: 'ELEMENT' + Tag variants: SW-AXIS-CONT """ def __init__(self, - name: str, - max_number_of_elements: int | None = None, - array_size_handling: ar_enum.ArraySizeHandling | None = None, - array_size_semantics: ar_enum.ArraySizeSemantics | None = None, - index_data_type_ref: IndexDataTypeRef | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.array_size_handling: ar_enum.ArraySizeHandling | None = None # .ARRAY-SIZE-HANDLING - self.array_size_semantics: ar_enum.ArraySizeSemantics | None = None # .ARRAY-SIZE-SEMANTICS - self.max_number_of_elements: int | None = None # ."MAX-NUMBER-OF-ELEMENTS - self.index_data_type_ref: IndexDataTypeRef | None = None # .INDEX-DATA-TYPE-REF - self._assign_optional("array_size_handling", array_size_handling, ar_enum.ArraySizeHandling) - self._assign_optional("array_size_semantics", array_size_semantics, ar_enum.ArraySizeSemantics) - self._assign_optional_positive_int("max_number_of_elements", max_number_of_elements) - self._assign_optional("index_data_type_ref", index_data_type_ref, IndexDataTypeRef) + category: ar_enum.CalibrationAxisCategory | None = None, + unit_ref: UnitRef | None = None, + unit_display_name: SingleLanguageUnitNames | None = None, + sw_axis_index: int | str | None = None, + sw_array_size: ValueList | None = None, + sw_values_phys: SwValues | None = None) -> None: + self.category: ar_enum.CalibrationAxisCategory = None # .CATEGORY + self.unit_ref: UnitRef = None # .UNIT-REF + self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME + self.sw_axis_index: int | str = None # .SW-AXIS-INDEX + self.sw_array_size: ValueList = None # .SW-ARRAYSIZE + self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS + self._assign_optional('category', category, ar_enum.CalibrationAxisCategory) + self._assign_optional_strict('unit_ref', unit_ref, UnitRef) + self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames) + if sw_axis_index is not None: + if isinstance(sw_axis_index, (int, str)): + self.sw_axis_index = sw_axis_index + else: + error_msg = "Invalid type for parameter 'sw_axis_index'. Expected 'int' or 'str', " + raise TypeError(error_msg + f"got '{str(type(sw_axis_index))}'") + self._assign_optional_strict('sw_array_size', sw_array_size, ValueList) + self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues) -class ApplicationArrayDataType(ApplicationCompositeDataType): +class SwValueCont(ARObject): """ - Complex type AR:APPLICATION-ARRAY-DATA-TYPE + Complex type AR:SW-VALUE-CONT Type: Concrete - Tag variants: 'APPLICATION-ARRAY-DATA-TYPE' + Tag variants: SW-VALUE-CONT """ def __init__(self, - name: str, - dynamic_array_size_profile: str | None = None, - element: ApplicationArrayElement | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.dynamic_array_size_profile: str | None = None # .DYNAMIC-ARRAY-SIZE-PROFILE - self.element: ApplicationArrayElement | None = None # .ELEMENT - self._assign_optional('dynamic_array_size_profile', dynamic_array_size_profile, str) - self._assign_optional_strict('element', element, ApplicationArrayElement) - - def ref(self) -> ApplicationDataTypeRef | None: - """ - Returns a reference to this element or - None if the element is not yet part of a package - """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE) - + unit_ref: UnitRef | None = None, + unit_display_name: SingleLanguageUnitNames | None = None, + sw_array_size: ValueList | None = None, + sw_values_phys: SwValues | None = None) -> None: + self.unit_ref: UnitRef = None # .UNIT-REF + self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME + self.sw_array_size: ValueList = None # .SW-ARRAYSIZE + self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS + self._assign_optional_strict('unit_ref', unit_ref, UnitRef) + self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames) + self._assign_optional_strict('sw_array_size', sw_array_size, ValueList) + self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues) -class ApplicationRecordElement(ApplicationCompositeElementDataPrototype): - """ - Complex type AR:APPLICATION-RECORD-ELEMENT - Type: Concrete - Tag variants: 'APPLICATION-RECORD-ELEMENT' - """ - def __init__(self, - name: str, - is_optional: bool | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.is_optional: bool | None = None # .IS-OPTIONAL - self._assign_optional('is_optional', is_optional, bool) +# --- Constant and value specifications -class ApplicationRecordDataType(ApplicationCompositeDataType): +class ValueSpecification(ARObject): """ - Complex type AR:APPLICATION-RECORD-DATA-TYPE - Type: Concrete - Tag variants: 'APPLICATION-RECORD-DATA-TYPE' + Group AR:VALUE-SPECIFCATION + Type: Abstract + Base class for value specifications """ - def __init__(self, - name: str, - elements: ApplicationRecordElement | list[ApplicationRecordElement] | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.elements: list[ApplicationRecordElement] = [] - if elements is not None: - if isinstance(elements, ApplicationRecordElement): - self.append(elements) - elif isinstance(elements, list): - self.extend(elements) + def __init__(self, label: str | None = None) -> None: + self.label = label # .SHORT-LABEL + # .VARIATION-POINT not supported - def append(self, element: ApplicationRecordElement) -> None: - """ - Appends element to elements list + @classmethod + def make_value_with_check(cls, + value: InitValueArgType | None = None, + ) -> ValueSpecificationElement: """ - if isinstance(element, ApplicationRecordElement): - self.elements.append(element) - else: - raise TypeError("'element' must be of type ApplicationRecordElement") + #convenience-method - def extend(self, elements: list[ApplicationRecordElement]) -> None: - """ - Extends elements to elements list - """ - for element in elements: # We want to type-check each element before adding to internal list - self.append(element) + Wrapper for checking and creating init values based on different value types - def ref(self) -> ApplicationDataTypeRef | None: - """ - Returns a reference to this element or - None if the element is not yet part of a package + The main differences compared to make_value are: + * Returns None if input value is None. + * Can create ConstantReference objects if given ConstantRef input. """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return ApplicationDataTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE) + if value is not None: + if isinstance(value, ValueSpecification): + return value # Already a proper init-value + elif isinstance(value, ConstantRef): + return ConstantReference(value) # Wrap inside constant reference + elif isinstance(value, (int, float, str, list, tuple)): + return cls.make_value(value) # Attempt to create a new value based on raw python data + else: + raise TypeError(f"Unsupported type: {str(type(value))}") + return None - -class DataTypeMap(ARObject): - """ - Complex type AR:DATA-TYPE-MAP - Type: Concrete - Tag variants: 'DATA-TYPE-MAP' - """ - - def __init__(self, - appl_data_type_ref: ApplicationDataTypeRef | None = None, - impl_data_type_ref: ImplementationDataTypeRef | None = None, - ) -> None: - self.appl_data_type_ref = appl_data_type_ref # .APPLICATION-DATA-TYPE-REF - self.impl_data_type_ref = impl_data_type_ref # .IMPLEMENTATION-DATA-TYPE-REF - - -class DataTypeMappingSet(ARElement): - """ - Complex type AR:DATA-TYPE-MAPPING-SET - Type: Concrete - Tag variants: 'DATA-TYPE-MAPPING-SET' - """ - - def __init__(self, - name: str, - data_type_maps: DataTypeMap | list[DataTypeMap] | None = None, - **kwargs: dict) -> None: - super().__init__(name, **kwargs) - self.data_type_maps: list[DataTypeMap] = [] # .DATA-TYPE-MAPS - self.mode_request_type_maps = [] # .MODE-REQUEST-TYPE-MAPS (Not yet implemented) - if data_type_maps is not None: - if isinstance(data_type_maps, DataTypeMap): - self.append(data_type_maps) - elif isinstance(data_type_maps, list): - for data_type_map in data_type_maps: - self.append(data_type_map) - else: - raise TypeError(f'data_type_maps: Invalid type "{str(type(data_type_maps))}"') - - def append(self, element: DataTypeMap) -> None: - """ - Appends element to one of the inner lists based on parameter type - Currently, appending to mode_request_type_maps isn't - implemented. - """ - if isinstance(element, DataTypeMap): - self.data_type_maps.append(element) - else: - raise TypeError(f'Unexpected type: "{str(type(element))}"') - - -class ValueList(ARObject): - """ - Complex type AR:VALUE-LIST - Type: Concrete - Tag variants: 'SW-ARRAYSIZE' - """ - - def __init__(self, values: list[int | float | NumericalValue] | None = None) -> None: - self.values = [] - if values is not None: - if isinstance(values, (int, float)): - self.append(values) - else: - for value in values: - self.append(value) - - def append(self, value: int | float | NumericalValue) -> None: - """ - Adds value to list of values - """ - if isinstance(value, (int, float, NumericalValue)): - self.values.append(value) - else: - raise TypeError(f"Invalid type for value: {str(type(value))}") - - -# Software address method (partly implemented) - - -class SwAddrMethod(ARElement): - """ - Complex type AR:SW-ADDR-METHOD - Type: Concrete - Tag Variants: 'SW-ADDR-METHOD' - """ - - def __init__(self, name: str, **kwargs) -> None: - super().__init__(name, **kwargs) - self.memory_allocation_keyword_policy = None # .MEMORY-ALLOCATION-KEYWORD-POLICY - self.options = [] # .OPTIONS - self.section_initialization_policy = None # .SECTION-INITIALIZATION-POLICY - self.section_type = None # .SECTION-TYPE - - def ref(self) -> SwAddrMethodRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - return None if ref_str is None else SwAddrMethodRef(ref_str) - -# --- Calibration data elements - - -SwValueElement = Union[int, float, str, NumericalValue, "ValueGroup"] # Type alias - - -class SwValues(ARObject): - """ - Complex type AR:SW-VALUES - Type: Concrete - Tag variants: SW-VALUES-PHYS - """ - - def __init__(self, - values: list[SwValueElement] | None = None) -> None: - self.values = [] - if values is not None: - if isinstance(values, (int, float, str, NumericalValue, ValueGroup)): - self.append(values) - elif isinstance(values, list): - for value in values: - self.append(value) - - def append(self, value: SwValueElement) -> None: - """ - Appends value to list of values - XML elements not supported: - - - VTF - - VF - """ - if isinstance(value, (int, float, str, NumericalValue, ValueGroup)): - self.values.append(value) - else: - raise TypeError(f"Invalid value type: {str(type(value))}") - - -class ValueGroup(SwValues): - """ - Complex type AR:VALUE-GROUP - Type: Concrete - Tag variants: VG - """ - - def __init__(self, - label: str | MultilanguageLongName | tuple[ar_enum.Language, str] | LanguageLongName | None = None, - values: SwValues | None = None) -> None: - self.label: MultilanguageLongName | None = None - super().__init__(values) - if label is not None: - if isinstance(label, MultilanguageLongName): - self.label = label - elif isinstance(label, (tuple, LanguageLongName)): - self.label = MultilanguageLongName(label) - else: - raise TypeError(f"Invalid type for 'label': {str(type(label))}") - - -class SwAxisCont(ARObject): - """ - Complex type AR:SW-AXIS-CONT - Type: Concrete - Tag variants: SW-AXIS-CONT - """ - - def __init__(self, - category: ar_enum.CalibrationAxisCategory | None = None, - unit_ref: UnitRef | None = None, - unit_display_name: SingleLanguageUnitNames | None = None, - sw_axis_index: int | str | None = None, - sw_array_size: ValueList | None = None, - sw_values_phys: SwValues | None = None) -> None: - self.category: ar_enum.CalibrationAxisCategory = None # .CATEGORY - self.unit_ref: UnitRef = None # .UNIT-REF - self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME - self.sw_axis_index: int | str = None # .SW-AXIS-INDEX - self.sw_array_size: ValueList = None # .SW-ARRAYSIZE - self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS - self._assign_optional('category', category, ar_enum.CalibrationAxisCategory) - self._assign_optional_strict('unit_ref', unit_ref, UnitRef) - self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames) - if sw_axis_index is not None: - if isinstance(sw_axis_index, (int, str)): - self.sw_axis_index = sw_axis_index - else: - error_msg = "Invalid type for parameter 'sw_axis_index'. Expected 'int' or 'str', " - raise TypeError(error_msg + f"got '{str(type(sw_axis_index))}'") - self._assign_optional_strict('sw_array_size', sw_array_size, ValueList) - self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues) - - -class SwValueCont(ARObject): - """ - Complex type AR:SW-VALUE-CONT - Type: Concrete - Tag variants: SW-VALUE-CONT - """ - - def __init__(self, - unit_ref: UnitRef | None = None, - unit_display_name: SingleLanguageUnitNames | None = None, - sw_array_size: ValueList | None = None, - sw_values_phys: SwValues | None = None) -> None: - self.unit_ref: UnitRef = None # .UNIT-REF - self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME - self.sw_array_size: ValueList = None # .SW-ARRAYSIZE - self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS - self._assign_optional_strict('unit_ref', unit_ref, UnitRef) - self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames) - self._assign_optional_strict('sw_array_size', sw_array_size, ValueList) - self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues) - - -# --- Constant and value specifications - - -class ValueSpecification(ARObject): - """ - Group AR:VALUE-SPECIFCATION - Type: Abstract - Base class for value specifications - """ - - def __init__(self, label: str | None = None) -> None: - self.label = label # .SHORT-LABEL - # .VARIATION-POINT not supported - - @classmethod - def make_value_with_check(cls, - value: InitValueArgType | None = None, - ) -> ValueSpecificationElement: - """ - #convenience-method - - Wrapper for checking and creating init values based on different value types - - The main differences compared to make_value are: - * Returns None if input value is None. - * Can create ConstantReference objects if given ConstantRef input. - """ - if value is not None: - if isinstance(value, ValueSpecification): - return value # Already a proper init-value - elif isinstance(value, ConstantRef): - return ConstantReference(value) # Wrap inside constant reference - elif isinstance(value, (int, float, str, list, tuple)): - return cls.make_value(value) # Attempt to create a new value based on raw python data - else: - raise TypeError(f"Unsupported type: {str(type(value))}") - return None - - @classmethod - def make_value(cls, data: Any) -> ValueSpecificationElement: - """ - #convenience-method + @classmethod + def make_value(cls, data: Any) -> ValueSpecificationElement: + """ + #convenience-method Builds value specification based on Python data Format 1 - data is not a tuple: @@ -3360,9 +2785,9 @@ def make_constant(cls, value: tuple[str, Any] | Any, **kwargs) -> "ConstantSpecification": """ - #convenience-method - Creates a new constant object and populates it from Python data. + + #convenience-method """ value = ValueSpecification.make_value(value) return cls(name, value, **kwargs) @@ -3505,12 +2930,51 @@ def ref(self) -> PackageRef: return None if ref_str is None else PackageRef(ref_str) +class BehaviorSettings: + """ + Enables users to customize settings in SwcInternalBehavior such as naming conventions. + """ + + def __init__(self) -> None: + + # Default prefix used for generating event names + self.background_event_prefix: str | None = None # BackgroundEvent prefix + self.data_receive_error_event_prefix: str | None = None # DataReceiveErrorEvent prefix + self.data_receive_event_prefix: str | None = None # DataReceivedEvent prefix + self.init_event_prefix: str | None = None # InitEvent prefix + self.operation_invoked_event_prefix: str | None = None # OperationInvokedEvent prefix + self.swc_mode_manager_error_event_prefix: str | None = None # SwcModeManagerErrorEvent prefix + self.swc_mode_switch_event_prefix: str | None = None # SwcModeSwitchEvent prefix + self.timing_event_prefix: str | None = None # TimingEvent prefix + + def set_value(self, name: str, value: str): + """ + Updates a single value with error check + """ + if hasattr(self, name): + if not isinstance(value, str): + raise TypeError(f"value: Expected string type. Got {str(type(value))}") + setattr(self, name, value) + else: + raise KeyError(f"name: Invalid name '{name}'") + + def update(self, value_map: dict[str, str]): + """ + Updates multiple values using keys in value_map, with error-check + """ + for name, value in value_map.items(): + self.set_value(name, value) + + class PackageCollection: """ Base class that maintains a collection of AUTOSAR packages """ - def __init__(self, packages: list[Package] | None = None) -> None: + def __init__(self, packages: list[Package] | None = None, + behavior_settings: BehaviorSettings | None = None) -> None: + self.parent = None + self.behavior_settings = behavior_settings self.packages: list[Package] = [] # .PACKAGES self._package_dict = {} # internal package map if packages is not None: @@ -3530,10 +2994,14 @@ def append(self, package: Package): self.packages.append(package) self._package_dict[package.name] = package - def find(self, ref: str) -> Any: + def find(self, ref: str | BaseRef) -> Any: """ Finds item by reference """ + if isinstance(ref, BaseRef): + ref = str(ref) + if not isinstance(ref, str): + raise TypeError("ref: Must be either a string or a valid reference class") if ref.startswith('/'): ref = ref[1:] parts = ref.partition('/') @@ -3558,7 +3026,7 @@ def create_package(self, name: str, **kwargs) -> Package: self.append(package) return package - def make_packages(self, *refs: list[str]) -> Package | list[Package]: + def make_packages(self, *refs: str) -> Package | list[Package]: """ Recursively creates packages from reference(s) Returns a list of created packages. @@ -4317,7 +3785,9 @@ def __init__(self, mode_group: ModeDeclarationGroupPrototype | None = None, **kwargs) -> None: super().__init__(name, **kwargs) + # .MODE-GROUP self.mode_group: ModeDeclarationGroupPrototype | None = None + self._assign_optional_strict("mode_group", mode_group, ModeDeclarationGroupPrototype) def ref(self) -> PortInterfaceRef | None: @@ -4344,6 +3814,7 @@ def create_mode_group(self, will overwrite the previous value. """ self.mode_group = ModeDeclarationGroupPrototype(name, type_ref, calibration_access, **kwargs) + self.mode_group.parent = self return self.mode_group # --- System Template Elements @@ -4808,11 +4279,18 @@ def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "R outer dict keys are element names and each value is another dict containing key-value pairs for one com-spec + Note: Avoid manually setting the data_element_ref option, it will be automatically set for you. + For ClientServerInterface: If interface has a single operation: kwargs is a dict with key-value pairs for one com-spec If interface has multiple operations: kwargs is a dict of dict where outer dict keys are operation names and each value is another dict containing key-value pairs for one com-spec + Note: Avoid manually setting the operation_ref option, it will be automatically set for you. + + For ModeSwitchInterface: + kwargs is a dict with key-value pairs for one com-spec + Note: Avoid manually setting the mode_group_ref option, it will be automatically set for you. """ if isinstance(port_interface, SenderReceiverInterface): if len(port_interface.data_elements) == 0: @@ -4820,6 +4298,7 @@ def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "R if len(port_interface.data_elements) == 1: data_element: VariableDataPrototype = port_interface.data_elements[0] if data_element.is_queued: + assert data_element.ref() is not None 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) @@ -4835,9 +4314,10 @@ def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "R if data_element.name in unprocessed: unprocessed.remove(data_element.name) com_spec_args = kwargs[data_element.name] + assert data_element.ref() is not None if data_element.is_queued: - com_spec = QueuedSenderComSpec(data_element_ref=data_element.ref(), - **com_spec_args) + com_spec = QueuedReceiverComSpec(data_element_ref=data_element.ref(), + **com_spec_args) else: com_spec = cls.make_non_queued_receiver_com_spec(data_element_ref=data_element.ref(), **com_spec_args) @@ -4847,7 +4327,7 @@ def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "R msg = f"{port_interface.name}: Data element(s) not found in port interface: '{element_names}'" raise ValueError(msg) return com_spec_list - if isinstance(port_interface, ClientServerInterface): + elif isinstance(port_interface, ClientServerInterface): if len(port_interface.operations) == 0: raise ValueError(f"{port_interface.name}: Port interface must have at least one operation") if len(port_interface.operations) == 1: @@ -4862,12 +4342,18 @@ def make_from_port_interface(cls, port_interface: PortInterface, **kwargs) -> "R if operation.name in unprocessed: unprocessed.remove(operation.name) com_spec_args = kwargs[operation.name] + assert operation.ref() is not None com_spec = ClientComSpec(operation_ref=operation.ref(), **com_spec_args) com_spec_list.append(com_spec) if len(unprocessed) > 0: operations = ', '.join(list[unprocessed]) raise ValueError(f"{port_interface.name}: Operation(s) not found in port interface: '{operations}'") return com_spec_list + elif isinstance(port_interface, ModeSwitchInterface): + if port_interface.mode_group is None: + raise ValueError(f"{port_interface.name}: Port interface doesn't have a mode group set") + assert port_interface.mode_group.ref() is not None + return ModeSwitchReceiverComSpec(mode_group_ref=port_interface.mode_group.ref(), **kwargs) else: raise NotImplementedError(str(type(port_interface))) @@ -5128,340 +4614,1114 @@ class PortPrototype(Identifiable): # .VARIATION-POINT not supported -class ProvidePortPrototype(PortPrototype): - """ - Complex type AR:P-PORT-PROTOTYPE - Tag variants: 'P-PORT-PROTOTYPE' +class ProvidePortPrototype(PortPrototype): + """ + Complex type AR:P-PORT-PROTOTYPE + Tag variants: 'P-PORT-PROTOTYPE' + + Includes AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE + """ + + def __init__(self, + name: str, + port_interface_ref: PortInterfaceRef | None = None, + com_spec: ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.com_spec: list[ProvidePortComSpec] = [] # .PROVIDED-COM-SPECS + self.port_interface_ref: PortInterfaceRef | None = None # .PROVIDED-INTERFACE-TREF + self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) + if com_spec is not None: + if isinstance(com_spec, ProvidePortComSpec): + self.append_com_spec(com_spec) + elif isinstance(com_spec, (list, tuple)): + 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 ProvidePortComSpec") + + def ref(self) -> PortPrototypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + + def append_com_spec(self, com_spec: ProvidePortComSpec) -> None: + """ + Adds comspec to internal list of com-specs + """ + if isinstance(com_spec, ProvidePortComSpec): + self.com_spec.append(com_spec) + else: + raise TypeError("com_spec must be of a type derived from ProvidePortComSpec") + + +class RequirePortPrototype(PortPrototype): + """ + Complex type AR:R-PORT-PROTOTYPE + Tag variants: 'R-PORT-PROTOTYPE' + + Includes AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE + """ + + def __init__(self, + name: str, + port_interface_ref: PortInterfaceRef | None = None, + com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, + allow_unconnected: bool | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.com_spec: list[RequirePortComSpec] = [] # .REQUIRED-COM-SPECS + self.allow_unconnected: bool | None = None # .MAY-BE-UNCONNECTED + self.port_interface_ref: PortInterfaceRef | None = None # .REQUIRED-INTERFACE-TREF + self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) + self._assign_optional("allow_unconnected", allow_unconnected, bool) + if com_spec is not None: + if isinstance(com_spec, RequirePortComSpec): + self.append_com_spec(com_spec) + elif isinstance(com_spec, (list, tuple)): + for com_spec_elem in com_spec: + self.append_com_spec(com_spec_elem) + else: + 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: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + + def append_com_spec(self, com_spec: RequirePortComSpec) -> None: + """ + Adds comspec to internal list of com-specs + """ + if isinstance(com_spec, RequirePortComSpec): + self.com_spec.append(com_spec) + else: + raise TypeError("com_spec must be of type RequirePortComSpec") + + +class PRPortPrototype(PortPrototype): + """ + Complex type AR:PR-PORT-PROTOTYPE + Tag variants: 'PR-PORT-PROTOTYPE' + + Includes AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE and AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE + """ + + def __init__(self, + name: str, + port_interface_ref: PortInterfaceRef | None = None, + provided_com_spec: ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + required_com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.port_interface_ref: PortInterfaceRef | None = None + self.provided_com_spec: list[ProvidePortComSpec] = [] + self.required_com_spec: list[RequirePortComSpec] = [] + self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) + if provided_com_spec is not None: + if isinstance(provided_com_spec, ProvidePortComSpec): + self.append_com_spec(provided_com_spec) + elif isinstance(required_com_spec, (list, tuple)): + for com_spec_elem in provided_com_spec: + self.append_com_spec(com_spec_elem) + else: + raise TypeError("provided_com_spec must be of a type derived from ProvidePortComSpec") + if required_com_spec is not None: + if isinstance(required_com_spec, RequirePortComSpec): + self.append_com_spec(required_com_spec) + elif isinstance(required_com_spec, (list, tuple)): + for com_spec_elem in required_com_spec: + self.append_com_spec(com_spec_elem) + else: + raise TypeError("required_com_spec must be of a type derived from RequirePortComSpec") + + def ref(self) -> PortPrototypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE) + + def append_com_spec(self, com_spec: ProvidePortComSpec | RequirePortComSpec) -> None: + """ + Append com-spec to internal list(s) of com-specs + """ + if isinstance(com_spec, ProvidePortComSpec): + self.provided_com_spec.append(com_spec) + elif isinstance(com_spec, RequirePortComSpec): + self.required_com_spec.append(com_spec) + else: + raise TypeError("com_spec must be of either type ProvidePortComSpec, RequirePortComSpec") + + +class SwComponentType(ARElement, Searchable): + """ + Group AR:SW-COMPONENT-TYPE + """ + + def __init__(self, + name: str, + ports: PortPrototypeElement | list[PortPrototypeElement] | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + # .SW-COMPONENT-DOCUMENTATIONS not supported + # .CONSISTENCY-NEEDSS not supported + self.ports: list[PortPrototypeElement] = [] # .PORTS + # .PORT_GROUPS not yet supported + # .SWC-MAPPING-CONSTRAINT-REFS not yet supported + # .UNIT-GROUP-REFS not yet supported + if ports is not None: + if isinstance(ports, PortPrototype): + self.append_port(ports) + elif isinstance(ports, list): + for port in ports: + self.append_port(port) + else: + msg_part_1 = "ports: Type must be ProvidePortPrototype, RequirePortPrototype, PRPortPrototype" + msg_part_2 = " or a list of those types." + raise TypeError(msg_part_1 + msg_part_2 + f" Got {str(type(ports))}") + + 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." + raise TypeError(msg + f" Got {str(type(port))}") + + @property + def provide_ports(self) -> Iterator[ProvidePortPrototype]: + """ + P-PORTS + """ + for port in self.ports: + if isinstance(port, ProvidePortPrototype): + yield port + + @property + def require_ports(self) -> Iterator[RequirePortPrototype]: + """ + R-PORTS + """ + for port in self.ports: + if isinstance(port, RequirePortPrototype): + yield port + + @property + def pr_ports(self) -> Iterator[PRPortPrototype]: + """ + PR-PORTS + """ + for port in self.ports: + if isinstance(port, PRPortPrototype): + yield port + + def find(self, ref: str) -> Identifiable | None: + """ + Searches port names for a match in ref + """ + parts = ref.partition('/') + for elem in self.ports: + if elem.name == parts[0]: + return elem + return None + + def create_p_port(self, + name: str, + port_interface: PortInterface | None = None, + com_spec: dict | list[dict] | ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + **kwargs) -> ProvidePortPrototype: + """ + #convenience-method + + 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_provide_port(self, + name: str, + port_interface: PortInterface | None = None, + com_spec: dict | list[dict] | ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + **kwargs) -> ProvidePortPrototype: + """ + #convenience-method + + Alias for create_p_port + """ + return self.create_p_port(name, port_interface, com_spec, **kwargs) + + def create_r_port(self, + name: str, + port_interface: PortInterface, + com_spec: dict | list[dict] | RequirePortComSpec | list[RequirePortComSpec] | None = None, + allow_unconnected: bool | None = None, + **kwargs) -> RequirePortPrototype: + """ + #convenience-method + + 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_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: + """ + #convenience-method + + Alias for create_r_port + """ + return self.create_r_port(name, port_interface, com_spec, allow_unconnected, **kwargs) + + def create_pr_port(self, + name: str, + port_interface: PortInterface | None = None, + provided_com_spec: ProvidePortComSpec | list[ProvidePortComSpec] | None = None, + required_com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, + **kwargs) -> PRPortPrototype: + """ + #convenience-method + + Creates a new pr-port and adds it to the internal list of ports + """ + if provided_com_spec is not None: + if isinstance(provided_com_spec, dict): + provided_com_spec = ProvidePortComSpec.make_from_port_interface(port_interface, **provided_com_spec) + assert provided_com_spec is not None + if required_com_spec is not None: + if isinstance(required_com_spec, dict): + required_com_spec = RequirePortComSpec.make_from_port_interface(port_interface, **required_com_spec) + assert required_com_spec is not None + port = PRPortPrototype(name, port_interface.ref(), provided_com_spec, required_com_spec, **kwargs) + self.append_port(port) + return port + + def find_r_port(self, port_name: str) -> RequirePortPrototype | PRPortPrototype | None: + """ + Finds r-port by name + """ + for port in self.ports: + if isinstance(port, (RequirePortPrototype, PRPortPrototype)) and port.name == port_name: + return port + return None + + def find_p_port(self, port_name: str) -> ProvidePortPrototype | PRPortPrototype | None: + """ + Finds p-port by name + """ + for port in self.ports: + if isinstance(port, (ProvidePortPrototype, PRPortPrototype)) and port.name == port_name: + return port + return None + + def get_data_element_in_port(self, + port: RequirePortPrototype | ProvidePortPrototype, + data_element_name: str | None = None, + ) -> VariableDataPrototype | None: + """ + Finds data element in given port + """ + workspace = port.root_collection() + assert workspace is not None + port_interface = workspace.find(port.port_interface_ref) + if port_interface is None: + raise ar_except.InvalidReferenceError(str(port.port_interface_ref)) + if isinstance(port_interface, SenderReceiverInterface): + if not data_element_name: + if not len(port_interface.data_elements) == 1: + msg = "data_element_name: Undefined value is not allowed when "\ + "the port interface has more than one data element" + raise ValueError(msg) + return port_interface.data_elements[0] + else: + for elem in port_interface.data_elements: + if elem.name == data_element_name: + return elem + else: + raise TypeError(f"Only SenderReceiverInterface is currently supported, got {str(type(port_interface))}") + return None + + def get_operation_in_port(self, + port: PortPrototype, + operation_name: str + ) -> ClientServerOperation: + """ + Finds client-server operation in given port + """ + workspace = port.root_collection() + assert workspace is not None + port_interface = workspace.find(port.port_interface_ref) + if port_interface is None: + raise ar_except.InvalidReferenceError(str(port.port_interface_ref)) + if isinstance(port_interface, ClientServerInterface): + if not operation_name: + if not len(port_interface.operations) == 1: + msg = "operation_name: Undefined value is not allowed when "\ + "the port interface has more than one operation" + raise ValueError(msg) + return port_interface.operations[0] + else: + for operation in port_interface.operations: + if operation.name == operation_name: + return operation + else: + raise TypeError(f"port: '{port.name}' doesn't reference port with ClientServerInterface") + return None + + def get_mode_declaration_group_in_port(self, + port: PortPrototype, + ) -> ModeDeclarationGroupPrototype | None: + """ + Finds mode declaration group in given port + """ + workspace = port.root_collection() + assert workspace is not None + port_interface = workspace.find(port.port_interface_ref) + if port_interface is None: + raise ar_except.InvalidReferenceError(str(port.port_interface_ref)) + if isinstance(port_interface, ModeSwitchInterface): + return port_interface.mode_group + else: + raise TypeError(f"port: Expected a port referencing a ModeSwitchInterface, got {str(type(port_interface))}") + return None + + +class AtomicSoftwareComponentType(SwComponentType): + """ + Group AR:ATOMIC-SW-COMPONENT-TYPE + """ + + def __init__(self, + name: str, + internal_behavior: Union["SwcInternalBehavior", None] = None, + symbol_props: SymbolProps | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self._internal_behavior: SwcInternalBehavior | None = None + self.symbol_props = None # AR:SYMBOL-PROPS + self._assign_optional_strict("_internal_behavior", internal_behavior, SwcInternalBehavior) + self._assign_optional_strict("symbol_props", symbol_props, SymbolProps) + + @property + def internal_behavior(self) -> Union["SwcInternalBehavior", None]: + """ + Internal behavior getter + """ + return self._internal_behavior + + @internal_behavior.setter + def internal_behavior(self, value: Union["SwcInternalBehavior", None]): + """ + Internal behavior setter + """ + self._internal_behavior = value + if value is not None: + value.parent = self + + def create_internal_behavior(self, name: str = None, **kwargs) -> "SwcInternalBehavior": + """ + Creates an empty internal behavior object and adds it to the component. + If the name argument is left as None, a default name will be created based on the name of + the software component + + #convenience-method + """ + if name is None: + name = self.name + "_InternalBehavior" + self.internal_behavior = SwcInternalBehavior(name, **kwargs) + return self.internal_behavior + + +class ApplicationSoftwareComponentType(AtomicSoftwareComponentType): + """ + Complex type AR:APPLICATION-SW-COMPONENT-TYPE + Tag variants: 'APPLICATION-SW-COMPONENT-TYPE' + + Same constructor as parent class + """ + + def ref(self) -> SwComponentTypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return SwComponentTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE) + + +class SwComponentPrototype(Identifiable): + """ + Complex type AR:SW-COMPONENT-PROTOTYPE + Tag variants: 'SW-COMPONENT-PROTOTYPE' + """ + + def __init__(self, + name: str, + type_ref: SwComponentTypeRef | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.type_ref: SwComponentTypeRef | None = None + self._assign_optional_strict("type_ref", type_ref, SwComponentTypeRef) + + def ref(self) -> SwComponentPrototypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + return None if ref_str is None else SwComponentPrototypeRef(ref_str) + + +class PortInCompositionTypeInstanceRef(ARObject): + """ + Merge of complex types AR:P-PORT-IN-COMPOSITION-INSTANCE-REF + and R-PORT-IN-COMPOSITION-INSTANCE-REF + Tag variants: 'PROVIDER-IREF' | 'P-PORT-IN-COMPOSITION-INSTANCE-REF' | + 'REQUESTER-IREF'| 'R-PORT-IN-COMPOSITION-INSTANCE-REF' + """ + + def __init__(self, + component_ref: SwComponentPrototypeRef | None = None, + port_ref: PortPrototypeRef | None = None, + ) -> None: + super().__init__() + self.component_ref: SwComponentPrototypeRef | None = None # .CONTEXT-COMPONENT-REF + self.port_ref: PortPrototypeRef | None = None # .TARGET-P-PORT-REF or .TARGET-R-PORT-REF + self._assign_optional_strict("component_ref", component_ref, SwComponentPrototypeRef) + self._assign_optional_strict("port_ref", port_ref, PortPrototypeRef) + + +class SwConnector(Identifiable): + """ + Group AR:SW-CONNECTOR + """ + + def __init__(self, + name: str, + **kwargs) -> None: + super().__init__(name, **kwargs) + # .MAPPING-REF not yet supported + # .VARIATION-POINT not supported + + +class AssemblySwConnector(SwConnector): + """ + Complex type AR:ASSEMBLY-SW-CONNECTOR + Tag variants: 'ASSEMBLY-SW-CONNECTOR' + """ + + def __init__(self, + name: str, + provide_port: PortInCompositionTypeInstanceRef | None = None, + require_port: PortInCompositionTypeInstanceRef | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.provide_port: PortInCompositionTypeInstanceRef | None = None # .PROVIDER-IREF + self.require_port: PortInCompositionTypeInstanceRef | None = None # .REQUESTER-IREF + self._assign_optional_strict("provide_port", provide_port, PortInCompositionTypeInstanceRef) + self._assign_optional_strict("require_port", require_port, PortInCompositionTypeInstanceRef) + + +class DelegationSwConnector(SwConnector): + """ + Complex type AR:DELEGATION-SW-CONNECTOR + Tag variants: 'DELEGATION-SW-CONNECTOR' + """ + + def __init__(self, + name: str, + inner_port: PortInCompositionTypeInstanceRef | None = None, + outer_port: PortPrototypeRef | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.inner_port: PortInCompositionTypeInstanceRef | None = None # .INNER-PORT-IREF + self.outer_port: PortPrototypeRef | None = None # .OUTER-PORT-REF" + self._assign_optional_strict("inner_port", inner_port, PortInCompositionTypeInstanceRef) + self._assign_optional_strict("outer_port", outer_port, PortPrototypeRef) + + @property + def xml_tag(self) -> str | None: + """ + Returns a suitable XML-tag for inner_port_ref based on port reference type. + Raises exception is port reference isn't set or if port-reference contains invalid value + """ + if self.inner_port.port_ref is not None: + if self.inner_port.port_ref.is_provide_port_ref: + return "P-PORT-IN-COMPOSITION-INSTANCE-REF" + if self.inner_port.port_ref.is_require_port_ref: + return "R-PORT-IN-COMPOSITION-INSTANCE-REF" + return None + + +class PassThroughSwConnector(SwConnector): + """ + Complex type AR:PASS-THROUGH-SW-CONNECTOR + Tag variants: 'PASS-THROUGH-SW-CONNECTOR' + """ + + def __init__(self, + name: str, + provide_port: PortPrototypeRef | None = None, + require_port: PortPrototypeRef | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.provide_port: PortPrototypeRef | None = None # .PROVIDED-OUTER-PORT-REF + self.require_port: PortPrototypeRef | None = None # .REQUIRED-OUTER-PORT-REF + # .SERVICE-INTERFACE-ELEMENT-MAPPING-REFS not yet supported + self._assign_optional_strict("provide_port", provide_port, PortPrototypeRef) + self._assign_optional_strict("require_port", require_port, PortPrototypeRef) + + +class CompositionSwComponentType(SwComponentType, Searchable): + """ + Complex type AR:COMPOSITION-SW-COMPONENT-TYPE + Tag variants: 'COMPOSITION-SW-COMPONENT-TYPE' + """ + + def __init__(self, + name: str, + components: SwComponentPrototype | list[SwComponentPrototype] | None = None, + connectors: SwConnectorElement | list[SwConnectorElement] = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.components: list[SwComponentPrototype] = [] # .COMPONENTS + self.connectors: list[SwConnectorElement] = [] # .CONNECTORS + # .CONSTANT-VALUE-MAPPING-REFS not yet supported + # .DATA-TYPE-MAPPING-REFS not yet supported + # .INSTANTIATION-RTE-EVENT-PROPSS not yet supported + if components is not None: + if isinstance(components, SwComponentPrototype): + self.append_component(components) + elif isinstance(components, list): + for component in components: + self.append_component(component) + else: + raise TypeError(f"components: Invalid type '{str(type(components))}'") + if connectors is not None: + if isinstance(connectors, (AssemblySwConnector, DelegationSwConnector, PassThroughSwConnector)): + self.append_connector(connectors) + elif isinstance(connectors, list): + for connector in connectors: + self.append_connector(connector) + else: + raise TypeError(f"components: Invalid type '{str(type(connectors))}'") + + def ref(self) -> SwComponentTypeRef | None: + """ + Returns a reference to this element or None if the element + is not yet part of a package + """ + ref_str = self._calc_ref_string() + if ref_str is None: + return None + return SwComponentTypeRef(ref_str, ar_enum.IdentifiableSubTypes.COMPOSITION_SW_COMPONENT_TYPE) + + def append_component(self, component: SwComponentPrototype) -> None: + """ + Appends components prototype to internal list + """ + if isinstance(component, SwComponentPrototype): + component.parent = self + self.components.append(component) + else: + raise TypeError(f"component: Invalid type {(str(type(component)))}") + + def append_connector(self, connector: SwConnectorElement) -> None: + """ + Appends components prototype to internal list + """ + if isinstance(connector, (AssemblySwConnector, DelegationSwConnector, PassThroughSwConnector)): + connector.parent = self + self.connectors.append(connector) + else: + raise TypeError(f"connector: Invalid type {(str(type(connector)))}") + + def find(self, ref: str) -> Identifiable | None: + """ + Searches components and connectors for a match in ref + """ + parts = ref.partition('/') + for elem in self.components: + if elem.name == parts[0]: + return elem + for elem in self.connectors: + if elem.name == parts[0]: + return elem + return super().find(ref) + + def create_component_prototype(self, + component_type: SwComponentType, + name: str = None, + **kwargs) -> SwComponentPrototype: + """ + #convenience-method + + Creates a new SwComponentPrototype object from the source SwComponentType and adds it + to the internal list of components. + By default the created SwComponentPrototype will have the same name as the source + SwComponentType. The optional name argument can be used to give it a different name. + """ + if name is None: + name = component_type.name + component_prototype = SwComponentPrototype(name, component_type.ref(), **kwargs) + self.append_component(component_prototype) + return component_prototype + + def create_connector(self, + port_ref1: str, + port_ref2: str, + workspace: Searchable) -> None: + """ + #convenience-method + + Creates a connector between two ports in the composition + port_ref1 and port_ref2 can be of any of these formats: + * 'component_name/port_name' - references a port of an inner component + * 'port_name' - references a port in the composition itself + + Depending on the combination of ports this function automatically determines + the type of connector to create which can be one of: + * AssemblySwConnector + * DelegationSwConnector + * PassThroughSwConnector + """ + assert workspace is not None + port1, component1 = self._analyze_port_ref(workspace, port_ref1) + port2, component2 = self._analyze_port_ref(workspace, port_ref2) + + if component1 is None and component2 is None: + return self._create_pass_through_connector(port1, port2) + elif component1 is None: + return self._create_delegation_connector(component2, port2, port1) + elif component2 is None: + return self._create_delegation_connector(component1, port1, port2) + else: + requester_component: SwComponentPrototype = None + provider_component: SwComponentPrototype = None + provide_port: PortPrototype = None + require_port: PortPrototype = None + if isinstance(port1, RequirePortPrototype) and isinstance(port2, ProvidePortPrototype): + requester_component, provider_component = component1, component2 + require_port, provide_port = port1, port2 + elif isinstance(port1, ProvidePortPrototype) and isinstance(port2, RequirePortPrototype): + requester_component, provider_component = component2, component1 + require_port, provide_port = port2, port1 + elif isinstance(port1, RequirePortPrototype) and isinstance(port2, RequirePortPrototype): + raise ValueError('cannot create assembly connector between two require-ports') + else: + raise ValueError('cannot create assembly connector between two provide-ports') + return self._create_assembly_connector(provider_component, provide_port, + requester_component, require_port) + + def _analyze_port_ref(self, + workspace: Searchable, + port_ref: str) -> tuple[PortPrototype, Union[SwComponentPrototype, None]]: + """ + Analyze port reference string and attempts to determine what component + and port are referenced. + """ + port: PortPrototype | None = None + port_name: str | None = None + parts = split_ref(port_ref) + if len(parts) > 1: + if len(parts) == 2: # Format is 'component_name/port_name'? + port_name = parts[1] + for elem in self.components: + if elem.name == parts[0]: + component = workspace.find(str(elem.type_ref)) + if component is None: + raise ValueError(f"Invalid reference: {elem.type_ref}") + if not isinstance(component, SwComponentType): + msg = f"Reference is not a valid SwComponentType: {elem.type_ref}" + raise ValueError(msg) + port = component.find(port_name) + if (port is None) or (not isinstance(port, PortPrototype)): + msg = f"Component '{component.name}' does not seem to have a port with name '{port_name}'" + raise ValueError(msg) + return port, elem + else: + raise ValueError(f"Invalid format: '{port_ref}'") + else: # Format is 'port_name' + # Leaving component as None here is a reminder to the caller to create a delegation or a + # pass-through connector + port_name = parts[0] + port = self.find(port_name) + if (port is None) or (not isinstance(port, PortPrototype)): + msg = f"Component '{self.name}' does not seem to have a port with name '{port_name}'" + raise ValueError(msg) + return port, None + + def _create_assembly_connector(self, + provider_component: SwComponentPrototype, + provide_port: PortPrototype, + requester_component: SwComponentPrototype, + require_port: PortPrototype) -> AssemblySwConnector: + """ + Internal helper function for creating assembly connector + """ + connector_name = '_'.join([provider_component.name, + provide_port.name, + requester_component.name, + require_port.name]) + provider_iref = PortInCompositionTypeInstanceRef(provider_component.ref(), provide_port.ref()) + requester_iref = PortInCompositionTypeInstanceRef(requester_component.ref(), require_port.ref()) + connector = AssemblySwConnector(connector_name, provider_iref, requester_iref) + if self.find(connector_name) is not None: + raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") + self.append_connector(connector) + return connector + + def _create_delegation_connector(self, + inner_component: SwComponentPrototype, + inner_port: PortPrototype, + outer_port: PortPrototype) -> DelegationSwConnector: + if isinstance(outer_port, ProvidePortPrototype): + connector_name = '_'.join([inner_component.name, inner_port.name, outer_port.name]) + else: + connector_name = '_'.join([outer_port.name, inner_component.name, inner_port.name]) + inner_port_iref = PortInCompositionTypeInstanceRef(inner_component.ref(), inner_port.ref()) + connector = DelegationSwConnector(connector_name, inner_port_iref, outer_port.ref()) + if self.find(connector_name) is not None: + raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") + self.connectors.append(connector) + return connector + + def _create_pass_through_connector(self, + provide_port: ProvidePortPrototype, + require_port: RequirePortPrototype) -> PassThroughSwConnector: + connector_name = '_'.join([provide_port.name, require_port.name]) + connector = PassThroughSwConnector(connector_name, provide_port.ref(), require_port.ref()) + if self.find(connector_name) is not None: + raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") + self.connectors.append(connector) + return connector + + +class POperationInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:P-OPERATION-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'OPERATION-IREF' + """ + + def __init__(self, + context_port: AbstractProvidedPortPrototypeRef | None = None, + target_provided_operation: ClientServerOperationRef | str | None = None, + ) -> None: + # .CONTEXT-P-PORT-REF (Keep name consistent in similar classes) + self.context_port: AbstractProvidedPortPrototypeRef | None = None + # .TARGET-PROVIDED-OPERATION-REF + self.target_provided_operation: ClientServerOperationRef | None = None + self._assign_optional("context_port", context_port, AbstractProvidedPortPrototypeRef) + self._assign_optional("target_provided_operation", target_provided_operation, ClientServerOperationRef) + - Includes AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE +class PModeGroupInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF' | 'MODE-GROUP-IREF' | + 'SWC-MODE-GROUP-IREF' """ def __init__(self, - name: str, - port_interface_ref: PortInterfaceRef | None = None, - com_spec: ProvidePortComSpec | list[ProvidePortComSpec] | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.com_spec: list[ProvidePortComSpec] = [] # .PROVIDED-COM-SPECS - self.port_interface_ref: PortInterfaceRef | None = None # .PROVIDED-INTERFACE-TREF - self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) - if com_spec is not None: - if isinstance(com_spec, ProvidePortComSpec): - self.append_com_spec(com_spec) - elif isinstance(com_spec, (list, tuple)): - 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 ProvidePortComSpec") - - def ref(self) -> PortPrototypeRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + context_port: AbstractProvidedPortPrototypeRef | None = None, + context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | str | None = None, + ) -> None: + # .CONTEXT-P-PORT-REF + self.context_port: AbstractProvidedPortPrototypeRef | None = None + # .CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF + self.context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | None = None - def append_com_spec(self, com_spec: ProvidePortComSpec) -> None: - """ - Adds comspec to internal list of com-specs - """ - if isinstance(com_spec, ProvidePortComSpec): - self.com_spec.append(com_spec) - else: - raise TypeError("com_spec must be of a type derived from ProvidePortComSpec") + self._assign_optional("context_port", context_port, AbstractProvidedPortPrototypeRef) + self._assign_optional("context_mode_declaration_group_prototype", + context_mode_declaration_group_prototype, + ModeDeclarationGroupPrototypeRef) -class RequirePortPrototype(PortPrototype): +class PTriggerInAtomicSwcTypeInstanceRef(ARObject): """ - Complex type AR:R-PORT-PROTOTYPE - Tag variants: 'R-PORT-PROTOTYPE' - - Includes AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE + Complex type AR:P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF + Tag variants: 'P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF' | 'SWC-TRIGGER-IREF' | + 'TRIGGER-IREF' """ def __init__(self, - name: str, - port_interface_ref: PortInterfaceRef | None = None, - com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, - allow_unconnected: bool | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.com_spec: list[RequirePortComSpec] = [] # .REQUIRED-COM-SPECS - self.allow_unconnected: bool | None = None # .MAY-BE-UNCONNECTED - self.port_interface_ref: PortInterfaceRef | None = None # .REQUIRED-INTERFACE-TREF - self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) - self._assign_optional("allow_unconnected", allow_unconnected, bool) - if com_spec is not None: - if isinstance(com_spec, RequirePortComSpec): - self.append_com_spec(com_spec) - elif isinstance(com_spec, (list, tuple)): - for com_spec_elem in com_spec: - self.append_com_spec(com_spec_elem) - else: - msg = "com_spec: Needs be of a type derived from RequirePortComSpec." - raise TypeError(msg + f" Got {str(type(com_spec))}") + context_port: AbstractProvidedPortPrototypeRef | None = None, + target_trigger: TriggerRef | str | None = None, + ) -> None: + # .CONTEXT-P-PORT-REF (Keep name consistent in similar classes) + self.context_port: AbstractProvidedPortPrototypeRef | None = None + # .TARGET-TRIGGER-REF + self.target_trigger: TriggerRef | None = None + self._assign_optional("context_port", context_port, AbstractProvidedPortPrototypeRef) + self._assign_optional("target_trigger", target_trigger, TriggerRef) - def ref(self) -> PortPrototypeRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) - def append_com_spec(self, com_spec: RequirePortComSpec) -> None: - """ - Adds comspec to internal list of com-specs - """ - if isinstance(com_spec, RequirePortComSpec): - self.com_spec.append(com_spec) - else: - raise TypeError("com_spec must be of type RequirePortComSpec") +class RModeInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:R-MODE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DISABLED-MODE-IREF' | 'MODE-IREF' + """ + def __init__(self, + context_port: AbstractRequiredPortPrototypeRef | None = None, + context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | None = None, + target_mode_declaration: ModeDeclarationRef | None = None, + ) -> None: + # .CONTEXT-PORT-REF + self.context_port: AbstractRequiredPortPrototypeRef | None = None + # .CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF + self.context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | None = None + # .TARGET-MODE-DECLARATION-REF + self.target_mode_declaration: ModeDeclarationRef | None = None + self._assign_optional("context_port", context_port, AbstractRequiredPortPrototypeRef) + self._assign_optional("context_mode_declaration_group_prototype", + context_mode_declaration_group_prototype, + ModeDeclarationGroupPrototypeRef) + self._assign_optional("target_mode_declaration", target_mode_declaration, ModeDeclarationRef) -class PRPortPrototype(PortPrototype): + +class RVariableInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:R-VARIABLE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DATA-IREF' """ - Complex type AR:PR-PORT-PROTOTYPE - Tag variants: 'PR-PORT-PROTOTYPE' - Includes AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE and AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE + def __init__(self, + context_port: AbstractRequiredPortPrototypeRef | None = None, + target_data_element: VariableDataPrototypeRef | str | None = None, + ) -> None: + # .CONTEXT-R-PORT-REF (Keep name consistent in similar classes) + self.context_port: AbstractRequiredPortPrototypeRef | None = None + # .TARGET-DATA-ELEMENT-REF + self.target_data_element: VariableDataPrototypeRef | None = None + + self._assign_optional("context_port", context_port, AbstractRequiredPortPrototypeRef) + self._assign_optional("target_data_element", target_data_element, VariableDataPrototypeRef) + + +class RTriggerInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:R-TRIGGER-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'TRIGGER-IREF' | 'REQUIRED-TRIGGER-IREF' """ def __init__(self, - name: str, - port_interface_ref: PortInterfaceRef | None = None, - provided_com_spec: ProvidePortComSpec | list[ProvidePortComSpec] | None = None, - required_com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - self.port_interface_ref: PortInterfaceRef | None = None - self.provided_com_spec: list[ProvidePortComSpec] = [] - self.required_com_spec: list[RequirePortComSpec] = [] - self._assign_optional_strict("port_interface_ref", port_interface_ref, PortInterfaceRef) - if provided_com_spec is not None: - if isinstance(provided_com_spec, ProvidePortComSpec): - self.append_com_spec(provided_com_spec) - elif isinstance(required_com_spec, (list, tuple)): - for com_spec_elem in provided_com_spec: - self.append_com_spec(com_spec_elem) - else: - raise TypeError("provided_com_spec must be of a type derived from ProvidePortComSpec") - if required_com_spec is not None: - if isinstance(required_com_spec, RequirePortComSpec): - self.append_com_spec(required_com_spec) - elif isinstance(required_com_spec, (list, tuple)): - for com_spec_elem in required_com_spec: - self.append_com_spec(com_spec_elem) - else: - raise TypeError("required_com_spec must be of a type derived from RequirePortComSpec") + context_port: AbstractRequiredPortPrototypeRef | None = None, + target_trigger: TriggerRef | str | None = None, + ) -> None: + # .CONTEXT-R-PORT-REF (Keep name consistent in similar classes) + self.context_port: AbstractRequiredPortPrototypeRef | None = None + # .TARGET-TRIGGER-REF + self.target_trigger: TriggerRef | None = None - def ref(self) -> PortPrototypeRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE) + self._assign_optional("context_port", context_port, AbstractRequiredPortPrototypeRef) + self._assign_optional("target_trigger", target_trigger, TriggerRef) - def append_com_spec(self, com_spec: ProvidePortComSpec | RequirePortComSpec) -> None: - """ - Append com-spec to internal list(s) of com-specs - """ - if isinstance(com_spec, ProvidePortComSpec): - self.provided_com_spec.append(com_spec) - elif isinstance(com_spec, RequirePortComSpec): - self.required_com_spec.append(com_spec) - else: - raise TypeError("com_spec must be of either type ProvidePortComSpec, RequirePortComSpec") +# --- SWC internal behavior elements -class SwComponentType(ARElement, Searchable): +class ArVariableInImplementationDataInstanceRef(ARObject): """ - Group AR:SW-COMPONENT-TYPE + Complex type AR:AR-VARIABLE-IN-IMPLEMENTATION-DATA-INSTANCE-REF + Tag variants: 'AUTOSAR-VARIABLE-IN-IMPL-DATATYPE' | 'IMPLEMENTATION-DATA-TYPE-ELEMENT' """ + ContextDataPrototypeArgType = Union[AbstractImplementationDataTypeElementRef, + list[AbstractImplementationDataTypeElementRef]] + def __init__(self, - name: str, - ports: PortPrototypeElement | list[PortPrototypeElement] | None = None, - **kwargs) -> None: - super().__init__(name, **kwargs) - # .SW-COMPONENT-DOCUMENTATIONS not supported - # .CONSISTENCY-NEEDSS not supported - self.ports: list[PortPrototypeElement] = [] # .PORTS - # .PORT_GROUPS not yet supported - # .SWC-MAPPING-CONSTRAINT-REFS not yet supported - # .UNIT-GROUP-REFS not yet supported - if ports is not None: - if isinstance(ports, PortPrototype): - self.append_port(ports) - elif isinstance(ports, list): - for port in ports: - self.append_port(port) - else: - msg_part_1 = "ports: Type must be ProvidePortPrototype, RequirePortPrototype, PRPortPrototype" - msg_part_2 = " or a list of those types." - raise TypeError(msg_part_1 + msg_part_2 + f" Got {str(type(ports))}") + port_prototype_ref: PortPrototypeRef | None = None, + root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None, + context_data_prototype_refs: ContextDataPrototypeArgType | None = None, + target_data_prototype_ref: AbstractImplementationDataTypeElementRef | None = None + ) -> None: + super().__init__() + # .PORT-PROTOTYPE-REF + self.port_prototype_ref: PortPrototypeRef | None = None + # .ROOT-VARIABLE-DATA-PROTOTYPE-REF + self.root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None + # .CONTEXT-DATA-PROTOTYPE-REFS + self.context_data_prototype_refs: list[AbstractImplementationDataTypeElementRef] = [] + # .TARGET-DATA-PROTOTYPE-REF + self.target_data_prototype_ref: AbstractImplementationDataTypeElementRef | None = None - 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." - raise TypeError(msg + f" Got {str(type(port))}") + self._assign_optional_strict("port_prototype_ref", port_prototype_ref, PortPrototypeRef) + self._assign_optional_strict("root_variable_data_prototype_ref", + root_variable_data_prototype_ref, + VariableDataPrototypeRef) + self._assign_optional_strict("target_data_prototype_ref", + target_data_prototype_ref, + AbstractImplementationDataTypeElementRef) + if context_data_prototype_refs is not None: + if isinstance(context_data_prototype_refs, AbstractImplementationDataTypeElementRef): + self.append_context_data_protype_ref(context_data_prototype_refs) + elif isinstance(context_data_prototype_refs, list): + for context_data_prototype_ref in context_data_prototype_refs: + self.append_context_data_protype_ref(context_data_prototype_ref) - @property - def provide_ports(self) -> Iterator[ProvidePortPrototype]: + def append_context_data_protype_ref(self, context_data_prototype_ref: AbstractImplementationDataTypeElementRef): """ - P-PORTS + Appends datatype reference to internal list of context data type references """ - for port in self.ports: - if isinstance(port, ProvidePortPrototype): - yield port + if isinstance(context_data_prototype_ref, AbstractImplementationDataTypeElementRef): + self.context_data_prototype_refs.append(context_data_prototype_ref) + else: + raise TypeError("context_data_prototype_ref must be of type AbstractImplementationDataTypeElementRef") - @property - def require_ports(self) -> Iterator[RequirePortPrototype]: - """ - R-PORTS - """ - for port in self.ports: - if isinstance(port, RequirePortPrototype): - yield port - @property - def pr_ports(self) -> Iterator[PRPortPrototype]: - """ - PR-PORTS - """ - for port in self.ports: - if isinstance(port, PRPortPrototype): - yield port +class VariableInAtomicSWCTypeInstanceRef(ARObject): + """ + Complex type AR:VARIABLE-IN-ATOMIC-SWC-TYPE-INSTANCE-REF + Tag variants: 'AUTOSAR-VARIABLE-IREF' + """ - def find(self, ref: str) -> Identifiable | None: - """ - Searches port names for a match in ref - """ - parts = ref.partition('/') - for elem in self.ports: - if elem.name == parts[0]: - return elem - return None + ContextDataPrototypeArgType = Union[ApplicationCompositeElementDataPrototypeRef, + list[ApplicationCompositeElementDataPrototypeRef]] - def create_provide_port(self, - name: str, - port_interface: PortInterface | None = None, - com_spec: dict | list[dict] | ProvidePortComSpec | list[ProvidePortComSpec] | None = None, - **kwargs) -> ProvidePortPrototype: - """ - #convenience-method + def __init__(self, + port_prototype_ref: PortPrototypeRef | None = None, + root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None, + context_data_prototype_refs: ContextDataPrototypeArgType | None = None, + target_data_prototype_ref: DataPrototypeRef | None = None, + ) -> None: + super().__init__() + # .PORT-PROTOTYPE-REF + self.port_prototype_ref: PortPrototypeRef | None = None + # .ROOT-VARIABLE-DATA-PROTOTYPE-REF + self.root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None + # .CONTEXT-DATA-PROTOTYPE-REF + self.context_data_prototype_refs: list[ApplicationCompositeElementDataPrototypeRef] = [] + # .TARGET-DATA-PROTOTYPE-REF + self.target_data_prototype_ref: DataPrototypeRef | None = None - 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 + self._assign_optional_strict("port_prototype_ref", port_prototype_ref, PortPrototypeRef) + self._assign_optional_strict("root_variable_data_prototype_ref", + root_variable_data_prototype_ref, VariableDataPrototypeRef) + self._assign_optional_strict("target_data_prototype_ref", target_data_prototype_ref, DataPrototypeRef) + if context_data_prototype_refs is not None: + if isinstance(context_data_prototype_refs, ApplicationCompositeElementDataPrototypeRef): + self.append_context_data_protype_ref(context_data_prototype_refs) + elif isinstance(context_data_prototype_refs, list): + for context_data_prototype_ref in context_data_prototype_refs: + self.append_context_data_protype_ref(context_data_prototype_ref) - 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: + def append_context_data_protype_ref(self, context_data_prototype_ref: ApplicationCompositeElementDataPrototypeRef): """ - #convenience-method - - Creates a new require port and adds it to the internal list of ports + Appends datatype reference to internal list of context data type references """ - 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 + if isinstance(context_data_prototype_ref, ApplicationCompositeElementDataPrototypeRef): + self.context_data_prototype_refs.append(context_data_prototype_ref) + else: + raise TypeError("context_data_prototype_ref must be of type AbstractImplementationDataTypeElementRef") - def create_pr_port(self, - name: str, - port_interface_ref: PortInterfaceRef | None = None, - com_spec: RequirePortComSpec | list[RequirePortComSpec] | None = None, - **kwargs) -> PRPortPrototype: - """ - #convenience-method - 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 AutosarVariableRef(ARObject): + """ + Complex type AR:AUTOSAR-VARIABLE-REF + Tag variants: 'VARIABLE-INSTANCE' | 'NV-RAM-BLOCK-ELEMENT' | 'READ-NV-DATA' | + 'WRITTEN-NV-DATA' | 'WRITTEN-READ-NV-DATA' | 'USED-DATA-ELEMENT' | + 'AUTOSAR-VARIABLE' | 'ACCESSED-VARIABLE' + """ + + def __init__(self, + ar_variable_in_impl_datatype: ArVariableInImplementationDataInstanceRef | None = None, + ar_variable_iref: VariableInAtomicSWCTypeInstanceRef | None = None, + local_variable_ref: VariableDataPrototypeRef | None = None + ) -> None: + super().__init__() + # .AUTOSAR-VARIABLE-IN-IMPL-DATATYPE + self.ar_variable_in_impl_datatype: ArVariableInImplementationDataInstanceRef | None = None + # .AUTOSAR-VARIABLE-IREF + self.ar_variable_iref: VariableInAtomicSWCTypeInstanceRef | None = None + # .LOCAL-VARIABLE-REF + self.local_variable_ref: VariableDataPrototypeRef | None = None + self._assign_optional_strict("ar_variable_in_impl_datatype", + ar_variable_in_impl_datatype, + ArVariableInImplementationDataInstanceRef) + self._assign_optional_strict("ar_variable_iref", + ar_variable_iref, + VariableInAtomicSWCTypeInstanceRef) + self._assign_optional_strict("local_variable_ref", + local_variable_ref, + VariableDataPrototypeRef) -class AtomicSoftwareComponentType(SwComponentType): +class VariableAccess(Identifiable): """ - Group AR:ATOMIC-SW-COMPONENT-TYPE + Complex type AR:VARIABLE-ACCESS + Tag variants: 'REPLACE-WITH' | 'VARIABLE-ACCESS' """ def __init__(self, name: str, - internal_behavior: Union["SwcInternalBehavior", None] = None, - symbol_props: SymbolProps | None = None, + accessed_variable: AutosarVariableRef | None = None, + scope: ar_enum.VariableAccessScope | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self._internal_behavior: SwcInternalBehavior | None = None - self.symbol_props = None # AR:SYMBOL-PROPS - self._assign_optional_strict("_internal_behavior", internal_behavior, SwcInternalBehavior) - self._assign_optional_strict("symbol_props", symbol_props, SymbolProps) - - @property - def internal_behavior(self) -> Union["SwcInternalBehavior", None]: - """ - Internal behavior getter - """ - return self._internal_behavior - - @internal_behavior.setter - def internal_behavior(self, value: Union["SwcInternalBehavior", None]): - """ - Internal behavior setter - """ - self._internal_behavior = value - if value is not None: - value.parent = self + # .ACCESSED-VARIABLE + self.accessed_variable: AutosarVariableRef | None = None + # .SCOPE + self.scope: ar_enum.VariableAccessScope | None = None - def create_internal_behavior(self, name: str = None, **kwargs) -> "SwcInternalBehavior": - """ - Creates an empty internal behavior object and adds it to the component. - If the name argument is left as None, a default name will be created based on the name of - the software component - """ - if name is None: - name = self.name + "_InternalBehavior" - self.internal_behavior = SwcInternalBehavior(name, **kwargs) - return self.internal_behavior + # .VARIATION-POINT not supported + self._assign_optional_strict("accessed_variable", accessed_variable, AutosarVariableRef) + self._assign_optional("scope", scope, ar_enum.VariableAccessScope) -class ApplicationSoftwareComponentType(AtomicSoftwareComponentType): +class SwcImplementation(Implementation): """ - Complex type AR:APPLICATION-SW-COMPONENT-TYPE - Tag variants: 'APPLICATION-SW-COMPONENT-TYPE' - - Same constructor as parent class + Complex type AR:SWC-IMPLEMENTATION + Tag variants: 'SWC-IMPLEMENTATION' """ - def ref(self) -> SwComponentTypeRef | None: + def __init__(self, + name: str, + behavior_ref: SwcInternalBehaviorRef | None = None, + code_descriptors: Code | list[Code] | None = None, + required_rte_vendor: str | None = None, + **kwargs) -> None: + super().__init__(name, code_descriptors, **kwargs) + self.behavior_ref: SwcInternalBehaviorRef | None = None + # .PER-INSTANCE-MEMORY-SIZES not yet supported + self.required_rte_vendor: str | None = None + self._assign_optional("behavior_ref", behavior_ref, SwcInternalBehaviorRef) + self._assign_optional_strict("required_rte_vendor", required_rte_vendor, str) + + def ref(self) -> SwcImplementationRef | None: """ Returns a reference to this element or None if the element is not yet part of a package @@ -5469,515 +5729,630 @@ def ref(self) -> SwComponentTypeRef | None: ref_str = self._calc_ref_string() if ref_str is None: return None - return SwComponentTypeRef(ref_str, ar_enum.IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE) + return SwcImplementationRef(ref_str) -class SwComponentPrototype(Identifiable): +class ExecutableEntityActivationReason(ImplementationProps): """ - Complex type AR:SW-COMPONENT-PROTOTYPE - Tag variants: 'SW-COMPONENT-PROTOTYPE' + Complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' """ def __init__(self, name: str, - type_ref: SwComponentTypeRef | None = None, + bit_position: int | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.type_ref: SwComponentTypeRef | None = None - self._assign_optional_strict("type_ref", type_ref, SwComponentTypeRef) - - def ref(self) -> SwComponentPrototypeRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - return None if ref_str is None else SwComponentPrototypeRef(ref_str) + self.bit_position: int | None = None + self._assign_optional_positive_int("bit_position", bit_position) -class PortInCompositionTypeInstanceRef(ARObject): +class ExclusiveAreaRefConditional(ARObject): """ - Merge of complex types AR:P-PORT-IN-COMPOSITION-INSTANCE-REF - and R-PORT-IN-COMPOSITION-INSTANCE-REF - Tag variants: 'PROVIDER-IREF' | 'P-PORT-IN-COMPOSITION-INSTANCE-REF' | - 'REQUESTER-IREF'| 'R-PORT-IN-COMPOSITION-INSTANCE-REF' + Complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' """ def __init__(self, - component_ref: SwComponentPrototypeRef | None = None, - port_ref: PortPrototypeRef | None = None, - ) -> None: - super().__init__() - self.component_ref: SwComponentPrototypeRef | None = None # .CONTEXT-COMPONENT-REF - self.port_ref: PortPrototypeRef | None = None # .TARGET-P-PORT-REF or .TARGET-R-PORT-REF - self._assign_optional_strict("component_ref", component_ref, SwComponentPrototypeRef) - self._assign_optional_strict("port_ref", port_ref, PortPrototypeRef) + exclusive_area_ref: ExclusiveAreaRef | str | None = None) -> None: + self.exclusive_area_ref: ExclusiveAreaRef | None = None # .EXCLUSIVE-AREA-REF + self._assign_optional("exclusive_area_ref", exclusive_area_ref, ExclusiveAreaRef) -class SwConnector(Identifiable): - """ - Group AR:SW-CONNECTOR - """ +ActivationReasonArgumentType = ExecutableEntityActivationReason | list[ExecutableEntityActivationReason] | None +CanEnterLeaveArgumentType = Union[ExclusiveAreaRefConditional, + list[ExclusiveAreaRefConditional], + ExclusiveAreaRef, + list[ExclusiveAreaRef], + str, + None] - def __init__(self, - name: str, - **kwargs) -> None: - super().__init__(name, **kwargs) - # .MAPPING-REF not yet supported - # .VARIATION-POINT not supported +ExclusiveAreaNestingOrderArgumentType = ExclusiveAreaNestingOrderRef | list[ExclusiveAreaNestingOrderRef] | None +RunsInsidesArgumentType = Union[ExclusiveAreaRefConditional, + list[ExclusiveAreaRefConditional], + ExclusiveAreaRef, + list[ExclusiveAreaRef], + str, + None] +ExclusiveAreaElementArgumentType = ExclusiveAreaRefConditional | ExclusiveAreaRef | str -class AssemblySwConnector(SwConnector): + +class ExecutableEntity(Identifiable): """ - Complex type AR:ASSEMBLY-SW-CONNECTOR - Tag variants: 'ASSEMBLY-SW-CONNECTOR' + Group AR:EXECUTABLE-ENTITY """ def __init__(self, name: str, - provide_port: PortInCompositionTypeInstanceRef | None = None, - require_port: PortInCompositionTypeInstanceRef | None = None, + activation_reasons: ActivationReasonArgumentType = None, + can_enter_leave: CanEnterLeaveArgumentType = None, + exclusive_area_nesting_order: ExclusiveAreaNestingOrderArgumentType = None, + minimum_start_interval: int | float | None = None, + reentrancy_level: ar_enum.ReentrancyLevel | None = None, + runs_insides: RunsInsidesArgumentType = None, + sw_addr_method: str | SwAddrMethodRef | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.provide_port: PortInCompositionTypeInstanceRef | None = None # .PROVIDER-IREF - self.require_port: PortInCompositionTypeInstanceRef | None = None # .REQUESTER-IREF - self._assign_optional_strict("provide_port", provide_port, PortInCompositionTypeInstanceRef) - self._assign_optional_strict("require_port", require_port, PortInCompositionTypeInstanceRef) + self.activation_reasons: list[ExecutableEntityActivationReason] = [] # .ACTIVATION-REASONS + # .CAN-ENTERS or CAN-ENTER-EXCLUSIVE-AREA-REFS depending on schema version + self.can_enter_leave: list[ExclusiveAreaRefConditional] = [] + self.exclusive_area_nesting_order: list[ExclusiveAreaNestingOrderRef] = [] # .EXCLUSIVE-AREA-NESTING-ORDER-REFS + self.minimum_start_interval: float | None = None # .MINIMUM-START-INTERVAL + self.reentrancy_level: ar_enum.ReentrancyLevel | None = None # .REENTRANCY-LEVEL + # .RUNS-INSIDES or .RUNS-INSIDE-EXCLUSIVE-AREA-REFS depending on schema version + self.runs_insides: list[ExclusiveAreaRefConditional] = [] + self.sw_addr_method: str | SwAddrMethodRef | None = None # .SW-ADDR-METHOD-REF + + if activation_reasons is not None: + if isinstance(activation_reasons, list): + for activation_reason in activation_reasons: + self.append_activation_reason(activation_reason) + else: + self.append_activation_reason(activation_reasons) + if can_enter_leave is not None: + if isinstance(can_enter_leave, list): + for elem in can_enter_leave: + self.append_can_enter_leave(elem) + else: + self.append_can_enter_leave(can_enter_leave) + if exclusive_area_nesting_order is not None: + if isinstance(exclusive_area_nesting_order, ExclusiveAreaNestingOrderRef): + self.append_exclusive_area_nesting_order(exclusive_area_nesting_order) + elif isinstance(exclusive_area_nesting_order, list): + for elem in exclusive_area_nesting_order: + self.append_exclusive_area_nesting_order(elem) + self._assign_optional("minimum_start_interval", minimum_start_interval, float) + self._assign_optional("reentrancy_level", reentrancy_level, ar_enum.ReentrancyLevel) + if runs_insides is not None: + if isinstance(runs_insides, list): + for elem in runs_insides: + self.append_runs_insides(elem) + else: + self.append_runs_insides(runs_insides) + self._assign_optional('sw_addr_method', sw_addr_method, SwAddrMethodRef) + def append_activation_reason(self, activation_reason: ExecutableEntityActivationReason) -> None: + """ + Appends activation_reason to internal list of activation reasons + """ + if isinstance(activation_reason, ExecutableEntityActivationReason): + self.activation_reasons.append(activation_reason) + else: + raise TypeError("activation_reason must be of type ExecutableEntityActivationReason") -class DelegationSwConnector(SwConnector): + def append_can_enter_leave(self, value: ExclusiveAreaElementArgumentType) -> None: + """ + The executable entity can enter/leave the referenced exclusive area through explicit API calls + """ + if isinstance(value, ExclusiveAreaRefConditional): + self.can_enter_leave.append(value) + elif isinstance(value, (ExclusiveAreaRef, str)): + self.can_enter_leave.append(ExclusiveAreaRefConditional(value)) + else: + raise TypeError("value: Invalid type. Expected one of ExclusiveAreaRefConditional, ExclusiveAreaRef, str.") + + def append_exclusive_area_nesting_order(self, exclusive_area_nesting_order: ExclusiveAreaNestingOrderRef) -> None: + """ + Appends exclusive area reference to internal list of nesting orders + """ + if isinstance(exclusive_area_nesting_order, ExclusiveAreaNestingOrderRef): + self.exclusive_area_nesting_order.append(exclusive_area_nesting_order) + else: + raise TypeError("exclusive_area_nesting_order must be of type ExclusiveAreaRefConditional") + + def append_runs_insides(self, value: ExclusiveAreaElementArgumentType) -> None: + """ + The executable entity runs completely inside the referenced exclusive area + """ + if isinstance(value, ExclusiveAreaRefConditional): + self.runs_insides.append(value) + elif isinstance(value, (ExclusiveAreaRef, str)): + self.runs_insides.append(ExclusiveAreaRefConditional(value)) + else: + raise TypeError("value: Invalid type. Expected one of ExclusiveAreaRefConditional, ExclusiveAreaRef, str.") + + +class RunnableEntity(ExecutableEntity): """ - Complex type AR:DELEGATION-SW-CONNECTOR - Tag variants: 'DELEGATION-SW-CONNECTOR' + Complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + Only implements base class features for now. """ def __init__(self, name: str, - inner_port: PortInCompositionTypeInstanceRef | None = None, - outer_port: PortPrototypeRef | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.inner_port: PortInCompositionTypeInstanceRef | None = None # .INNER-PORT-IREF - self.outer_port: PortPrototypeRef | None = None # .OUTER-PORT-REF" - self._assign_optional_strict("inner_port", inner_port, PortInCompositionTypeInstanceRef) - self._assign_optional_strict("outer_port", outer_port, PortPrototypeRef) - @property - def xml_tag(self) -> str | None: + def ref(self) -> RunnableEntityRef | None: """ - Returns a suitable XML-tag for inner_port_ref based on port reference type. - Raises exception is port reference isn't set or if port-reference contains invalid value + Returns a reference to this element or + None if the element is not yet part of a package """ - if self.inner_port.port_ref is not None: - if self.inner_port.port_ref.is_provide_port_ref: - return "P-PORT-IN-COMPOSITION-INSTANCE-REF" - if self.inner_port.port_ref.is_require_port_ref: - return "R-PORT-IN-COMPOSITION-INSTANCE-REF" - return None + ref_str = self._calc_ref_string() + return None if ref_str is None else RunnableEntityRef(ref_str) -class PassThroughSwConnector(SwConnector): +class RteEvent(Identifiable): """ - Complex type AR:PASS-THROUGH-SW-CONNECTOR - Tag variants: 'PASS-THROUGH-SW-CONNECTOR' + Group AR:RTE-EVENT """ def __init__(self, name: str, - provide_port: PortPrototypeRef | None = None, - require_port: PortPrototypeRef | None = None, + start_on_event: RunnableEntityRef | None = None, + disabled_modes: RModeInAtomicSwcInstanceRef | list[RModeInAtomicSwcInstanceRef] | None = None, **kwargs) -> None: super().__init__(name, **kwargs) - self.provide_port: PortPrototypeRef | None = None # .PROVIDED-OUTER-PORT-REF - self.require_port: PortPrototypeRef | None = None # .REQUIRED-OUTER-PORT-REF - # .SERVICE-INTERFACE-ELEMENT-MAPPING-REFS not yet supported - self._assign_optional_strict("provide_port", provide_port, PortPrototypeRef) - self._assign_optional_strict("require_port", require_port, PortPrototypeRef) + # .DISABLED-MODE-IREFS + self.disabled_modes: list[RModeInAtomicSwcInstanceRef] = [] + # .START-ON-EVENT-REF + self.start_on_event: RunnableEntityRef | None = None + if disabled_modes is not None: + if isinstance(disabled_modes, RModeInAtomicSwcInstanceRef): + self.append_disabled_mode(disabled_modes) + elif isinstance(disabled_modes, list): + for disabled_mode in disabled_modes: + self.append_disabled_mode(disabled_mode) + self._assign_optional("start_on_event", start_on_event, RunnableEntityRef) + + def append_disabled_mode(self, disabled_mode: RModeInAtomicSwcInstanceRef) -> None: + """ + Adds reference to the modes that disable the event + """ + if isinstance(disabled_mode, RModeInAtomicSwcInstanceRef): + self.disabled_modes.append(disabled_mode) + else: + raise TypeError("disabled_mode must be of type RModeInAtomicSwcInstanceRef") -class CompositionSwComponentType(SwComponentType, Searchable): +class AsynchronousServerCallReturnsEvent(RteEvent): """ - Complex type AR:COMPOSITION-SW-COMPONENT-TYPE - Tag variants: 'COMPOSITION-SW-COMPONENT-TYPE' + Complex type AR:ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT + Tag variants: 'ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT' """ def __init__(self, name: str, - components: SwComponentPrototype | list[SwComponentPrototype] | None = None, - connectors: SwConnectorElement | list[SwConnectorElement] = None, + start_on_event: RunnableEntityRef | str | None = None, + event_source: AsynchronousServerCallResultPointRef | str | None = None, **kwargs) -> None: - super().__init__(name, **kwargs) - self.components: list[SwComponentPrototype] = [] # .COMPONENTS - self.connectors: list[SwConnectorElement] = [] # .CONNECTORS - # .CONSTANT-VALUE-MAPPING-REFS not yet supported - # .DATA-TYPE-MAPPING-REFS not yet supported - # .INSTANTIATION-RTE-EVENT-PROPSS not yet supported - if components is not None: - if isinstance(components, SwComponentPrototype): - self.append_component(components) - elif isinstance(components, list): - for component in components: - self.append_component(component) - else: - raise TypeError(f"components: Invalid type '{str(type(components))}'") - if connectors is not None: - if isinstance(connectors, (AssemblySwConnector, DelegationSwConnector, PassThroughSwConnector)): - self.append_connector(connectors) - elif isinstance(connectors, list): - for connector in connectors: - self.append_connector(connector) - else: - raise TypeError(f"components: Invalid type '{str(type(connectors))}'") + super().__init__(name, start_on_event, **kwargs) + # .EVENT-SOURCE-REF + self.event_source: AsynchronousServerCallResultPointRef | None = None + self._assign_optional("event_source", event_source, AsynchronousServerCallResultPointRef) - def ref(self) -> SwComponentTypeRef | None: - """ - Returns a reference to this element or None if the element - is not yet part of a package - """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return SwComponentTypeRef(ref_str, ar_enum.IdentifiableSubTypes.COMPOSITION_SW_COMPONENT_TYPE) - def append_component(self, component: SwComponentPrototype) -> None: - """ - Appends components prototype to internal list - """ - if isinstance(component, SwComponentPrototype): - component.parent = self - self.components.append(component) - else: - raise TypeError(f"component: Invalid type {(str(type(component)))}") +class BackgroundEvent(RteEvent): + """ + Complex Type AR:BACKGROUND-EVENT + Tag variants: 'BACKGROUND-EVENT' + Inherits constructor from base-class + """ - def append_connector(self, connector: SwConnectorElement) -> None: - """ - Appends components prototype to internal list - """ - if isinstance(connector, (AssemblySwConnector, DelegationSwConnector, PassThroughSwConnector)): - connector.parent = self - self.connectors.append(connector) - else: - raise TypeError(f"connector: Invalid type {(str(type(connector)))}") - def find(self, ref: str) -> Identifiable | None: - """ - Searches components and connectors for a match in ref - """ - parts = ref.partition('/') - for elem in self.components: - if elem.name == parts[0]: - return elem - for elem in self.connectors: - if elem.name == parts[0]: - return elem - return super().find(ref) +class DataReceiveErrorEvent(RteEvent): + """ + Complex Type AR:DATA-RECEIVE-ERROR-EVENT + Tag variants: 'DATA-RECEIVE-ERROR-EVENT' + """ - def create_component_prototype(self, - component_type: SwComponentType, - name: str = None, - **kwargs) -> SwComponentPrototype: + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + data: RVariableInAtomicSwcInstanceRef | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .DATA-IREF + self.data: RVariableInAtomicSwcInstanceRef | None = None + self._assign_optional_strict("data", data, RVariableInAtomicSwcInstanceRef) + + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + context_port: AbstractRequiredPortPrototypeRef | None = None, + target_data_element: VariableDataPrototypeRef | str | None = None, + **kwargs) -> "DataReceiveErrorEvent": """ #convenience-method - Creates a new SwComponentPrototype object from the source SwComponentType and adds it - to the internal list of components. - By default the created SwComponentPrototype will have the same name as the source - SwComponentType. The optional name argument can be used to give it a different name. + Simplified creation method that automatically creates + and uses the necessary RVariableInAtomicSwcInstanceRef object """ - if name is None: - name = component_type.name - component_prototype = SwComponentPrototype(name, component_type.ref(), **kwargs) - self.append_component(component_prototype) - return component_prototype + data = RVariableInAtomicSwcInstanceRef(context_port, target_data_element) + return cls(name, start_on_event, data, **kwargs) - def create_connector(self, - port_ref1: str, - port_ref2: str, - workspace: Searchable) -> None: + +class DataReceivedEvent(RteEvent): + """ + Complex Type AR:DATA-RECEIVED-EVENT + Tag variants: 'DATA-RECEIVED-EVENT' + """ + + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + data: RVariableInAtomicSwcInstanceRef | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .DATA-IREF + self.data: RVariableInAtomicSwcInstanceRef | None = None + self._assign_optional_strict("data", data, RVariableInAtomicSwcInstanceRef) + + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + context_port: AbstractRequiredPortPrototypeRef | None = None, + target_data_element: VariableDataPrototypeRef | str | None = None, + **kwargs) -> "DataReceivedEvent": """ #convenience-method - Creates a connector between two ports in the composition - port_ref1 and port_ref2 can be of any of these formats: - * 'component_name/port_name' - references a port of an inner component - * 'port_name' - references a port in the composition itself - - Depending on the combination of ports this function automatically determines - the type of connector to create which can be one of: - * AssemblySwConnector - * DelegationSwConnector - * PassThroughSwConnector + Simplified creation method that automatically creates + and uses the necessary RVariableInAtomicSwcInstanceRef object """ - assert workspace is not None - port1, component1 = self._analyze_port_ref(workspace, port_ref1) - port2, component2 = self._analyze_port_ref(workspace, port_ref2) + data = RVariableInAtomicSwcInstanceRef(context_port, target_data_element) + return cls(name, start_on_event, data, **kwargs) - if component1 is None and component2 is None: - return self._create_pass_through_connector(port1, port2) - elif component1 is None: - return self._create_delegation_connector(component2, port2, port1) - elif component2 is None: - return self._create_delegation_connector(component1, port1, port2) - else: - requester_component: SwComponentPrototype = None - provider_component: SwComponentPrototype = None - provide_port: PortPrototype = None - require_port: PortPrototype = None - if isinstance(port1, RequirePortPrototype) and isinstance(port2, ProvidePortPrototype): - requester_component, provider_component = component1, component2 - require_port, provide_port = port1, port2 - elif isinstance(port1, ProvidePortPrototype) and isinstance(port2, RequirePortPrototype): - requester_component, provider_component = component2, component1 - require_port, provide_port = port2, port1 - elif isinstance(port1, RequirePortPrototype) and isinstance(port2, RequirePortPrototype): - raise ValueError('cannot create assembly connector between two require-ports') - else: - raise ValueError('cannot create assembly connector between two provide-ports') - return self._create_assembly_connector(provider_component, provide_port, - requester_component, require_port) - def _analyze_port_ref(self, - workspace: Searchable, - port_ref: str) -> tuple[PortPrototype, Union[SwComponentPrototype, None]]: - """ - Analyze port reference string and attempts to determine what component - and port are referenced. - """ - port: PortPrototype | None = None - port_name: str | None = None - parts = split_ref(port_ref) - if len(parts) > 1: - if len(parts) == 2: # Format is 'component_name/port_name'? - port_name = parts[1] - for elem in self.components: - if elem.name == parts[0]: - component = workspace.find(str(elem.type_ref)) - if component is None: - raise ValueError(f"Invalid reference: {elem.type_ref}") - if not isinstance(component, SwComponentType): - msg = f"Reference is not a valid SwComponentType: {elem.type_ref}" - raise ValueError(msg) - port = component.find(port_name) - if (port is None) or (not isinstance(port, PortPrototype)): - msg = f"Component '{component.name}' does not seem to have a port with name '{port_name}'" - raise ValueError(msg) - return port, elem - else: - raise ValueError(f"Invalid format: '{port_ref}'") - else: # Format is 'port_name' - # Leaving component as None here is a reminder to the caller to create a delegation or a - # pass-through connector - port_name = parts[0] - port = self.find(port_name) - if (port is None) or (not isinstance(port, PortPrototype)): - msg = f"Component '{self.name}' does not seem to have a port with name '{port_name}'" - raise ValueError(msg) - return port, None +class DataSendCompletedEvent(RteEvent): + """ + Complex Type AR:DATA-SEND-COMPLETED-EVENT + Tag variants: 'DATA-SEND-COMPLETED-EVENT' + """ - def _create_assembly_connector(self, - provider_component: SwComponentPrototype, - provide_port: PortPrototype, - requester_component: SwComponentPrototype, - require_port: PortPrototype) -> AssemblySwConnector: + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + event_source: VariableAccessRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .EVENT-SOURCE-REF + self.event_source: VariableAccessRef | None = None + self._assign_optional("event_source", event_source, VariableAccessRef) + + +class DataWriteCompletedEvent(RteEvent): + """ + Complex Type AR:DATA-WRITE-COMPLETED-EVENT + Tag variants: 'DATA-WRITE-COMPLETED-EVENT' + """ + + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + event_source: VariableAccessRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .EVENT-SOURCE-REF + self.event_source: VariableAccessRef | None = None + self._assign_optional("event_source", event_source, VariableAccessRef) + + +class ExternalTriggerOccurredEvent(RteEvent): + """ + Complex Type AR:EXTERNAL-TRIGGER-OCCURRED-EVENT + Tag variants: 'EXTERNAL-TRIGGER-OCCURRED-EVENT' + """ + + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + trigger: RTriggerInAtomicSwcInstanceRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .TRIGGER-IREF + self.trigger: RTriggerInAtomicSwcInstanceRef | None = None + self._assign_optional_strict("trigger", trigger, RTriggerInAtomicSwcInstanceRef) + + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + context_port: AbstractRequiredPortPrototypeRef | None = None, + target_trigger: TriggerRef | str | None = None, + **kwargs) -> "ExternalTriggerOccurredEvent": """ - Internal helper function for creating assembly connector + #convenience-method """ - connector_name = '_'.join([provider_component.name, - provide_port.name, - requester_component.name, - require_port.name]) - provider_iref = PortInCompositionTypeInstanceRef(provider_component.ref(), provide_port.ref()) - requester_iref = PortInCompositionTypeInstanceRef(requester_component.ref(), require_port.ref()) - connector = AssemblySwConnector(connector_name, provider_iref, requester_iref) - if self.find(connector_name) is not None: - raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") - self.append_connector(connector) - return connector + trigger = RTriggerInAtomicSwcInstanceRef(context_port, target_trigger) + return cls(name, start_on_event, trigger, **kwargs) - def _create_delegation_connector(self, - inner_component: SwComponentPrototype, - inner_port: PortPrototype, - outer_port: PortPrototype) -> DelegationSwConnector: - if isinstance(outer_port, ProvidePortPrototype): - connector_name = '_'.join([inner_component.name, inner_port.name, outer_port.name]) - else: - connector_name = '_'.join([outer_port.name, inner_component.name, inner_port.name]) - inner_port_iref = PortInCompositionTypeInstanceRef(inner_component.ref(), inner_port.ref()) - connector = DelegationSwConnector(connector_name, inner_port_iref, outer_port.ref()) - if self.find(connector_name) is not None: - raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") - self.connectors.append(connector) - return connector - def _create_pass_through_connector(self, - provide_port: ProvidePortPrototype, - require_port: RequirePortPrototype) -> PassThroughSwConnector: - connector_name = '_'.join([provide_port.name, require_port.name]) - connector = PassThroughSwConnector(connector_name, provide_port.ref(), require_port.ref()) - if self.find(connector_name) is not None: - raise ValueError(f"{self.name}: Connector with name '{connector_name}' already exists") - self.connectors.append(connector) - return connector +class InitEvent(RteEvent): + """ + Complex Type AR:INIT-EVENT + Tag variants: 'INIT-EVENT' + Inherits constructor from base-class + """ -# --- SWC internal behavior elements + +class InternalTriggerOccurredEvent(RteEvent): + """ + Complex type AR:INTERNAL-TRIGGER-OCCURRED-EVENT + Tag variants: 'INTERNAL-TRIGGER-OCCURRED-EVENT' + """ + + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + event_source: InternalTriggeringPointRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .EVENT-SOURCE-REF + self.event_source: InternalTriggeringPointRef | None = None + self._assign_optional("event_source", event_source, InternalTriggeringPointRef) -class ArVariableInImplementationDataInstanceRef(ARObject): +class ModeSwitchedAckEvent(RteEvent): """ - Complex type AR:AR-VARIABLE-IN-IMPLEMENTATION-DATA-INSTANCE-REF - Tag variants: 'AUTOSAR-VARIABLE-IN-IMPL-DATATYPE' | 'IMPLEMENTATION-DATA-TYPE-ELEMENT' + Complex type AR:MODE-SWITCHED-ACK-EVENT + Tag variants: 'MODE-SWITCHED-ACK-EVENT' """ - ContextDataPrototypeArgType = Union[AbstractImplementationDataTypeElementRef, - list[AbstractImplementationDataTypeElementRef]] - def __init__(self, - port_prototype_ref: PortPrototypeRef | None = None, - root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None, - context_data_prototype_refs: ContextDataPrototypeArgType | None = None, - target_data_prototype_ref: AbstractImplementationDataTypeElementRef | None = None - ) -> None: - super().__init__() - # .PORT-PROTOTYPE-REF - self.port_prototype_ref: PortPrototypeRef | None = None - # .ROOT-VARIABLE-DATA-PROTOTYPE-REF - self.root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None - # .CONTEXT-DATA-PROTOTYPE-REFS - self.context_data_prototype_refs: list[AbstractImplementationDataTypeElementRef] = [] - # .TARGET-DATA-PROTOTYPE-REF - self.target_data_prototype_ref: AbstractImplementationDataTypeElementRef | None = None + name: str, + start_on_event: RunnableEntityRef | str | None = None, + event_source: ModeSwitchPointRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .EVENT-SOURCE-REF + self.event_source: ModeSwitchPointRef | None = None + self._assign_optional("event_source", event_source, ModeSwitchPointRef) - self._assign_optional_strict("port_prototype_ref", port_prototype_ref, PortPrototypeRef) - self._assign_optional_strict("root_variable_data_prototype_ref", - root_variable_data_prototype_ref, - VariableDataPrototypeRef) - self._assign_optional_strict("target_data_prototype_ref", - target_data_prototype_ref, - AbstractImplementationDataTypeElementRef) - if context_data_prototype_refs is not None: - if isinstance(context_data_prototype_refs, AbstractImplementationDataTypeElementRef): - self.append_context_data_protype_ref(context_data_prototype_refs) - elif isinstance(context_data_prototype_refs, list): - for context_data_prototype_ref in context_data_prototype_refs: - self.append_context_data_protype_ref(context_data_prototype_ref) - def append_context_data_protype_ref(self, context_data_prototype_ref: AbstractImplementationDataTypeElementRef): +class OperationInvokedEvent(RteEvent): + """ + Complex type AR:OPERATION-INVOKED-EVENT + Tag variants: 'OPERATION-INVOKED-EVENT' + """ + + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + operation: POperationInAtomicSwcInstanceRef | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .OPERATION-IREF + self.operation: POperationInAtomicSwcInstanceRef | None = None + self._assign_optional_strict("operation", operation, POperationInAtomicSwcInstanceRef) + + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + context_port: AbstractProvidedPortPrototypeRef | None = None, + target_provided_operation: ClientServerOperationRef | str | None = None, + **kwargs) -> "OperationInvokedEvent": """ - Appends datatype reference to internal list of context data type references + #convenience-method + + Simplified creation method that automatically creates + and uses the necessary POperationInAtomicSwcInstanceRef object """ - if isinstance(context_data_prototype_ref, AbstractImplementationDataTypeElementRef): - self.context_data_prototype_refs.append(context_data_prototype_ref) - else: - raise TypeError("context_data_prototype_ref must be of type AbstractImplementationDataTypeElementRef") + operation = POperationInAtomicSwcInstanceRef(context_port, target_provided_operation) + return cls(name, start_on_event, operation, **kwargs) -class VariableInAtomicSWCTypeInstanceRef(ARObject): +SwcModeSwitchEventModeType = Union[RModeInAtomicSwcInstanceRef, + tuple[RModeInAtomicSwcInstanceRef, RModeInAtomicSwcInstanceRef], + None] + + +class SwcModeManagerErrorEvent(RteEvent): """ - Complex type AR:VARIABLE-IN-ATOMIC-SWC-TYPE-INSTANCE-REF - Tag variants: 'AUTOSAR-VARIABLE-IREF' + Complex type AR:SWC-MODE-MANAGER-ERROR-EVENT + Tag variants: 'SWC-MODE-MANAGER-ERROR-EVENT' """ - ContextDataPrototypeArgType = Union[ApplicationCompositeElementDataPrototypeRef, - list[ApplicationCompositeElementDataPrototypeRef]] + def __init__(self, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + mode_group: PModeGroupInAtomicSwcInstanceRef | str | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .MODE-GROUP-IREF + self.mode_group: PModeGroupInAtomicSwcInstanceRef | None = None + self._assign_optional_strict("mode_group", mode_group, PModeGroupInAtomicSwcInstanceRef) + + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + context_port: AbstractProvidedPortPrototypeRef | None = None, + context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | str | None = None, + **kwargs) -> "SwcModeManagerErrorEvent": + """ + #convenience-method + """ + mode_group = PModeGroupInAtomicSwcInstanceRef(context_port, context_mode_declaration_group_prototype) + return cls(name, start_on_event, mode_group, **kwargs) + + +class SwcModeSwitchEvent(RteEvent): + """ + Complex type AR:SWC-MODE-SWITCH-EVENT + Tag variants: 'SWC-MODE-SWITCH-EVENT' + """ def __init__(self, - port_prototype_ref: PortPrototypeRef | None = None, - root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None, - context_data_prototype_refs: ContextDataPrototypeArgType | None = None, - target_data_prototype_ref: DataPrototypeRef | None = None, - ) -> None: - super().__init__() - # .PORT-PROTOTYPE-REF - self.port_prototype_ref: PortPrototypeRef | None = None - # .ROOT-VARIABLE-DATA-PROTOTYPE-REF - self.root_variable_data_prototype_ref: VariableDataPrototypeRef | None = None - # .CONTEXT-DATA-PROTOTYPE-REF - self.context_data_prototype_refs: list[ApplicationCompositeElementDataPrototypeRef] = [] - # .TARGET-DATA-PROTOTYPE-REF - self.target_data_prototype_ref: DataPrototypeRef | None = None - self._assign_optional_strict("port_prototype_ref", port_prototype_ref, PortPrototypeRef) - self._assign_optional_strict("root_variable_data_prototype_ref", - root_variable_data_prototype_ref, VariableDataPrototypeRef) - self._assign_optional_strict("target_data_prototype_ref", target_data_prototype_ref, DataPrototypeRef) - if context_data_prototype_refs is not None: - if isinstance(context_data_prototype_refs, ApplicationCompositeElementDataPrototypeRef): - self.append_context_data_protype_ref(context_data_prototype_refs) - elif isinstance(context_data_prototype_refs, list): - for context_data_prototype_ref in context_data_prototype_refs: - self.append_context_data_protype_ref(context_data_prototype_ref) + name: str, + start_on_event: RunnableEntityRef | str | None = None, + activation: ar_enum.ModeActivationKind | None = None, + mode: SwcModeSwitchEventModeType = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .ACTIVATION + self.activation: ar_enum.ModeActivationKind | None = None + # .MODE-IREFS + self.mode: SwcModeSwitchEventModeType = None + + self._assign_optional("activation", activation, ar_enum.ModeActivationKind) + if mode is not None: + if isinstance(mode, RModeInAtomicSwcInstanceRef): + self.mode = mode + elif isinstance(mode, tuple): + if (isinstance(mode[0], RModeInAtomicSwcInstanceRef) and # noqa W504 + isinstance(mode[1], RModeInAtomicSwcInstanceRef)): + self.mode = mode + else: + raise TypeError("Both values of mode tuple must be of type RModeInAtomicSwcInstanceRef") + else: + msg_part1 = "Invalid type for parameter 'mode'. " + msg_part2 = "Expected types are RModeInAtomicSwcInstanceRef or tuple of same type." + msg_part3 = f"Got {str(type(mode))}" + raise TypeError(msg_part1 + msg_part2 + msg_part3) - def append_context_data_protype_ref(self, context_data_prototype_ref: ApplicationCompositeElementDataPrototypeRef): + @classmethod + def make(cls, + name: str, + start_on_event: RunnableEntityRef | str | None = None, + activation: ar_enum.ModeActivationKind | None = None, + context_port: AbstractRequiredPortPrototypeRef | None = None, + context_mode_declaration_group_prototype: ModeDeclarationGroupPrototypeRef | None = None, + target_mode_declaration: ModeDeclarationRef | None = None, + **kwargs) -> "SwcModeSwitchEvent": """ - Appends datatype reference to internal list of context data type references + #convenience-method + + Only suitable for ON-ENTRY and ON-EXIT activation types. + For ON-TRANSITION activation, use the class constructor instead. + """ - if isinstance(context_data_prototype_ref, ApplicationCompositeElementDataPrototypeRef): - self.context_data_prototype_refs.append(context_data_prototype_ref) - else: - raise TypeError("context_data_prototype_ref must be of type AbstractImplementationDataTypeElementRef") + mode = RModeInAtomicSwcInstanceRef(context_port, + context_mode_declaration_group_prototype, + target_mode_declaration) + return cls(name, start_on_event, activation, mode, **kwargs) -class AutosarVariableRef(ARObject): +class TimingEvent(RteEvent): """ - Complex type AR:AUTOSAR-VARIABLE-REF - Tag variants: 'VARIABLE-INSTANCE' | 'NV-RAM-BLOCK-ELEMENT' | 'READ-NV-DATA' | - 'WRITTEN-NV-DATA' | 'WRITTEN-READ-NV-DATA' | 'USED-DATA-ELEMENT' | - 'AUTOSAR-VARIABLE' | 'ACCESSED-VARIABLE' + Complex type AR:TIMING-EVENT + Tag variants: 'TIMING-EVENT' """ def __init__(self, - ar_variable_in_impl_datatype: ArVariableInImplementationDataInstanceRef | None = None, - ar_variable_iref: VariableInAtomicSWCTypeInstanceRef | None = None, - local_variable_ref: VariableDataPrototypeRef | None = None - ) -> None: - super().__init__() - # .AUTOSAR-VARIABLE-IN-IMPL-DATATYPE - self.ar_variable_in_impl_datatype: ArVariableInImplementationDataInstanceRef | None = None - # .AUTOSAR-VARIABLE-IREF - self.ar_variable_iref: VariableInAtomicSWCTypeInstanceRef | None = None - # .LOCAL-VARIABLE-REF - self.local_variable_ref: VariableDataPrototypeRef | None = None - self._assign_optional_strict("ar_variable_in_impl_datatype", - ar_variable_in_impl_datatype, - ArVariableInImplementationDataInstanceRef) - self._assign_optional_strict("ar_variable_iref", - ar_variable_iref, - VariableInAtomicSWCTypeInstanceRef) - self._assign_optional_strict("local_variable_ref", - local_variable_ref, - VariableDataPrototypeRef) + name: str, + start_on_event: RunnableEntityRef | str | None = None, + period: int | float | None = None, + offset: int | float | None = None, + **kwargs) -> None: + super().__init__(name, start_on_event, **kwargs) + # .OFFSET + self.offset: int | float | None = None + # .PERIOD + self.period: int | float | None = None + self._assign_optional("offset", offset, float) + self._assign_optional("period", period, float) -class VariableAccess(Identifiable): + +class TransformerHardErrorEvent(RteEvent): """ - Complex type AR:VARIABLE-ACCESS - Tag variants: 'REPLACE-WITH' | 'VARIABLE-ACCESS' + Complex type AR:TRANSFORMER-HARD-ERROR-EVENT + Tag variants: 'TRANSFORMER-HARD-ERROR-EVENT' """ def __init__(self, name: str, - accessed_variable: AutosarVariableRef | None = None, - scope: ar_enum.VariableAccessScope | None = None, + start_on_event: RunnableEntityRef | str | None = None, + operation: POperationInAtomicSwcInstanceRef | None = None, + required_trigger: RTriggerInAtomicSwcInstanceRef | None = None, + trigger: PTriggerInAtomicSwcTypeInstanceRef | None = None, **kwargs) -> None: - super().__init__(name, **kwargs) - self.accessed_variable: AutosarVariableRef | None = None # .ACCESSED-VARIABLE - self.scope: ar_enum.VariableAccessScope | None = None # .SCOPE - # .VARIATION-POINT not supported - self._assign_optional_strict("accessed_variable", accessed_variable, AutosarVariableRef) - self._assign_optional("scope", scope, ar_enum.VariableAccessScope) + super().__init__(name, start_on_event, **kwargs) + # .OPERATION-IREF + self.operation: POperationInAtomicSwcInstanceRef | None = None + # .REQUIRED-TRIGGER-IREF + self.required_trigger: RTriggerInAtomicSwcInstanceRef | None = None + # .TRIGGER-IREF + self.trigger: PTriggerInAtomicSwcTypeInstanceRef | None = None + + self._assign_optional_strict("operation", operation, POperationInAtomicSwcInstanceRef) + self._assign_optional_strict("required_trigger", required_trigger, RTriggerInAtomicSwcInstanceRef) + self._assign_optional_strict("trigger", trigger, PTriggerInAtomicSwcTypeInstanceRef) + + +class InternalBehavior(Identifiable): + """ + Group AR:INTERNAL-BEHAVIOR + This is just a placeholder. Will be implemented later. + """ -class SwcInternalBehavior(Identifiable): +class SwcInternalBehavior(InternalBehavior): """ Complex type AR:SWC-INTERNAL-BEHAVIOR Tag variants: 'SWC-INTERNAL-BEHAVIOR' - This is just a placeholder. Will be implemented later. + Implementation is very limited for now """ def __init__(self, name: str, + runnables: RunnableEntity | list[RunnableEntity] | None = None, + events: RteEvent | list[RteEvent] | None = None, **kwargs) -> None: super().__init__(name, **kwargs) + # .RUNNABLES + self.runnables: list[RunnableEntity] = [] + # .EVENTS + self.events: list[RteEvent] = [] + + if runnables is not None: + if isinstance(runnables, list): + for runnable in runnables: + self.append_runnable(runnable) + else: + self.append_runnable(runnables) + + if events is not None: + if isinstance(events, list): + for event in events: + self.append_event(event) + else: + self.append_event(events) + + def _get_valid_parent(self) -> SwComponentType: + """ + Verifies that this object has valid SoftwareComponent as parent before returning it + """ + if self.parent is None or not isinstance(self.parent, SwComponentType): + raise RuntimeError("Behavior object doesn't have a valid parent") + return self.parent + + def _get_valid_behavior_settings(self) -> BehaviorSettings: + """ + Verifies that the root collection has a valid behavior_settings object and returns it + """ + swc = self._get_valid_parent() + workspace = swc.root_collection() + if not isinstance(workspace.behavior_settings, BehaviorSettings): + raise TypeError("Root collection doesn't seem to be a valid workspace") + return workspace.behavior_settings def ref(self) -> SwcInternalBehaviorRef | None: """ @@ -5987,32 +6362,506 @@ def ref(self) -> SwcInternalBehaviorRef | None: ref_str = self._calc_ref_string() return None if ref_str is None else SwcInternalBehaviorRef(ref_str) + def append_runnable(self, runnable: RunnableEntity) -> None: + """ + Adds runnable to internal list of runnables + """ + if isinstance(runnable, RunnableEntity): + runnable.parent = self + self.runnables.append(runnable) + else: + raise TypeError(f"runnable must be of type RunnableEntity. Got {str(type(runnable))}") -class SwcImplementation(Implementation): - """ - Complex type AR:SWC-IMPLEMENTATION - Tag variants: 'SWC-IMPLEMENTATION' - """ + def append_event(self, event: RteEvent) -> None: + """ + Adds event to internal list of events + """ + if isinstance(event, RteEvent): + event.parent = self + self.events.append(event) + else: + raise TypeError(f"event must derive from RteEvent. Got {str(type(event))}") - def __init__(self, - name: str, - behavior_ref: SwcInternalBehaviorRef | None = None, - code_descriptors: Code | list[Code] | None = None, - required_rte_vendor: str | None = None, - **kwargs) -> None: - super().__init__(name, code_descriptors, **kwargs) - self.behavior_ref: SwcInternalBehaviorRef | None = None - # .PER-INSTANCE-MEMORY-SIZES not yet supported - self.required_rte_vendor: str | None = None - self._assign_optional("behavior_ref", behavior_ref, SwcInternalBehaviorRef) - self._assign_optional_strict("required_rte_vendor", required_rte_vendor, str) + def create_runnable(self, + name: str, + activation_reasons: ActivationReasonArgumentType = None, + can_enter_leave: CanEnterLeaveArgumentType = None, + exclusive_area_nesting_order: ExclusiveAreaNestingOrderArgumentType = None, + minimum_start_interval: int | float | None = None, + reentrancy_level: ar_enum.ReentrancyLevel | None = None, + runs_insides: RunsInsidesArgumentType = None, + sw_addr_method: str | SwAddrMethodRef | None = None, + **kwargs) -> RunnableEntity: + """ + Adds a new RunnableEntity to this object - def ref(self) -> SwcImplementationRef | None: + #convenience-method """ - Returns a reference to this element or None if the element - is not yet part of a package + data = {"activation_reasons": activation_reasons, + "can_enter_leave": can_enter_leave, + "exclusive_area_nesting_order": exclusive_area_nesting_order, + "minimum_start_interval": minimum_start_interval, + "reentrancy_level": reentrancy_level, + "runs_insides": runs_insides, + "sw_addr_method": sw_addr_method} + data.update(kwargs) + runnable = RunnableEntity(name, **data) + self.append_runnable(runnable) + return runnable + + def find_runnable(self, name: str) -> RunnableEntity | None: + """ + Find runnable by name. Returns None if no runnable is found. + """ + for runnable in self.runnables: + if runnable.name == name: + return runnable + return None + + def _make_unique_event_name(self, event_name: str) -> str: + """ + Checks if event_name is unique in internal event list. + If not, then it automatically starts to add an integer-based name suffix ("_0", "_1" etc.). + Calling this function could potentially invalidate existing event references. + Note: Not yet implemented + """ + return self._make_unique_name_in_list(self.events, event_name) + + def _make_unique_name_in_list(self, elements: list[Referrable], base_name: str): + """ + Attempts to find a unique name in the list of elements. + This function can modify names in the given list. + If an element with the name base_name already exists in the list it will + append "_0" to the existing element and any newly added element will have + its suffix automatically increased by 1. + Returns a new name which is guaranteed to be unique in the given list + """ + has_index = False + highest_index = 0 + unpatched_elem: Referrable | None = None + expr = re.compile(base_name + r'_(\d+)') + for element in elements: + result = expr.match(element.name) + if result is not None: + has_index = True + index = int(result.group(1)) + if index > highest_index: + highest_index = index + elif element.name == base_name: + unpatched_elem = element + if unpatched_elem is not None: + unpatched_elem.name = '_'.join([unpatched_elem.name, '0']) + if has_index or unpatched_elem is not None: + return '_'.join([base_name, str(highest_index + 1)]) + else: + return base_name + + def create_background_event(self, + runnable_name: str, + event_name: str | None = None, + **kwargs + ) -> BackgroundEvent: """ - ref_str = self._calc_ref_string() - if ref_str is None: - return None - return SwcImplementationRef(ref_str) + Adds a new BackgroundEvent to this SwcInternalBehavior object. + + #convenience-method + """ + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.background_event_prefix: + event_name = behavior_settings.background_event_prefix + runnable_name + else: + msg = "event_name: Unable to dynamically create event name,"\ + " background_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = BackgroundEvent(unique_event_name, runnable.ref(), **kwargs) + self.append_event(event) + return event + + def create_data_receive_error_event(self, + runnable_name: str, + port_data_element: str, + event_name: str | None = None, + **kwargs + ) -> DataReceiveErrorEvent: + """ + Adds a new DataReceiveErrorEvent to this SwcInternalBehavior object + port_data_element is a string with format '/' or + just '' which can be used in the special situation when the port interface + only has a single data element. + + #convenience-method + """ + swc = self._get_valid_parent() + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + name_parts = split_ref_strict(port_data_element) + if len(name_parts) == 1: + port_name, data_element_name = name_parts[0], None + else: + port_name, data_element_name = name_parts[0], name_parts[1] + context_port = swc.find_r_port(port_name) + if context_port is None: + raise ValueError(f"port_data_element: '{port_data_element}' does not name an existing R-PORT or PR-PORT") + target_data_element = swc.get_data_element_in_port(context_port, data_element_name) + if target_data_element is None: + msg = f"port_data_element: '{port_data_element}' does not name an existing data element in port interface" + raise ValueError(msg) + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.data_receive_error_event_prefix: + event_name = behavior_settings.data_receive_error_event_prefix + "_".join([runnable_name, + context_port.name, + target_data_element.name]) + else: + msg = "event_name: Unable to dynamically create event name,"\ + " data_receive_error_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = DataReceiveErrorEvent.make(unique_event_name, + runnable.ref(), + context_port.ref(), + target_data_element.ref(), + **kwargs) + self.append_event(event) + return event + + def create_data_received_event(self, + runnable_name: str, + data_element_ref: str, + event_name: str | None = None, + **kwargs + ) -> DataReceivedEvent: + """ + Adds a new DataReceivedEvent to this SwcInternalBehavior object + data_element_ref is a string with format '/' or + just '' which can be used in the special situation when the port interface + only has a single data element. + + #convenience-method + """ + swc = self._get_valid_parent() + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + name_parts = split_ref_strict(data_element_ref) + if len(name_parts) == 1: + port_name, data_element_name = name_parts[0], None + else: + port_name, data_element_name = name_parts[0], name_parts[1] + context_port = swc.find_r_port(port_name) + if context_port is None: + raise ValueError(f"data_element_ref: '{data_element_ref}' does not name an existing R-PORT or PR-PORT") + target_data_element = swc.get_data_element_in_port(context_port, data_element_name) + if target_data_element is None: + msg = f"data_element_ref: '{data_element_ref}' does not name an existing data element in port interface" + raise ValueError(msg) + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.data_receive_event_prefix: + event_name = behavior_settings.data_receive_event_prefix + "_".join([runnable_name, + context_port.name, + target_data_element.name]) + else: + msg = "event_name: Unable to dynamically create event name,"\ + " data_receive_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = DataReceivedEvent.make(unique_event_name, + runnable.ref(), + context_port.ref(), + target_data_element.ref(), + **kwargs) + self.append_event(event) + return event + + def create_data_send_completed_event(self, + runnable_name: str, + data_element_ref: str, + event_name: str | None = None, + **kwargs + ) -> DataSendCompletedEvent: + """ + Adds a new DataSendCompletedEvent to this SwcInternalBehavior object + data_element_ref is a string with format '/' or + just '' which can be used in the special situation when the port interface + only has a single data element. + The given runnable must have a data send point referencing the port and data element. + Note: Unable to complete implementation. Requires support for port-access in runnables. + + #convenience-method + """ + raise NotImplementedError("References to data send points are not yet supported") + + def create_data_write_completed_event(self, + runnable_name: str, + data_element_ref: str, + event_name: str | None = None, + **kwargs + ) -> DataWriteCompletedEvent: + """ + Adds a new DataWriteCompletedEvent to this SwcInternalBehavior object + data_element_ref is a string with format '/' or + just '' which can be used in the special situation when the port interface + only has a single data element. + The given runnable must have a data send point referencing the port and data element. + Note: Not implemented due to lack of support for data write access + + #convenience-method + """ + raise NotImplementedError("References to data write access are not yet supported") + + def create_init_event(self, + runnable_name: str, + event_name: str | None = None, + **kwargs + ) -> InitEvent: + """ + Adds a new InitEvent to this SwcInternalBehavior object + + #convenience-method + """ + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.init_event_prefix: + event_name = behavior_settings.init_event_prefix + runnable_name + else: + msg = "event_name: Unable to dynamically create event name,"\ + " init_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = InitEvent(unique_event_name, runnable.ref(), **kwargs) + self.append_event(event) + return event + + def create_operation_invoked_event(self, + runnable_name: str, + operation_ref: str, + event_name: str | None = None, + **kwargs + ) -> OperationInvokedEvent: + """ + Adds a new OperationInvokedEvent to this object + operation_ref is a string with format / + + #convenience-method + """ + swc = self._get_valid_parent() + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + name_parts = split_ref_strict(operation_ref) + if len(name_parts) == 1: + port_name, operation_name = name_parts[0], None + else: + port_name, operation_name = name_parts[0], name_parts[1] + context_port = swc.find_p_port(port_name) + if context_port is None: + raise ValueError(f"port_name: '{port_name}' does not name an existing P-PORT or PR-PORT") + target_provided_operation = swc.get_operation_in_port(context_port, operation_name) + if target_provided_operation is None: + raise ValueError(f"operation_ref: '{operation_ref}' does not name a valid operation in port interface") + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.operation_invoked_event_prefix: + prefix = behavior_settings.operation_invoked_event_prefix + event_name = prefix + "_".join([runnable_name, + context_port.name, + target_provided_operation.name]) + else: + msg = "event_name: Unable to dynamically create event name,"\ + " operation_invoked_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = OperationInvokedEvent.make(unique_event_name, + runnable.ref(), + context_port.ref(), + target_provided_operation.ref(), + **kwargs) + self.append_event(event) + return event + + def create_swc_mode_manager_error_event(self, + runnable_name: str, + port_name: str, + event_name: str | None = None, + **kwargs + ) -> SwcModeManagerErrorEvent: + """ + Adds a new SwcModeManagerErrorEvent to this object + + #convenience-method + """ + swc = self._get_valid_parent() + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + context_port = swc.find_p_port(port_name) + if context_port is None: + raise ValueError(f"port_name: '{port_name}' does not name an existing P-PORT or PR-PORT") + context_mode_declaration_group = swc.get_mode_declaration_group_in_port(context_port) + if context_mode_declaration_group is None: + msg = f"port_name: '{port_name}' does not name a valid ModeDeclarationGroupPrototype in port interface" + raise ValueError(msg) + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.swc_mode_manager_error_event_prefix: + prefix = behavior_settings.swc_mode_manager_error_event_prefix + event_name = prefix + "_".join([runnable_name, + context_port.name, + context_mode_declaration_group.name]) + else: + msg = "event_name: Unable to dynamically create event name,"\ + " swc_mode_manager_error_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = SwcModeManagerErrorEvent.make(unique_event_name, + runnable.ref(), + context_port.ref(), + context_mode_declaration_group.ref(), + **kwargs) + self.append_event(event) + return event + + def create_swc_mode_mode_switch_event(self, + runnable_name: str, + mode_ref: str | list[str] | tuple[str, str], + activation: ar_enum.ModeActivationKind | None = None, + event_name: str | None = None, + **kwargs + ) -> SwcModeSwitchEvent: + """ + Adds a new SwcModeSwitchEvent to this SwcInternalBehavior object. + mode_ref is a string with format '/'. + mode_ref can also be a 2-element list or a 2-tuple containing strings with same format as above. + The second version is used for creating events for specific mode transitions. + + #convenience-method + """ + swc = self._get_valid_parent() + workspace = swc.root_collection() + assert workspace is not None + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.swc_mode_switch_event_prefix: + prefix = behavior_settings.swc_mode_switch_event_prefix + event_name = prefix + runnable_name + else: + msg = "event_name: Unable to dynamically create event name,"\ + " swc_mode_switch_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + expected_formats = "Expected formats: '', '/', tuple[str, str]" + if isinstance(mode_ref, str): + if len(mode_ref) == 0: + raise ValueError("mode_ref: Invalid argument. " + expected_formats) + context_port, context_mode_declaration_group, target_mode_declaration = ( + self._get_swc_mode_switch_event_args(workspace, swc, mode_ref)) + event = SwcModeSwitchEvent.make(unique_event_name, + runnable.ref(), + activation, + context_port.ref(), + context_mode_declaration_group.ref(), + target_mode_declaration.ref(), + **kwargs) + elif isinstance(mode_ref, (list, tuple)): + if len(mode_ref) != 2: + raise ValueError("mode_ref: Must be exactly two elements in tuple or list") + instance_refs = [] + for ref in mode_ref: + if isinstance(ref, str): + if len(ref) == 0: + raise ValueError("mode_ref: Invalid argument. " + expected_formats) + context_port, context_mode_declaration_group, target_mode_declaration = ( + self._get_swc_mode_switch_event_args(workspace, swc, ref)) + instance_refs.append(RModeInAtomicSwcInstanceRef(context_port.ref(), + context_mode_declaration_group.ref(), + target_mode_declaration.ref())) + else: + raise TypeError(f"mode_ref: Invalid type '{str(type(ref))}'. " + expected_formats) + event = SwcModeSwitchEvent(unique_event_name, + runnable.ref(), + activation, + (instance_refs[0], instance_refs[1]), + **kwargs) + else: + raise TypeError(f"mode_ref: Unsupported type '{str(type(mode_ref))}'") + self.append_event(event) + return event + + def create_timing_event(self, + runnable_name: str, + period: int | float | None = None, + offset: int | float | None = None, + event_name: str | None = None, + **kwargs) -> TimingEvent: + """ + Adds a new TimingEvent to this object + + #convenience-method + """ + runnable = self.find_runnable(runnable_name) + if runnable is None: + raise KeyError(f"Found no runnable with name '{runnable_name}'") + if event_name is None: + behavior_settings = self._get_valid_behavior_settings() + if behavior_settings.timing_event_prefix: + prefix = behavior_settings.timing_event_prefix + event_name = prefix + runnable_name + else: + msg = "event_name: Unable to dynamically create event name,"\ + " timing_event_prefix is not set in behavior settings" + raise RuntimeError(msg) + assert isinstance(event_name, str) + unique_event_name = self._make_unique_event_name(event_name) + event = TimingEvent(unique_event_name, runnable.ref(), period, offset, **kwargs) + self.append_event(event) + return event + + ModeSwitchEventArgsReturnType = tuple[RequirePortPrototype, ModeDeclarationGroupPrototype, ModeDeclaration] + + def _get_swc_mode_switch_event_args(self, + workspace: PackageCollection, + swc: AtomicSoftwareComponentType, + mode_ref: str + ) -> ModeSwitchEventArgsReturnType: + """ + Helper function for create_swc_mode_switch_event + """ + name_parts = split_ref_strict(mode_ref) + if len(name_parts) != 2: + raise ValueError("mode_ref: Formatting error, expected /") + port_name, mode_declaration_name = name_parts[0], name_parts[1] + context_port = swc.find_r_port(port_name) + if context_port is None: + raise ValueError(f"mode_ref: '{mode_ref}' does not name an existing R-PORT or PR-PORT") + context_mode_declaration_group = swc.get_mode_declaration_group_in_port(context_port) + if context_mode_declaration_group is None: + msg = f"mode_ref: '{mode_ref}' does not name a valid ModeDeclarationGroupPrototype in port interface" + raise ValueError(msg) + target_mode_declaration_group: ModeDeclarationGroup | None + target_mode_declaration_group = workspace.find(context_mode_declaration_group.type_ref) + if target_mode_declaration_group is None: + raise ar_except.InvalidReferenceError(str(context_mode_declaration_group.type_ref)) + target_mode_declaration: ModeDeclaration | None = target_mode_declaration_group.find(mode_declaration_name) + if target_mode_declaration is None: + raise ValueError(f"mode_ref: '{mode_ref}' does not name a valid mode declaration in ModeDeclarationGroup") + return context_port, context_mode_declaration_group, target_mode_declaration diff --git a/src/autosar/xml/enumeration.py b/src/autosar/xml/enumeration.py index 0a49547..0ec2200 100644 --- a/src/autosar/xml/enumeration.py +++ b/src/autosar/xml/enumeration.py @@ -208,39 +208,47 @@ class IdentifiableSubTypes(Enum): APPLICATION_SW_COMPONENT_TYPE = 14 AR_PACKAGE = 15 ARGUMENT_DATA_PROTOTYPE = 16 - AUTOSAR_DATA_PROTOTYPE = 17 - AUTOSAR_DATA_TYPE = 18 - BSW_MODULE_ENTRY = 19 - CLIENT_SERVER_INTERFACE = 20 - CLIENT_SERVER_OPERATION = 21 - COMPOSITION_SW_COMPONENT_TYPE = 22 - COMPU_METHOD = 23 - CONSTANT_SPECIFICATION = 24 - DATA_CONSTR = 25 - DATA_PROTOTYPE = 26 - E2E_PROFILE_COMPATIBILITY_PROPS = 27 - IMPLEMENTATION_DATA_TYPE = 28 - IMPLEMENTATION_DATA_TYPE_ELEMENT = 29 - MODE_DECLARATION = 30 - MODE_DECLARATION_GROUP = 31 - MODE_DECLARATION_GROUP_PROTOTYPE = 32 - MODE_SWITCH_INTERFACE = 33 - NV_DATA_INTERFACE = 34 - P_PORT_PROTOTYPE = 35 - PARAMETER_INTERFACE = 36 - PARAMETER_DATA_PROTOTYPE = 37 - PHYSICAL_DIMENSION = 38 - PORT_PROTOTYPE = 39 - PR_PORT_PROTOTYPE = 40 - R_PORT_PROTOTYPE = 41 - SENDER_RECEIVER_INTERFACE = 42 - SW_ADDR_METHOD = 43 - SW_BASE_TYPE = 44 - SW_COMPONENT_PROTOTYPE = 45 - SWC_IMPLEMENTATION = 46 - SWC_INTERNAL_BEHAVIOR = 47 - UNIT = 48 - VARIABLE_DATA_PROTOTYPE = 49 + ASYNCHRONOUS_SERVER_CALL_RESULT_POINT = 17 + AUTOSAR_DATA_PROTOTYPE = 18 + AUTOSAR_DATA_TYPE = 19 + BSW_MODULE_ENTRY = 20 + CLIENT_SERVER_INTERFACE = 21 + CLIENT_SERVER_OPERATION = 22 + COMPOSITION_SW_COMPONENT_TYPE = 23 + COMPU_METHOD = 24 + CONSTANT_SPECIFICATION = 25 + DATA_CONSTR = 26 + DATA_PROTOTYPE = 27 + E2E_PROFILE_COMPATIBILITY_PROPS = 28 + EXCLUSIVE_AREA = 29 + EXCLUSIVE_AREA_NESTING_ORDER = 30 + IMPLEMENTATION_DATA_TYPE = 31 + IMPLEMENTATION_DATA_TYPE_ELEMENT = 32 + INTERNAL_TRIGGERING_POINT = 33 + MODE_DECLARATION = 34 + MODE_DECLARATION_GROUP = 35 + MODE_DECLARATION_GROUP_PROTOTYPE = 36 + MODE_SWITCH_INTERFACE = 37 + MODE_SWITCH_POINT = 38 + NV_DATA_INTERFACE = 39 + P_PORT_PROTOTYPE = 40 + PARAMETER_INTERFACE = 41 + PARAMETER_DATA_PROTOTYPE = 42 + PHYSICAL_DIMENSION = 43 + PORT_PROTOTYPE = 44 + PR_PORT_PROTOTYPE = 45 + R_PORT_PROTOTYPE = 46 + RUNNABLE_ENTITY = 47 + SENDER_RECEIVER_INTERFACE = 48 + SW_ADDR_METHOD = 49 + SW_BASE_TYPE = 50 + SW_COMPONENT_PROTOTYPE = 51 + SWC_IMPLEMENTATION = 52 + SWC_INTERNAL_BEHAVIOR = 53 + TRIGGER = 54 + UNIT = 55 + VARIABLE_ACCESS = 56 + VARIABLE_DATA_PROTOTYPE = 57 class IntervalType(Enum): @@ -407,6 +415,16 @@ class Language(Enum): ZU = 136 # Zulu +class ModeActivationKind(Enum): + """ + AR:MODE-ACTIVATION-KIND--SIMPLE + """ + + ON_ENTRY = 0 + ON_EXIT = 1 + ON_TRANSITION = 2 + + class ModeErrorReactionPolicy(Enum): """ AR:MODE-ERROR-REACTION-POLICY-ENUM--SIMPLE @@ -465,6 +483,16 @@ class PageWide(Enum): PGWIDE = 1 +class ReentrancyLevel(Enum): + """ + AR:REENTRANCY-LEVEL-ENUM--SIMPLE + """ + + MULTICORE_REENTRANT = 0 + NON_REENTRANT = 1 + SINGLE_CORE_REENTRANT = 2 + + class ScaleConstraintValidity(Enum): """ AR:SCALE-CONSTR-VALIDITY-ENUM--SIMPLE @@ -708,8 +736,9 @@ class VersionedTextValue: "APPLICATION-RECORD-DATA-TYPE": IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE, "APPLICATION-RECORD-ELEMENT": IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT, "APPLICATION-SW-COMPONENT-TYPE": IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE, - "AR-PACKAGE": IdentifiableSubTypes.AR_PACKAGE, "ARGUMENT-DATA-PROTOTYPE": IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE, + "AR-PACKAGE": IdentifiableSubTypes.AR_PACKAGE, + "ASYNCHRONOUS-SERVER-CALL-RESULT-POINT": IdentifiableSubTypes.ASYNCHRONOUS_SERVER_CALL_RESULT_POINT, "AUTOSAR-DATA-PROTOTYPE": IdentifiableSubTypes.AUTOSAR_DATA_PROTOTYPE, "AUTOSAR-DATA-TYPE": IdentifiableSubTypes.AUTOSAR_DATA_TYPE, "BSW-MODULE-ENTRY": IdentifiableSubTypes.BSW_MODULE_ENTRY, @@ -720,12 +749,16 @@ class VersionedTextValue: "CONSTANT-SPECIFICATION": IdentifiableSubTypes.CONSTANT_SPECIFICATION, "DATA-CONSTR": IdentifiableSubTypes.DATA_CONSTR, "E-2-E-PROFILE-COMPATIBILITY-PROPS": IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS, + "EXCLUSIVE-AREA": IdentifiableSubTypes.EXCLUSIVE_AREA, + "EXCLUSIVE-AREA-NESTING-ORDER": IdentifiableSubTypes.EXCLUSIVE_AREA_NESTING_ORDER, "IMPLEMENTATION-DATA-TYPE": IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE, "IMPLEMENTATION-DATA-TYPE-ELEMENT": IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE_ELEMENT, + "INTERNAL-TRIGGERING-POINT": IdentifiableSubTypes.INTERNAL_TRIGGERING_POINT, "MODE-DECLARATION": IdentifiableSubTypes.MODE_DECLARATION, "MODE-DECLARATION-GROUP": IdentifiableSubTypes.MODE_DECLARATION_GROUP, "MODE-DECLARATION-GROUP-PROTOTYPE": IdentifiableSubTypes.MODE_DECLARATION_GROUP_PROTOTYPE, "MODE-SWITCH-INTERFACE": IdentifiableSubTypes.MODE_SWITCH_INTERFACE, + "MODE-SWITCH-POINT": IdentifiableSubTypes.MODE_SWITCH_POINT, "NV-DATA-INTERFACE": IdentifiableSubTypes.NV_DATA_INTERFACE, "P-PORT-PROTOTYPE": IdentifiableSubTypes.P_PORT_PROTOTYPE, "PARAMETER-DATA-PROTOTYPE": IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE, @@ -734,13 +767,16 @@ class VersionedTextValue: "PORT-PROTOTYPE": IdentifiableSubTypes.PORT_PROTOTYPE, "PR-PORT-PROTOTYPE": IdentifiableSubTypes.PR_PORT_PROTOTYPE, "R-PORT-PROTOTYPE": IdentifiableSubTypes.R_PORT_PROTOTYPE, + "RUNNABLE-ENTITY": IdentifiableSubTypes.RUNNABLE_ENTITY, "SENDER-RECEIVER-INTERFACE": IdentifiableSubTypes.SENDER_RECEIVER_INTERFACE, "SW-ADDR-METHOD": IdentifiableSubTypes.SW_ADDR_METHOD, "SW-BASE-TYPE": IdentifiableSubTypes.SW_BASE_TYPE, "SW-COMPONENT-PROTOTYPE": IdentifiableSubTypes.SW_COMPONENT_PROTOTYPE, "SWC-IMPLEMENTATION": IdentifiableSubTypes.SWC_IMPLEMENTATION, "SWC-INTERNAL-BEHAVIOR": IdentifiableSubTypes.SWC_INTERNAL_BEHAVIOR, + "TRIGGER": IdentifiableSubTypes.TRIGGER, "UNIT": IdentifiableSubTypes.UNIT, + "VARIABLE-ACCESS": IdentifiableSubTypes.VARIABLE_ACCESS, "VARIABLE-DATA-PROTOTYPE": IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE, }, "IntervalType": { @@ -890,6 +926,11 @@ class VersionedTextValue: "ZH": Language.ZH, "ZU": Language.ZU, }, + "ModeActivationKind": { + "ON-ENTRY": ModeActivationKind.ON_ENTRY, + "ON-EXIT": ModeActivationKind.ON_EXIT, + "ON-TRANSITION": ModeActivationKind.ON_TRANSITION, + }, "ModeErrorReactionPolicy": { "DEFAULT-MODE": ModeErrorReactionPolicy.DEFAULT_MODE, "LAST-MODE": ModeErrorReactionPolicy.LAST_MODE @@ -911,6 +952,11 @@ class VersionedTextValue: "NO-PGWIDE": PageWide.NO_PGWIDE, "PGWIDE": PageWide.PGWIDE, }, + "ReentrancyLevel": { + "MULTICORE-REENTRANT": ReentrancyLevel.MULTICORE_REENTRANT, + "NON-REENTRANT": ReentrancyLevel.NON_REENTRANT, + "SINGLE-CORE-REENTRANT": ReentrancyLevel.SINGLE_CORE_REENTRANT + }, "ScaleConstraintValidity": { "NOT-AVAILABLE": ScaleConstraintValidity.NOT_AVAILABLE, "NOT-DEFINED": ScaleConstraintValidity.NOT_DEFINED, @@ -1066,39 +1112,47 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas "APPLICATION-SW-COMPONENT-TYPE", # 14 "ARGUMENT-DATA-PROTOTYPE", # 15 "AR-PACKAGE", # 16 - "AUTOSAR-DATA-PROTOTYPE", # 17 - "AUTOSAR-DATA-TYPE", # 18 - "BSW-MODULE-ENTRY", # 19 - "CLIENT-SERVER-INTERFACE", # 20 - "CLIENT-SERVER-OPERATION", # 21 - "COMPOSITION-SW-COMPONENT-TYPE", # 22 - "COMPU-METHOD", # 23 - "CONSTANT-SPECIFICATION", # 24 - "DATA-CONSTR", # 25 - "DATA-PROTOTYPE", # 26 - "E-2-E-PROFILE-COMPATIBILITY-PROPS", # 27 - "IMPLEMENTATION-DATA-TYPE", # 28 - "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 29 - "MODE-DECLARATION", # 30 - "MODE-DECLARATION-GROUP", # 31 - "MODE-DECLARATION-GROUP-PROTOTYPE", # 32 - "MODE-SWITCH-INTERFACE", # 33 - "NV-DATA-INTERFACE", # 34 - "P-PORT-PROTOTYPE", # 35 - "PARAMETER-INTERFACE", # 36 - "PARAMETER-DATA-PROTOTYPE", # 37 - "PHYSICAL-DIMENSION", # 38 - "PORT-PROTOTYPE", # 39 - "PR-PORT-PROTOTYPE", # 40 - "R-PORT-PROTOTYPE", # 41 - "SENDER-RECEIVER-INTERFACE", # 42 - "SW-ADDR-METHOD", # 43 - "SW-BASE-TYPE", # 44 - "SW-COMPONENT-PROTOTYPE", # 45 - "SWC-IMPLEMENTATION", # 46 - "SWC-INTERNAL-BEHAVIOR", # 47 - "UNIT", # 48 - "VARIABLE-DATA-PROTOTYPE", # 49 + "ASYNCHRONOUS-SERVER-CALL-RESULT-POINT", # 17 + "AUTOSAR-DATA-PROTOTYPE", # 18 + "AUTOSAR-DATA-TYPE", # 19 + "BSW-MODULE-ENTRY", # 20 + "CLIENT-SERVER-INTERFACE", # 21 + "CLIENT-SERVER-OPERATION", # 22 + "COMPOSITION-SW-COMPONENT-TYPE", # 23 + "COMPU-METHOD", # 24 + "CONSTANT-SPECIFICATION", # 25 + "DATA-CONSTR", # 26 + "DATA-PROTOTYPE", # 27 + "E-2-E-PROFILE-COMPATIBILITY-PROPS", # 28 + "EXCLUSIVE-AREA", # 29 + "EXCLUSIVE-AREA-NESTING-ORDER", # 30 + "IMPLEMENTATION-DATA-TYPE", # 31 + "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 32 + "INTERNAL-TRIGGERING-POINT", # 33 + "MODE-DECLARATION", # 34 + "MODE-DECLARATION-GROUP", # 35 + "MODE-DECLARATION-GROUP-PROTOTYPE", # 36 + "MODE-SWITCH-INTERFACE", # 37 + "MODE-SWITCH-POINT", # 38 + "NV-DATA-INTERFACE", # 39 + "P-PORT-PROTOTYPE", # 40 + "PARAMETER-INTERFACE", # 41 + "PARAMETER-DATA-PROTOTYPE", # 42 + "PHYSICAL-DIMENSION", # 43 + "PORT-PROTOTYPE", # 44 + "PR-PORT-PROTOTYPE", # 45 + "R-PORT-PROTOTYPE", # 46 + "RUNNABLE-ENTITY", # 47 + "SENDER-RECEIVER-INTERFACE", # 48 + "SW-ADDR-METHOD", # 49 + "SW-BASE-TYPE", # 50 + "SW-COMPONENT-PROTOTYPE", # 51 + "SWC-IMPLEMENTATION", # 52 + "SWC-INTERNAL-BEHAVIOR", # 53 + "TRIGGER", # 54 + "UNIT", # 55 + "VARIABLE-ACCESS", # 56 + "VARIABLE-DATA-PROTOTYPE", # 57 ], "IntervalType": [ "CLOSED", # 0 @@ -1247,6 +1301,11 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas "ZH", # 135 "ZU", # 136 ], + "ModeActivationKind": [ + "ON-ENTRY", # 0 + "ON-EXIT", # 1 + "ON-TRANSITION", # 2 + ], "ModeErrorReactionPolicy": [ "DEFAULT-MODE", # 0 "LAST-MODE" # 1 @@ -1268,6 +1327,11 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas "NO-PGWIDE", # 0 "PGWIDE", # 1 ], + "ReentrancyLevel": [ + "MULTICORE-REENTRANT", # 0 + "NON-REENTRANT", # 1 + "SINGLE-CORE-REENTRANT" # 2 + ], "ScaleConstraintValidity": [ "NOT-AVAILABLE", # 0 "NOT-DEFINED", # 1 diff --git a/src/autosar/xml/exception.py b/src/autosar/xml/exception.py index 9fee3f2..e7c931b 100644 --- a/src/autosar/xml/exception.py +++ b/src/autosar/xml/exception.py @@ -35,3 +35,9 @@ def __init__(self, name: str, expected_types: str | list[str] | tuple[str], valu expected = ", ".join(expected_types) msg = f"{name}: Invalid type. Expected one of ({expected}), got '{str(type(value))}'" super().__init__(msg) + + +class InvalidReferenceError(ValueError): + """ + Reference is invalid + """ diff --git a/src/autosar/xml/reader.py b/src/autosar/xml/reader.py index 0b23fcd..09d7332 100644 --- a/src/autosar/xml/reader.py +++ b/src/autosar/xml/reader.py @@ -29,6 +29,22 @@ ar_element.ModeSwitchReceiverComSpec, ar_element.ClientComSpec] +RteEventElement = Union[ar_element.AsynchronousServerCallReturnsEvent, + ar_element.BackgroundEvent, + ar_element.DataReceivedEvent, + ar_element.DataReceiveErrorEvent, + ar_element.DataSendCompletedEvent, + ar_element.DataWriteCompletedEvent, + ar_element.ExternalTriggerOccurredEvent, + ar_element.InitEvent, + ar_element.InternalTriggerOccurredEvent, + ar_element.ModeSwitchedAckEvent, + ar_element.OperationInvokedEvent, + ar_element.SwcModeManagerErrorEvent, + ar_element.SwcModeSwitchEvent, + ar_element.TimingEvent, + ar_element.TransformerHardErrorEvent] + # Helper classes @@ -185,6 +201,23 @@ def __init__(self, 'MODE-SWITCH-RECEIVER-COM-SPEC': self._read_mode_switch_receiver_com_spec, 'CLIENT-COM-SPEC': self._read_client_com_spec, } + self.switcher_rte_event = { + 'ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT': self._read_async_server_call_returns_event, + 'BACKGROUND-EVENT': self._read_background_event, + 'DATA-RECEIVE-ERROR-EVENT': self._read_data_receive_error_event, + 'DATA-RECEIVED-EVENT': self._read_data_received_event, + 'DATA-SEND-COMPLETED-EVENT': self._read_data_send_completed_event, + 'DATA-WRITE-COMPLETED-EVENT': self._read_data_write_completed_event, + 'EXTERNAL-TRIGGER-OCCURRED-EVENT': self._read_external_trigger_occured_event, + 'INIT-EVENT': self._read_init_event, + 'INTERNAL-TRIGGER-OCCURRED-EVENT': self._read_internal_trigger_occured_event, + 'MODE-SWITCHED-ACK-EVENT': self._read_mode_switched_ack_event, + 'OPERATION-INVOKED-EVENT': self._read_operation_invoked_event, + 'SWC-MODE-MANAGER-ERROR-EVENT': self._read_swc_mode_manager_error_event, + 'SWC-MODE-SWITCH-EVENT': self._read_swc_mode_switch_event, + 'TIMING-EVENT': self._read_timing_event, + 'TRANSFORMER-HARD-ERROR-EVENT': self._read_transformer_hard_error_event, + } self.switcher_non_collectable = { # Non-collectable, used only for unit testing # Documentation elements 'ANNOTATION': self._read_annotation, @@ -264,7 +297,26 @@ def __init__(self, 'AUTOSAR-VARIABLE-IREF': self._read_variable_in_atomic_swc_type_instance_ref, 'ACCESSED-VARIABLE': self._read_autosar_variable_ref, 'VARIABLE-ACCESS': self._read_variable_access, + 'EXECUTABLE-ENTITY-ACTIVATION-REASON': self._read_executable_entity_activation_reason, + 'EXCLUSIVE-AREA-REF-CONDITIONAL': self._read_exclusive_area_ref_conditional, + 'DISABLED-MODE-IREF': self._read_r_mode_in_atomic_swc_instance_ref, 'SWC-INTERNAL-BEHAVIOR': self._read_swc_internal_behavior, + 'RUNNABLE-ENTITY': self._read_runnable_entity, + 'ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT': self._read_async_server_call_returns_event, + 'BACKGROUND-EVENT': self._read_background_event, + 'DATA-RECEIVE-ERROR-EVENT': self._read_data_receive_error_event, + 'DATA-RECEIVED-EVENT': self._read_data_received_event, + 'DATA-SEND-COMPLETED-EVENT': self._read_data_send_completed_event, + 'DATA-WRITE-COMPLETED-EVENT': self._read_data_write_completed_event, + 'EXTERNAL-TRIGGER-OCCURRED-EVENT': self._read_external_trigger_occured_event, + 'INIT-EVENT': self._read_init_event, + 'INTERNAL-TRIGGER-OCCURRED-EVENT': self._read_internal_trigger_occured_event, + 'MODE-SWITCHED-ACK-EVENT': self._read_mode_switched_ack_event, + 'OPERATION-INVOKED-EVENT': self._read_operation_invoked_event, + 'SWC-MODE-MANAGER-ERROR-EVENT': self._read_swc_mode_manager_error_event, + 'SWC-MODE-SWITCH-EVENT': self._read_swc_mode_switch_event, + 'TIMING-EVENT': self._read_timing_event, + 'TRANSFORMER-HARD-ERROR-EVENT': self._read_transformer_hard_error_event, } self.switcher_all = {} self.switcher_all.update(self.switcher_collectable) @@ -324,7 +376,7 @@ def read_str_elem(self, xml: str, type_name: str | None = None) -> None | ar_ele else: raise NotImplementedError(f"Found no reader for '{elem.tag}'") - # Utility methods + # --- Utility methods def _report_unprocessed_elements(self, xml_elements: ChildElementMap): """ @@ -405,7 +457,7 @@ def _read_integer(self, text: str) -> int: raise ar_exception.ParseError(f"Failed to parse integer: {text}") from exc return value - # Abstract base classes + # --- Abstract base classes def _read_referrable(self, element_map: ChildElementMap, data: dict) -> None: """ @@ -507,7 +559,7 @@ def _read_admin_data_sd(self, xml_element: ElementTree.Element) -> dict[str, str value = xml_element.text return {key: value} - # AUTOSAR Document + # --- AUTOSAR Document def _read_root_element(self) -> None: self._read_schema_version() @@ -613,7 +665,7 @@ def _read_sub_packages(self, package: ar_element.Package, xml_packages: ElementT assert isinstance(child_package, ar_element.Package) package.append(child_package) - # Documentation elements + # --- Documentation elements def _read_annotation(self, xml_elem: ElementTree.Element) -> ar_element.Annotation: """ @@ -1240,7 +1292,7 @@ def _read_compu_numerator_denominator_values(self, xml_element: ElementTree.Elem values.append(num_val.value) return tuple(values) - # Constraint elements + # --- Constraint elements def _read_data_constraint(self, xml_element: ElementTree.Element) -> ar_element.DataConstraint: """ @@ -1380,7 +1432,7 @@ def _read_scale_constraint(self, xml_element: ElementTree.Element) -> ar_element data["upper_limit_type"] = interval_type return ar_element.ScaleConstraint(**data) - # Unit elements + # --- Unit elements def _read_unit(self, xml_element: ElementTree.Element) -> ar_element.Unit: """ @@ -1415,7 +1467,7 @@ def _read_unit_group(self, child_elements: ChildElementMap, data: dict) -> None: if xml_child is not None: data["physical_dimension_ref"] = self._read_physical_dimension_ref(xml_child) - # Common structure elements + # --- Common structure elements def _read_data_filter(self, xml_element: ElementTree.Element) -> ar_element.DataFilter: """ @@ -1515,7 +1567,7 @@ def _read_implementation(self, child_elements: ChildElementMap, data: dict) -> N child_elements.skip("USED-CODE-GENERATOR") child_elements.skip("VENDOR-ID") - # Data type elements + # --- Data type elements def _read_sw_addr_method(self, xml_element: ElementTree.Element) -> ar_element.SwAddrMethod: """ @@ -1657,8 +1709,7 @@ def _read_sw_data_def_props_content(self, child_elements: ChildElementMap, data: data['annotations'] = self._read_annotations(xml_child) xml_child = child_elements.get('SW-ADDR-METHOD-REF') if xml_child is not None: - data['sw_addr_method_ref'] = self._read_sw_addr_method_ref( - xml_child) + data['sw_addr_method_ref'] = self._read_sw_addr_method_ref(xml_child) xml_child = child_elements.get('SW-ALIGNMENT') if xml_child is not None: try: @@ -2198,7 +2249,7 @@ def _read_argument_data_prototype_group(self, child_elements: ChildElementMap, d child_elements.skip("TYPE-BLUEPRINTS") # Not supported child_elements.skip("VARIATION-POINT") # Not supported -# --- Reference elements + # --- Reference elements def _read_base_ref_attributes(self, attr: dict, data: dict) -> None: """ @@ -2208,13 +2259,15 @@ def _read_base_ref_attributes(self, attr: dict, data: dict) -> None: if data['dest'] is None: raise ar_exception.ParseError("Missing required attribute 'DEST'") + def _read_ref_dest(self, xml_elem: ElementTree.Element) -> ar_enum.IdentifiableSubTypes: + data = {} + self._read_base_ref_attributes(xml_elem.attrib, data) + return ar_enum.xml_to_enum('IdentifiableSubTypes', data['dest'], self.schema_version) + def _read_compu_method_ref(self, xml_elem: ElementTree.Element) -> ar_element.CompuMethodRef: """ Reads AR:COMPU-METHOD-REF - Type: Concrete Tag Variants: 'COMPU-METHOD-REF' - - Note: the name of this complex type is anonymous in the XML achema """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2527,7 +2580,7 @@ def _read_data_prototype_ref(self, xml_elem: ElementTree.Element ) -> ar_element.DataPrototypeRef: """ - Reads references to References to DATA-PROTOTYPE--SUBTYPES-ENUM + Reads references to DATA-PROTOTYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2538,7 +2591,7 @@ def _read_port_interface_ref(self, xml_elem: ElementTree.Element ) -> ar_element.PortInterfaceRef: """ - Reads references to References to PORT-INTERFACE--SUBTYPES-ENUM + Reads references to PORT-INTERFACE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2549,7 +2602,7 @@ def _read_sw_component_type_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwComponentTypeRef: """ - Reads references to References to SW-COMPONENT-TYPE--SUBTYPES-ENUM + Reads references to SW-COMPONENT-TYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2560,7 +2613,7 @@ def _read_sw_component_prototype_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwComponentPrototypeRef: """ - Reads reference to references to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM + Reads reference to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2573,7 +2626,7 @@ def _read_swc_internal_behavior_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwcInternalBehaviorRef: """ - Reads reference to references to SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM + Reads reference to SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2582,7 +2635,108 @@ def _read_swc_internal_behavior_ref(self, raise ar_exception.ParseError(msg) return ar_element.SwcInternalBehaviorRef(xml_elem.text) -# --- Constant and value specifications + def _read_exclusive_area_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.ExclusiveAreaRef: + """ + Reads references to AR:EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + data = {} + self._read_base_ref_attributes(xml_elem.attrib, data) + dest_enum = ar_enum.xml_to_enum('IdentifiableSubTypes', data['dest'], self.schema_version) + return ar_element.ExclusiveAreaRef(xml_elem.text, dest_enum) + + def _read_exclusive_area_nesting_order_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.ExclusiveAreaNestingOrderRef: + """ + Reads references to AR:EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + data = {} + self._read_base_ref_attributes(xml_elem.attrib, data) + dest_enum = ar_enum.xml_to_enum('IdentifiableSubTypes', data['dest'], self.schema_version) + return ar_element.ExclusiveAreaNestingOrderRef(xml_elem.text, dest_enum) + + def _read_abstract_required_port_prototype_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.AbstractRequiredPortPrototypeRef: + """ + Reads references to AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE--SUBTYPES-ENUM + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.AbstractRequiredPortPrototypeRef(xml_elem.text, dest_enum) + + def _read_abstract_provided_port_prototype_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.AbstractProvidedPortPrototypeRef: + """ + Reads references to AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE--SUBTYPES-ENUM + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.AbstractProvidedPortPrototypeRef(xml_elem.text, dest_enum) + + def _read_runnable_entity_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.RunnableEntityRef: + """ + Reads references to RUNNABLE-ENTITY--SUBTYPES-ENUM + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.RunnableEntityRef(xml_elem.text, dest_enum) + + def _read_variable_access_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.VariableAccessRef: + """ + Reads references to AR:VARIABLE-ACCESS--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' | 'VARIABLE-ACCESS-REF' | 'TARGET-VARIABLE-ACCESS-REF' + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.VariableAccessRef(xml_elem.text, dest_enum) + + def _read_mode_switch_point_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.TriggerRef: + """ + Reads references to AR:MODE-SWITCH-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.ModeSwitchPointRef(xml_elem.text, dest_enum) + + def _read_async_server_call_result_point_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.AsynchronousServerCallResultPointRef: + """ + Reads references to AR:ASYNCHRONOUS-SERVER-CALL-RESULT-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.AsynchronousServerCallResultPointRef(xml_elem.text, dest_enum) + + def _read_trigger_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.TriggerRef: + """ + Reads references to AR:TRIGGER--SUBTYPES-ENUM + Tag variants: 'TRIGGER-REF' | 'RELEASED-TRIGGER-REF' | 'MASTERED-TRIGGER-REF' | + 'TARGET-TRIGGER-REF' | 'SOURCE-TRIGGER-REF' | 'BSW-TRIGGER-REF' | + 'FIRST-TRIGGER-REF' | 'SECOND-TRIGGER-REF' + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.TriggerRef(xml_elem.text, dest_enum) + + def _read_internal_triggering_point_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.InternalTriggeringPointRef: + """ + Reads references to AR:INTERNAL-TRIGGERING-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + dest_enum = self._read_ref_dest(xml_elem) + return ar_element.InternalTriggeringPointRef(xml_elem.text, dest_enum) + + # --- Constant and value specifications def _read_text_value_specification(self, xml_element: ElementTree.Element) -> ar_element.TextValueSpecification: @@ -4228,6 +4382,120 @@ def _read_swc_implementation_group(self, child_elements: ChildElementMap, data: if xml_child is not None: data["required_rte_vendor"] = xml_child.text + def _read_p_mode_group_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.PModeGroupInAtomicSwcInstanceRef: + """ + Reads complex type AR:P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF' | 'MODE-GROUP-IREF' | + 'SWC-MODE-GROUP-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-P-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_provided_port_prototype_ref(xml_child) + xml_child = child_elements.get("CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF") + if xml_child is not None: + child_element = self._read_mode_declaration_group_prototype_ref(xml_child) + data["context_mode_declaration_group_prototype"] = child_element + return ar_element.PModeGroupInAtomicSwcInstanceRef(**data) + + def _read_p_operation_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.POperationInAtomicSwcInstanceRef: + """ + Complex type AR:P-OPERATION-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'OPERATION-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-P-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_provided_port_prototype_ref(xml_child) + xml_child = child_elements.get("TARGET-PROVIDED-OPERATION-REF") + if xml_child is not None: + data["target_provided_operation"] = self._read_client_server_operation_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.POperationInAtomicSwcInstanceRef(**data) + + def _read_p_trigger_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.PTriggerInAtomicSwcTypeInstanceRef: + """ + Reads complex type AR:P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF + Tag variants: 'P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF' | 'SWC-TRIGGER-IREF' | + 'TRIGGER-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-P-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_provided_port_prototype_ref(xml_child) + xml_child = child_elements.get("TARGET-TRIGGER-REF") + if xml_child is not None: + data["target_trigger"] = self._read_trigger_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.PTriggerInAtomicSwcTypeInstanceRef(**data) + + def _read_r_mode_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.RModeInAtomicSwcInstanceRef: + """ + Reads complex type AR:R-MODE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DISABLED-MODE-IREF' | 'MODE-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_required_port_prototype_ref(xml_child) + xml_child = child_elements.get("CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF") + if xml_child is not None: + child_element = self._read_mode_declaration_group_prototype_ref(xml_child) + data["context_mode_declaration_group_prototype"] = child_element + xml_child = child_elements.get("TARGET-MODE-DECLARATION-REF") + if xml_child is not None: + data["target_mode_declaration"] = self._read_mode_declaration_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.RModeInAtomicSwcInstanceRef(**data) + + def _read_r_variable_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.RVariableInAtomicSwcInstanceRef: + """ + Reads complex type AR:R-VARIABLE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DATA-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-R-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_required_port_prototype_ref(xml_child) + xml_child = child_elements.get("TARGET-DATA-ELEMENT-REF") + if xml_child is not None: + data["target_data_element"] = self._read_variable_data_prototype_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.RVariableInAtomicSwcInstanceRef(**data) + + def _read_r_trigger_in_atomic_swc_instance_ref(self, + xml_element: ElementTree.Element + ) -> ar_element.RTriggerInAtomicSwcInstanceRef: + """ + Reads complex type AR:R-TRIGGER-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'TRIGGER-IREF' | 'REQUIRED-TRIGGER-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("CONTEXT-R-PORT-REF") + if xml_child is not None: + data["context_port"] = self._read_abstract_required_port_prototype_ref(xml_child) + xml_child = child_elements.get("TARGET-TRIGGER-REF") + if xml_child is not None: + data["target_trigger"] = self._read_trigger_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.RTriggerInAtomicSwcInstanceRef(**data) + # --- Internal Behavior elements def _read_variable_in_impl_data_instance_ref(self, @@ -4345,6 +4613,467 @@ def _read_autosar_variable_ref_group(self, child_elements: ChildElementMap, data if xml_child is not None: data["local_variable_ref"] = self._read_variable_data_prototype_ref(xml_child) + def _read_executable_entity_activation_reason(self, + xml_element: ElementTree.Element + ) -> ar_element.ExecutableEntityActivationReason: + """ + Reads complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_implementation_props(child_elements, data) + xml_child = child_elements.get("BIT-POSITION") + if xml_child is not None: + data["bit_position"] = ar_element.PositiveIntegerValue(xml_child.text).value + self._report_unprocessed_elements(child_elements) + return ar_element.ExecutableEntityActivationReason(**data) + + def _read_exclusive_area_ref_conditional(self, + xml_element: ElementTree.Element + ) -> ar_element.ExclusiveAreaRefConditional: + """ + Reads complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("EXCLUSIVE-AREA-REF") + if xml_child is not None: + data["exclusive_area_ref"] = self._read_exclusive_area_ref(xml_child) + child_elements.skip("VARIATION-POINT") # Not supported + self._report_unprocessed_elements(child_elements) + return ar_element.ExclusiveAreaRefConditional(**data) + + def _read_executable_entity(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:EXECUTABLE-ENTITY + """ + xml_child = child_elements.get("ACTIVATION-REASONS") + if xml_child is not None: + activation_reasons = [] + for xml_grand_child in xml_child.findall("./EXECUTABLE-ENTITY-ACTIVATION-REASON"): + activation_reasons.append(self._read_executable_entity_activation_reason(xml_grand_child)) + data["activation_reasons"] = activation_reasons + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + xml_child = child_elements.get("CAN-ENTER-EXCLUSIVE-AREA-REFS") + if xml_child is not None: + can_enter_leave = [] + for xml_grand_child in xml_child.findall("./CAN-ENTER-EXCLUSIVE-AREA-REF"): + # The class constructor will automatically upgrade these references to + # ExclusiveAreaRefConditional elements. + can_enter_leave.append(self._read_exclusive_area_ref(xml_grand_child)) + data["can_enter_leave"] = can_enter_leave + else: + xml_child = child_elements.get("CAN-ENTERS") + if xml_child is not None: + can_enter_leave = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-REF-CONDITIONAL"): + can_enter_leave.append(self._read_exclusive_area_ref_conditional(xml_grand_child)) + data["can_enter_leave"] = can_enter_leave + xml_child = child_elements.get("EXCLUSIVE-AREA-NESTING-ORDER-REFS") + if xml_child is not None: + exclusive_area_nesting_order = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-NESTING-ORDER-REF"): + exclusive_area_nesting_order.append(self._read_exclusive_area_nesting_order_ref(xml_grand_child)) + data["exclusive_area_nesting_order"] = exclusive_area_nesting_order + xml_child = child_elements.get("MINIMUM-START-INTERVAL") + if xml_child is not None: + data["minimum_start_interval"] = self._read_number(xml_child.text) + xml_child = child_elements.get("REENTRANCY-LEVEL") + if xml_child is not None: + data["reentrancy_level"] = ar_enum.xml_to_enum("ReentrancyLevel", xml_child.text) + if self.schema_version < 50: + xml_child = child_elements.get("RUNS-INSIDE-EXCLUSIVE-AREA-REFS") + if xml_child is not None: + runs_insides = [] + for xml_grand_child in xml_child.findall("./RUNS-INSIDE-EXCLUSIVE-AREA-REF"): + # The class constructor will automatically upgrade these references to + # ExclusiveAreaRefConditional elements. + runs_insides.append(self._read_exclusive_area_ref(xml_grand_child)) + data["runs_insides"] = runs_insides + else: + xml_child = child_elements.get("RUNS-INSIDES") + if xml_child is not None: + runs_insides = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-REF-CONDITIONAL"): + runs_insides.append(self._read_exclusive_area_ref_conditional(xml_grand_child)) + data["runs_insides"] = runs_insides + xml_child = child_elements.get('SW-ADDR-METHOD-REF') + if xml_child is not None: + data['sw_addr_method'] = self._read_sw_addr_method_ref(xml_child) + + def _read_runnable_entity(self, xml_element: ElementTree.Element) -> ar_element.RunnableEntity: + """ + Reads complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_executable_entity(child_elements, data) + self._read_runnable_entity_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.RunnableEntity(**data) + + def _read_runnable_entity_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:RUNNABLE-ENTITY + These elements will be implemented in the next releae + """ + child_elements.skip("ARGUMENTS") + child_elements.skip("ASYNCHRONOUS-SERVER-CALL-RESULT-POINTS") + child_elements.skip("CAN-BE-INVOKED-CONCURRENTLY") + child_elements.skip("DATA-READ-ACCESSS") + child_elements.skip("DATA-RECEIVE-POINT-BY-ARGUMENTS") + child_elements.skip("DATA-RECEIVE-POINT-BY-VALUES") + child_elements.skip("DATA-SEND-POINTS") + child_elements.skip("DATA-WRITE-ACCESSS") + child_elements.skip("EXTERNAL-TRIGGERING-POINTS") + child_elements.skip("INTERNAL-TRIGGERING-POINTS") + child_elements.skip("MODE-ACCESS-POINTS") + child_elements.skip("MODE-SWITCH-POINTS") + child_elements.skip("PARAMETER-ACCESSS") + child_elements.skip("READ-LOCAL-VARIABLES") + child_elements.skip("SERVER-CALL-POINTS") + child_elements.skip("SYMBOL") + child_elements.skip("WAIT-POINTS") + child_elements.skip("WRITTEN-LOCAL-VARIABLES") + child_elements.skip("VARIATION-POINT") + + def _read_rte_event_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:RTE-EVENT + """ + xml_child = child_elements.get("DISABLED-MODE-IREFS") + if xml_child is not None: + disabled_modes = [] + for xml_grand_child in xml_child.findall("./DISABLED-MODE-IREF"): + disabled_modes.append(self._read_r_mode_in_atomic_swc_instance_ref(xml_grand_child)) + data["disabled_modes"] = disabled_modes + xml_child = child_elements.get("START-ON-EVENT-REF") + if xml_child is not None: + data["start_on_event"] = self._read_runnable_entity_ref(xml_child) + child_elements.skip("VARIATION-POINT") # Not supported + + def _read_async_server_call_returns_event(self, + xml_element: ElementTree.Element + ) -> ar_element.AsynchronousServerCallReturnsEvent: + """ + Reads complex type AR:ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT + Tag variants: 'ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("EVENT-SOURCE-REF") + if xml_child is not None: + data["event_source"] = self._read_async_server_call_result_point_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.AsynchronousServerCallReturnsEvent(**data) + + def _read_background_event(self, + xml_element: ElementTree.Element + ) -> ar_element.BackgroundEvent: + """ + Reads complex Type AR:BACKGROUND-EVENT + Tag variants: 'BACKGROUND-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.BackgroundEvent(**data) + + def _read_data_receive_error_event(self, + xml_element: ElementTree.Element + ) -> ar_element.DataReceiveErrorEvent: + """ + Reads complex Type AR:DATA-RECEIVE-ERROR-EVENT + Tag variants: 'DATA-RECEIVE-ERROR-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("DATA-IREF") + if xml_child is not None: + data["data"] = self._read_r_variable_in_atomic_swc_instance_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.DataReceiveErrorEvent(**data) + + def _read_data_received_event(self, + xml_element: ElementTree.Element + ) -> ar_element.DataReceivedEvent: + """ + Reads complex Type AR:DATA-RECEIVED-EVENT + Tag variants: 'DATA-RECEIVED-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("DATA-IREF") + if xml_child is not None: + data["data"] = self._read_r_variable_in_atomic_swc_instance_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.DataReceivedEvent(**data) + + def _read_data_send_completed_event(self, + xml_element: ElementTree.Element + ) -> ar_element.DataSendCompletedEvent: + """ + Reads complex Type AR:DATA-SEND-COMPLETED-EVENT + Tag variants: 'DATA-SEND-COMPLETED-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("EVENT-SOURCE-REF") + if xml_child is not None: + data["event_source"] = self._read_variable_access_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.DataSendCompletedEvent(**data) + + def _read_data_write_completed_event(self, + xml_element: ElementTree.Element + ) -> ar_element.DataWriteCompletedEvent: + """ + Reads complex type AR:DATA-WRITE-COMPLETED-EVENT + Tag variants: 'DATA-WRITE-COMPLETED-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("EVENT-SOURCE-REF") + if xml_child is not None: + data["event_source"] = self._read_variable_access_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.DataWriteCompletedEvent(**data) + + def _read_external_trigger_occured_event(self, + xml_element: ElementTree.Element + ) -> ar_element.ExternalTriggerOccurredEvent: + """ + Writes complex type AR:R-TRIGGER-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'TRIGGER-IREF' | 'REQUIRED-TRIGGER-IREF' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("TRIGGER-IREF") + if xml_child is not None: + data["trigger"] = self._read_r_trigger_in_atomic_swc_instance_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.ExternalTriggerOccurredEvent(**data) + + def _read_init_event(self, + xml_element: ElementTree.Element + ) -> ar_element.InitEvent: + """ + Reads complex Type AR:INIT-EVENT + Tag variants: 'INIT-EVENT'' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.InitEvent(**data) + + def _read_internal_trigger_occured_event(self, + xml_element: ElementTree.Element + ) -> ar_element.InternalTriggerOccurredEvent: + """ + Reads complex type AR:INTERNAL-TRIGGER-OCCURRED-EVENT + Tag variants: 'INTERNAL-TRIGGER-OCCURRED-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("EVENT-SOURCE-REF") + if xml_child is not None: + data["event_source"] = self._read_internal_triggering_point_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.InternalTriggerOccurredEvent(**data) + + def _read_mode_switched_ack_event(self, + xml_element: ElementTree.Element + ) -> ar_element.ModeSwitchedAckEvent: + """ + Reads Complex type MODE-SWITCHED-ACK-EVENT + Tag variants: 'MODE-SWITCHED-ACK-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("EVENT-SOURCE-REF") + if xml_child is not None: + data["event_source"] = self._read_mode_switch_point_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.ModeSwitchedAckEvent(**data) + + def _read_operation_invoked_event(self, + xml_element: ElementTree.Element + ) -> ar_element.OperationInvokedEvent: + """ + Complex type AR:OPERATION-INVOKED-EVENT + Tag variants: 'OPERATION-INVOKED-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("OPERATION-IREF") + if xml_child is not None: + data["operation"] = self._read_p_operation_in_atomic_swc_instance_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.OperationInvokedEvent(**data) + + def _read_swc_mode_manager_error_event(self, + xml_element: ElementTree.Element + ) -> ar_element.SwcModeManagerErrorEvent: + """ + Reads complex type AR:SWC-MODE-MANAGER-ERROR-EVENT + Tag variants: 'SWC-MODE-MANAGER-ERROR-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("MODE-GROUP-IREF") + if xml_child is not None: + data["mode_group"] = self._read_p_mode_group_in_atomic_swc_instance_ref(xml_child) + self._report_unprocessed_elements(child_elements) + return ar_element.SwcModeManagerErrorEvent(**data) + + def _read_swc_mode_switch_event(self, + xml_element: ElementTree.Element + ) -> ar_element.SwcModeSwitchEvent: + """ + Reads complex type AR:SWC-MODE-SWITCH-EVENT + Tag variants: 'SWC-MODE-SWITCH-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + self._read_swc_mode_switch_event_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.SwcModeSwitchEvent(**data) + + def _read_swc_mode_switch_event_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:SWC-MODE-SWITCH-EVENT + """ + xml_child = child_elements.get("ACTIVATION") + if xml_child is not None: + data["activation"] = ar_enum.xml_to_enum("ModeActivationKind", xml_child.text) + xml_child = child_elements.get("MODE-IREFS") + if xml_child is not None: + modes = [] + for xml_grand_child in xml_child.findall("./MODE-IREF"): + modes.append(self._read_r_mode_in_atomic_swc_instance_ref(xml_grand_child)) + if len(modes) == 0: + pass + elif len(modes) == 1: + data["mode"] = modes[0] + elif len(modes) == 2: + data["mode"] = (modes[0], modes[1]) + else: + self._raise_parse_error(xml_child, "Max two mode references are allowed") + + def _read_timing_event(self, + xml_element: ElementTree.Element + ) -> ar_element.TimingEvent: + """ + Reads complex type AR:TIMING-EVENT + Tag variants: 'TIMING-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + xml_child = child_elements.get("OFFSET") + if xml_child is not None: + data["offset"] = self._read_number(xml_child.text) + xml_child = child_elements.get("PERIOD") + if xml_child is not None: + data["period"] = self._read_number(xml_child.text) + self._report_unprocessed_elements(child_elements) + return ar_element.TimingEvent(**data) + + def _read_transformer_hard_error_event(self, + xml_element: ElementTree.Element + ) -> ar_element.TransformerHardErrorEvent: + """ + Writes complex type AR:TRANSFORMER-HARD-ERROR-EVENT + Tag variants: 'TRANSFORMER-HARD-ERROR-EVENT' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_rte_event_group(child_elements, data) + self._read_transformer_hard_error_event_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.TransformerHardErrorEvent(**data) + + def _read_transformer_hard_error_event_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:TRANSFORMER-HARD-ERROR-EVENT + """ + xml_child = child_elements.get("OPERATION-IREF") + if xml_child is not None: + data["operation"] = self._read_p_operation_in_atomic_swc_instance_ref(xml_child) + xml_child = child_elements.get("REQUIRED-TRIGGER-IREF") + if xml_child is not None: + data["required_trigger"] = self._read_r_trigger_in_atomic_swc_instance_ref(xml_child) + xml_child = child_elements.get("TRIGGER-IREF") + if xml_child is not None: + data["trigger"] = self._read_p_trigger_in_atomic_swc_instance_ref(xml_child) + def _read_swc_internal_behavior(self, xml_element: ElementTree.Element) -> ar_element.SwcInternalBehavior: """ Reads complex type AR:SWC-INTERNAL-BEHAVIOR @@ -4357,5 +5086,62 @@ def _read_swc_internal_behavior(self, xml_element: ElementTree.Element) -> ar_el self._read_referrable(child_elements, data) self._read_multi_language_referrable(child_elements, data) self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_internal_behavior_group(child_elements, data) + self._read_swc_internal_behavior_group(child_elements, data) self._report_unprocessed_elements(child_elements) return ar_element.SwcInternalBehavior(**data) + + def _read_internal_behavior_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:INTERNAL-BEHAVIOR + Will be implemented in a future version + """ + child_elements.skip("CONSTANT-MEMORYS") + child_elements.skip("CONSTANT-VALUE-MAPPING-REFS") + child_elements.skip("DATA-TYPE-MAPPING-REFS") + child_elements.skip("EXCLUSIVE-AREAS") + child_elements.skip("EXCLUSIVE-AREA-NESTING-ORDERS") + child_elements.skip("STATIC-MEMORYS") + + def _read_swc_internal_behavior_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:SWC-INTERNAL-BEHAVIOR + Most of it will be implemented in a future version + """ + child_elements.skip("AR-TYPED-PER-INSTANCE-MEMORYS") + xml_child = child_elements.get("EVENTS") + if xml_child is not None: + events = [] + for xml_grand_child in xml_child.findall("./*"): + events.append(self._read_rte_event_element(xml_grand_child)) + data["events"] = events + child_elements.skip("EXCLUSIVE-AREA-POLICYS") + child_elements.skip("EXPLICIT-INTER-RUNNABLE-VARIABLES") + child_elements.skip("HANDLE-TERMINATION-AND-RESTART") + child_elements.skip("INCLUDED-DATA-TYPE-SETS") + child_elements.skip("INCLUDED-MODE-DECLARATION-GROUP-SETS") + child_elements.skip("INSTANTIATION-DATA-DEF-PROPSS") + child_elements.skip("PER-INSTANCE-MEMORYS") + child_elements.skip("PER-INSTANCE-PARAMETERS") + child_elements.skip("PORT-API-OPTIONS") + xml_child = child_elements.get("RUNNABLES") + if xml_child is not None: + runnables = [] + for xml_grand_child in xml_child.findall("./RUNNABLE-ENTITY"): + runnables.append(self._read_runnable_entity(xml_grand_child)) + data["runnables"] = runnables + child_elements.skip("SERVICE-DEPENDENCYS") + child_elements.skip("SHARED-PARAMETERS") + child_elements.skip("SUPPORTS-MULTIPLE-INSTANTIATION") + child_elements.skip("VARIATION-POINT-PROXYS") + child_elements.skip("VARIATION-POINT") + + def _read_rte_event_element(self, xml_element: ElementTree.Element) -> RteEventElement: + """ + Reads one RTE event element + """ + read_method = self.switcher_rte_event.get(xml_element.tag, None) + if read_method is not None: + return read_method(xml_element) + else: + raise KeyError(f"Found no reader for '{xml_element.tag}'") diff --git a/src/autosar/xml/reference.py b/src/autosar/xml/reference.py new file mode 100644 index 0000000..8b0ada7 --- /dev/null +++ b/src/autosar/xml/reference.py @@ -0,0 +1,679 @@ +""" +AUTOSAR XML Reference classes +""" + +from autosar.xml.base import BaseRef +import autosar.xml.enumeration as ar_enum + + +class SwBaseTypeRef(BaseRef): + """ + SwBaseType reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.SW_BASE_TYPE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.SW_BASE_TYPE} + + +class PackageRef(BaseRef): + """ + References to AR-PACKAGE--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.AR_PACKAGE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.AR_PACKAGE} + + +class CompuMethodRef(BaseRef): + """ + CompuMethod reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.COMPU_METHOD + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.COMPU_METHOD} + + +class FunctionPtrSignatureRef(BaseRef): + """ + Function pointer signature reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.BSW_MODULE_ENTRY + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.BSW_MODULE_ENTRY} + + +class ImplementationDataTypeRef(BaseRef): + """ + ImplementationDataType reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE} + + +class SwAddrMethodRef(BaseRef): + """ + SwAddrMethod reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD} + + +class DataConstraintRef(BaseRef): + """ + DataConstraint reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.DATA_CONSTR + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.DATA_CONSTR} + + +class PhysicalDimensionRef(BaseRef): + """ + PhysicalDimension reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.PHYSICAL_DIMENSION + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.PHYSICAL_DIMENSION} + + +class UnitRef(BaseRef): + """ + DataConstraint reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.UNIT + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.UNIT} + + +class IndexDataTypeRef(BaseRef): + """ + IndexDataType reference + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE} + + +class ApplicationDataTypeRef(BaseRef): + """ + Application data type reference + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_DEFERRED_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE} + + +class ApplicationCompositeElementDataPrototypeRef(BaseRef): + """ + References to APPLICATION-COMPOSITE-ELEMENT-DATA-PROTOTYPE--SUBTYPES-ENUM + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_ELEMENT, + ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_ELEMENT_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT, + } + + +class AutosarDataTypeRef(BaseRef): + """ + References to AR:AUTOSAR-DATA-TYPE--SUBTYPES-ENUM + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ABSTRACT_IMPLEMENTATION_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_DEFERRED_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_PRIMITIVE_DATA_TYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE, + ar_enum.IdentifiableSubTypes.AUTOSAR_DATA_TYPE, + ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE} + + +class ConstantRef(BaseRef): + """ + Reference to ConstantSpecification + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.CONSTANT_SPECIFICATION + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.CONSTANT_SPECIFICATION} + + +class VariableDataPrototypeRef(BaseRef): + """ + Reference to VariableDataPrototype + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE} + + +class ParameterDataPrototypeRef(BaseRef): + """ + Reference to ParameterDataPrototype + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE} + + +class ApplicationErrorRef(BaseRef): + """ + Reference to ApplicationError + tag variants: 'POSSIBLE-ERROR-REF' + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.APPLICATION_ERROR) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_ERROR} + + +class ModeDeclarationRef(BaseRef): + """ + Reference to ModeDeclaration + tag variants: 'TARGET-MODE-DECLARATION-REF' | 'INITIAL-MODE-REF' | + 'FIRST-MODE-REF' | 'SECOND-MODE-REF' | 'MODE-DECLARATION-REF' | + 'DEFAULT-MODE-REF' | 'TARGET-MODE-REF' | 'ENTERED-MODE-REF' | + 'EXITED-MODE-REF' | 'ENTRY-MODE-DECLARATION-REF' | 'EXIT-MODE-DECLARATION-REF' + + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.MODE_DECLARATION) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION} + + +class ModeDeclarationGroupRef(BaseRef): + """ + Reference to ModeDeclarationGroup + Tag variants: 'MODE-DECLARATION-GROUP-REF' | 'TYPE-TREF' | 'MODE-GROUP-REF' + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP} + + +class ModeDeclarationGroupPrototypeRef(BaseRef): + """ + Reference to ModeDeclarationGroupPrototype + Tag variants: 'MODE-GROUP-REF' | 'REQUIRED-MODE-GROUP-REF' | 'FIRST-MODE-GROUP-REF' | + 'SECOND-MODE-GROUP-REF' | 'MODE-DECLARATION-GROUP-PROTOTYPE-REF' + (and more) + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP_PROTOTYPE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.MODE_DECLARATION_GROUP_PROTOTYPE} + + +class AutosarDataPrototypeRef(BaseRef): + """ + Reference to elements that derives from AutosarDataPrototype + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE} + + +class E2EProfileCompatibilityPropsRef(BaseRef): + """ + Reference to E2EProfileCompatibilityProps + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS} + + +class ClientServerOperationRef(BaseRef): + """ + Reference to ClientServerOperation + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.CLIENT_SERVER_OPERATION + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.CLIENT_SERVER_OPERATION} + + +class PortPrototypeRef(BaseRef): + """ + Reference to port prototype elements + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ABSTRACT_PROVIDED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.ABSTRACT_REQUIRED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE, + } + + @property + def is_provide_port_ref(self) -> bool: + """ + True if destination of port reference is a P-PORT + """ + p_port_values = {ar_enum.IdentifiableSubTypes.ABSTRACT_PROVIDED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE} + return self.dest in p_port_values + + @property + def is_require_port_ref(self) -> bool: + """ + True if destination of port reference is an R-PORT + """ + r_port_values = {ar_enum.IdentifiableSubTypes.ABSTRACT_REQUIRED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE} + return self.dest in r_port_values + + +class AbstractImplementationDataTypeElementRef(BaseRef): + """ + Reference to abstract or specific data-type elements + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ABSTRACT_IMPLEMENTATION_DATA_TYPE_ELEMENT, + ar_enum.IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE_ELEMENT} + + +class DataPrototypeRef(BaseRef): + """ + References to DATA-PROTOTYPE--SUBTYPES-ENUM + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_ARRAY_ELEMENT, + ar_enum.IdentifiableSubTypes.APPLICATION_COMPOSITE_ELEMENT_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT, + ar_enum.IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.AUTOSAR_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PARAMETER_DATA_PROTOTYPE, + ar_enum.IdentifiableSubTypes.VARIABLE_DATA_PROTOTYPE, + } + + +class PortInterfaceRef(BaseRef): + """ + References to PORT-INTERFACE--SUBTYPES-ENUM + + Only a small piece of the enum is currently implemented + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.CLIENT_SERVER_INTERFACE, + ar_enum.IdentifiableSubTypes.MODE_SWITCH_INTERFACE, + ar_enum.IdentifiableSubTypes.NV_DATA_INTERFACE, + ar_enum.IdentifiableSubTypes.PARAMETER_INTERFACE, + ar_enum.IdentifiableSubTypes.SENDER_RECEIVER_INTERFACE, + } + + +class SwComponentTypeRef(BaseRef): + """ + References to SW-COMPONENT-TYPE--SUBTYPES-ENUM + + Only a small piece of the enum is currently implemented + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE, + ar_enum.IdentifiableSubTypes.COMPOSITION_SW_COMPONENT_TYPE, + } + + +class SwComponentPrototypeRef(BaseRef): + """ + Reference to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.SW_COMPONENT_PROTOTYPE + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.SW_COMPONENT_PROTOTYPE} + + +class SwcInternalBehaviorRef(BaseRef): + """ + Reference to AR:SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.SWC_INTERNAL_BEHAVIOR + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.SWC_INTERNAL_BEHAVIOR} + + +class SwcImplementationRef(BaseRef): + """ + Reference to SwcImplementation + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.SWC_IMPLEMENTATION + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.SWC_IMPLEMENTATION} + + +class ExclusiveAreaRef(BaseRef): + """ + EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA} + + +class ExclusiveAreaNestingOrderRef(BaseRef): + """ + AR:EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA_NESTING_ORDER + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA_NESTING_ORDER} + + +class AbstractRequiredPortPrototypeRef(BaseRef): + """ + AR:ABSTRACT-REQUIRED-PORT-PROTOTYPE--SUBTYPES-ENUM + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ABSTRACT_REQUIRED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE} + + +class AbstractProvidedPortPrototypeRef(BaseRef): + """ + AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE--SUBTYPES-ENUM + """ + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ABSTRACT_PROVIDED_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE, + ar_enum.IdentifiableSubTypes.PR_PORT_PROTOTYPE} + + +class RunnableEntityRef(BaseRef): + """ + AR:RUNNABLE-ENTITY--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.RUNNABLE_ENTITY + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.RUNNABLE_ENTITY} + + +class VariableAccessRef(BaseRef): + """ + VARIABLE-ACCESS--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.VARIABLE_ACCESS + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.VARIABLE_ACCESS} + + +class ModeSwitchPointRef(BaseRef): + """ + AR:MODE-SWITCH-POINT--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.MODE_SWITCH_POINT + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.MODE_SWITCH_POINT} + + +class AsynchronousServerCallResultPointRef(BaseRef): + """ + AR:ASYNCHRONOUS-SERVER-CALL-RESULT-POINT--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.ASYNCHRONOUS_SERVER_CALL_RESULT_POINT + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.ASYNCHRONOUS_SERVER_CALL_RESULT_POINT} + + +class TriggerRef(BaseRef): + """ + AR:TRIGGER--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.TRIGGER + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.TRIGGER} + + +class InternalTriggeringPointRef(BaseRef): + """ + AR:INTERNAL-TRIGGERING-POINT--SUBTYPES-ENUM + """ + + def __init__(self, value: str, + dest: ar_enum.IdentifiableSubTypes = ar_enum.IdentifiableSubTypes.INTERNAL_TRIGGERING_POINT + ) -> None: + super().__init__(value, dest) + + @classmethod + def accepted_sub_types(cls) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.INTERNAL_TRIGGERING_POINT} diff --git a/src/autosar/xml/workspace.py b/src/autosar/xml/workspace.py index b6ca8e9..a343455 100644 --- a/src/autosar/xml/workspace.py +++ b/src/autosar/xml/workspace.py @@ -79,12 +79,12 @@ class Workspace(ar_element.PackageCollection): """ def __init__(self, config_file_path: str | None = None, document_root: str | None = None) -> None: + super().__init__(behavior_settings=ar_element.BehaviorSettings()) self.namespaces: dict[str, Namespace] = {} self.documents: list[DocumentConfig] = [] self.document_mappings: list[PackageToDocumentMapping] = [] self.document_root = document_root self.package_map: dict[str, ar_element.Package] = {} # Each key is user-defined - super().__init__() if config_file_path is not None: self.load_config(config_file_path) @@ -219,6 +219,9 @@ def load_config(self, file_path: str) -> None: if document_mapping is not None: for mapping in document_mapping.values(): self._create_document_mapping_from_config(mapping) + behavior_settings = config.get("behavior", None) + if behavior_settings is not None: + self.behavior_settings.update(behavior_settings) def _write_document_from_config(self, writer: Writer, diff --git a/src/autosar/xml/writer.py b/src/autosar/xml/writer.py index b9294c1..38d6328 100644 --- a/src/autosar/xml/writer.py +++ b/src/autosar/xml/writer.py @@ -7,6 +7,7 @@ import sys import math import decimal +import autosar.base as ar_base import autosar.xml.document as ar_document import autosar.xml.element as ar_element import autosar.xml.enumeration as ar_enum @@ -181,8 +182,11 @@ class Writer(_XMLWriter): ARXML writer class """ - def __init__(self) -> None: + def __init__(self, + schema_version: int = ar_base.DEFAULT_SCHEMA_VERSION) -> None: super().__init__(indentation_step=2) + self.schema_version = schema_version + # Elements found in AR:PACKAGE self.switcher_collectable = { # Package @@ -249,6 +253,23 @@ def __init__(self) -> None: 'ModeSwitchReceiverComSpec': self._write_mode_switch_receiver_com_spec, 'ClientComSpec': self._write_client_com_spec, } + self.switcher_rte_event = { + 'AsynchronousServerCallReturnsEvent': self._write_async_server_call_returns_event, + 'BackgroundEvent': self._write_background_event, + 'DataReceiveErrorEvent': self._write_data_receive_error_event, + 'DataReceivedEvent': self._write_data_received_event, + 'DataSendCompletedEvent': self._write_data_send_completed_event, + 'DataWriteCompletedEvent': self._write_data_write_completed_event, + 'ExternalTriggerOccurredEvent': self._write_external_trigger_occured_event, + 'InitEvent': self._write_init_event, + 'InternalTriggerOccurredEvent': self._write_internal_trigger_occured_event, + 'ModeSwitchedAckEvent': self._write_mode_switched_ack_event, + 'OperationInvokedEvent': self._write_operation_invoked_event, + 'SwcModeManagerErrorEvent': self._write_swc_mode_manager_error_event, + 'SwcModeSwitchEvent': self._write_swc_mode_switch_event, + 'TimingEvent': self._write_timing_event, + 'TransformerHardErrorEvent': self._write_transformer_hard_error_event, + } # Elements used only for unit test purposes self.switcher_non_collectable = { # Documentation elements @@ -326,13 +347,31 @@ def __init__(self) -> None: 'AssemblySwConnector': self._write_assembly_sw_connector, 'DelegationSwConnector': self._write_delegation_sw_connector, 'PassThroughSwConnector': self._write_passthrough_sw_connector, + 'RModeInAtomicSwcInstanceRef': self._write_r_mode_in_atomic_swc_instance_ref, # SWC internal behavior elements 'ArVariableInImplementationDataInstanceRef': self._write_variable_in_impl_data_instance_ref, 'VariableInAtomicSWCTypeInstanceRef': self._write_variable_in_atomic_swc_type_instance_ref, 'AutosarVariableRef': self._write_autosar_variable_ref, 'VariableAccess': self._write_variable_access, 'SwcInternalBehavior': self._write_swc_internal_behavior, - + 'ExecutableEntityActivationReason': self._write_executable_entity_activation_reason, + 'ExclusiveAreaRefConditional': self._write_exclusive_area_ref_conditional, + 'RunnableEntity': self._write_runnable_entity, + 'AsynchronousServerCallReturnsEvent': self._write_async_server_call_returns_event, + 'BackgroundEvent': self._write_background_event, + 'DataReceiveErrorEvent': self._write_data_receive_error_event, + 'DataReceivedEvent': self._write_data_received_event, + 'DataSendCompletedEvent': self._write_data_send_completed_event, + 'DataWriteCompletedEvent': self._write_data_write_completed_event, + 'ExternalTriggerOccurredEvent': self._write_external_trigger_occured_event, + 'InitEvent': self._write_init_event, + 'InternalTriggerOccurredEvent': self._write_internal_trigger_occured_event, + 'ModeSwitchedAckEvent': self._write_mode_switched_ack_event, + 'OperationInvokedEvent': self._write_operation_invoked_event, + 'SwcModeManagerErrorEvent': self._write_swc_mode_manager_error_event, + 'SwcModeSwitchEvent': self._write_swc_mode_switch_event, + 'TimingEvent': self._write_timing_event, + 'TransformerHardErrorEvent': self._write_transformer_hard_error_event, } self.switcher_all = {} # All concrete elements (used for unit testing) self.switcher_all.update(self.switcher_collectable) @@ -439,6 +478,7 @@ def _write_admin_data(self, data: dict) -> None: # AUTOSAR Document def _write_document(self, document: ar_document.Document, skip_root_attr: bool = False): + self.schema_version = document.schema_version self._add_line('') if skip_root_attr: self._add_child("AUTOSAR") @@ -1899,6 +1939,11 @@ def _collect_base_ref_attr(self, attr: TupleList) -> None: attr.append(('DEST', ar_enum.enum_to_xml(elem.dest))) + def _write_ref_content(self, elem: ar_element.BaseRef, tag: str): + attr: TupleList = [] + self._collect_base_ref_attr(elem, attr) + self._add_content(tag, elem.value, attr) + def _write_compu_method_ref(self, elem: ar_element.CompuMethodRef) -> None: """ Writes complex type AR:COMPU-METHOD-REF @@ -1971,8 +2016,7 @@ def _write_sw_base_type_ref(self, elem: ar_element.SwBaseTypeRef) -> None: def _write_sw_addr_method_ref(self, elem: ar_element.SwAddrMethodRef) -> None: """ - Writes complex type AR:SW-ADDR-METHOD-REF - Type: Concrete + Writes references to AR:SW-ADDR-METHOD--SUBTYPES-ENUM Tag variants: 'SW-ADDR-METHOD-REF' """ assert isinstance(elem, ar_element.SwAddrMethodRef) @@ -2230,6 +2274,49 @@ def _write_sw_component_prototype_ref(self, self._collect_base_ref_attr(elem, attr) self._add_content(tag, elem.value, attr) + def _write_exclusive_area_ref(self, + elem: ar_element.ExclusiveAreaRef, + tag: str) -> None: + """ + Writes references to EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + assert isinstance(elem, ar_element.ExclusiveAreaRef) + attr: TupleList = [] + self._collect_base_ref_attr(elem, attr) + self._add_content(tag, elem.value, attr) + + def _write_exclusive_area_nesting_order_ref(self, + elem: ar_element.ExclusiveAreaNestingOrderRef, + tag: str) -> None: + """ + Writes references to EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + assert isinstance(elem, ar_element.ExclusiveAreaNestingOrderRef) + attr: TupleList = [] + self._collect_base_ref_attr(elem, attr) + self._add_content(tag, elem.value, attr) + + def _write_abstract_required_port_prototype_ref(self, + elem: ar_element.AbstractRequiredPortPrototypeRef, + tag: str) -> None: + """ + Writes references to AR:ABSTRACT-REQUIRED-PORT'-PROTOTYPE--SUBTYPES-ENUM + Tag variants: 'REQUIRED-OUTER-PORT-REF' | 'CONTEXT-R-PORT-REF' | 'CONTEXT-PORT-REF' + 'TARGET-R-PORT-REF' | + """ + assert isinstance(elem, ar_element.AbstractRequiredPortPrototypeRef) + self._write_ref_content(elem, tag) + + def _write_abstract_provided_port_prototype_ref(self, + elem: ar_element.AbstractProvidedPortPrototypeRef, + tag: str) -> None: + """ + Writes references to AR:ABSTRACT-PROVIDED-PORT-PROTOTYPE--SUBTYPES-ENUM + Tag variants: 'CONTEXT-P-PORT-REF' | 'TARGET-P-PORT-REF' | 'PROVIDED-OUTER-PORT-REF' + """ + assert isinstance(elem, ar_element.AbstractProvidedPortPrototypeRef) + self._write_ref_content(elem, tag) + def _write_swc_internal_behavior_ref(self, elem: ar_element.SwcInternalBehaviorRef, tag: str) -> None: @@ -2241,6 +2328,67 @@ def _write_swc_internal_behavior_ref(self, self._collect_base_ref_attr(elem, attr) self._add_content(tag, elem.value, attr) + def _write_runnable_entity_ref(self, + elem: ar_element.RunnableEntityRef, + tag: str) -> None: + """ + Writes references to RUNNABLE-ENTITY--SUBTYPES-ENUM + """ + assert isinstance(elem, ar_element.RunnableEntityRef) + self._write_ref_content(elem, tag) + + def _write_variable_access_ref(self, + elem: ar_element.VariableAccessRef, + tag: str) -> None: + """ + Writes references to AR:VARIABLE-ACCESS--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' | 'VARIABLE-ACCESS-REF' | 'TARGET-VARIABLE-ACCESS-REF' + """ + assert isinstance(elem, ar_element.VariableAccessRef) + self._write_ref_content(elem, tag) + + def _write_mode_switch_point_ref(self, + elem: ar_element.ModeSwitchPointRef + ) -> None: + """ + Writes references to AR:MODE-SWITCH-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + assert isinstance(elem, ar_element.ModeSwitchPointRef) + self._write_ref_content(elem, "EVENT-SOURCE-REF") + + def _write_async_server_call_result_point_ref(self, + elem: ar_element.AsynchronousServerCallResultPointRef + ) -> None: + """ + Writes references to AR:ASYNCHRONOUS-SERVER-CALL-RESULT-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + assert isinstance(elem, ar_element.AsynchronousServerCallResultPointRef) + self._write_ref_content(elem, "EVENT-SOURCE-REF") + + def _write_trigger_ref(self, + elem: ar_element.TriggerRef, + tag: str) -> None: + """ + Writes references to AR:TRIGGER--SUBTYPES-ENUM + Tag variants: 'TRIGGER-REF' | 'RELEASED-TRIGGER-REF' | 'MASTERED-TRIGGER-REF' | + 'TARGET-TRIGGER-REF' | 'SOURCE-TRIGGER-REF' | 'BSW-TRIGGER-REF' | + 'FIRST-TRIGGER-REF' | 'SECOND-TRIGGER-REF' + """ + assert isinstance(elem, ar_element.TriggerRef) + self._write_ref_content(elem, tag) + + def _write_internal_triggering_point_ref(self, + elem: ar_element.InternalTriggeringPointRef + ) -> None: + """ + Writes references to AR:INTERNAL-TRIGGERING-POINT--SUBTYPES-ENUM + Tag variants: 'EVENT-SOURCE-REF' + """ + assert isinstance(elem, ar_element.InternalTriggeringPointRef) + self._write_ref_content(elem, "EVENT-SOURCE-REF") + # -- Constant and value specifications def _write_text_value_specification(self, elem: ar_element.TextValueSpecification) -> None: @@ -3634,7 +3782,124 @@ def _write_swc_implementation_group(self, elem: ar_element.SwcImplementation) -> if elem.required_rte_vendor is not None: self._add_content("REQUIRED-RTE-VENDOR", elem.required_rte_vendor) - # SWC Internal behavior elements + def _write_p_mode_group_in_atomic_swc_instance_ref(self, + elem: ar_element.PModeGroupInAtomicSwcInstanceRef, + tag: str) -> None: + """ + Writes complex type AR:P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'P-MODE-GROUP-IN-ATOMIC-SWC-INSTANCE-REF' | 'MODE-GROUP-IREF' | + 'SWC-MODE-GROUP-IREF' + """ + assert isinstance(elem, ar_element.PModeGroupInAtomicSwcInstanceRef) + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_provided_port_prototype_ref(elem.context_port, "CONTEXT-P-PORT-REF") + if elem.context_mode_declaration_group_prototype is not None: + self._write_mode_declaration_group_prototype_ref(elem.context_mode_declaration_group_prototype, + "CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF") + self._leave_child() + + def _write_p_operation_in_atomic_swc_instance_ref(self, + elem: ar_element.POperationInAtomicSwcInstanceRef + ) -> None: + """ + Writes complex type AR:P-OPERATION-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'OPERATION-IREF' + """ + assert isinstance(elem, ar_element.POperationInAtomicSwcInstanceRef) + tag = "OPERATION-IREF" + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_provided_port_prototype_ref(elem.context_port, "CONTEXT-P-PORT-REF") + if elem.target_provided_operation is not None: + self._write_client_server_operation_ref(elem.target_provided_operation, + "TARGET-PROVIDED-OPERATION-REF") + self._leave_child() + + def _write_p_trigger_in_atomic_swc_instance_ref(self, + elem: ar_element.PTriggerInAtomicSwcTypeInstanceRef, + tag: str + ) -> None: + """ + Writes complex type AR:P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF + Tag variants: 'P-TRIGGER-IN-ATOMIC-SWC-TYPE-INSTANCE-REF' | 'SWC-TRIGGER-IREF' | + 'TRIGGER-IREF' + """ + assert isinstance(elem, ar_element.PTriggerInAtomicSwcTypeInstanceRef) + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_provided_port_prototype_ref(elem.context_port, "CONTEXT-P-PORT-REF") + if elem.target_trigger is not None: + self._write_trigger_ref(elem.target_trigger, "TARGET-TRIGGER-REF") + self._leave_child() + + def _write_r_mode_in_atomic_swc_instance_ref(self, elem: ar_element.RModeInAtomicSwcInstanceRef, tag: str) -> None: + """ + Writes complex type AR:R-MODE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DISABLED-MODE-IREF' | 'MODE-IREF' + """ + assert isinstance(elem, ar_element.RModeInAtomicSwcInstanceRef) + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_required_port_prototype_ref(elem.context_port, "CONTEXT-PORT-REF") + if elem.context_mode_declaration_group_prototype is not None: + self._write_mode_declaration_group_prototype_ref(elem.context_mode_declaration_group_prototype, + "CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF") + if elem.target_mode_declaration is not None: + self._write_mode_declaration_ref(elem.target_mode_declaration, "TARGET-MODE-DECLARATION-REF") + self._leave_child() + + def _write_r_variable_in_atomic_swc_instance_ref(self, + elem: ar_element.RVariableInAtomicSwcInstanceRef + ) -> None: + """ + Writes complex type AR:R-VARIABLE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DATA-IREF' + """ + assert isinstance(elem, ar_element.RVariableInAtomicSwcInstanceRef) + tag = "DATA-IREF" + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_required_port_prototype_ref(elem.context_port, "CONTEXT-R-PORT-REF") + if elem.target_data_element is not None: + self._write_variable_data_prototype_ref(elem.target_data_element, "TARGET-DATA-ELEMENT-REF") + self._leave_child() + + def _write_r_trigger_in_atomic_swc_instance_ref(self, + elem: ar_element.RTriggerInAtomicSwcInstanceRef, + tag: str + ) -> None: + """ + Write complex type AR:R-TRIGGER-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'TRIGGER-IREF' | 'REQUIRED-TRIGGER-IREF' + """ + assert isinstance(elem, ar_element.RTriggerInAtomicSwcInstanceRef) + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.context_port is not None: + self._write_abstract_required_port_prototype_ref(elem.context_port, "CONTEXT-R-PORT-REF") + if elem.target_trigger is not None: + self._write_trigger_ref(elem.target_trigger, "TARGET-TRIGGER-REF") + self._leave_child() + + # --- SWC Internal behavior elements def _write_variable_in_impl_data_instance_ref(self, elem: ar_element.ArVariableInImplementationDataInstanceRef, @@ -3717,6 +3982,7 @@ def _write_variable_access(self, elem: ar_element.VariableAccess, tag: str) -> N Writes complex type AR:VARIABLE-ACCESS Tag variants: 'REPLACE-WITH' | 'VARIABLE-ACCESS' """ + assert isinstance(elem, ar_element.VariableAccess) self._add_child(tag) self._write_referrable(elem) self._write_multilanguage_referrable(elem) @@ -3727,6 +3993,364 @@ def _write_variable_access(self, elem: ar_element.VariableAccess, tag: str) -> N self._add_content("SCOPE", ar_enum.enum_to_xml(elem.scope)) self._leave_child() + def _write_executable_entity_activation_reason(self, + elem: ar_element.ExecutableEntityActivationReason) -> None: + """ + Writes complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' + """ + assert isinstance(elem, ar_element.ExecutableEntityActivationReason) + self._add_child("EXECUTABLE-ENTITY-ACTIVATION-REASON") + self._write_referrable(elem) + self._write_implementation_props(elem) + if elem.bit_position is not None: + self._add_content("BIT-POSITION", str(elem.bit_position)) + self._leave_child() + + def _write_exclusive_area_ref_conditional(self, + elem: ar_element.ExclusiveAreaRefConditional) -> None: + """ + Writes complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' + """ + assert isinstance(elem, ar_element.ExclusiveAreaRefConditional) + tag = "EXCLUSIVE-AREA-REF-CONDITIONAL" + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.exclusive_area_ref is not None: + self._write_exclusive_area_ref(elem.exclusive_area_ref, "EXCLUSIVE-AREA-REF") + self._leave_child() + + def _write_executable_entity(self, elem: ar_element.ExecutableEntity) -> None: + """ + Writes group AR:EXECUTABLE-ENTITY + """ + if elem.activation_reasons: + self._add_child("ACTIVATION-REASONS") + for activation_reason in elem.activation_reasons: + self._write_executable_entity_activation_reason(activation_reason) + self._leave_child() + if elem.can_enter_leave: + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + self._add_child("CAN-ENTER-EXCLUSIVE-AREA-REFS") + for child_elem in elem.can_enter_leave: + self._write_exclusive_area_ref(child_elem.exclusive_area_ref, + "CAN-ENTER-EXCLUSIVE-AREA-REF") + self._leave_child() + else: + self._add_child("CAN-ENTERS") + for child_elem in elem.can_enter_leave: + self._write_exclusive_area_ref_conditional(child_elem) + self._leave_child() + if elem.exclusive_area_nesting_order: + self._add_child("EXCLUSIVE-AREA-NESTING-ORDER-REFS") + for nesting_order_ref in elem.exclusive_area_nesting_order: + self._write_exclusive_area_nesting_order_ref(nesting_order_ref, + "EXCLUSIVE-AREA-NESTING-ORDER-REF") + self._leave_child() + if elem.minimum_start_interval is not None: + self._add_content("MINIMUM-START-INTERVAL", self._format_number(elem.minimum_start_interval)) + if elem.reentrancy_level is not None: + self._add_content("REENTRANCY-LEVEL", ar_enum.enum_to_xml(elem.reentrancy_level)) + if elem.runs_insides: + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + self._add_child("RUNS-INSIDE-EXCLUSIVE-AREA-REFS") + for child_elem in elem.runs_insides: + self._write_exclusive_area_ref(child_elem.exclusive_area_ref, + "RUNS-INSIDE-EXCLUSIVE-AREA-REF") + self._leave_child() + else: + self._add_child("RUNS-INSIDES") + for child_elem in elem.runs_insides: + self._write_exclusive_area_ref_conditional(child_elem) + self._leave_child() + if elem.sw_addr_method is not None: + self._write_sw_addr_method_ref(elem.sw_addr_method) + + def _write_runnable_entity(self, elem: ar_element.RunnableEntity) -> None: + """ + Writes complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + + This is in early stage, most will be implemented later + """ + assert isinstance(elem, ar_element.RunnableEntity) + self._add_child("RUNNABLE-ENTITY") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_executable_entity(elem) + self._leave_child() + + def _write_runnable_entity_group(self, elem: ar_element.RunnableEntity) -> None: + """ + Writes group type AR:RUNNABLE-ENTITY + + This is just a placeholder. Will be implemented later + """ + + def _write_rte_event_group(self, elem: ar_element.RteEvent) -> None: + """ + Writes group AR:RTE-EVENT + """ + if elem.disabled_modes: + self._add_child("DISABLED-MODE-IREFS") + for disabled_mode in elem.disabled_modes: + self._write_r_mode_in_atomic_swc_instance_ref(disabled_mode, "DISABLED-MODE-IREF") + self._leave_child() + if elem.start_on_event is not None: + self._write_runnable_entity_ref(elem.start_on_event, "START-ON-EVENT-REF") + + def _write_async_server_call_returns_event(self, elem: ar_element.AsynchronousServerCallReturnsEvent) -> None: + """ + Writes complex type AR:ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT + Tag variants: 'ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT' + """ + assert isinstance(elem, ar_element.AsynchronousServerCallReturnsEvent) + self._add_child("ASYNCHRONOUS-SERVER-CALL-RETURNS-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.event_source is not None: + self._write_async_server_call_result_point_ref(elem.event_source) + self._leave_child() + + def _write_background_event(self, elem: ar_element.BackgroundEvent) -> None: + """ + Writes complex Type AR:BACKGROUND-EVENT + Tag variants: 'BACKGROUND-EVENT' + """ + assert isinstance(elem, ar_element.BackgroundEvent) + self._add_child("BACKGROUND-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + self._leave_child() + + def _write_data_receive_error_event(self, elem: ar_element.DataReceiveErrorEvent) -> None: + """ + Writes complex Type AR:DATA-RECEIVE-ERROR-EVENT + Tag variants: 'DATA-RECEIVE-ERROR-EVENT' + """ + assert isinstance(elem, ar_element.DataReceiveErrorEvent) + self._add_child("DATA-RECEIVE-ERROR-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.data is not None: + self._write_r_variable_in_atomic_swc_instance_ref(elem.data) + self._leave_child() + + def _write_data_received_event(self, elem: ar_element.DataReceivedEvent) -> None: + """ + Writes complex Type AR:DATA-RECEIVED-EVENT + Tag variants: 'DATA-RECEIVED-EVENT' + """ + assert isinstance(elem, ar_element.DataReceivedEvent) + self._add_child("DATA-RECEIVED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.data is not None: + self._write_r_variable_in_atomic_swc_instance_ref(elem.data) + self._leave_child() + + def _write_data_send_completed_event(self, elem: ar_element.DataSendCompletedEvent) -> None: + """ + Writes complex Type AR:DATA-SEND-COMPLETED-EVENT + Tag variants: 'DATA-SEND-COMPLETED-EVENT' + """ + assert isinstance(elem, ar_element.DataSendCompletedEvent) + self._add_child("DATA-SEND-COMPLETED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.event_source is not None: + self._write_variable_access_ref(elem.event_source, "EVENT-SOURCE-REF") + self._leave_child() + + def _write_data_write_completed_event(self, elem: ar_element.DataWriteCompletedEvent) -> None: + """ + Writes complex Type AR:DATA-WRITE-COMPLETED-EVENT + Tag variants: 'DATA-WRITE-COMPLETED-EVENT' + """ + assert isinstance(elem, ar_element.DataWriteCompletedEvent) + self._add_child("DATA-WRITE-COMPLETED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.event_source is not None: + self._write_variable_access_ref(elem.event_source, "EVENT-SOURCE-REF") + self._leave_child() + + def _write_external_trigger_occured_event(self, elem: ar_element.ExternalTriggerOccurredEvent) -> None: + """ + Writes complex Type AR:EXTERNAL-TRIGGER-OCCURRED-EVENT + Tag variants: 'EXTERNAL-TRIGGER-OCCURRED-EVENT' + """ + assert isinstance(elem, ar_element.ExternalTriggerOccurredEvent) + self._add_child("EXTERNAL-TRIGGER-OCCURRED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.trigger is not None: + self._write_r_trigger_in_atomic_swc_instance_ref(elem.trigger, "TRIGGER-IREF") + self._leave_child() + + def _write_init_event(self, elem: ar_element.InitEvent) -> None: + """ + Writes complex type AR:INIT-EVENT + Tag variants: 'INIT-EVENT' + """ + assert isinstance(elem, ar_element.InitEvent) + self._add_child("INIT-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + self._leave_child() + + def _write_internal_trigger_occured_event(self, elem: ar_element.InternalTriggerOccurredEvent) -> None: + """ + Writes complex type AR:INTERNAL-TRIGGER-OCCURRED-EVENT + Tag variants: 'INTERNAL-TRIGGER-OCCURRED-EVENT' + """ + assert isinstance(elem, ar_element.InternalTriggerOccurredEvent) + self._add_child("INTERNAL-TRIGGER-OCCURRED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.event_source is not None: + self._write_internal_triggering_point_ref(elem.event_source) + self._leave_child() + + def _write_mode_switched_ack_event(self, elem: ar_element.ModeSwitchedAckEvent) -> None: + """ + Writes complex type MODE-SWITCHED-ACK-EVENT + Tag variants: 'MODE-SWITCHED-ACK-EVENT' + """ + assert isinstance(elem, ar_element.ModeSwitchedAckEvent) + self._add_child("MODE-SWITCHED-ACK-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.event_source is not None: + self._write_mode_switch_point_ref(elem.event_source) + self._leave_child() + + def _write_operation_invoked_event(self, elem: ar_element.OperationInvokedEvent) -> None: + """ + Writes complex type AR:OPERATION-INVOKED-EVENT + Tag variants: 'OPERATION-INVOKED-EVENT' + """ + assert isinstance(elem, ar_element.OperationInvokedEvent) + self._add_child("OPERATION-INVOKED-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.operation is not None: + self._write_p_operation_in_atomic_swc_instance_ref(elem.operation) + self._leave_child() + + def _write_swc_mode_manager_error_event(self, elem: ar_element.SwcModeManagerErrorEvent) -> None: + """ + Writes complex type AR:SWC-MODE-MANAGER-ERROR-EVENT + Tag variants: 'SWC-MODE-MANAGER-ERROR-EVENT' + """ + assert isinstance(elem, ar_element.SwcModeManagerErrorEvent) + self._add_child("SWC-MODE-MANAGER-ERROR-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.mode_group is not None: + self._write_p_mode_group_in_atomic_swc_instance_ref(elem.mode_group, "MODE-GROUP-IREF") + self._leave_child() + + def _write_swc_mode_switch_event(self, elem: ar_element.SwcModeSwitchEvent) -> None: + """ + Writes complex type AR:SWC-MODE-SWITCH-EVENT + Tag variants: 'SWC-MODE-SWITCH-EVENT' + """ + assert isinstance(elem, ar_element.SwcModeSwitchEvent) + self._add_child("SWC-MODE-SWITCH-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + self._write_swc_mode_switch_event_group(elem) + self._leave_child() + + def _write_swc_mode_switch_event_group(self, elem: ar_element.SwcModeSwitchEvent) -> None: + """ + Writes group AR:SWC-MODE-SWITCH-EVENT + """ + if elem.activation is not None: + self._add_content("ACTIVATION", ar_enum.enum_to_xml(elem.activation)) + if elem.mode is not None: + self._add_child("MODE-IREFS") + if isinstance(elem.mode, tuple): + self._write_r_mode_in_atomic_swc_instance_ref(elem.mode[0], "MODE-IREF") + self._write_r_mode_in_atomic_swc_instance_ref(elem.mode[1], "MODE-IREF") + else: + self._write_r_mode_in_atomic_swc_instance_ref(elem.mode, "MODE-IREF") + self._leave_child() + + def _write_timing_event(self, elem: ar_element.TimingEvent) -> None: + """ + Writes complex type AR:TIMING-EVENT + Tag variants: 'TIMING-EVENT' + """ + assert isinstance(elem, ar_element.TimingEvent) + self._add_child("TIMING-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + if elem.offset is not None: + self._add_content("OFFSET", self._format_number(elem.offset)) + if elem.period is not None: + self._add_content("PERIOD", self._format_number(elem.period)) + self._leave_child() + + def _write_transformer_hard_error_event(self, elem: ar_element.TransformerHardErrorEvent) -> None: + """ + Writes complex type AR:TRANSFORMER-HARD-ERROR-EVENT + Tag variants: 'TRANSFORMER-HARD-ERROR-EVENT' + """ + assert isinstance(elem, ar_element.TransformerHardErrorEvent) + self._add_child("TRANSFORMER-HARD-ERROR-EVENT") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_rte_event_group(elem) + self._write_transformer_hard_error_event_group(elem) + self._leave_child() + + def _write_transformer_hard_error_event_group(self, elem: ar_element.TransformerHardErrorEvent) -> None: + if elem.operation is not None: + self._write_p_operation_in_atomic_swc_instance_ref(elem.operation) + if elem.required_trigger is not None: + self._write_r_trigger_in_atomic_swc_instance_ref(elem.required_trigger, "REQUIRED-TRIGGER-IREF") + if elem.trigger is not None: + self._write_p_trigger_in_atomic_swc_instance_ref(elem.trigger, "TRIGGER-IREF") + def _write_swc_internal_behavior(self, elem: ar_element.SwcInternalBehavior) -> None: """ Writes complex type AR:SWC-INTERNAL-BEHAVIOR @@ -3738,4 +4362,39 @@ def _write_swc_internal_behavior(self, elem: ar_element.SwcInternalBehavior) -> self._write_referrable(elem) self._write_multilanguage_referrable(elem) self._write_identifiable(elem) + self._write_internal_behavior_group(elem) + self._write_swc_internal_behavior_group(elem) self._leave_child() + + def _write_internal_behavior_group(self, elem: ar_element.InternalBehavior) -> None: + """ + Writes group AR:INTERNAL-BEHAVIOR + This is just a placeholder. Will be implemented later. + """ + + def _write_swc_internal_behavior_group(self, elem: ar_element.SwcInternalBehavior) -> None: + """ + Writes group AR:SWC-INTERNAL-BEHAVIOR + Most of it will be implemented in a future version + """ + if elem.events: + self._add_child("EVENTS") + for event in elem.events: + self._write_rte_event_element(event) + self._leave_child() + if elem.runnables: + self._add_child("RUNNABLES") + for runnable in elem.runnables: + self._write_runnable_entity(runnable) + self._leave_child() + + def _write_rte_event_element(self, elem: ar_element.RteEvent) -> None: + """ + Writes COM-SPEC for R-PORT + """ + class_name = elem.__class__.__name__ + write_method = self.switcher_rte_event.get(class_name, None) + if write_method is not None: + write_method(elem) + else: + raise NotImplementedError(f"Found no writer for class {class_name}") diff --git a/tests/xml/test_reference.py b/tests/xml/test_reference.py new file mode 100644 index 0000000..3bb89ea --- /dev/null +++ b/tests/xml/test_reference.py @@ -0,0 +1,26 @@ +"""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 +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.xml.enumeration as ar_enum # noqa E402 + + +class TestPortReferences(unittest.TestCase): + + def test_abstract_require_port_prototype_ref(self): + + rport_ref = ar_element.PortPrototypeRef("/ComponentTypes/MyApplicationComponent/RequirePort1", + ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + pport_ref = ar_element.PortPrototypeRef("/ComponentTypes/MyApplicationComponent/ProvidePort1", + ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + ar_element.AbstractRequiredPortPrototypeRef(rport_ref.value, rport_ref.dest) + with self.assertRaises(ValueError): + ar_element.AbstractRequiredPortPrototypeRef(pport_ref.value, pport_ref.dest) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/xml/test_software_component_builder.py b/tests/xml/test_software_component_builder.py index b9a7326..5737914 100644 --- a/tests/xml/test_software_component_builder.py +++ b/tests/xml/test_software_component_builder.py @@ -7,6 +7,7 @@ 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.xml.enumeration as ar_enum # noqa E402 import autosar # noqa E402 @@ -20,6 +21,7 @@ def create_packages(workspace: autosar.xml.workspace.Workspace) -> dict[str, ar_ "PlatformCompuMethods", "Constants", "PortInterfaces", + "ModeDeclarations", "ComponentTypes"], workspace.make_packages("AUTOSAR_Platform/BaseTypes", "AUTOSAR_Platform/ImplementationDataTypes", @@ -27,6 +29,7 @@ def create_packages(workspace: autosar.xml.workspace.Workspace) -> dict[str, ar_ "AUTOSAR_Platform/CompuMethods", "Constants", "PortInterfaces", + "ModeDeclarations", "ComponentTypes"))) return packages @@ -74,9 +77,27 @@ def create_platform_types(packages: dict[str, ar_element.Package]): packages["PlatformImplementationDataTypes"].append(uint32_impl_type) +def create_mode_declaration_groups(packages: dict[str, ar_element.Package]): + """ + Creates mode declarations + """ + vehicle_mode = ar_element.ModeDeclarationGroup("VehicleMode", ["OFF", + "PARKING", + "ACCESSORY", + "CRANKING", + "RUNNING"]) + packages["ModeDeclarations"].append(vehicle_mode) + vehicle_mode.initial_mode_ref = vehicle_mode.find("OFF").ref() + + application_mode = ar_element.ModeDeclarationGroup("ApplicationMode", ["INACTIVE", + "ACTIVE"]) + packages["ModeDeclarations"].append(application_mode) + application_mode.initial_mode_ref = application_mode.find("INACTIVE").ref() + + def create_vehicle_speed_interface(packages: dict[str, ar_element.Package]) -> ar_element.SenderReceiverInterface: """ - Create sender-receiver port interfaces used in example + Create sender-receiver port interface for vehicle speed """ uint16_impl_t = packages["PlatformImplementationDataTypes"].find("uint16") port_interface = ar_element.SenderReceiverInterface("VehicleSpeed_I") @@ -85,6 +106,64 @@ def create_vehicle_speed_interface(packages: dict[str, ar_element.Package]) -> a return port_interface +def create_engine_speed_interface(packages: dict[str, ar_element.Package]) -> ar_element.SenderReceiverInterface: + """ + Create sender-receiver port interface for engine speed + """ + uint16_impl_t = packages["PlatformImplementationDataTypes"].find("uint16") + port_interface = ar_element.SenderReceiverInterface("EngineSpeed_I") + port_interface.create_data_element("EngineSpeed", type_ref=uint16_impl_t.ref()) + packages["PortInterfaces"].append(port_interface) + return port_interface + + +def create_safe_state_interface(packages: dict[str, ar_element.Package]) -> ar_element.SenderReceiverInterface: + """ + Create sender-receiver port interface for safe state + """ + boolean_impl_t = packages["PlatformImplementationDataTypes"].find("boolean") + port_interface = ar_element.SenderReceiverInterface("SafeState_I") + port_interface.create_data_element("SafeState", type_ref=boolean_impl_t.ref()) + packages["PortInterfaces"].append(port_interface) + return port_interface + + +def create_vehicle_mode_interface(packages: dict[str, ar_element.Package]) -> ar_element.ModeSwitchInterface: + """ + Create mode switch interface + """ + mode_declaration_group = packages["ModeDeclarations"].find("VehicleMode") + portinterface = ar_element.ModeSwitchInterface("VehicleMode_I") + portinterface.create_mode_group("mode", mode_declaration_group.ref()) + packages["PortInterfaces"].append(portinterface) + return portinterface + + +def create_application_mode_interface(packages: dict[str, ar_element.Package]) -> ar_element.ModeSwitchInterface: + """ + Create mode switch interface + """ + mode_declaration_group = packages["ModeDeclarations"].find("ApplicationMode") + portinterface = ar_element.ModeSwitchInterface("ApplicationMode_I") + portinterface.create_mode_group("mode", mode_declaration_group.ref()) + packages["PortInterfaces"].append(portinterface) + return portinterface + + +def create_timer_interface(packages: dict[str, ar_element.Package]) -> ar_element.ClientServerInterface: + """ + Create mode switch interface + """ + uint32_impl_t = packages["PlatformImplementationDataTypes"].find("uint32") + portinterface = ar_element.ClientServerInterface("Timer_I", is_service=False) + packages["PortInterfaces"].append(portinterface) + operation = portinterface.create_operation("GetTime") + operation.create_out_argument("value", + server_arg_impl_policy=ar_enum.ServerArgImplPolicy.USE_ARGUMENT_TYPE, + type_ref=uint32_impl_t.ref()) + return portinterface + + def create_init_value(packages, name: str, value: Any) -> ar_element.ConstantSpecification: """ Creates VehicleSpeed init value @@ -100,6 +179,7 @@ def create_application_swc(packages): """ swc = ar_element.ApplicationSoftwareComponentType("MyApplication") packages["ComponentTypes"].append(swc) + swc.create_internal_behavior("MyApplication_InternalBehavior") return swc @@ -163,5 +243,338 @@ def test_numerical_init_value(self): self.assertEqual(com_spec.init_value.value, 65535) +class TestSwcPortFinderAPI(unittest.TestCase): + + def create_swc(self, workspace: autosar.xml.Workspace) -> ar_element.ApplicationSoftwareComponentType: + packages = create_packages(workspace) + create_platform_types(packages) + vehicle_speed_interface = create_vehicle_speed_interface(packages) + engine_speed_interface = create_engine_speed_interface(packages) + safe_state_interface = create_safe_state_interface(packages) + swc = create_application_swc(packages) + swc.create_provide_port("VehicleSpeed", vehicle_speed_interface, com_spec={'init_value': 65535}) + swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={'init_value': 65535}) + swc.create_pr_port("SafeState", safe_state_interface, provided_com_spec={'init_value': False}) + return swc + + def test_find_r_port(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + self.assertIsInstance(swc, ar_element.ApplicationSoftwareComponentType) + port = swc.find_r_port("EngineSpeed") + self.assertIsInstance(port, ar_element.RequirePortPrototype) + self.assertEqual(port.name, "EngineSpeed") + port = swc.find_r_port("SafeState") + self.assertIsInstance(port, ar_element.PRPortPrototype) + self.assertEqual(port.name, "SafeState") + self.assertIsNone(swc.find_r_port("VehicleSpeed")) + + def test_find_p_port(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + self.assertIsInstance(swc, ar_element.ApplicationSoftwareComponentType) + port = swc.find_p_port("VehicleSpeed") + self.assertIsInstance(port, ar_element.ProvidePortPrototype) + self.assertEqual(port.name, "VehicleSpeed") + port = swc.find_p_port("SafeState") + self.assertIsInstance(port, ar_element.PRPortPrototype) + self.assertEqual(port.name, "SafeState") + self.assertIsNone(swc.find_p_port("EngineSpeed")) + + +class TestRootCollectionAPI(unittest.TestCase): + + def create_swc(self, workspace: autosar.xml.Workspace) -> ar_element.ApplicationSoftwareComponentType: + packages = create_packages(workspace) + create_platform_types(packages) + engine_speed_interface = create_engine_speed_interface(packages) + swc = create_application_swc(packages) + swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={'init_value': 65535}) + return swc + + def test_find_root_from_package(self): + workspace = autosar.xml.Workspace() + packages = create_packages(workspace) + package = packages["PortInterfaces"] + root = package.root_collection() + self.assertIs(root, workspace) + + def test_find_root_from_swc(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + root = swc.root_collection() + self.assertIs(root, workspace) + + def test_find_root_from_port(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + port = swc.find_r_port("EngineSpeed") + root = port.root_collection() + self.assertIs(root, workspace) + + +class TestWorkspaceFinder(unittest.TestCase): + + def create_swc(self, workspace: autosar.xml.Workspace) -> ar_element.ApplicationSoftwareComponentType: + packages = create_packages(workspace) + create_platform_types(packages) + engine_speed_interface = create_engine_speed_interface(packages) + swc = create_application_swc(packages) + swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={'init_value': 65535}) + return swc + + def test_find_port_by_reference(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + port1 = swc.find_r_port("EngineSpeed") + self.assertEqual(str(port1.ref()), "/ComponentTypes/MyApplication/EngineSpeed") + port2 = workspace.find(port1.ref()) + self.assertIs(port1, port2) + + def test_find_port_interface_by_reference(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + port: ar_element.RequirePortPrototype = swc.find_r_port("EngineSpeed") + self.assertEqual(str(port.port_interface_ref), "/PortInterfaces/EngineSpeed_I") + port_interface = workspace.find(port.port_interface_ref) + self.assertIsInstance(port_interface, ar_element.SenderReceiverInterface) + self.assertEqual(port_interface.name, "EngineSpeed_I") + + +class TestPortInterfaceSubElementsGetterAPI(unittest.TestCase): + + def create_swc(self, workspace: autosar.xml.Workspace) -> ar_element.ApplicationSoftwareComponentType: + packages = create_packages(workspace) + create_platform_types(packages) + vehicle_speed_interface = create_vehicle_speed_interface(packages) + engine_speed_interface = create_engine_speed_interface(packages) + swc = create_application_swc(packages) + swc.create_provide_port("VehicleSpeed", vehicle_speed_interface, com_spec={'init_value': 65535}) + swc.create_require_port("EngineSpeed", engine_speed_interface, com_spec={'init_value': 65535}) + return swc + + def test_find_data_element_on_p_port_with_sender_receiver_interface(self): + workspace = autosar.xml.Workspace() + swc = self.create_swc(workspace) + port: ar_element.RequirePortPrototype = swc.find_p_port("VehicleSpeed") + # With data element name + data_element1 = swc.get_data_element_in_port(port, "VehicleSpeed") + self.assertIsInstance(data_element1, ar_element.VariableDataPrototype) + self.assertEqual(str(data_element1.ref()), "/PortInterfaces/VehicleSpeed_I/VehicleSpeed") + # Without data element name + data_element2 = swc.get_data_element_in_port(port) + self.assertIs(data_element1, data_element2) + + +class TestEventCreaterAPI(unittest.TestCase): + + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.expected_behavior_ref = "/ComponentTypes/MyApplication/MyApplication_InternalBehavior" + + def create_swc(self, workspace: autosar.xml.Workspace) -> ar_element.ApplicationSoftwareComponentType: + packages = create_packages(workspace) + create_platform_types(packages) + create_mode_declaration_groups(packages) + engine_speed_interface = create_engine_speed_interface(packages) + vehicle_mode_interface = create_vehicle_mode_interface(packages) + application_mode_interface = create_application_mode_interface(packages) + timer_interface = create_timer_interface(packages) + swc = create_application_swc(packages) + swc.create_r_port("EngineSpeed", engine_speed_interface, com_spec={'init_value': 65535}) + swc.create_r_port("VehicleMode", vehicle_mode_interface, com_spec={'supports_async': False}) + swc.create_p_port("ApplicationMode", application_mode_interface) + swc.create_p_port("Timer", timer_interface) + return swc + + def test_create_background_event(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("background_event_prefix", "BT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Background") + event = behavior.create_background_event("MyApplication_Background") + self.assertIsInstance(event, ar_element.BackgroundEvent) + self.assertEqual(event.name, "BT_MyApplication_Background") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_Background") + + def test_create_data_receive_error_event_using_port_name_only(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("data_receive_error_event_prefix", "DRET_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("EngineSpeed_Updated") + event = behavior.create_data_receive_error_event("EngineSpeed_Updated", "EngineSpeed") + self.assertIsInstance(event, ar_element.DataReceiveErrorEvent) + self.assertEqual(event.name, "DRET_EngineSpeed_Updated_EngineSpeed_EngineSpeed") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/EngineSpeed_Updated") + self.assertEqual(str(event.data.context_port), "/ComponentTypes/MyApplication/EngineSpeed") + self.assertEqual(str(event.data.target_data_element), "/PortInterfaces/EngineSpeed_I/EngineSpeed") + + def test_create_data_receive_error_event_using_port_and_data_element(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("data_receive_error_event_prefix", "DRET_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("EngineSpeed_Updated") + event = behavior.create_data_receive_error_event("EngineSpeed_Updated", "EngineSpeed/EngineSpeed") + self.assertIsInstance(event, ar_element.DataReceiveErrorEvent) + self.assertEqual(event.name, "DRET_EngineSpeed_Updated_EngineSpeed_EngineSpeed") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/EngineSpeed_Updated") + self.assertEqual(str(event.data.context_port), "/ComponentTypes/MyApplication/EngineSpeed") + self.assertEqual(str(event.data.target_data_element), "/PortInterfaces/EngineSpeed_I/EngineSpeed") + + def test_create_data_received_event_using_port_name_only(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("data_receive_event_prefix", "DRT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("EngineSpeed_Updated") + event = behavior.create_data_received_event("EngineSpeed_Updated", "EngineSpeed") + self.assertIsInstance(event, ar_element.DataReceivedEvent) + self.assertEqual(event.name, "DRT_EngineSpeed_Updated_EngineSpeed_EngineSpeed") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/EngineSpeed_Updated") + self.assertEqual(str(event.data.context_port), "/ComponentTypes/MyApplication/EngineSpeed") + self.assertEqual(str(event.data.target_data_element), "/PortInterfaces/EngineSpeed_I/EngineSpeed") + + def test_create_data_received_event_using_port_and_data_element(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("data_receive_event_prefix", "DRT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("EngineSpeed_Updated") + event = behavior.create_data_received_event("EngineSpeed_Updated", "EngineSpeed/EngineSpeed") + self.assertIsInstance(event, ar_element.DataReceivedEvent) + self.assertEqual(event.name, "DRT_EngineSpeed_Updated_EngineSpeed_EngineSpeed") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/EngineSpeed_Updated") + self.assertEqual(str(event.data.context_port), "/ComponentTypes/MyApplication/EngineSpeed") + self.assertEqual(str(event.data.target_data_element), "/PortInterfaces/EngineSpeed_I/EngineSpeed") + + def test_create_init_event(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("init_event_prefix", "IT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Init") + event = behavior.create_init_event("MyApplication_Init") + self.assertIsInstance(event, ar_element.InitEvent) + self.assertEqual(event.name, "IT_MyApplication_Init") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_Init") + + def test_create_operation_invoked_event_port_name_only(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("operation_invoked_event_prefix", "OIT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_GetTime") + event = behavior.create_operation_invoked_event("MyApplication_GetTime", "Timer") + self.assertIsInstance(event, ar_element.OperationInvokedEvent) + self.assertEqual(event.name, "OIT_MyApplication_GetTime_Timer_GetTime") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_GetTime") + self.assertEqual(str(event.operation.context_port), "/ComponentTypes/MyApplication/Timer") + self.assertEqual(str(event.operation.target_provided_operation), "/PortInterfaces/Timer_I/GetTime") + + def test_create_operation_invoked_event_with_operation_name(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("operation_invoked_event_prefix", "OIT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_GetTime") + event = behavior.create_operation_invoked_event("MyApplication_GetTime", "Timer/GetTime") + self.assertIsInstance(event, ar_element.OperationInvokedEvent) + self.assertEqual(event.name, "OIT_MyApplication_GetTime_Timer_GetTime") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_GetTime") + self.assertEqual(str(event.operation.context_port), "/ComponentTypes/MyApplication/Timer") + self.assertEqual(str(event.operation.target_provided_operation), "/PortInterfaces/Timer_I/GetTime") + + def test_create_swc_mode_manager_error_event(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("swc_mode_manager_error_event_prefix", "MMET_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_ApplicationModeError") + event = behavior.create_swc_mode_manager_error_event("MyApplication_ApplicationModeError", "ApplicationMode") + self.assertIsInstance(event, ar_element.SwcModeManagerErrorEvent) + self.assertEqual(event.name, "MMET_MyApplication_ApplicationModeError_ApplicationMode_mode",) + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_ApplicationModeError") + self.assertEqual(str(event.mode_group.context_port), "/ComponentTypes/MyApplication/ApplicationMode") + self.assertEqual(str(event.mode_group.context_mode_declaration_group_prototype), + "/PortInterfaces/ApplicationMode_I/mode") + + def test_create_swc_mode_switch_event(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("swc_mode_switch_event_prefix", "MST_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Init") + event = behavior.create_swc_mode_mode_switch_event("MyApplication_Init", + "VehicleMode/ACCESSORY") + self.assertIsInstance(event, ar_element.SwcModeSwitchEvent) + self.assertEqual(event.name, "MST_MyApplication_Init",) + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_Init") + self.assertEqual(str(event.mode.context_port), "/ComponentTypes/MyApplication/VehicleMode") + self.assertEqual(str(event.mode.context_mode_declaration_group_prototype), "/PortInterfaces/VehicleMode_I/mode") + self.assertEqual(str(event.mode.target_mode_declaration), "/ModeDeclarations/VehicleMode/ACCESSORY") + + def test_create_swc_mode_switch_event_with_transition(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("swc_mode_switch_event_prefix", "MST_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Init") + event = behavior.create_swc_mode_mode_switch_event("MyApplication_Init", + ["VehicleMode/PARKING", "VehicleMode/ACCESSORY"]) + self.assertIsInstance(event, ar_element.SwcModeSwitchEvent) + self.assertEqual(event.name, "MST_MyApplication_Init",) + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_Init") + self.assertEqual(str(event.mode[0].context_port), "/ComponentTypes/MyApplication/VehicleMode") + self.assertEqual(str(event.mode[0].context_mode_declaration_group_prototype), + "/PortInterfaces/VehicleMode_I/mode") + self.assertEqual(str(event.mode[0].target_mode_declaration), "/ModeDeclarations/VehicleMode/PARKING") + self.assertEqual(str(event.mode[1].context_port), "/ComponentTypes/MyApplication/VehicleMode") + self.assertEqual(str(event.mode[1].context_mode_declaration_group_prototype), + "/PortInterfaces/VehicleMode_I/mode") + self.assertEqual(str(event.mode[1].target_mode_declaration), "/ModeDeclarations/VehicleMode/ACCESSORY") + + def test_create_multiple_swc_mode_switch_events_with_same_base_name(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("swc_mode_switch_event_prefix", "MST_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Init") + event1 = behavior.create_swc_mode_mode_switch_event("MyApplication_Init", + "VehicleMode/ACCESSORY", + ar_enum.ModeActivationKind.ON_ENTRY) + event2 = behavior.create_swc_mode_mode_switch_event("MyApplication_Init", + "VehicleMode/PARKING", + ar_enum.ModeActivationKind.ON_ENTRY) + event3 = behavior.create_swc_mode_mode_switch_event("MyApplication_Init", + "VehicleMode/RUNNING", + ar_enum.ModeActivationKind.ON_ENTRY) + + self.assertIsInstance(event1, ar_element.SwcModeSwitchEvent) + self.assertIsInstance(event2, ar_element.SwcModeSwitchEvent) + self.assertIsInstance(event3, ar_element.SwcModeSwitchEvent) + self.assertEqual(event1.name, "MST_MyApplication_Init_0",) + self.assertEqual(event2.name, "MST_MyApplication_Init_1",) + self.assertEqual(event3.name, "MST_MyApplication_Init_2",) + self.assertEqual(str(event1.mode.target_mode_declaration), "/ModeDeclarations/VehicleMode/ACCESSORY") + self.assertEqual(str(event2.mode.target_mode_declaration), "/ModeDeclarations/VehicleMode/PARKING") + self.assertEqual(str(event3.mode.target_mode_declaration), "/ModeDeclarations/VehicleMode/RUNNING") + + def test_create_timing_event_without_offset(self): + workspace = autosar.xml.Workspace() + workspace.behavior_settings.set_value("timing_event_prefix", "TMT_") + swc = self.create_swc(workspace) + behavior = swc.internal_behavior + behavior.create_runnable("MyApplication_Run") + event = behavior.create_timing_event("MyApplication_Run", 0.02) + self.assertIsInstance(event, ar_element.TimingEvent) + self.assertEqual(event.name, "TMT_MyApplication_Run") + self.assertEqual(str(event.start_on_event), self.expected_behavior_ref + "/MyApplication_Run") + self.assertAlmostEqual(event.period, 0.02) + self.assertIsNone(event.offset) + + if __name__ == '__main__': unittest.main() diff --git a/tests/xml/test_software_component_elements.py b/tests/xml/test_software_component_elements.py index 2c053fa..d94b92b 100644 --- a/tests/xml/test_software_component_elements.py +++ b/tests/xml/test_software_component_elements.py @@ -10,7 +10,7 @@ import autosar # noqa E402 -class TestTestModeSwitchedAckRequest(unittest.TestCase): +class TestModeSwitchedAckRequest(unittest.TestCase): def test_empty(self): element = ar_element.ModeSwitchedAckRequest() @@ -2051,5 +2051,65 @@ def test_required_rte_vendor(self): self.assertEqual(str(elem.required_rte_vendor), vendor_name) +class TestRModeInAtomicSwcInstanceRef(unittest.TestCase): + + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.xml_tag = "DISABLED-MODE-IREF" + + def test_empty(self): + element = ar_element.RModeInAtomicSwcInstanceRef() + writer = autosar.xml.Writer() + xml = writer.write_str_elem(element, self.xml_tag) + self.assertEqual(xml, '') + reader = autosar.xml.Reader() + elem: ar_element.RModeInAtomicSwcInstanceRef = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RModeInAtomicSwcInstanceRef) + + def test_context_port(self): + ref_str = "/Components/ComponentName/RequirePortName" + port_ref = ar_element.PortPrototypeRef(ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + element = ar_element.RModeInAtomicSwcInstanceRef(context_port=port_ref) + writer = autosar.xml.Writer() + xml = f''' + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element, self.xml_tag), xml) + reader = autosar.xml.Reader() + elem: ar_element.RModeInAtomicSwcInstanceRef = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(elem.context_port), ref_str) + self.assertEqual(elem.context_port.dest, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + + def test_context_mode_declaration_group_prototype(self): + ref_str = "/ModeDeclarationGroups/ModeDeclarationGroupName" + mode_decl_ref = ar_element.ModeDeclarationGroupPrototypeRef(ref_str) + element = ar_element.RModeInAtomicSwcInstanceRef(context_mode_declaration_group_prototype=mode_decl_ref) + writer = autosar.xml.Writer() + tag = "CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF" + xml = f''' + <{tag} DEST="MODE-DECLARATION-GROUP-PROTOTYPE">{ref_str} +''' + self.assertEqual(writer.write_str_elem(element, self.xml_tag), xml) + reader = autosar.xml.Reader() + elem: ar_element.RModeInAtomicSwcInstanceRef = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(elem.context_mode_declaration_group_prototype), ref_str) + + def test_target_mode_declaration(self): + ref_str = "/ModeDeclarationGroups/ModeDeclarationGroupName/ModeName" + mode_ref = ar_element.ModeDeclarationRef(ref_str) + element = ar_element.RModeInAtomicSwcInstanceRef(target_mode_declaration=mode_ref) + writer = autosar.xml.Writer() + xml = f''' + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element, self.xml_tag), xml) + reader = autosar.xml.Reader() + elem: ar_element.RModeInAtomicSwcInstanceRef = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(elem.target_mode_declaration), ref_str) + + if __name__ == '__main__': unittest.main() diff --git a/tests/xml/test_swc_internal_behavior.py b/tests/xml/test_swc_internal_behavior.py index b494b84..cb75d36 100644 --- a/tests/xml/test_swc_internal_behavior.py +++ b/tests/xml/test_swc_internal_behavior.py @@ -226,5 +226,1622 @@ def test_local_variable_ref(self): self.assertIsInstance(elem.local_variable_ref, ar_element.VariableDataPrototypeRef) +class TestExecutableEntityActivationReason(unittest.TestCase): + + def test_read_write_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.ExecutableEntityActivationReason('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExecutableEntityActivationReason = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExecutableEntityActivationReason) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_read_write_bit_position(self): + writer = autosar.xml.Writer() + element = ar_element.ExecutableEntityActivationReason('MyName', bit_position=0) + xml = ''' + MyName + 0 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExecutableEntityActivationReason = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExecutableEntityActivationReason) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.bit_position, 0) + + +class TestExclusiveAreaRefConditional(unittest.TestCase): + + def test_empty(self): + element = ar_element.ExclusiveAreaRefConditional() + writer = autosar.xml.Writer() + xml = writer.write_str_elem(element) + self.assertEqual(xml, '') + reader = autosar.xml.Reader() + elem: ar_element.ExclusiveAreaRefConditional = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExclusiveAreaRefConditional) + + def test_exclusive_area_ref_from_str(self): + ref_str = "/ExclusiveAreas/AreaName" + element = ar_element.ExclusiveAreaRefConditional(ref_str) + writer = autosar.xml.Writer() + xml = f''' + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExclusiveAreaRefConditional = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(elem.exclusive_area_ref), ref_str) + + +class TestExecutableEntity(unittest.TestCase): + """ + ExecutableEntity is a base class. Use RunnableEntity + for unit testing. + """ + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_activation_reasons_from_element(self): + writer = autosar.xml.Writer() + reason = ar_element.ExecutableEntityActivationReason("MyReason", 1, symbol="MySymbol") + element = ar_element.RunnableEntity('MyName', activation_reasons=reason) + xml = ''' + MyName + + + MyReason + MySymbol + 1 + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.activation_reasons), 1) + activation_reason = elem.activation_reasons[0] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason') + + def test_activation_reasons_from_list(self): + writer = autosar.xml.Writer() + reasons = [ar_element.ExecutableEntityActivationReason("MyReason1", 0, symbol="MySymbol1"), + ar_element.ExecutableEntityActivationReason("MyReason2", 1, symbol="MySymbol2")] + element = ar_element.RunnableEntity('MyName', activation_reasons=reasons) + xml = ''' + MyName + + + MyReason1 + MySymbol1 + 0 + + + MyReason2 + MySymbol2 + 1 + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.activation_reasons), 2) + activation_reason = elem.activation_reasons[0] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason1') + activation_reason = elem.activation_reasons[1] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason2') + + def test_can_enters_from_element(self): + """ + CAN-ENTERS is used for XML schema version >= 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_can_enters_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_can_enter_exclusive_area_from_element(self): + """ + CAN-ENTER-EXCLUSIVE-AREA-REFS is used for XML schema version < 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_can_enter_exclusive_area_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + # During XML reading, elements of type ExclusiveAreaRef are automatically wrapped + # inside the newer ExclusiveAreaRefConditional element + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_can_enter_create_directly_from_reference_string(self): + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + + def test_can_enter_create_from_list_of_reference_strings(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', can_enter_leave=[ref_str1, ref_str2]) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + + def test_exclusive_area_nesting_order_refs_from_element(self): + ref_str = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder" + writer = autosar.xml.Writer() + exclusive_area_nesting_order = ar_element.ExclusiveAreaNestingOrderRef(ref_str) + element = ar_element.RunnableEntity('MyName', exclusive_area_nesting_order=exclusive_area_nesting_order) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.exclusive_area_nesting_order), 1) + nesting_order: ar_element.ExclusiveAreaNestingOrderRef = elem.exclusive_area_nesting_order[0] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str) + + def test_exclusive_area_nesting_order_refs_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder1" + writer = autosar.xml.Writer() + exclusive_area_nesting_order = [ar_element.ExclusiveAreaNestingOrderRef(ref_str1), + ar_element.ExclusiveAreaNestingOrderRef(ref_str1)] + element = ar_element.RunnableEntity('MyName', exclusive_area_nesting_order=exclusive_area_nesting_order) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.exclusive_area_nesting_order), 2) + nesting_order: ar_element.ExclusiveAreaNestingOrderRef = elem.exclusive_area_nesting_order[0] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str1) + nesting_order = elem.exclusive_area_nesting_order[1] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str2) + + def test_minimum_start_interval_100ms(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', minimum_start_interval=0.1) + xml = ''' + MyName + 0.1 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertAlmostEqual(elem.minimum_start_interval, 0.1) + + def test_minimum_start_interval_2s(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', minimum_start_interval=2) + xml = ''' + MyName + 2 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.minimum_start_interval, 2) + + def test_reentrancy_level(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', + reentrancy_level=ar_enum.ReentrancyLevel.SINGLE_CORE_REENTRANT) + xml = ''' + MyName + SINGLE-CORE-REENTRANT +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.reentrancy_level, ar_enum.ReentrancyLevel.SINGLE_CORE_REENTRANT) + + def test_runs_insides_from_element(self): + """ + RUNS-INSIDES is used for XML schema version >= 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_runs_insides_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_runs_inside_exclusive_area_from_element(self): + """ + RUNS-INSIDE-EXCLUSIVE-AREA-REFS is used for XML schema version < 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_run_insides_exclusive_area_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + # During XML reading, elements of type ExclusiveAreaRef are automatically wrapped + # inside the newer ExclusiveAreaRefConditional element + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_sw_addr_method_from_element(self): + ref_str = '/SwAddrMethods/DEFAULT' + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', + sw_addr_method=ar_element.SwAddrMethodRef(ref_str)) + xml = f''' + MyName + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + ref = elem.sw_addr_method + self.assertEqual(ref.value, '/SwAddrMethods/DEFAULT') + self.assertEqual(ref.dest, ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD) + + def test_create_sw_addr_method_from_string(self): + ref_str = '/SwAddrMethods/DEFAULT' + element = ar_element.RunnableEntity('MyName', sw_addr_method=ref_str) + ref = element.sw_addr_method + self.assertEqual(ref.value, '/SwAddrMethods/DEFAULT') + self.assertEqual(ref.dest, ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD) + + +class TestInitEvent(unittest.TestCase): + """ + Tests elements from RTEEvent base class. + InitEvent doesn't have any additional elements except those inherited + from RTEEvent. + """ + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.InitEvent('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InitEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InitEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_disabled_modes_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + target_mode_decl_ref_str = "/ModeDclrGroups/BswM_Mode/POSTRUN" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + context_mode_decl_group = ar_element.ModeDeclarationGroupPrototypeRef(context_mode_decl_group_ref_str) + target_mode_decl = ar_element.ModeDeclarationRef(target_mode_decl_ref_str) + disabled_mode = ar_element.RModeInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group, + target_mode_declaration=target_mode_decl) + element = ar_element.InitEvent('MyName', + disabled_modes=disabled_mode) + writer = autosar.xml.Writer() + xml = f''' + MyName + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InitEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InitEvent) + self.assertEqual(len(elem.disabled_modes), 1) + child = elem.disabled_modes[0] + self.assertIsInstance(child, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(child.target_mode_declaration), target_mode_decl_ref_str) + + def test_disabled_modes_from_list(self): + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + target_mode_decl_refs = ["/ModeDclrGroups/BswM_Mode/POSTRUN", + "/ModeDclrGroups/BswM_Mode/STARTUP", + "/ModeDclrGroups/BswM_Mode/SHUTDOWN", + ] + disabled_modes = [] + for target_mode_decl_ref in target_mode_decl_refs: + context_port = ar_element.PortPrototypeRef(context_port_ref_str, + ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + context_mode_decl_group = ar_element.ModeDeclarationGroupPrototypeRef(context_mode_decl_group_ref_str) + target_mode_decl = ar_element.ModeDeclarationRef(target_mode_decl_ref) + disabled_modes.append(ar_element.RModeInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group, + target_mode_declaration=target_mode_decl)) + element = ar_element.InitEvent('MyName', + disabled_modes=disabled_modes) + writer = autosar.xml.Writer() + xml = f''' + MyName + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_refs[0]} + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_refs[1]} + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_refs[2]} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InitEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InitEvent) + self.assertEqual(len(elem.disabled_modes), 3) + child = elem.disabled_modes[0] + self.assertIsInstance(child, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(child.target_mode_declaration), target_mode_decl_refs[0]) + child = elem.disabled_modes[1] + self.assertIsInstance(child, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(child.target_mode_declaration), target_mode_decl_refs[1]) + child = elem.disabled_modes[2] + self.assertIsInstance(child, ar_element.RModeInAtomicSwcInstanceRef) + self.assertEqual(str(child.target_mode_declaration), target_mode_decl_refs[2]) + + def test_start_on_event(self): + ref_str = '/ComponentTypes/MyComponent/MyComponent_InternalBehavior/MyComponent_Init' + element = ar_element.InitEvent('MyName', + start_on_event=ar_element.RunnableEntityRef(ref_str)) + writer = autosar.xml.Writer() + xml = f''' + MyName + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InitEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InitEvent) + self.assertEqual(str(elem.start_on_event), ref_str) + + +class TestDataReceiveErrorEvent(unittest.TestCase): + """ + Base elements are tested in TestInitEvent + """ + + def test_name_only(self): + element = ar_element.DataReceiveErrorEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceiveErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataReceiveErrorEvent) + self.assertEqual(elem.name, 'MyName') + + def test_data_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/CurrentWorkload" + target_data_element_str = "/PortInterfaces/CurrentWorkload_I/CurrentWorkload" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + target_data_element = ar_element.VariableDataPrototypeRef(target_data_element_str) + data = ar_element.RVariableInAtomicSwcInstanceRef(context_port=context_port, + target_data_element=target_data_element) + element = ar_element.DataReceiveErrorEvent('MyName', + data=data) + xml = f''' + MyName + + {context_port_ref_str} + {target_data_element_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceiveErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataReceiveErrorEvent) + inner: ar_element.RVariableInAtomicSwcInstanceRef = elem.data + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_data_element), target_data_element_str) + + def test_create_using_conveneince_method(self): + start_on_event_ref_str = "/ComponentTypes/MyComponent/InternalBehavior/MyRunnable" + context_port_ref_str = "/ComponentTypes/MyComponent/CurrentWorkload" + target_data_element_str = "/PortInterfaces/CurrentWorkload_I/CurrentWorkload" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + element = ar_element.DataReceiveErrorEvent.make('MyName', + start_on_event_ref_str, + context_port, + target_data_element_str) + xml = f''' + MyName + {start_on_event_ref_str} + + {context_port_ref_str} + {target_data_element_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceiveErrorEvent = reader.read_str_elem(xml) + self.assertEqual(str(elem.start_on_event), start_on_event_ref_str) + self.assertIsInstance(elem, ar_element.DataReceiveErrorEvent) + inner: ar_element.RVariableInAtomicSwcInstanceRef = elem.data + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_data_element), target_data_element_str) + + +class TestDataReceivedEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.DataReceivedEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceivedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataReceivedEvent) + self.assertEqual(elem.name, 'MyName') + + def test_data_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/CurrentWorkload" + target_data_element_str = "/PortInterfaces/CurrentWorkload_I/CurrentWorkload" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + target_data_element = ar_element.VariableDataPrototypeRef(target_data_element_str) + data = ar_element.RVariableInAtomicSwcInstanceRef(context_port=context_port, + target_data_element=target_data_element) + element = ar_element.DataReceivedEvent('MyName', + data=data) + xml = f''' + MyName + + {context_port_ref_str} + {target_data_element_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceivedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataReceivedEvent) + inner: ar_element.RVariableInAtomicSwcInstanceRef = elem.data + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_data_element), target_data_element_str) + + def test_create_using_conveneince_method(self): + start_on_event_ref_str = "/ComponentTypes/MyComponent/InternalBehavior/MyRunnable" + context_port_ref_str = "/ComponentTypes/MyComponent/CurrentWorkload" + target_data_element_str = "/PortInterfaces/CurrentWorkload_I/CurrentWorkload" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + element = ar_element.DataReceivedEvent.make('MyName', + start_on_event_ref_str, + context_port, + target_data_element_str) + xml = f''' + MyName + {start_on_event_ref_str} + + {context_port_ref_str} + {target_data_element_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataReceivedEvent = reader.read_str_elem(xml) + self.assertEqual(str(elem.start_on_event), start_on_event_ref_str) + self.assertIsInstance(elem, ar_element.DataReceivedEvent) + inner: ar_element.RVariableInAtomicSwcInstanceRef = elem.data + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_data_element), target_data_element_str) + + +class TestDataSendCompletedEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.DataSendCompletedEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataSendCompletedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataSendCompletedEvent) + self.assertEqual(elem.name, 'MyName') + + def test_event_source(self): + variable_access_ref_str = "/ComponentTypes/MyComponent/MyComponent_InternalBehavior/run/SEND_ButtonPressed" + variable_access_ref = ar_element.VariableAccessRef(variable_access_ref_str) + element = ar_element.DataSendCompletedEvent('MyName', event_source=variable_access_ref) + xml = f''' + MyName + {variable_access_ref_str} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataSendCompletedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataSendCompletedEvent) + self.assertEqual(str(elem.event_source), variable_access_ref_str) + + +class TestDataWriteCompletedEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.DataWriteCompletedEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataWriteCompletedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataWriteCompletedEvent) + self.assertEqual(elem.name, 'MyName') + + def test_event_source(self): + variable_access_ref_str = "/ComponentTypes/MyComponent/MyComponent_InternalBehavior/run/SEND_ButtonPressed" + variable_access_ref = ar_element.VariableAccessRef(variable_access_ref_str) + element = ar_element.DataWriteCompletedEvent('MyName', event_source=variable_access_ref) + xml = f''' + MyName + {variable_access_ref_str} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.DataWriteCompletedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.DataWriteCompletedEvent) + self.assertEqual(str(elem.event_source), variable_access_ref_str) + + +class TestModeSwitchedAckEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.ModeSwitchedAckEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ModeSwitchedAckEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ModeSwitchedAckEvent) + self.assertEqual(elem.name, 'MyName') + + def test_event_source(self): + mode_switch_point_ref_str = "/ComponentTypes/MyComponent/MyComponent_InternalBehavior" \ + "/ack/SWITCH_ModePortName_ModeGroupName" + variable_access_ref = ar_element.ModeSwitchPointRef(mode_switch_point_ref_str) + element = ar_element.ModeSwitchedAckEvent('MyName', event_source=variable_access_ref) + xml = f''' + MyName + {mode_switch_point_ref_str} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ModeSwitchedAckEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ModeSwitchedAckEvent) + self.assertEqual(str(elem.event_source), mode_switch_point_ref_str) + + +class TestOperationInvokedEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.OperationInvokedEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.OperationInvokedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.OperationInvokedEvent) + self.assertEqual(elem.name, 'MyName') + + def test_operation_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/StoredData" + target_operation_ref_str = "/PortInterfaces/StoredData_I/Read" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + target_operation = ar_element.ClientServerOperationRef(target_operation_ref_str) + operation = ar_element.POperationInAtomicSwcInstanceRef(context_port=context_port, + target_provided_operation=target_operation) + element = ar_element.OperationInvokedEvent('MyName', + operation=operation) + dest_str = "CLIENT-SERVER-OPERATION" + xml = f''' + MyName + + {context_port_ref_str} + {target_operation_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.OperationInvokedEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.OperationInvokedEvent) + inner: ar_element.POperationInAtomicSwcInstanceRef = elem.operation + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_provided_operation), target_operation_ref_str) + + def test_create_using_conveneince_method(self): + start_on_event_ref_str = "/ComponentTypes/MyComponent/InternalBehavior/MyRunnable" + context_port_ref_str = "/ComponentTypes/MyComponent/StoredData" + target_operation_ref_str = "/PortInterfaces/StoredData_I/Read" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + element = ar_element.OperationInvokedEvent.make('MyName', + start_on_event_ref_str, + context_port, + target_operation_ref_str) + dest_str = "CLIENT-SERVER-OPERATION" + xml = f''' + MyName + {start_on_event_ref_str} + + {context_port_ref_str} + {target_operation_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.OperationInvokedEvent = reader.read_str_elem(xml) + self.assertEqual(str(elem.start_on_event), start_on_event_ref_str) + self.assertIsInstance(elem, ar_element.OperationInvokedEvent) + inner: ar_element.POperationInAtomicSwcInstanceRef = elem.operation + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_provided_operation), target_operation_ref_str) + + +class TestSwcModeSwitchEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.SwcModeSwitchEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeSwitchEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeSwitchEvent) + self.assertEqual(elem.name, 'MyName') + + def test_activation(self): + element = ar_element.SwcModeSwitchEvent('MyName', + activation=ar_enum.ModeActivationKind.ON_ENTRY) + writer = autosar.xml.Writer() + xml = ''' + MyName + ON-ENTRY +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeSwitchEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeSwitchEvent) + self.assertEqual(elem.activation, ar_enum.ModeActivationKind.ON_ENTRY) + + def test_mode_from_single_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + target_mode_decl_ref_str = "/ModeDclrGroups/BswM_Mode/POSTRUN" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + context_mode_decl_group = ar_element.ModeDeclarationGroupPrototypeRef(context_mode_decl_group_ref_str) + target_mode_decl = ar_element.ModeDeclarationRef(target_mode_decl_ref_str) + mode_instance = ar_element.RModeInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group, + target_mode_declaration=target_mode_decl) + element = ar_element.SwcModeSwitchEvent('MyName', + mode=mode_instance) + xml = f''' + MyName + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_ref_str} + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeSwitchEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeSwitchEvent) + mode: ar_element.RModeInAtomicSwcInstanceRef = elem.mode + self.assertEqual(str(mode.context_port), context_port_ref_str) + self.assertEqual(str(mode.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + self.assertEqual(str(mode.target_mode_declaration), target_mode_decl_ref_str) + + def test_mode_from_tuple_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + target_mode_decl_ref_str1 = "/ModeDclrGroups/BswM_Mode/RUN" + target_mode_decl_ref_str2 = "/ModeDclrGroups/BswM_Mode/POSTRUN" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + context_mode_decl_group = ar_element.ModeDeclarationGroupPrototypeRef(context_mode_decl_group_ref_str) + target_mode_decl1 = ar_element.ModeDeclarationRef(target_mode_decl_ref_str1) + target_mode_decl2 = ar_element.ModeDeclarationRef(target_mode_decl_ref_str2) + mode_instance1 = ar_element.RModeInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group, + target_mode_declaration=target_mode_decl1) + mode_instance2 = ar_element.RModeInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group, + target_mode_declaration=target_mode_decl2) + element = ar_element.SwcModeSwitchEvent('MyName', + mode=(mode_instance1, mode_instance2)) + xml = f''' + MyName + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_ref_str1} + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_ref_str2} + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeSwitchEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeSwitchEvent) + mode: ar_element.RModeInAtomicSwcInstanceRef = elem.mode[0] + self.assertEqual(str(mode.context_port), context_port_ref_str) + self.assertEqual(str(mode.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + self.assertEqual(str(mode.target_mode_declaration), target_mode_decl_ref_str1) + mode = elem.mode[1] + self.assertEqual(str(mode.context_port), context_port_ref_str) + self.assertEqual(str(mode.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + self.assertEqual(str(mode.target_mode_declaration), target_mode_decl_ref_str2) + + def test_create_using_conveneince_method(self): + start_on_event_ref_str = "/ComponentTypes/MyComponent/InternalBehavior/MyRunnable" + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + target_mode_decl_ref_str = "/ModeDclrGroups/BswM_Mode/RUN" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + context_mode_decl_group = ar_element.ModeDeclarationGroupPrototypeRef(context_mode_decl_group_ref_str) + target_mode_decl = ar_element.ModeDeclarationRef(target_mode_decl_ref_str) + element = ar_element.SwcModeSwitchEvent.make('MyName', + start_on_event_ref_str, + ar_enum.ModeActivationKind.ON_ENTRY, + context_port, + context_mode_decl_group, + target_mode_decl) + xml = f''' + MyName + {start_on_event_ref_str} + ON-ENTRY + + + {context_port_ref_str} + \ +{context_mode_decl_group_ref_str} + {target_mode_decl_ref_str} + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeSwitchEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeSwitchEvent) + mode: ar_element.RModeInAtomicSwcInstanceRef = elem.mode + self.assertEqual(str(mode.context_port), context_port_ref_str) + self.assertEqual(str(mode.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + self.assertEqual(str(mode.target_mode_declaration), target_mode_decl_ref_str) + + +class TestTimingEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.TimingEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TimingEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TimingEvent) + self.assertEqual(elem.name, 'MyName') + + def test_offset_from_int(self): + offset = 1 + element = ar_element.TimingEvent('MyName', offset=offset) + xml = f''' + MyName + {offset} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TimingEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TimingEvent) + self.assertAlmostEqual(elem.offset, offset) + + def test_offset_from_float(self): + offset = 0.1 + element = ar_element.TimingEvent('MyName', offset=offset) + xml = f''' + MyName + {offset} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TimingEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TimingEvent) + self.assertAlmostEqual(elem.offset, offset) + + def test_period_from_int(self): + period = 1 + element = ar_element.TimingEvent('MyName', period=period) + xml = f''' + MyName + {period} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TimingEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TimingEvent) + self.assertAlmostEqual(elem.period, period) + + def test_period_from_float(self): + period = 0.1 + element = ar_element.TimingEvent('MyName', period=period) + xml = f''' + MyName + {period} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TimingEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TimingEvent) + self.assertAlmostEqual(elem.period, period) + + +class TestAsynchronousServerCallReturnsEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.AsynchronousServerCallReturnsEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.AsynchronousServerCallReturnsEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.AsynchronousServerCallReturnsEvent) + self.assertEqual(elem.name, 'MyName') + + def test_event_source(self): + srv_call_result_point_ref_str = "/ComponentTypes/MyComponent/MyComponent_InternalBehavior/SRV_ResultPoint" + srv_call_result_point_ref = ar_element.AsynchronousServerCallResultPointRef(srv_call_result_point_ref_str) + element = ar_element.AsynchronousServerCallReturnsEvent('MyName', event_source=srv_call_result_point_ref) + dest_str = "ASYNCHRONOUS-SERVER-CALL-RESULT-POINT" + xml = f''' + MyName + {srv_call_result_point_ref_str} +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.AsynchronousServerCallReturnsEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.AsynchronousServerCallReturnsEvent) + self.assertEqual(str(elem.event_source), srv_call_result_point_ref_str) + + +class TestBackgroundEvent(unittest.TestCase): + """ + This event doesn't have any additional elements outside its base class. + """ + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.BackgroundEvent('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.BackgroundEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.BackgroundEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + +class TestExternalTriggerOccurredEvent(unittest.TestCase): + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.ExternalTriggerOccurredEvent('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExternalTriggerOccurredEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExternalTriggerOccurredEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_data_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/MyPort" + target_trigger_ref_str = "/Triggers/MyTrigger" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + target_trigger = ar_element.TriggerRef(target_trigger_ref_str) + trigger = ar_element.RTriggerInAtomicSwcInstanceRef(context_port=context_port, + target_trigger=target_trigger) + element = ar_element.ExternalTriggerOccurredEvent('MyName', + trigger=trigger) + xml = f''' + MyName + + {context_port_ref_str} + {target_trigger_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExternalTriggerOccurredEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExternalTriggerOccurredEvent) + inner: ar_element.RTriggerInAtomicSwcInstanceRef = elem.trigger + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_trigger), target_trigger_ref_str) + + def test_create_using_conveneince_method(self): + context_port_ref_str = "/ComponentTypes/MyComponent/MyPort" + target_trigger_ref_str = "/Triggers/MyTrigger" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + element = ar_element.ExternalTriggerOccurredEvent.make('MyName', + context_port=context_port, + target_trigger=target_trigger_ref_str) + xml = f''' + MyName + + {context_port_ref_str} + {target_trigger_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExternalTriggerOccurredEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExternalTriggerOccurredEvent) + inner: ar_element.RTriggerInAtomicSwcInstanceRef = elem.trigger + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_trigger), target_trigger_ref_str) + + +class TestInternalTriggerOccurredEvent(unittest.TestCase): + + def test_name_only(self): + element = ar_element.InternalTriggerOccurredEvent('MyName') + writer = autosar.xml.Writer() + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InternalTriggerOccurredEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InternalTriggerOccurredEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_event_source(self): + target_trigger_ref_str = "/Triggers/MyTrigger" + writer = autosar.xml.Writer() + element = ar_element.InternalTriggerOccurredEvent('MyName', + event_source=target_trigger_ref_str) + xml = f''' + MyName + {target_trigger_ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.InternalTriggerOccurredEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.InternalTriggerOccurredEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + +class TestSwcModeManagerErrorEvent(unittest.TestCase): + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.SwcModeManagerErrorEvent('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeManagerErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeManagerErrorEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_mode_group_from_element(self): + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + mode_instance = ar_element.PModeGroupInAtomicSwcInstanceRef( + context_port=context_port, + context_mode_declaration_group_prototype=context_mode_decl_group_ref_str) + element = ar_element.SwcModeManagerErrorEvent('MyName', + mode_group=mode_instance) + tag = "CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF" + xml = f''' + MyName + + {context_port_ref_str} + <{tag} DEST="MODE-DECLARATION-GROUP-PROTOTYPE">{context_mode_decl_group_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeManagerErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeManagerErrorEvent) + mode_group: ar_element.PModeGroupInAtomicSwcInstanceRef = elem.mode_group + self.assertEqual(str(mode_group.context_port), context_port_ref_str) + self.assertEqual(str(mode_group.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + + def test_mode_group_using_convenience_method(self): + start_on_event_ref_str = "/ComponentTypes/MyComponent/InternalBehavior/MyRunnable" + context_port_ref_str = "/ComponentTypes/MyComponent/BswM_Mode" + context_mode_decl_group_ref_str = "/PortInterfaces/BswM_ModeSwitchInterface/BswM_Mode" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + element = ar_element.SwcModeManagerErrorEvent.make('MyName', + start_on_event_ref_str, + context_port, + context_mode_decl_group_ref_str) + tag = "CONTEXT-MODE-DECLARATION-GROUP-PROTOTYPE-REF" + xml = f''' + MyName + {start_on_event_ref_str} + + {context_port_ref_str} + <{tag} DEST="MODE-DECLARATION-GROUP-PROTOTYPE">{context_mode_decl_group_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcModeManagerErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcModeManagerErrorEvent) + self.assertEqual(str(elem.start_on_event), start_on_event_ref_str) + mode_group: ar_element.PModeGroupInAtomicSwcInstanceRef = elem.mode_group + self.assertEqual(str(mode_group.context_port), context_port_ref_str) + self.assertEqual(str(mode_group.context_mode_declaration_group_prototype), context_mode_decl_group_ref_str) + + +class TestTransformerHardErrorEvent(unittest.TestCase): + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.TransformerHardErrorEvent('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TransformerHardErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TransformerHardErrorEvent) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_operation(self): + context_port_ref_str = "/ComponentTypes/MyComponent/StoredData" + target_operation_ref_str = "/PortInterfaces/PortInterfaceName/OperationName" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + target_operation = ar_element.ClientServerOperationRef(target_operation_ref_str) + operation = ar_element.POperationInAtomicSwcInstanceRef(context_port=context_port, + target_provided_operation=target_operation) + element = ar_element.TransformerHardErrorEvent('MyName', + operation=operation) + dest_str = "CLIENT-SERVER-OPERATION" + xml = f''' + MyName + + {context_port_ref_str} + {target_operation_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TransformerHardErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TransformerHardErrorEvent) + inner: ar_element.POperationInAtomicSwcInstanceRef = elem.operation + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_provided_operation), target_operation_ref_str) + + def test_required_trigger(self): + context_port_ref_str = "/ComponentTypes/MyComponent/MyPort" + target_trigger_ref_str = "/Triggers/MyTrigger" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.R_PORT_PROTOTYPE) + target_trigger = ar_element.TriggerRef(target_trigger_ref_str) + trigger = ar_element.RTriggerInAtomicSwcInstanceRef(context_port=context_port, + target_trigger=target_trigger) + element = ar_element.TransformerHardErrorEvent('MyName', + required_trigger=trigger) + xml = f''' + MyName + + {context_port_ref_str} + {target_trigger_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TransformerHardErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TransformerHardErrorEvent) + inner: ar_element.RTriggerInAtomicSwcInstanceRef = elem.required_trigger + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_trigger), target_trigger_ref_str) + + def test_trigger(self): + context_port_ref_str = "/ComponentTypes/MyComponent/MyPort" + target_trigger_ref_str = "/Triggers/MyTrigger" + context_port = ar_element.PortPrototypeRef(context_port_ref_str, ar_enum.IdentifiableSubTypes.P_PORT_PROTOTYPE) + target_trigger = ar_element.TriggerRef(target_trigger_ref_str) + trigger = ar_element.PTriggerInAtomicSwcTypeInstanceRef(context_port=context_port, + target_trigger=target_trigger) + element = ar_element.TransformerHardErrorEvent('MyName', + trigger=trigger) + xml = f''' + MyName + + {context_port_ref_str} + {target_trigger_ref_str} + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.TransformerHardErrorEvent = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.TransformerHardErrorEvent) + inner: ar_element.PTriggerInAtomicSwcTypeInstanceRef = elem.trigger + self.assertEqual(str(inner.context_port), context_port_ref_str) + self.assertEqual(str(inner.target_trigger), target_trigger_ref_str) + + +class TestSwcInternalBehavior(unittest.TestCase): + """ + Most elements are not implemented yet + """ + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.SwcInternalBehavior('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + # Base class elements + # IMPLEMENT LATER: CONSTANT-MEMORYS + # IMPLEMENT LATER: CONSTANT-VALUE-MAPPING-REFS + # IMPLEMENT LATER: DATA-TYPE-MAPPING-REFS + # IMPLEMENT LATER: EXCLUSIVE-AREAS + # IMPLEMENT LATER: EXCLUSIVE-AREA-NESTING-ORDERS + # IMPLEMENT LATER: STATIC-MEMORYS + # Class elements + # IMPLEMENT LATER: AR-TYPED-PER-INSTANCE-MEMORYS + + # EVENTS + def test_init_event_from_element(self): + element = ar_element.SwcInternalBehavior('MyName', events=ar_element.InitEvent("MyEvent")) + xml = ''' + MyName + + + MyEvent + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(len(elem.events), 1) + event = elem.events[0] + self.assertIsInstance(event, ar_element.InitEvent) + self.assertEqual(event.name, "MyEvent") + + def test_timing_event_from_element(self): + element = ar_element.SwcInternalBehavior('MyName', events=ar_element.TimingEvent("MyEvent")) + xml = ''' + MyName + + + MyEvent + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(len(elem.events), 1) + event = elem.events[0] + self.assertIsInstance(event, ar_element.TimingEvent) + self.assertEqual(event.name, "MyEvent") + + def test_events_from_list(self): + init_event = ar_element.SwcModeSwitchEvent("InitEvent") + exit_event = ar_element.SwcModeSwitchEvent("ExitEvent") + periodic_event = ar_element.TimingEvent("PeriodicEvent") + element = ar_element.SwcInternalBehavior('MyName', events=[init_event, + exit_event, + periodic_event]) + xml = ''' + MyName + + + InitEvent + + + ExitEvent + + + PeriodicEvent + + +''' + writer = autosar.xml.Writer() + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(len(elem.events), 3) + self.assertIsInstance(elem.events[0], ar_element.SwcModeSwitchEvent) + self.assertEqual(elem.events[0].name, "InitEvent") + self.assertIsInstance(elem.events[1], ar_element.SwcModeSwitchEvent) + self.assertEqual(elem.events[1].name, "ExitEvent") + self.assertIsInstance(elem.events[2], ar_element.TimingEvent) + self.assertEqual(elem.events[2].name, "PeriodicEvent") + + # IMPLEMENT LATER: EXCLUSIVE-AREA-POLICYS + # IMPLEMENT LATER: EXPLICIT-INTER-RUNNABLE-VARIABLES + # IMPLEMENT LATER: HANDLE-TERMINATION-AND-RESTART + # IMPLEMENT LATER: IMPLICIT-INTER-RUNNABLE-VARIABLES + # IMPLEMENT LATER: INCLUDED-DATA-TYPE-SETS + # IMPLEMENT LATER: INCLUDED-MODE-DECLARATION-GROUP-SETS + # IMPLEMENT LATER: INSTANTIATION-DATA-DEF-PROPSS + # IMPLEMENT LATER: PER-INSTANCE-MEMORYS + # IMPLEMENT LATER: PER-INSTANCE-PARAMETERS + # IMPLEMENT LATER: PORT-API-OPTIONS + + # RUNNABLES + + def test_runnables_from_element(self): + writer = autosar.xml.Writer() + element = ar_element.SwcInternalBehavior('MyName', runnables=ar_element.RunnableEntity("MyRunnable")) + xml = ''' + MyName + + + MyRunnable + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(len(elem.runnables), 1) + runnable = elem.runnables[0] + self.assertIsInstance(runnable, ar_element.RunnableEntity) + + def test_runnables_from_list(self): + writer = autosar.xml.Writer() + runnable1 = ar_element.RunnableEntity("MyRunnable1") + runnable2 = ar_element.RunnableEntity("MyRunnable2") + runnable3 = ar_element.RunnableEntity("MyRunnable3") + element = ar_element.SwcInternalBehavior('MyName', runnables=[runnable1, + runnable2, + runnable3]) + xml = ''' + MyName + + + MyRunnable1 + + + MyRunnable2 + + + MyRunnable3 + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.SwcInternalBehavior = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.SwcInternalBehavior) + self.assertEqual(len(elem.runnables), 3) + runnable = elem.runnables[0] + self.assertIsInstance(runnable, ar_element.RunnableEntity) + self.assertEqual(runnable.name, "MyRunnable1") + runnable = elem.runnables[1] + self.assertIsInstance(runnable, ar_element.RunnableEntity) + self.assertEqual(runnable.name, "MyRunnable2") + runnable = elem.runnables[2] + self.assertIsInstance(runnable, ar_element.RunnableEntity) + self.assertEqual(runnable.name, "MyRunnable3") + + # IMPLEMENT LATER: SERVICE-DEPENDENCYS" + # IMPLEMENT LATER: SHARED-PARAMETERS + # IMPLEMENT LATER: SUPPORTS-MULTIPLE-INSTANTIATION + # NOT SUPPORTED: VARIATION-POINT-PROXYS + # NOT SUPPORTED: VARIATION-POINT + + if __name__ == '__main__': unittest.main() diff --git a/tests/xml/test_workspace.py b/tests/xml/test_workspace.py index be1df52..57897c1 100644 --- a/tests/xml/test_workspace.py +++ b/tests/xml/test_workspace.py @@ -146,5 +146,59 @@ def test_get_package_ref_by_role_with_custom_role(self): "/DataTypes") +class BehaviorSettingsTests(unittest.TestCase): + + def test_background_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("background_event_prefix", "BT_") + self.assertEqual(workspace.behavior_settings.background_event_prefix, "BT_") + + def test_data_receive_error_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("data_receive_error_event_prefix", "DRET_") + self.assertEqual(workspace.behavior_settings.data_receive_error_event_prefix, "DRET_") + + def test_data_receive_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("data_receive_event_prefix", "DRT_") + self.assertEqual(workspace.behavior_settings.data_receive_event_prefix, "DRT_") + + def test_init_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("init_event_prefix", "IT_") + self.assertEqual(workspace.behavior_settings.init_event_prefix, "IT_") + + def test_operation_invoked_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("operation_invoked_event_prefix", "OIT_") + self.assertEqual(workspace.behavior_settings.operation_invoked_event_prefix, "OIT_") + + def test_swc_mode_manager_error_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("swc_mode_manager_error_event_prefix", "MMET_") + self.assertEqual(workspace.behavior_settings.swc_mode_manager_error_event_prefix, "MMET_") + + def test_swc_mode_switch_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("swc_mode_switch_event_prefix", "MST_") + self.assertEqual(workspace.behavior_settings.swc_mode_switch_event_prefix, "MST_") + + def test_timing_event_prefix(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.set_value("timing_event_prefix", "TMT_") + self.assertEqual(workspace.behavior_settings.timing_event_prefix, "TMT_") + + def test_set_multiple(self): + workspace = ar_workspace.Workspace() + workspace.behavior_settings.update({"init_event_prefix": "IT_", + "operation_invoked_event_prefix": "OIT_", + "swc_mode_switch_event_prefix": "MST_", + "timing_event_prefix": "TMT_"}) + self.assertEqual(workspace.behavior_settings.init_event_prefix, "IT_") + self.assertEqual(workspace.behavior_settings.operation_invoked_event_prefix, "OIT_") + self.assertEqual(workspace.behavior_settings.swc_mode_switch_event_prefix, "MST_") + self.assertEqual(workspace.behavior_settings.timing_event_prefix, "TMT_") + + if __name__ == '__main__': unittest.main()