From 7c074c1f854ca8c231496458c93b84a54b97cf44 Mon Sep 17 00:00:00 2001 From: Constantin Christmann <constantin.christmann@vector.com> Date: Thu, 17 Apr 2025 07:54:34 +0000 Subject: [PATCH] Upload of initial contribution from Vector. --- .clang-format | 89 + .clang-tidy | 82 + .devcontainer/Dockerfile | 93 + .devcontainer/devcontainer.json | 66 + .gitignore | 11 + .pre-commit-config.yaml | 27 + .pre-commit-hooks/perform-build.sh | 6 + .pre-commit-hooks/perform-format.sh | 6 + .pre-commit-hooks/perform-lint.sh | 6 + .pre-commit-hooks/perform-test.sh | 6 + .vscode/scripts/mk.sh | 29 + .vscode/scripts/reinstall_wheels.sh | 24 + .vscode/settings.json | 17 + .vscode/tasks.json | 75 + Container/README.md | 8 + Container/build.sh | 4 + Container/conan/conanfile.txt | 3 + Container/conan/gcc12__x86_64-pc-linux-elf | 14 + Container/eclipse.Dockerfile | 137 + Container/scripts/conan-helper.sh | 38 + Demo/HelloVaf/README.md | 359 + Demo/HelloVaf/model/app_module1.py | 12 + Demo/HelloVaf/model/app_module2.py | 12 + Demo/HelloVaf/model/hello_interfaces.py | 5 + Demo/HelloVaf/model/hello_vaf.py | 25 + Demo/HelloVaf/src/app_module1/app_module1.cpp | 62 + Demo/HelloVaf/src/app_module1/app_module1.h | 38 + Demo/HelloVaf/src/app_module2/app_module2.cpp | 64 + Demo/README.md | 14 + Demo/SilKit/README.md | 617 + Demo/SilKit/model/collision_detection.py | 18 + Demo/SilKit/model/interfaces.py | 76 + Demo/SilKit/model/sensor_fusion.py | 36 + Demo/SilKit/model/sil_kit_demo.py | 96 + Demo/SilKit/model/test_module.py | 41 + .../collision_detection.h | 44 + .../src/collision_detection.cpp | 97 + .../nssensorfusion/sensor_fusion.h | 49 + .../src/sensor_fusion/src/sensor_fusion.cpp | 141 + .../nstestmodule/test_module.h | 43 + .../src/test_module/src/test_module.cpp | 172 + Demo/Vss/README.md | 183 + Demo/Vss/model/vaf/demo_executable.py | 31 + Demo/Vss/model/vaf/vss_consumer.py | 13 + Demo/Vss/model/vaf/vss_provider.py | 13 + Demo/Vss/model/vss/vss.json | 9201 ++++++++ Demo/Vss/src/vss_consumer/vss_consumer.cpp | 79 + Demo/Vss/src/vss_provider/vss_provider.cpp | 91 + Demo/figures/hello.drawio.svg | 4 + Demo/figures/silkit.drawio.svg | 4 + Demo/figures/vscode-remote-window.png | Bin 0 -> 4594 bytes Demo/figures/vscode-reopen-container.png | Bin 0 -> 19058 bytes Demo/figures/vss.drawio.svg | 4 + Documentation/.gitignore | 20 + Documentation/README.md | 11 + Documentation/contents/10_introduction.md | 53 + Documentation/contents/20_building_blocks.md | 26 + Documentation/contents/21_sw_architecture.md | 108 + Documentation/contents/22_workflow.md | 32 + Documentation/contents/23_model.md | 354 + Documentation/contents/24_api.md | 80 + Documentation/contents/25_configuration.md | 74 + Documentation/contents/26_platform_support.md | 23 + Documentation/contents/27_code_generation.md | 267 + Documentation/contents/28_sw_library.md | 204 + Documentation/contents/29_testing.md | 76 + Documentation/contents/30_glossary.md | 103 + Documentation/contents/figures/af-concept.svg | 1 + .../contents/figures/arch-app-module.svg | 142 + .../contents/figures/arch-app-module.uxf | 152 + .../contents/figures/arch-consumer-module.svg | 103 + .../contents/figures/arch-consumer-module.uxf | 105 + .../arch-consumer_get_register_api.svg | 575 + .../arch-consumer_get_register_api.uxf | 1111 + .../figures/arch-consumer_operation_api.svg | 95 + .../figures/arch-consumer_operation_api.uxf | 123 + .../contents/figures/arch-control-module.svg | 540 + .../contents/figures/arch-control-module.uxf | 478 + .../contents/figures/arch-executor-module.svg | 441 + .../contents/figures/arch-executor-module.uxf | 409 + .../figures/arch-internal-com-module.svg | 138 + .../figures/arch-internal-com-module.uxf | 135 + .../contents/figures/arch-module-if.svg | 151 + .../contents/figures/arch-module-if.uxf | 139 + .../contents/figures/arch-provider-module.svg | 103 + .../contents/figures/arch-provider-module.uxf | 105 + .../arch-provider_allocate_set_api.svg | 258 + .../arch-provider_allocate_set_api.uxf | 472 + .../figures/arch-provider_operation_api.svg | 277 + .../figures/arch-provider_operation_api.uxf | 441 + .../contents/figures/cac-cd_app_module.puml | 14 + .../contents/figures/cac-cd_app_module.svg | 27 + .../contents/figures/cac-cd_datatypes.puml | 63 + .../contents/figures/cac-cd_datatypes.svg | 95 + .../contents/figures/cac-cd_executable.puml | 17 + .../contents/figures/cac-cd_executable.svg | 30 + .../figures/cac-cd_module_interface.puml | 12 + .../figures/cac-cd_module_interface.svg | 25 + .../contents/figures/cac-cd_task.puml | 11 + .../contents/figures/cac-cd_task.svg | 24 + .../contents/figures/cac-overview.puml | 24 + .../contents/figures/cac-overview.svg | 43 + Documentation/contents/figures/stack-new.svg | 1 + .../contents/figures/stack-today.svg | 1 + .../contents/figures/vaf-cli.drawio.svg | 4 + Documentation/contents/figures/vaf-map.svg | 1 + README.md | 163 +- Rakefile | 141 + SwLibraries/README.md | 38 + SwLibraries/vaf_core_library/.gitignore | 1 + SwLibraries/vaf_core_library/CMakeLists.txt | 6 + .../vaf_core_library/cmake/vafcppConfig.cmake | 8 + SwLibraries/vaf_core_library/conanfile.py | 64 + .../vaf_core_library/lib/CMakeLists.txt | 46 + .../lib/include/tl/expected.h | 2506 +++ .../lib/include/vaf/controller_interface.h | 66 + .../lib/include/vaf/data_ptr.h | 155 + .../lib/include/vaf/error_domain.h | 62 + .../include/vaf/executable_controller_base.h | 105 + .../vaf/executable_controller_interface.h | 41 + .../lib/include/vaf/executor.h | 198 + .../vaf_core_library/lib/include/vaf/future.h | 101 + .../include/vaf/internal/data_ptr_helper.h | 41 + .../lib/include/vaf/logging.h | 211 + .../lib/include/vaf/module_states.h | 46 + .../include/vaf/receiver_handler_container.h | 39 + .../vaf_core_library/lib/include/vaf/result.h | 14 + .../lib/include/vaf/runtime.h | 18 + .../include/vaf/user_controller_interface.h | 27 + .../lib/src/controller_interface.cpp | 53 + .../lib/src/executable_controller_base.cpp | 313 + .../vaf_core_library/lib/src/executor.cpp | 114 + .../vaf_core_library/lib/src/logging.cpp | 13 + .../vaf_core_library/lib/src/runtime.cpp | 14 + .../vaf_core_library/test/CMakeLists.txt | 3 + .../vaf_core_library/test/src/test.cpp | 41 + .../test_package/CMakeLists.txt | 8 + .../test_package/conanfile.py | 26 + .../test_package/gcc12__x86_64-pc-linux-elf | 13 + .../test_package/gcc7__aarch64-pc-linux-elf | 13 + .../test_package/src/example.cpp | 19 + Tools/.gitkeep | 0 VAF/.gitignore | 86 + VAF/LICENSE | 0 VAF/Makefile | 8 + VAF/README.md | 3 + VAF/bootstrap/LICENSE | 1 + VAF/bootstrap/README.md | 0 VAF/bootstrap/pdm.lock | 504 + VAF/bootstrap/pyproject.toml | 60 + VAF/bootstrap/src | 0 VAF/pdm.lock | 1199 ++ VAF/pyproject.toml | 154 + VAF/python3-makefile/Makefile | 118 + VAF/python3-makefile/ruff.toml | 19 + VAF/src/vaf/__init__.py | 11 + VAF/src/vaf/__main__.py | 113 + VAF/src/vaf/__main_bootstrap__.py | 67 + .../cli_subcommands/project_subcmd.py | 102 + .../cli_subcommands/workspace_subcmd.py | 32 + .../cli_core/bootstrap/project_init_cmd.py | 196 + .../{{module_dir_name}}/.clang-format | 89 + .../{{module_dir_name}}/.clang-tidy | 97 + .../{{module_dir_name}}/.clangd | 10 + .../.conan/gcc11__x86_64-pc-linux-elf | 13 + .../.conan/gcc12__x86_64-pc-linux-elf | 13 + .../{{module_dir_name}}/.gitignore | 15 + .../{{module_dir_name}}/.vafconfig.json | 8 + .../{{module_dir_name}}/CMakeLists.txt.jinja | 47 + .../{{module_dir_name}}/README.md.jinja | 44 + .../{{module_dir_name}}/conanfile.py | 20 + .../implementation/CMakeLists.txt | 0 .../model/model.json.jinja | 19 + .../{{module_dir_name}}/model/model.py.jinja | 19 + .../model/{{module_name_snk}}.py.jinja | 12 + .../test-gen/CMakeLists.txt | 0 .../{{project_name}}/.gitignore | 15 + .../{{project_name}}/.vafconfig.json | 8 + .../{{project_name}}/README.md.jinja | 15 + .../{{project_name}}/model.py.jinja | 22 + .../{{project_name_snk}}.py.jinja | 15 + .../default/{{project_name}}/.clang-format | 89 + .../default/{{project_name}}/.clang-tidy | 97 + .../project/default/{{project_name}}/.clangd | 10 + .../.conan/gcc11__x86_64-pc-linux-elf | 13 + .../.conan/gcc12__x86_64-pc-linux-elf | 13 + .../default/{{project_name}}/.gitignore | 15 + .../default/{{project_name}}/.vafconfig.json | 8 + .../{{project_name}}/CMakeLists.txt.jinja | 44 + .../default/{{project_name}}/README.md.jinja | 52 + .../{{project_name}}/cmake/FindSilKit.cmake | 51 + .../default/{{project_name}}/conanfile.py | 20 + .../model/vaf/application_modules/__init__.py | 0 .../{{project_name}}/model/vaf/model.py.jinja | 17 + .../model/vaf/{{project_name_snk}}.py.jinja | 23 + .../{{project_name}}/src/CMakeLists.txt | 0 .../{{project_name}}/test-gen/CMakeLists.txt | 0 .../.devcontainer/devcontainer.json.jinja | 48 + .../{{workspace_name}}/.vafconfig.json | 4 + .../{{workspace_name}}/.vscode/launch.json | 17 + .../.vscode/scripts/set_cwd.sh | 24 + .../{{workspace_name}}/.vscode/settings.json | 6 + .../{{workspace_name}}/.vscode/tasks.json | 295 + .../vaf/cli_core/bootstrap/workspace_cmd.py | 64 + .../vaf/cli_core/common/click_extension.py | 308 + VAF/src/vaf/cli_core/common/click_help.py | 49 + VAF/src/vaf/cli_core/common/exceptions.py | 34 + VAF/src/vaf/cli_core/common/utils.py | 257 + .../main/cli_subcommands/make_subcmd.py | 187 + .../main/cli_subcommands/model_subcmd.py | 165 + .../main/cli_subcommands/project_subcmd.py | 322 + VAF/src/vaf/cli_core/main/make_cmd.py | 107 + VAF/src/vaf/cli_core/main/model_cmd.py | 327 + VAF/src/vaf/cli_core/main/project_cmd.py | 616 + .../import_instances.py.jinja | 17 + .../import_{{module_name_snk}}.py.jinja | 22 + .../__init__.py.jinja | 13 + .../__init__.py.jinja | 12 + VAF/src/vaf/constants.py | 14 + VAF/src/vaf/py.typed | 0 VAF/src/vaf/vafgeneration/__init__.py | 33 + VAF/src/vaf/vafgeneration/generation.py | 573 + .../templates/common/cmake_copyright.jinja | 15 + .../common/cmake_interface_library.jinja | 22 + .../templates/common/cmake_library.jinja | 30 + .../templates/common/cmake_subdirs.jinja | 5 + .../templates/common/copyright.jinja | 17 + .../templates/common/cpp_file_base.jinja | 13 + .../templates/common/h_file_base.jinja | 13 + ...application_communication_module_cpp.jinja | 128 + .../application_communication_module_h.jinja | 71 + .../vaf_application_module/base_cpp.jinja | 22 + .../vaf_application_module/base_h.jinja | 53 + .../cmake_implementation.jinja | 64 + .../vaf_application_module/module_cpp.jinja | 89 + .../vaf_application_module/module_h.jinja | 18 + .../test_base_cpp.jinja | 10 + .../vaf_application_module/test_base_h.jinja | 38 + .../vaf_application_module/test_cmake.jinja | 73 + .../test_main_cpp.jinja | 20 + .../test_module_cpp.jinja | 72 + .../vaf_cac_support/platform.py.jinja | 32 + .../vaf_cmake_common/data_types_cmake.jinja | 10 + .../templates/vaf_conan/conan_deps.list.jinja | 3 + .../vaf_controller/CMakeLists_txt.jinja | 68 + .../executable_controller_cpp.jinja | 93 + .../executable_controller_h.jinja | 24 + .../templates/vaf_controller/main_cpp.jinja | 11 + .../user_controller_CMakeLists_txt.jinja | 16 + .../vaf_controller/user_controller_cpp.jinja | 43 + .../vaf_controller/user_controller_h.jinja | 21 + .../templates/vaf_interface/macros.jinja | 64 + .../vaf_interface/macros_mocks.jinja | 58 + .../module_interface_consumer_h.jinja | 33 + .../module_interface_consumer_mock_h.jinja | 32 + .../module_interface_provider_h.jinja | 32 + .../module_interface_provider_mock_h.jinja | 31 + .../vaf_interface/operation_output.jinja | 18 + .../vaf_protobuf/basetypes_proto.jinja | 9 + .../vaf_protobuf/data_type_proto.jinja | 60 + .../vaf_protobuf/data_type_transformer.jinja | 181 + .../vaf_protobuf/interface_proto.jinja | 28 + .../vaf_protobuf/interface_transformer.jinja | 72 + .../vaf_protobuf/protobuf_cmake.jinja | 23 + .../vaf_silkit/consumer_module_cpp.jinja | 196 + .../vaf_silkit/consumer_module_h.jinja | 81 + .../templates/vaf_silkit/module_cmake.jinja | 6 + .../vaf_silkit/provider_module_cpp.jinja | 166 + .../vaf_silkit/provider_module_h.jinja | 57 + .../vaf_std_data_types/array_h.jinja | 12 + .../templates/vaf_std_data_types/enum_h.jinja | 11 + .../templates/vaf_std_data_types/map_h.jinja | 14 + .../vaf_std_data_types/string_h.jinja | 9 + .../vaf_std_data_types/struct_h.jinja | 15 + .../vaf_std_data_types/type_ref_h.jinja | 10 + .../vaf_std_data_types/vector_h.jinja | 12 + .../vaf_application_communication.py | 82 + .../vafgeneration/vaf_application_module.py | 477 + VAF/src/vaf/vafgeneration/vaf_cac_support.py | 119 + VAF/src/vaf/vafgeneration/vaf_cmake_common.py | 258 + VAF/src/vaf/vafgeneration/vaf_conan.py | 43 + VAF/src/vaf/vafgeneration/vaf_controller.py | 386 + .../vaf_generate_application_module.py | 145 + .../vaf/vafgeneration/vaf_generate_common.py | 227 + .../vaf/vafgeneration/vaf_generate_project.py | 163 + VAF/src/vaf/vafgeneration/vaf_interface.py | 195 + .../vaf/vafgeneration/vaf_protobuf_serdes.py | 465 + VAF/src/vaf/vafgeneration/vaf_silkit.py | 244 + .../vaf/vafgeneration/vaf_std_data_types.py | 118 + VAF/src/vaf/vafmodel/__init__.py | 8 + VAF/src/vaf/vafmodel/vafmodel.py | 733 + VAF/src/vaf/vafpy/__init__.py | 44 + VAF/src/vaf/vafpy/core.py | 58 + VAF/src/vaf/vafpy/datatypes.py | 202 + VAF/src/vaf/vafpy/elements.py | 274 + VAF/src/vaf/vafpy/executable.py | 305 + VAF/src/vaf/vafpy/factory.py | 124 + VAF/src/vaf/vafpy/model_runtime.py | 216 + VAF/src/vaf/vafpy/runtime.py | 559 + VAF/src/vaf/vafpy/task.py | 37 + VAF/src/vaf/vafpy/validator.py | 279 + VAF/src/vaf/vafvssimport/vss/__init__.py | 0 VAF/src/vaf/vafvssimport/vss/vss_model.py | 234 + VAF/src/vaf/vafvssimport/vss/vss_types.py | 233 + VAF/src/vaf/vafvssimport/vss_import.py | 45 + VAF/tests/Makefile | 68 + VAF/tests/ModelValidation/.schema-infos.json | 10 + .../test_schema_release_version.py | 31 + .../test_validate_to_vaf_schema.py | 52 + VAF/tests/__init__.py | 0 VAF/tests/component/cli/test_main.py | 79 + VAF/tests/conftest.py | 18 + VAF/tests/unit/__init__.py | 0 .../test_data/ftaf_263/model/vaf/model.json | 254 + .../test_data/ftaf_305/model/vaf/model.json | 112 + .../ftaf_305/model/vaf/model_module1.json | 16 + .../ftaf_305/model/vaf/model_module2.json | 16 + .../test_data/ftaf_460/goal-model.json | 112 + .../cli_core/test_data/ftaf_460/interfaces.py | 28 + .../test_data/ftaf_460/schoca_cola.py | 26 + .../unit/cli_core/test_data/ftaf_467/fake.py | 8 + .../test_data/ftaf_467/goal-model.json | 138 + .../cli_core/test_data/ftaf_467/interfaces.py | 27 + .../cli_core/test_data/ftaf_467/invisible.py | 10 + .../cli_core/test_data/ftaf_467/mockery.py | 9 + .../unit/cli_core/test_data/ftaf_467/model.py | 28 + .../unit/cli_core/test_data/minimal_vss.json | 7 + .../test_data/mock_prj/model/app/model.json | 144 + .../test_data/mock_prj/model/vaf/model.json | 254 + VAF/tests/unit/cli_core/test_make_cmd.py | 132 + VAF/tests/unit/cli_core/test_model_cmd.py | 184 + VAF/tests/unit/cli_core/test_project_cmd.py | 230 + VAF/tests/unit/vafgeneration/__init__.py | 0 .../application_communication/CMakeLists.txt | 35 + .../my_service_module.cpp | 205 + .../my_service_module.h | 93 + .../vafgeneration/application_module/app.cpp | 75 + .../vafgeneration/application_module/app.h | 38 + .../application_module/app_cmake.txt | 66 + .../application_module/apps_cmake.txt | 43 + .../vafgeneration/application_module/base.cpp | 36 + .../vafgeneration/application_module/base.h | 73 + .../application_module/base_cmake.txt | 35 + .../vafgeneration/application_module/main.cpp | 33 + .../application_module/test_base.cpp | 30 + .../application_module/test_base.h | 58 + .../application_module/test_cmake.txt | 64 + .../application_module/tests.cpp | 85 + .../cac_support/silkit.py.example | 30 + .../unit/vafgeneration/cmake_common/cmake.txt | 17 + .../vafgeneration/cmake_common/exe_cmake.txt | 18 + .../vafgeneration/cmake_common/libs_cmake.txt | 20 + .../cmake_common/libs_cmake_append.txt | 20 + .../cmake_common/libs_cmake_append2.txt | 20 + .../vafgeneration/controller/CMakeLists.txt | 63 + .../vafgeneration/controller/controller.cpp | 102 + .../vafgeneration/controller/controller.h | 45 + .../unit/vafgeneration/controller/main.cpp | 25 + .../controller/user_controller.cpp | 57 + .../controller/user_controller.h | 40 + .../model_changed_complex.json | 445 + .../sensor_fusion_base_test_goal.h | 81 + .../complex_changes/sensor_fusion_goal.cpp | 132 + .../complex_changes/sensor_fusion_goal.h | 47 + .../first_cycle_editing/CMakeLists.txt | 71 + .../sensor_fusion_base_test_edited.h | 74 + .../sensor_fusion_edited.cpp | 108 + .../sensor_fusion_edited.h | 47 + .../data/merge_strategy/model_base.json | 445 + .../merge_strategy/removal/model_changed.json | 413 + .../removal/sensor_fusion_base_test_goal.h | 62 + .../removal/sensor_fusion_goal.cpp | 84 + .../removal/sensor_fusion_goal.h | 38 + .../sensor_fusion_base_test_edited.h | 78 + .../sensor_fusion_edited.cpp | 111 + .../sensor_fusion_edited.h | 52 + .../simple_changes/model_changed.json | 446 + .../sensor_fusion_base_test_goal.h | 79 + .../simple_changes/sensor_fusion_goal.cpp | 108 + .../simple_changes/sensor_fusion_goal.h | 47 + .../model_changed.json | 446 + .../sensor_fusion_base_test_goal.h | 85 + .../sensor_fusion_goal.cpp | 135 + .../sensor_fusion_goal.h | 59 + .../input_model_examples/silkit.json | 66 + .../interface/test1_consumer_expected.h | 48 + .../interface/test1_consumer_mock_expected.h | 48 + .../interface/test1_provider_expected.h | 47 + .../interface/test1_provider_mock_expected.h | 47 + .../protobuf/protobuf_test.proto | 32 + .../protobuf/protobuf_test2.proto | 15 + .../silkit/my_consumer_module.cpp | 346 + .../vafgeneration/silkit/my_consumer_module.h | 97 + .../silkit/my_provider_module.cpp | 259 + .../vafgeneration/silkit/my_provider_module.h | 80 + .../test_application_communication.py | 105 + .../vafgeneration/test_application_module.py | 200 + .../unit/vafgeneration/test_cac_support.py | 383 + .../unit/vafgeneration/test_cmake_common.py | 109 + .../unit/vafgeneration/test_controller.py | 149 + .../unit/vafgeneration/test_generation.py | 213 + .../test_merge_after_regeneration.py | 332 + VAF/tests/unit/vafgeneration/test_protobuf.py | 258 + VAF/tests/unit/vafgeneration/test_silkit.py | 255 + .../unit/vafgeneration/test_vafinterface.py | 82 + .../unit/vafgeneration/test_vafproject.py | 61 + VAF/tests/unit/vafgeneration/test_vss.py | 43 + .../unit/vafgeneration/vss/seat_vss.json | 2114 ++ VAF/tests/unit/vafmodel/__init__.py | 0 VAF/tests/unit/vafmodel/test_example.py | 61 + VAF/tests/unit/vafmodel/test_model.json | 400 + VAF/tests/unit/vafmodel/test_model2.json | 254 + VAF/tests/unit/vafpy/__init__.py | 0 VAF/tests/unit/vafpy/test_cac.py | 541 + .../vafpy/test_data/common/.vafconfig.json | 8 + .../vafpy/test_data/common/silkit-model.json | 347 + .../unit/vafpy/test_data/common/silkit.py | 63 + .../test_data/common/vss-derived-model.json | 17474 ++++++++++++++++ VAF/tests/unit/vafpy/test_data/common/vss.py | 1196 ++ .../unit/vafpy/test_data/ftaf_258/model.py | 81 + .../unit/vafpy/test_data/ftaf_260/model.json | 295 + .../unit/vafpy/test_data/ftaf_260/model.py | 54 + .../vafpy/test_data/ftaf_260_bug/model.json | 392 + .../vafpy/test_data/ftaf_260_bug/model.py | 34 + .../test_data/ftaf_260_bug/silkit-model.json | 444 + .../unit/vafpy/test_data/ftaf_339/model.py | 75 + .../unit/vafpy/test_data/ftaf_354/model.py | 38 + .../vafpy/test_data/ftaf_386/app_module1.py | 12 + .../imported_models/InterfaceProject.json | 121 + .../imported_models/interface_project.py | 34 + .../unit/vafpy/test_data/ftaf_386/model.json | 54 + .../unit/vafpy/test_data/ftaf_386/model.py | 12 + .../vafpy/test_data/ftaf_394/app_module1.py | 9 + .../vafpy/test_data/ftaf_394/goal-model.json | 32 + .../unit/vafpy/test_data/ftaf_394/model.py | 12 + .../test_data/ftaf_394/silkit-model.json | 771 + .../unit/vafpy/test_data/ftaf_394/silkit.py | 44 + .../vafpy/test_data/ftaf_399/app_module1.py | 9 + .../unit/vafpy/test_data/ftaf_399/model.json | 471 + .../unit/vafpy/test_data/ftaf_399/model.py | 12 + .../test_data/ftaf_399/vss-derived-model.json | 1131 + .../unit/vafpy/test_data/ftaf_399/vss.py | 109 + .../unit/vafpy/test_data/ftaf_421/model.py | 65 + .../unit/vafpy/test_data/ftaf_421/silkit.py | 64 + .../vafpy/test_data/ftaf_422/app_module1.py | 12 + .../ftaf_422/imported_models/interface.json | 1232 ++ .../ftaf_422/imported_models/interface.py | 132 + .../unit/vafpy/test_data/ftaf_422/model.json | 998 + .../unit/vafpy/test_data/ftaf_422/model.py | 20 + .../unit/vafpy/test_data/ftaf_457/model.py | 35 + .../vafpy/test_data/ftaf_553/app_module1.py | 17 + .../ftaf_553/imported_models/Interfaces.json | 1279 ++ .../ftaf_553/imported_models/interfaces.py | 178 + .../unit/vafpy/test_data/ftaf_553/model.py | 19 + .../unit/vafpy/test_data/ftaf_576/model.json | 42 + .../unit/vafpy/test_data/ftaf_576/model.py | 21 + VAF/tests/unit/vafpy/test_example.py | 331 + VAF/tests/unit/vafvssimport/__init__.py | 0 .../vafvssimport/test_data/minimal_vss.json | 7 + .../unit/vafvssimport/test_export_arrays.py | 131 + .../unit/vafvssimport/test_export_enum.py | 99 + .../unit/vafvssimport/test_export_min_max.py | 69 + .../unit/vafvssimport/test_export_struct.py | 147 + .../unit/vafvssimport/test_vss_import.py | 24 + version.txt | 1 + 465 files changed, 83094 insertions(+), 66 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .pre-commit-hooks/perform-build.sh create mode 100644 .pre-commit-hooks/perform-format.sh create mode 100644 .pre-commit-hooks/perform-lint.sh create mode 100644 .pre-commit-hooks/perform-test.sh create mode 100644 .vscode/scripts/mk.sh create mode 100644 .vscode/scripts/reinstall_wheels.sh create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 Container/README.md create mode 100644 Container/build.sh create mode 100644 Container/conan/conanfile.txt create mode 100644 Container/conan/gcc12__x86_64-pc-linux-elf create mode 100644 Container/eclipse.Dockerfile create mode 100644 Container/scripts/conan-helper.sh create mode 100644 Demo/HelloVaf/README.md create mode 100644 Demo/HelloVaf/model/app_module1.py create mode 100644 Demo/HelloVaf/model/app_module2.py create mode 100644 Demo/HelloVaf/model/hello_interfaces.py create mode 100644 Demo/HelloVaf/model/hello_vaf.py create mode 100644 Demo/HelloVaf/src/app_module1/app_module1.cpp create mode 100644 Demo/HelloVaf/src/app_module1/app_module1.h create mode 100644 Demo/HelloVaf/src/app_module2/app_module2.cpp create mode 100644 Demo/README.md create mode 100644 Demo/SilKit/README.md create mode 100644 Demo/SilKit/model/collision_detection.py create mode 100644 Demo/SilKit/model/interfaces.py create mode 100644 Demo/SilKit/model/sensor_fusion.py create mode 100644 Demo/SilKit/model/sil_kit_demo.py create mode 100644 Demo/SilKit/model/test_module.py create mode 100644 Demo/SilKit/src/collision_detection/include/nsapplicationunit/nscollisiondetection/collision_detection.h create mode 100644 Demo/SilKit/src/collision_detection/src/collision_detection.cpp create mode 100644 Demo/SilKit/src/sensor_fusion/include/nsapplicationunit/nssensorfusion/sensor_fusion.h create mode 100644 Demo/SilKit/src/sensor_fusion/src/sensor_fusion.cpp create mode 100644 Demo/SilKit/src/test_module/include/nsapplicationunit/nstestmodule/test_module.h create mode 100644 Demo/SilKit/src/test_module/src/test_module.cpp create mode 100644 Demo/Vss/README.md create mode 100644 Demo/Vss/model/vaf/demo_executable.py create mode 100644 Demo/Vss/model/vaf/vss_consumer.py create mode 100644 Demo/Vss/model/vaf/vss_provider.py create mode 100644 Demo/Vss/model/vss/vss.json create mode 100644 Demo/Vss/src/vss_consumer/vss_consumer.cpp create mode 100644 Demo/Vss/src/vss_provider/vss_provider.cpp create mode 100644 Demo/figures/hello.drawio.svg create mode 100644 Demo/figures/silkit.drawio.svg create mode 100644 Demo/figures/vscode-remote-window.png create mode 100644 Demo/figures/vscode-reopen-container.png create mode 100644 Demo/figures/vss.drawio.svg create mode 100644 Documentation/.gitignore create mode 100644 Documentation/README.md create mode 100644 Documentation/contents/10_introduction.md create mode 100644 Documentation/contents/20_building_blocks.md create mode 100644 Documentation/contents/21_sw_architecture.md create mode 100644 Documentation/contents/22_workflow.md create mode 100644 Documentation/contents/23_model.md create mode 100644 Documentation/contents/24_api.md create mode 100644 Documentation/contents/25_configuration.md create mode 100644 Documentation/contents/26_platform_support.md create mode 100644 Documentation/contents/27_code_generation.md create mode 100644 Documentation/contents/28_sw_library.md create mode 100644 Documentation/contents/29_testing.md create mode 100644 Documentation/contents/30_glossary.md create mode 100644 Documentation/contents/figures/af-concept.svg create mode 100644 Documentation/contents/figures/arch-app-module.svg create mode 100644 Documentation/contents/figures/arch-app-module.uxf create mode 100644 Documentation/contents/figures/arch-consumer-module.svg create mode 100644 Documentation/contents/figures/arch-consumer-module.uxf create mode 100644 Documentation/contents/figures/arch-consumer_get_register_api.svg create mode 100644 Documentation/contents/figures/arch-consumer_get_register_api.uxf create mode 100644 Documentation/contents/figures/arch-consumer_operation_api.svg create mode 100644 Documentation/contents/figures/arch-consumer_operation_api.uxf create mode 100644 Documentation/contents/figures/arch-control-module.svg create mode 100644 Documentation/contents/figures/arch-control-module.uxf create mode 100644 Documentation/contents/figures/arch-executor-module.svg create mode 100644 Documentation/contents/figures/arch-executor-module.uxf create mode 100644 Documentation/contents/figures/arch-internal-com-module.svg create mode 100644 Documentation/contents/figures/arch-internal-com-module.uxf create mode 100644 Documentation/contents/figures/arch-module-if.svg create mode 100644 Documentation/contents/figures/arch-module-if.uxf create mode 100644 Documentation/contents/figures/arch-provider-module.svg create mode 100644 Documentation/contents/figures/arch-provider-module.uxf create mode 100644 Documentation/contents/figures/arch-provider_allocate_set_api.svg create mode 100644 Documentation/contents/figures/arch-provider_allocate_set_api.uxf create mode 100644 Documentation/contents/figures/arch-provider_operation_api.svg create mode 100644 Documentation/contents/figures/arch-provider_operation_api.uxf create mode 100644 Documentation/contents/figures/cac-cd_app_module.puml create mode 100644 Documentation/contents/figures/cac-cd_app_module.svg create mode 100644 Documentation/contents/figures/cac-cd_datatypes.puml create mode 100644 Documentation/contents/figures/cac-cd_datatypes.svg create mode 100644 Documentation/contents/figures/cac-cd_executable.puml create mode 100644 Documentation/contents/figures/cac-cd_executable.svg create mode 100644 Documentation/contents/figures/cac-cd_module_interface.puml create mode 100644 Documentation/contents/figures/cac-cd_module_interface.svg create mode 100644 Documentation/contents/figures/cac-cd_task.puml create mode 100644 Documentation/contents/figures/cac-cd_task.svg create mode 100644 Documentation/contents/figures/cac-overview.puml create mode 100644 Documentation/contents/figures/cac-overview.svg create mode 100644 Documentation/contents/figures/stack-new.svg create mode 100644 Documentation/contents/figures/stack-today.svg create mode 100644 Documentation/contents/figures/vaf-cli.drawio.svg create mode 100644 Documentation/contents/figures/vaf-map.svg create mode 100644 Rakefile create mode 100644 SwLibraries/README.md create mode 100644 SwLibraries/vaf_core_library/.gitignore create mode 100644 SwLibraries/vaf_core_library/CMakeLists.txt create mode 100644 SwLibraries/vaf_core_library/cmake/vafcppConfig.cmake create mode 100644 SwLibraries/vaf_core_library/conanfile.py create mode 100644 SwLibraries/vaf_core_library/lib/CMakeLists.txt create mode 100644 SwLibraries/vaf_core_library/lib/include/tl/expected.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/controller_interface.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/data_ptr.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/error_domain.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_interface.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/executor.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/future.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/internal/data_ptr_helper.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/logging.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/module_states.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/receiver_handler_container.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/result.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/runtime.h create mode 100644 SwLibraries/vaf_core_library/lib/include/vaf/user_controller_interface.h create mode 100644 SwLibraries/vaf_core_library/lib/src/controller_interface.cpp create mode 100644 SwLibraries/vaf_core_library/lib/src/executable_controller_base.cpp create mode 100644 SwLibraries/vaf_core_library/lib/src/executor.cpp create mode 100644 SwLibraries/vaf_core_library/lib/src/logging.cpp create mode 100644 SwLibraries/vaf_core_library/lib/src/runtime.cpp create mode 100644 SwLibraries/vaf_core_library/test/CMakeLists.txt create mode 100644 SwLibraries/vaf_core_library/test/src/test.cpp create mode 100644 SwLibraries/vaf_core_library/test_package/CMakeLists.txt create mode 100644 SwLibraries/vaf_core_library/test_package/conanfile.py create mode 100644 SwLibraries/vaf_core_library/test_package/gcc12__x86_64-pc-linux-elf create mode 100644 SwLibraries/vaf_core_library/test_package/gcc7__aarch64-pc-linux-elf create mode 100644 SwLibraries/vaf_core_library/test_package/src/example.cpp create mode 100644 Tools/.gitkeep create mode 100644 VAF/.gitignore create mode 100644 VAF/LICENSE create mode 100644 VAF/Makefile create mode 100644 VAF/README.md create mode 100644 VAF/bootstrap/LICENSE create mode 100644 VAF/bootstrap/README.md create mode 100644 VAF/bootstrap/pdm.lock create mode 100644 VAF/bootstrap/pyproject.toml create mode 100644 VAF/bootstrap/src create mode 100644 VAF/pdm.lock create mode 100644 VAF/pyproject.toml create mode 100644 VAF/python3-makefile/Makefile create mode 100644 VAF/python3-makefile/ruff.toml create mode 100644 VAF/src/vaf/__init__.py create mode 100644 VAF/src/vaf/__main__.py create mode 100644 VAF/src/vaf/__main_bootstrap__.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/cli_subcommands/project_subcmd.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/cli_subcommands/workspace_subcmd.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/project_init_cmd.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-format create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-tidy create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clangd create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc11__x86_64-pc-linux-elf create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc12__x86_64-pc-linux-elf create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.gitignore create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.vafconfig.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/CMakeLists.txt.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/README.md.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/conanfile.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/implementation/CMakeLists.txt create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.json.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/{{module_name_snk}}.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/test-gen/CMakeLists.txt create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.gitignore create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.vafconfig.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/README.md.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/model.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/{{project_name_snk}}.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-format create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-tidy create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clangd create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc11__x86_64-pc-linux-elf create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc12__x86_64-pc-linux-elf create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.gitignore create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.vafconfig.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/CMakeLists.txt.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/README.md.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/cmake/FindSilKit.cmake create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/conanfile.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/application_modules/__init__.py create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/model.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/{{project_name_snk}}.py.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/src/CMakeLists.txt create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/test-gen/CMakeLists.txt create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.devcontainer/devcontainer.json.jinja create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vafconfig.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/launch.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/scripts/set_cwd.sh create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/settings.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/tasks.json create mode 100644 VAF/src/vaf/cli_core/bootstrap/workspace_cmd.py create mode 100644 VAF/src/vaf/cli_core/common/click_extension.py create mode 100644 VAF/src/vaf/cli_core/common/click_help.py create mode 100644 VAF/src/vaf/cli_core/common/exceptions.py create mode 100644 VAF/src/vaf/cli_core/common/utils.py create mode 100644 VAF/src/vaf/cli_core/main/cli_subcommands/make_subcmd.py create mode 100644 VAF/src/vaf/cli_core/main/cli_subcommands/model_subcmd.py create mode 100644 VAF/src/vaf/cli_core/main/cli_subcommands/project_subcmd.py create mode 100644 VAF/src/vaf/cli_core/main/make_cmd.py create mode 100644 VAF/src/vaf/cli_core/main/model_cmd.py create mode 100644 VAF/src/vaf/cli_core/main/project_cmd.py create mode 100644 VAF/src/vaf/cli_core/main/templates/application_module_integration_instance_import/import_instances.py.jinja create mode 100644 VAF/src/vaf/cli_core/main/templates/application_module_integration_model_import/import_{{module_name_snk}}.py.jinja create mode 100644 VAF/src/vaf/cli_core/main/templates/application_module_integration_model_subfolder/__init__.py.jinja create mode 100644 VAF/src/vaf/cli_core/main/templates/interface_model_subfolder/__init__.py.jinja create mode 100644 VAF/src/vaf/constants.py create mode 100644 VAF/src/vaf/py.typed create mode 100644 VAF/src/vaf/vafgeneration/__init__.py create mode 100644 VAF/src/vaf/vafgeneration/generation.py create mode 100644 VAF/src/vaf/vafgeneration/templates/common/cmake_copyright.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/cmake_interface_library.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/cmake_library.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/cmake_subdirs.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/copyright.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/cpp_file_base.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/common/h_file_base.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/cmake_implementation.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_cmake.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_main_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_module_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_cac_support/platform.py.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_cmake_common/data_types_cmake.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_conan/conan_deps.list.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/CMakeLists_txt.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/main_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_CMakeLists_txt.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/macros.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/macros_mocks.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_mock_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_mock_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_interface/operation_output.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/basetypes_proto.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_proto.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_transformer.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_proto.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_transformer.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_protobuf/protobuf_cmake.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_silkit/module_cmake.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_cpp.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/array_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/enum_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/map_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/string_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/struct_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/type_ref_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/vector_h.jinja create mode 100644 VAF/src/vaf/vafgeneration/vaf_application_communication.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_application_module.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_cac_support.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_cmake_common.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_conan.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_controller.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_generate_application_module.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_generate_common.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_generate_project.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_interface.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_protobuf_serdes.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_silkit.py create mode 100644 VAF/src/vaf/vafgeneration/vaf_std_data_types.py create mode 100644 VAF/src/vaf/vafmodel/__init__.py create mode 100644 VAF/src/vaf/vafmodel/vafmodel.py create mode 100644 VAF/src/vaf/vafpy/__init__.py create mode 100644 VAF/src/vaf/vafpy/core.py create mode 100644 VAF/src/vaf/vafpy/datatypes.py create mode 100644 VAF/src/vaf/vafpy/elements.py create mode 100644 VAF/src/vaf/vafpy/executable.py create mode 100644 VAF/src/vaf/vafpy/factory.py create mode 100644 VAF/src/vaf/vafpy/model_runtime.py create mode 100644 VAF/src/vaf/vafpy/runtime.py create mode 100644 VAF/src/vaf/vafpy/task.py create mode 100644 VAF/src/vaf/vafpy/validator.py create mode 100644 VAF/src/vaf/vafvssimport/vss/__init__.py create mode 100644 VAF/src/vaf/vafvssimport/vss/vss_model.py create mode 100644 VAF/src/vaf/vafvssimport/vss/vss_types.py create mode 100644 VAF/src/vaf/vafvssimport/vss_import.py create mode 100644 VAF/tests/Makefile create mode 100644 VAF/tests/ModelValidation/.schema-infos.json create mode 100644 VAF/tests/ModelValidation/test_schema_release_version.py create mode 100644 VAF/tests/ModelValidation/test_validate_to_vaf_schema.py create mode 100644 VAF/tests/__init__.py create mode 100644 VAF/tests/component/cli/test_main.py create mode 100644 VAF/tests/conftest.py create mode 100644 VAF/tests/unit/__init__.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_263/model/vaf/model.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module1.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module2.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_460/goal-model.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_460/interfaces.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_460/schoca_cola.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/fake.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/goal-model.json create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/interfaces.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/invisible.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/mockery.py create mode 100644 VAF/tests/unit/cli_core/test_data/ftaf_467/model.py create mode 100644 VAF/tests/unit/cli_core/test_data/minimal_vss.json create mode 100644 VAF/tests/unit/cli_core/test_data/mock_prj/model/app/model.json create mode 100644 VAF/tests/unit/cli_core/test_data/mock_prj/model/vaf/model.json create mode 100644 VAF/tests/unit/cli_core/test_make_cmd.py create mode 100644 VAF/tests/unit/cli_core/test_model_cmd.py create mode 100644 VAF/tests/unit/cli_core/test_project_cmd.py create mode 100644 VAF/tests/unit/vafgeneration/__init__.py create mode 100644 VAF/tests/unit/vafgeneration/application_communication/CMakeLists.txt create mode 100644 VAF/tests/unit/vafgeneration/application_communication/my_service_module.cpp create mode 100644 VAF/tests/unit/vafgeneration/application_communication/my_service_module.h create mode 100644 VAF/tests/unit/vafgeneration/application_module/app.cpp create mode 100644 VAF/tests/unit/vafgeneration/application_module/app.h create mode 100644 VAF/tests/unit/vafgeneration/application_module/app_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/application_module/apps_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/application_module/base.cpp create mode 100644 VAF/tests/unit/vafgeneration/application_module/base.h create mode 100644 VAF/tests/unit/vafgeneration/application_module/base_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/application_module/main.cpp create mode 100644 VAF/tests/unit/vafgeneration/application_module/test_base.cpp create mode 100644 VAF/tests/unit/vafgeneration/application_module/test_base.h create mode 100644 VAF/tests/unit/vafgeneration/application_module/test_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/application_module/tests.cpp create mode 100644 VAF/tests/unit/vafgeneration/cac_support/silkit.py.example create mode 100644 VAF/tests/unit/vafgeneration/cmake_common/cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/cmake_common/exe_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/cmake_common/libs_cmake.txt create mode 100644 VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append.txt create mode 100644 VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append2.txt create mode 100644 VAF/tests/unit/vafgeneration/controller/CMakeLists.txt create mode 100644 VAF/tests/unit/vafgeneration/controller/controller.cpp create mode 100644 VAF/tests/unit/vafgeneration/controller/controller.h create mode 100644 VAF/tests/unit/vafgeneration/controller/main.cpp create mode 100644 VAF/tests/unit/vafgeneration/controller/user_controller.cpp create mode 100644 VAF/tests/unit/vafgeneration/controller/user_controller.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/model_changed_complex.json create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_base_test_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/CMakeLists.txt create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_base_test_edited.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/model_base.json create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/removal/model_changed.json create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_base_test_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_base_test_edited.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/model_changed.json create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_base_test_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/model_changed.json create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_base_test_goal.h create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.cpp create mode 100644 VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.h create mode 100644 VAF/tests/unit/vafgeneration/input_model_examples/silkit.json create mode 100644 VAF/tests/unit/vafgeneration/interface/test1_consumer_expected.h create mode 100644 VAF/tests/unit/vafgeneration/interface/test1_consumer_mock_expected.h create mode 100644 VAF/tests/unit/vafgeneration/interface/test1_provider_expected.h create mode 100644 VAF/tests/unit/vafgeneration/interface/test1_provider_mock_expected.h create mode 100644 VAF/tests/unit/vafgeneration/protobuf/protobuf_test.proto create mode 100644 VAF/tests/unit/vafgeneration/protobuf/protobuf_test2.proto create mode 100644 VAF/tests/unit/vafgeneration/silkit/my_consumer_module.cpp create mode 100644 VAF/tests/unit/vafgeneration/silkit/my_consumer_module.h create mode 100644 VAF/tests/unit/vafgeneration/silkit/my_provider_module.cpp create mode 100644 VAF/tests/unit/vafgeneration/silkit/my_provider_module.h create mode 100644 VAF/tests/unit/vafgeneration/test_application_communication.py create mode 100644 VAF/tests/unit/vafgeneration/test_application_module.py create mode 100644 VAF/tests/unit/vafgeneration/test_cac_support.py create mode 100644 VAF/tests/unit/vafgeneration/test_cmake_common.py create mode 100644 VAF/tests/unit/vafgeneration/test_controller.py create mode 100644 VAF/tests/unit/vafgeneration/test_generation.py create mode 100644 VAF/tests/unit/vafgeneration/test_merge_after_regeneration.py create mode 100644 VAF/tests/unit/vafgeneration/test_protobuf.py create mode 100644 VAF/tests/unit/vafgeneration/test_silkit.py create mode 100644 VAF/tests/unit/vafgeneration/test_vafinterface.py create mode 100644 VAF/tests/unit/vafgeneration/test_vafproject.py create mode 100644 VAF/tests/unit/vafgeneration/test_vss.py create mode 100644 VAF/tests/unit/vafgeneration/vss/seat_vss.json create mode 100644 VAF/tests/unit/vafmodel/__init__.py create mode 100644 VAF/tests/unit/vafmodel/test_example.py create mode 100644 VAF/tests/unit/vafmodel/test_model.json create mode 100644 VAF/tests/unit/vafmodel/test_model2.json create mode 100644 VAF/tests/unit/vafpy/__init__.py create mode 100644 VAF/tests/unit/vafpy/test_cac.py create mode 100644 VAF/tests/unit/vafpy/test_data/common/.vafconfig.json create mode 100644 VAF/tests/unit/vafpy/test_data/common/silkit-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/common/silkit.py create mode 100644 VAF/tests/unit/vafpy/test_data/common/vss-derived-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/common/vss.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_258/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_260/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_260/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_260_bug/silkit-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_339/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_354/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_386/app_module1.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/InterfaceProject.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/interface_project.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_386/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_386/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_394/app_module1.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_394/goal-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_394/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_394/silkit-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_394/silkit.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_399/app_module1.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_399/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_399/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_399/vss-derived-model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_399/vss.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_421/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_421/silkit.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_422/app_module1.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_422/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_422/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_457/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_553/app_module1.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/Interfaces.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/interfaces.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_553/model.py create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_576/model.json create mode 100644 VAF/tests/unit/vafpy/test_data/ftaf_576/model.py create mode 100644 VAF/tests/unit/vafpy/test_example.py create mode 100644 VAF/tests/unit/vafvssimport/__init__.py create mode 100644 VAF/tests/unit/vafvssimport/test_data/minimal_vss.json create mode 100644 VAF/tests/unit/vafvssimport/test_export_arrays.py create mode 100644 VAF/tests/unit/vafvssimport/test_export_enum.py create mode 100644 VAF/tests/unit/vafvssimport/test_export_min_max.py create mode 100644 VAF/tests/unit/vafvssimport/test_export_struct.py create mode 100644 VAF/tests/unit/vafvssimport/test_vss_import.py create mode 100644 version.txt diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1864376 --- /dev/null +++ b/.clang-format @@ -0,0 +1,89 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ (IWYU pragma:|VECTOR |VCA[_ ]|FETA[_ ]|COV_)|\\(trace|copydoc)[ ]+[^ ]' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..a5d1261 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,82 @@ +--- +Checks: > + -*, + clang-diagnostic-*, + clang-analyzer-*, + vector-*, + readability-*, + bugprone-*, + modernize-*, + performance-*, + cert-*, + cppcoreguidelines-*, + hicpp-*, + portability-*, + -readability-uppercase-literal-suffix, + -cert-dcl16-c, + -hicpp-uppercase-literal-suffix, + -readability-named-parameter, + -hicpp-named-parameter, + -readability-redundant-member-init, + -readability-make-member-function-const, + +FormatStyle: file + +# warnings are NOT treated as errors +WarningsAsErrors: "" + +# analyze all included headers (not system-headers) +HeaderFilterRegex: ".*" + +CheckOptions: + ########## readability-identifier-naming ######### + # Class, structs, enums and unions + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } # redundant with ClassCase + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + + # Functions and methods (all are treated equally, only FunctionCase needed) + - { key: readability-identifier-naming.FunctionCase, value: CamelCase } + + # Non-static and static non-const variables and pointers + - { key: readability-identifier-naming.VariableCase, value: lower_case } + + # static, global or constexpr constant variables + - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } + - { key: readability-identifier-naming.StaticConstantPrefix, value: k } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantPrefix, value: k } + - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } + - { key: readability-identifier-naming.ConstexprVariablePrefix, value: k } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantPrefix, value: k } + + # Class / Struct data members (including static members) + - { key: readability-identifier-naming.MemberCase, value: lower_case } + - { key: readability-identifier-naming.MemberSuffix, value: _ } + - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } + - { key: readability-identifier-naming.PublicMemberCase, value: lower_case } # public members dont require trailing _ + + # Parameters + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + + # Templates + - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } + - { key: readability-identifier-naming.ValueTemplateParameterCase, value: aNy_CasE } # not clearly specified + + # Miscellaneous + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE } + - { key: readability-identifier-naming.MacroDefinitionIgnoredRegexp, value: .*_H_ } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + + ########## End of readability-identifier-naming ########## + + - { key: vector-noexcept-special-functions.FunctionsToInclude, value: "Swap" } + - { key: hicpp-move-const-arg.CheckTriviallyCopyableMove, value: false } + - { key: performance-move-const-arg.CheckTriviallyCopyableMove, value: false } + +... diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..9312e1f --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,93 @@ +ARG USER="eclipse" +ARG PDM_VERSION="2.22.4" +ARG CONAN_VERSION="2.13.0" + +FROM ubuntu:24.04 AS vaf-base +ARG TZ="Europe/Berlin" +ARG USER +ARG CONAN_VERSION +ARG PDM_VERSION + +ENV LC_ALL="C.UTF-8" \ + LANG="C.UTF-8" + +# Install common APT packages +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + ccache \ + clangd \ + cmake \ + g++-12 \ + gdb \ + git \ + pipx \ + python3-pip \ + python3.12 \ + python3.12-venv \ + rake \ + sudo \ + nano \ + vim \ + emacs \ + ssh \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /var/cache/* \ + && rm -rf /var/log/* + +# Comment out and adapt the lines below to add SSL certificates if needed: +# ADD url-to-your-certificate-one /usr/local/share/ca-certificates/your-certificates-folder +# ADD url-to-your-certificate-two /usr/local/share/ca-certificates/your-certificates-folder +# RUN update-ca-certificates /usr/local/share/ca-certificates/ +# ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + +# Build & install SilKit +RUN mkdir -p /tmp/silkit \ + && git clone -j4 https://github.com/vectorgrp/sil-kit.git /tmp/silkit \ + && git -C /tmp/silkit checkout tags/v4.0.55 \ + && git -C /tmp/silkit submodule update --init --recursive \ + && mkdir /tmp/silkit/build \ + && cmake -DSILKIT_BUILD_DEMOS=OFF -DSILKIT_BUILD_TESTS=OFF -DSILKIT_BUILD_DASHBOARD=OFF -DSILKIT_BUILD_STATIC=ON \ + -S /tmp/silkit -B /tmp/silkit/build \ + && cmake --build /tmp/silkit/build --target install --parallel 12 \ + # Workaround for broken installation when building statically linked libraries + && cp /tmp/silkit/build/ThirdParty/_tp_spdlog/libspdlog.a /usr/local/lib/ \ + && cp /tmp/silkit/build/ThirdParty/_tp_yaml-cpp/libyaml-cpp.a /usr/local/lib/ \ + && cp /tmp/silkit/build/Release/libSilKit.a /usr/local/lib/ \ + && rm -rf /tmp/silkit + +# Create working directory and add user +RUN mkdir -p /workspaces \ + # Create a default user + && userdel -r ubuntu \ + && useradd -m -s /bin/bash -u 1000 ${USER} --groups sudo \ + # Allow usage of sudo without password + && echo "${USER} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${USER}_all \ + && chown -R ${USER}:${USER} /workspaces +USER ${USER} + +# Install common python dependencies +RUN pip3 install conan==${CONAN_VERSION} --break-system-packages \ + && pipx ensurepath \ + && pipx install pdm==${PDM_VERSION} \ + && pipx install pre-commit \ + && rm -rf /home/${USER}/.cache/* + +# Pre-build conan packages +RUN --mount=type=bind,source=SwLibraries/vaf_core_library,target=/tmp/vafcpp/src,readwrite \ + --mount=type=bind,source=Container/conan,target=/tmp/conan,readwrite \ + --mount=type=bind,source=version.txt,target=/tmp/version.txt \ + sudo chown -R 1000:1000 /tmp/vafcpp /tmp/conan \ + && export PATH="$PATH:/home/${USER}/.local/bin" \ + && cd /tmp/vafcpp/src \ + && conan create . --profile:all=./test_package/gcc12__x86_64-pc-linux-elf -s build_type=Release \ + && conan create . --profile:all=./test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug \ + && conan install /tmp/conan -pr:a=/tmp/conan/gcc12__x86_64-pc-linux-elf --build=missing \ + && conan install /tmp/conan -pr:a=/tmp/conan/gcc12__x86_64-pc-linux-elf --build=missing -s build_type=Debug \ + && conan cache clean + +WORKDIR /workspaces diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e7528a5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,66 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/cpp +{ + "name": "VAF", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "runArgs": [ + "--sysctl=net.ipv6.conf.all.disable_ipv6=0" + ], + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff" + }, + "editor.formatOnSave": true, + "json.format.keepLines": true, + "cmake.configureOnEdit": true, + "cmake.configureOnOpen": false, + "C_Cpp.intelliSenseEngine": "disabled", + "ruff.exclude": [ + ".pdm-build" + ], + "ruff.nativeServer": true + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "charliermarsh.ruff", + "llvm-vs-code-extensions.vscode-clangd", + "eamodio.gitlens", + "ms-python.python", + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "SanaAjani.taskrunnercode", + "tamasfe.even-better-toml", + "twxs.cmake", + "yzhang.markdown-all-in-one" + ] + } + }, + "containerEnv": { + "NODE_EXTRA_CA_CERTS": "/etc/ssl/certs/ca-certificates.crt", + "REQUESTS_CA_BUNDLE": "/etc/ssl/certs/ca-certificates.crt" + }, + // Adjust the user in the Dockerfile if you're changing it here. Otherwise the prebuilt conan packages are unavailable. + // "remoteUser": "eclipse", + "mounts": [ + // Uncomment the line below to mount your SSH keys into the container. + "source=${localEnv:HOME}/.ssh,target=/home/eclipse/.ssh,type=bind,consistency=cached", + // Uncomment the line below to mount your local SSL certificates into the container. + "source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt,type=bind,consistency=cached", + "source=vaf_bashhistory,target=/commandhistory,type=volume" + ], + "postCreateCommand": "sudo chown -R eclipse /commandhistory && echo \"export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history\" >> \"/home/eclipse/.bashrc\"", + "postStartCommand": "pre-commit install", + "capAdd": [ + "NET_ADMIN", + "NET_RAW" + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..861fc4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.tmp/ +*.bkp +.cache +build +.rake_tasks~ +.pdm-python +_vafinstall +vafinstall.tar.gz +public +VAF/.python-version +**/__pycache__/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..74c24f8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +repos: + - repo: local + hooks: + - id: vaf-commit-hook-format + name: VAF - make format + entry: ./.pre-commit-hooks/perform-format.sh + language: script + pass_filenames: false + verbose: true + - id: vaf-commit-hook-lint + name: VAF - make lint + entry: ./.pre-commit-hooks/perform-lint.sh + language: script + pass_filenames: false + verbose: true + - id: vaf-commit-hook-test + name: VAF - make test + entry: ./.pre-commit-hooks/perform-test.sh + language: script + pass_filenames: false + verbose: true + - id: vaf-commit-hook-build + name: VAF - make build + entry: ./.pre-commit-hooks/perform-build.sh + language: script + pass_filenames: false + verbose: true diff --git a/.pre-commit-hooks/perform-build.sh b/.pre-commit-hooks/perform-build.sh new file mode 100644 index 0000000..bfdb4e7 --- /dev/null +++ b/.pre-commit-hooks/perform-build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +CURRENT_DIR=$(pwd) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd $SCRIPT_DIR/../VAF +make build +cd $CURRENT_DIR diff --git a/.pre-commit-hooks/perform-format.sh b/.pre-commit-hooks/perform-format.sh new file mode 100644 index 0000000..4539e0c --- /dev/null +++ b/.pre-commit-hooks/perform-format.sh @@ -0,0 +1,6 @@ +#!/bin/bash +CURRENT_DIR=$(pwd) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd $SCRIPT_DIR/../VAF +make format +cd $CURRENT_DIR diff --git a/.pre-commit-hooks/perform-lint.sh b/.pre-commit-hooks/perform-lint.sh new file mode 100644 index 0000000..455ba3d --- /dev/null +++ b/.pre-commit-hooks/perform-lint.sh @@ -0,0 +1,6 @@ +#!/bin/bash +CURRENT_DIR=$(pwd) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd $SCRIPT_DIR/../VAF +make lint +cd $CURRENT_DIR diff --git a/.pre-commit-hooks/perform-test.sh b/.pre-commit-hooks/perform-test.sh new file mode 100644 index 0000000..b25586f --- /dev/null +++ b/.pre-commit-hooks/perform-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +CURRENT_DIR=$(pwd) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd $SCRIPT_DIR/../VAF +make test PYTEST_FLAGS="--runslow" +cd $CURRENT_DIR diff --git a/.vscode/scripts/mk.sh b/.vscode/scripts/mk.sh new file mode 100644 index 0000000..7c0f634 --- /dev/null +++ b/.vscode/scripts/mk.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Search Makefiles recursively in a directory named VAF and run make(1) there, if one is found +# + +DEPTH="$(pwd | tr -c -d / | wc -c)" +MOD=. +NPD="--no-print-directory" + +if [[ "$*" == *"-w"* || "$*" == *"--print-directory"* ]]; then + NPD= +fi + +while [[ $DEPTH -gt 0 ]]; do + if [[ -f $MOD/VAF/Makefile ]]; then + if [[ $MOD == "." ]]; then + make -C VAF "$@" + else + echo "make -C $MOD/VAF $*" + make $NPD -C $MOD/VAF "$@" + fi + exit $? + fi + MOD=$MOD/.. + (( DEPTH-- )) || true +done + +echo "No Makefile found in a directory named VAF." >&2 +exit 1 diff --git a/.vscode/scripts/reinstall_wheels.sh b/.vscode/scripts/reinstall_wheels.sh new file mode 100644 index 0000000..67707e7 --- /dev/null +++ b/.vscode/scripts/reinstall_wheels.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Search dist folder recursively and installs containing *.whl files, if found +# + +DEPTH="$(pwd | tr -c -d / | wc -c)" +MOD=. + +while [[ $DEPTH -gt 0 ]]; do + if [[ -d $MOD/dist ]]; then + for file in $MOD/dist/*.whl; do + if [[ -f $file ]]; then + echo "Installing $file" + pip3 install "$file" --force-reinstall --no-deps --break-system-packages + fi + done + exit 0 + fi + MOD=$MOD/.. + (( DEPTH-- )) || true +done + +echo "No wheels found." >&2 +exit 1 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e3247d8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "python.defaultInterpreterPath": "${workspaceFolder}/VAF/.venv/bin/python", + + // testing + "python.testing.pytestEnabled": true, + "python.testing.pytestArgs": [ + "--no-cov", // when using 'pytest-cov' we need to disable coverage when debugging + "VAF/tests", + "-vv", + "--runslow" + ], + "python.testing.unittestEnabled": false, + + // misc + "window.zoomLevel": 0, + "terminal.integrated.allowChords": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..50de0a9 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,75 @@ +{ + // See https://code.visualstudio.com/docs/editor/tasks + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "TestPythonPackage", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/mk.sh -w test", + "options": { + "cwd": "${fileDirname}" + }, + "presentation": { + "reveal": "silent", + "clear": true, + } + }, + { + "label": "TestSlowPythonPackage", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/mk.sh -w test PYTEST_FLAGS='--runslow'", + "options": { + "cwd": "${fileDirname}" + }, + "presentation": { + "reveal": "silent", + "clear": true, + } + }, + { + "label": "LintPythonPackage", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/mk.sh -w check-format lint", + "options": { + "cwd": "${fileDirname}" + }, + "presentation": { + "reveal": "silent", + "clear": true, + } + }, + { + "label": "LintTestPythonPackage", + "dependsOrder": "sequence", + "dependsOn": [ + "LintPythonPackage", + "TestSlowPythonPackage", + ], + }, + { + "label": "UpdatePythonPackage", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/mk.sh -w clean build && ${workspaceFolder}/.vscode/scripts/reinstall_wheels.sh", + "group": "build", + "options": { + "cwd": "${fileDirname}" + }, + "presentation": { + "reveal": "silent", + "clear": true, + } + }, + { + "label": "Build TC", + "type": "shell", + "command": "cd TechnicalConcept && make html", + "group": "build", + "options": { }, + "presentation": { + "reveal": "silent", + "clear": true, + } + }, + ] +} diff --git a/Container/README.md b/Container/README.md new file mode 100644 index 0000000..8010b97 --- /dev/null +++ b/Container/README.md @@ -0,0 +1,8 @@ +# Container + +Please use the provided build script `build.sh` to create the container image for further use in VAF +projects. + +>**âš ï¸ Note** +>Several dependencies get downloaded during this process. +>Please make sure that an active internet connection is available. diff --git a/Container/build.sh b/Container/build.sh new file mode 100644 index 0000000..3dc2b10 --- /dev/null +++ b/Container/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# When you modify the tags, be sure to also change the image parameter in the workspace devcontainer template. +docker build -t vaf:latest -t vaf:$(cat ../version.txt) -f eclipse.Dockerfile .. diff --git a/Container/conan/conanfile.txt b/Container/conan/conanfile.txt new file mode 100644 index 0000000..63431f2 --- /dev/null +++ b/Container/conan/conanfile.txt @@ -0,0 +1,3 @@ +[requires] +protobuf/5.27.0 +gtest/1.13.0 diff --git a/Container/conan/gcc12__x86_64-pc-linux-elf b/Container/conan/gcc12__x86_64-pc-linux-elf new file mode 100644 index 0000000..99e4709 --- /dev/null +++ b/Container/conan/gcc12__x86_64-pc-linux-elf @@ -0,0 +1,14 @@ +[settings] +arch=x86_64 +build_type=Release +compiler=gcc +compiler.version=12 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-12 +CXX=g++-12 diff --git a/Container/eclipse.Dockerfile b/Container/eclipse.Dockerfile new file mode 100644 index 0000000..8a4c60f --- /dev/null +++ b/Container/eclipse.Dockerfile @@ -0,0 +1,137 @@ +ARG USER="eclipse" +ARG PDM_VERSION="2.22.4" +ARG CONAN_VERSION="2.13.0" + +FROM ubuntu:24.04 AS vaf-base +ARG TZ="Europe/Berlin" +ARG USER +ARG CONAN_VERSION + +ENV LC_ALL="C.UTF-8" \ + LANG="C.UTF-8" + +# Install common APT packages +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + ccache \ + cmake \ + g++-12 \ + git \ + pipx \ + python3-pip \ + python3.12 \ + python3.12-venv \ + sudo \ + ssh \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /var/cache/* \ + && rm -rf /var/log/* + +# Comment out and adapt the lines below to add SSL certificates if needed: +# ADD url-to-your-certificate-one /usr/local/share/ca-certificates/your-certificates-folder +# ADD url-to-your-certificate-two /usr/local/share/ca-certificates/your-certificates-folder +# RUN update-ca-certificates /usr/local/share/ca-certificates/ +# ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + +# Create working directory and add user +RUN mkdir -p /workspaces \ + # Create a default user + && userdel -r ubuntu \ + && useradd -m -s /bin/bash -u 1000 ${USER} --groups sudo \ + # Allow usage of sudo without password + && echo "${USER} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${USER}_all \ + && chown -R ${USER}:${USER} /workspaces +USER ${USER} + +# Install common python dependencies +RUN pip3 install conan==${CONAN_VERSION} --break-system-packages\ + && rm -rf /home/${USER}/.cache/* + +WORKDIR /workspaces + +FROM vaf-base AS builder +ARG PDM_VERSION + +# Install build dependencies +RUN pipx ensurepath \ + && pipx install pdm==${PDM_VERSION} + +# Build SIL Kit +RUN mkdir -p /tmp/silkit \ + && git clone --recurse-submodules -j4 https://github.com/vectorgrp/sil-kit.git /tmp/silkit \ + && git -C /tmp/silkit checkout tags/v4.0.55 \ + && git -C /tmp/silkit submodule update --init --recursive \ + && mkdir /tmp/silkit/build \ + && cmake -DSILKIT_BUILD_DEMOS=OFF -DSILKIT_BUILD_TESTS=OFF -DSILKIT_BUILD_DASHBOARD=OFF -DSILKIT_BUILD_STATIC=ON \ + -DCMAKE_INSTALL_PREFIX=/tmp/silkit/install -S /tmp/silkit -B /tmp/silkit/build \ + && cmake --build /tmp/silkit/build --target install --parallel 12 + +# Build conan packages +RUN --mount=type=bind,source=SwLibraries/vaf_core_library,target=/tmp/vafcpp/src,readwrite \ + --mount=type=bind,source=Container/conan,target=/tmp/conan,readwrite \ + --mount=type=bind,source=version.txt,target=/tmp/version.txt \ + sudo chown -R 1000:1000 /tmp/vafcpp /tmp/conan \ + && export PATH="$PATH:/home/${USER}/.local/bin" \ + && cd /tmp/vafcpp/src \ + && conan create . --profile:all=./test_package/gcc12__x86_64-pc-linux-elf -s build_type=Release \ + && conan create . --profile:all=./test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug \ + && conan install /tmp/conan -pr:a=/tmp/conan/gcc12__x86_64-pc-linux-elf --build=missing \ + && conan install /tmp/conan -pr:a=/tmp/conan/gcc12__x86_64-pc-linux-elf --build=missing -s build_type=Debug \ + && conan cache clean + +# Build vafcli +RUN --mount=type=bind,source=VAF,target=/tmp/vaf/src,readwrite \ + --mount=type=bind,source=version.txt,target=/tmp/version.txt \ + sudo chown -R 1000:1000 /tmp/vaf \ + && rm -f /tmp/vaf/.python-version \ + && export PATH="$PATH:/home/${USER}/.local/bin" \ + && export PDM_BUILD_SCM_VERSION=$(cat /tmp/version.txt) \ + && make -C /tmp/vaf/src clean build \ + && mv /tmp/vaf/src/dist/*.whl /tmp/vaf + +FROM vaf-base AS devcontainer + +# Install packages requiring root permissions +USER root +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash-completion \ + clangd \ + emacs \ + gdb \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /var/cache/* \ + && rm -rf /var/log/* + +# Install SIL Kit +RUN --mount=type=bind,from=builder,source=/tmp/silkit,target=/tmp/silkit \ + cp /tmp/silkit/install/bin/* /usr/local/bin/ \ + && cp -r /tmp/silkit/install/include/silkit /usr/local/include/ \ + && cp -r /tmp/silkit/install/lib/cmake /usr/local/lib/ \ + # Workaround for broken installation when building statically linked libraries + && cp /tmp/silkit/build/ThirdParty/_tp_spdlog/libspdlog.a /usr/local/lib/ \ + && cp /tmp/silkit/build/ThirdParty/_tp_yaml-cpp/libyaml-cpp.a /usr/local/lib/ \ + && cp /tmp/silkit/build/Release/libSilKit.a /usr/local/lib/ + +# Switch user and set environment variables +USER ${USER} +ENV PATH="$PATH:/home/${USER}/.local/bin" + +# Install remaining artifacts from build stage +RUN --mount=type=bind,from=builder,source=/tmp/vaf,target=/tmp/vaf \ + # Install vafcli + pip3 install /tmp/vaf/*.whl --break-system-packages \ + && rm -rf /home/${USER}/.cache/* \ + && _VAF_COMPLETE=bash_source vaf | sudo tee /usr/share/bash-completion/completions/vaf > /dev/null + +COPY --from=builder /home/${USER}/.conan2 /home/${USER}/.conan2 + +# Add Demos +COPY Demo /opt/vaf/Demo diff --git a/Container/scripts/conan-helper.sh b/Container/scripts/conan-helper.sh new file mode 100644 index 0000000..fce711e --- /dev/null +++ b/Container/scripts/conan-helper.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +usage() { + echo "Usage: $0" + echo -e "\t --get-package PKG_NAME VERSION BUILD_TYPE COMPILER_VERSION CPP_STD" + echo -e "\t --get-path PKG_NAME VERSION" + exit 1 +} + +function get_path { + json_data=$(conan list "$pkg_name/$version:*" --format json) + revision=$(echo "$json_data" | jq -r ".\"Local Cache\".\"$pkg_name/$version\".revisions | keys[0]") + package=$(echo "$json_data" | jq -r ".\"Local Cache\".\"$pkg_name/$version\".revisions.\"$revision\".packages | keys[0]") + + conan cache path "$pkg_name/$version#$revision:$package" +} + +if [ $# -lt 3 ]; then + usage +fi + +func=$1 +pkg_name=$2 +version=$3 +shift 3 + +case $func in + --get-path) + get_path "$@" + ;; + --get-package) + get_package "$@" + ;; + *) + usage + ;; +esac diff --git a/Demo/HelloVaf/README.md b/Demo/HelloVaf/README.md new file mode 100644 index 0000000..4eb306d --- /dev/null +++ b/Demo/HelloVaf/README.md @@ -0,0 +1,359 @@ +# Hello VAF Demo + +This `Hello, World!` style demo, introduces to the Vehicle Application Framework (VAF) with a simple +example. The figure below provides a schematic illustration to give an overview of its building +blocks: + + + +`AppModule1` provides a communication interface that is used by `AppModule2`. + +The first application module periodically sends a message of format `Hello, VAF! - MsgID: <ID>` +to the second application module. The second module subscribes to message changes and prints new +messages on the terminal. It uses an operation to periodically change the MsgID of the first +application module, which is part of the message above. + +## Prerequisites + +### Docker setup +All steps in this tutorial are executed from within a container. Recipe and build script for the +appropriate VAF image are provided in the [Container](../../Container/README.md) folder of this +project repository. + +Execute `docker images` to check if a REPOSITORY named `vaf` with TAG `latest` is available in the +list before moving on to the next steps. + +### Workspace +The Vehicle Application Framework (VAF) supports three different project types, *interface project*, +*app-module project*, and *integration project*. These project types are useful for the organization +of small and large projects but especially helpful, when working with distributed development teams. + +To group projects that belong together, it is recommended to create a so-called *workspace*. This +parent folder contains for example a devcontainer file to facilitate the work with VS Code. + +To create a workspace, navigate to the target location, then use the below command to start a VAF +container and finally, create a VAF workspace there and enter the new directory. +``` bash +cd <some-dir> +docker run -it --rm --network=host -v$PWD:$PWD -w$PWD vaf:latest /bin/bash + +vaf workspace init +Enter your workspace name: VafWorkspace + +cd VafWorkspace +``` + +The following steps of the tutorial can either be executed in this already open terminal window or +directly from VS Code as described below. + +### VS Code setup +To work with the VS Code container extension, enter a VAF workspace directory and make sure to +re-open the folder in the container: + +* Open a remote window (bottom-left corner) + + + +* Re-open project in container + + + +In the bottom-left corner you find also a task runner extension that supports with the individual +steps of the VAF workflow. Commands can be clicked instead of using the command line interface. + +>**â„¹ï¸ Note** +> The execution path gets derived from the current working directory based on the currently opened +> file in editor area of the IDE. + +## Project setup + +First step is to create an integration project. This type of project deals with the integration of +an application, which includes instantiation and wiring of application modules, configuration of the +executable(s), and finally, the build of the binaries for execution on the target machine. +Application module projects can either be created in place, i.e., as sub-project of an integration +project, or imported from some external location. For the sake of simplicity, this demo makes use of +the first option. + +First step is to create the required projects by using the following CLI commands: + +``` bash +vaf project init integration +Enter your project name: HelloVaf +? Enter the directory to store your project in . + +cd HelloVaf + +vaf project create app-module +Enter the name of the app-module: AppModule1 +Enter the namespace of the app-module: demo +? Enter the path to the project root directory . + +vaf project create app-module +Enter the name of the app-module: AppModule2 +Enter the namespace of the app-module: demo +? Enter the path to the project root directory . +``` + +The above commands create the structure of the corresponding projects. The application module +sub-projects are stored in the `HelloVaf/src/application_modules` directory, i.e., directly in the +integration project. + +## Definition of interfaces + +Communication between application modules is defined by means of communication interfaces. The +Configuration as Code (CaC) file for this step is part of the project template and located in the +`model` folder of each app-module sub-project. Extend the `app_module1.py` file of the first +app-module located in `HelloVaf/src/application_modules/app_module1/model` as follows: + +``` python +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) +``` + +This snippet defines a simple interface containing one data element (`Message`) and one operation +(`SetMsgId`). + +As this interface definition is also used by the other app-module, make sure to copy the above +definition to the corresponding CaC file of the second app-module. + +## Configuration of application modules + +Next step is the configuration of both app-modules. For `AppModule1`, modify the generated template +of the CaC file to add a provider instance of the above interface and a periodically executed task: + +``` python +app_module1.add_provided_interface("HelloWorldProvider", interface) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=500)) +app_module1.add_task(task=periodic_task) +``` + +The configuration snippet for `AppModule2` is almost similar. Only the interface instance is a +consumed one in this case: + +``` python +app_module2.add_consumed_interface("HelloWorldConsumer", interface) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=1000)) +app_module2.add_task(task=periodic_task) +``` + +With this, the Configuration as Code part is complete. Next step is to start the code generation for +both app-modules. Change to the appropriate project directories +`HelloVaf/src/application_modules/app_module1` and `HelloVaf/src/application_modules/app_module2` to +run: + +``` bash +vaf project generate +``` + +This step provides the implementation stubs in the `implementation` subdirectory of the app-module +projects. It also configures CMake with a release and debug preset to enable support by the VS Code +CMake Tools extension as well as IntelliSense features. + +## Implementation of business logic +Now, some business logic can be added according to the demo description in the introduction of this +tutorial. For that, the periodic tasks of both app-modules need to be implemented. Further, an +operation handler needs to be registered in `AppModule1`. In `AppModule2` a data element handler is +needed. + +In the first app-module, add the following snippet to the constructor +(see `HelloVaf/src/application_modules/app_module1/implementation/src/app_module1.cpp`): + +``` cpp +HelloWorldProvider_->RegisterOperationHandler_SetMsgId( + [this](const std::uint8_t& msg_id) { msg_id_ = static_cast<uint8_t>(msg_id); } +); +``` + +Next, extend the periodic task with a simple method: + +``` cpp +std::string myMsg = "Hello, VAF! - MsgID: " + std::to_string(msg_id_); +HelloWorldProvider_->Set_Message(myMsg.c_str()); +``` + +Additionally, a member attribute must be defined in the corresponding header file of AppModule1: + +``` cpp + private: + uint8_t msg_id_; +``` + +In the constructor of the second app-module, register a data element handler as follows: + +``` cpp +HelloWorldConsumer_->RegisterDataElementHandler_Message( + GetName(), + [](const auto& hello_text) { std::cout << "Received: " << *hello_text << std::endl; } +); +``` + +Further, modify the periodic task to include the following snippet: + +``` cpp +static uint8_t msg_id = 0; +HelloWorldConsumer_->SetMsgId(msg_id++); +``` + +Also, extend the include directives, for example with `#include <iostream>` in `app_module2.cpp`. + +>**â„¹ï¸ Note** +> To check for compilation errors, you can compile the app-modules into static libraries using `vaf +> make build` inside of the app-module project directory. + +## Executable configuration + +Returning to the integration project, both application modules can now be instantiated. Those +instances are then mapped to some executable, and finally, connected among each other. First, +however, the model changes from the application module projects above must be updated as to be +present on the level of the integration project. To do so, run the following command from the +integration projects' root directory, i.e. `HelloVaf`: + +``` bash +vaf model update +``` + +Select both application modules in the appearing interactive dialog. + +Now, the CaC file of the integration project in `HelloVaf/model/vaf/hello_vaf.py` can be extended: + +``` python +# Create executable instances +executable = Executable("HelloVaf") + +# Add application modules to executable instances +executable.add_application_module(AppModule1, [(Instances.AppModule1.Tasks.PeriodicTask, timedelta(milliseconds=10), 0)]) +executable.add_application_module(AppModule2, [(Instances.AppModule2.Tasks.PeriodicTask, timedelta(milliseconds=10), 1)]) +``` + +The above config snippet adds one instance of each app-module to the `HelloVaf` executable, enables +the periodic tasks, and sets them with a time budget of 10 ms and a preferred execution order. + +Next step is the connection of the two application modules: +``` python +# Connect the internal application module instances +executable.connect_interfaces( + AppModule1, + Instances.AppModule1.ProvidedInterfaces.HelloWorldProvider, + AppModule2, + Instances.AppModule2.ConsumedInterfaces.HelloWorldConsumer, +) +``` + +Now, the project configuration is complete. The source code on executable-level can be generated +and the executable can be built as listed below: + +``` bash +vaf project generate +vaf make install +``` + +>**â„¹ï¸ Note** +> If something changes in any sub-project of the integration project, the entire integration project +> with all it's dependencies can be regenerated using `vaf project generate --mode ALL`. This also +> includes the `vaf model update` command as mentioned at the beginning of this section. + +## Running the application + +After the successful install step, the binary executable is located in the +`HelloVaf/build/<build_type>/install` directory and can be executed from there as follows: + +``` bash +cd build/Release/install/opt/HelloVaf/ +./bin/HelloVaf +``` + +You should see the following output on your terminal: + +``` +UserController::PreInitialize +ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kNotOperational +ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kNotOperational +ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kNotOperational +UserController::PostInitialize +UserController::PreStart +ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kStarting +ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kOperational +ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kStarting +ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kOperational +UserController::PostStart +ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kStarting +ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kOperational +Received: Hello, VAF! - MsgID: 0 +Received: Hello, VAF! - MsgID: 0 +Received: Hello, VAF! - MsgID: 1 +Received: Hello, VAF! - MsgID: 1 +Received: Hello, VAF! - MsgID: 2 +Received: Hello, VAF! - MsgID: 2 +Received: Hello, VAF! - MsgID: 3 +... +``` + +## Introduction to interface projects + +In the above example, the interface definition is needed in both application module projects and +had to be copied. This works for small projects but even there, it can easily happen that +definitions diverge from each other. In consequence, consolidation or merging is needed. + +To avoid such situations, *interface projects* in the VAF can be used to define communication +interfaces in a central location. Application module projects can then import these interfaces to +the Configuration as Code level for further use. + +The following steps illustrate, how an interface project can be added to the above example. +At first, create a new interface project in your workspace, i.e., next to the `HelloVaf` folder: + +``` bash +vaf project init interface +Enter your project name: HelloInterfaces +? Enter the directory to store your project in . +``` + +The interface definitions that earlier got directly added to the configuration in the app-module +projects can now go here. To specify the `HelloWorldIf`, extend the generated `hello_interfaces.py` +file as follows: + +``` python +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) +``` + +Next, generate the corresponding data exchange format of this interface definition: + +``` bash +cd HelloInterfaces +vaf model generate +``` + +Switch to the directory of each application module project and run the following command to import +the interface project. Choose the path to the `HelloInterfaces/export/HelloInterfaces.json` file +in the interactive prompt: + +``` bash +vaf project import +``` + +The original interface definition can now be removed from both app-module configurations. Instead, +the following line must be uncommented: + +``` python +from .imported_models import * +``` + +The interface can now be used through the imported CaC helper as illustrated below: + +``` python +app_module1.add_provided_interface("HelloWorldProvider", hello_interfaces.Demo.hello_world_if) +``` + +Apply those changes for both application modules. + +Finally and due to changes in both app-modules, the executable can be rebuilt by navigating to the +integration project directory and running the following commands: + +``` bash +vaf project generate --mode ALL +vaf make install +``` diff --git a/Demo/HelloVaf/model/app_module1.py b/Demo/HelloVaf/model/app_module1.py new file mode 100644 index 0000000..bb17289 --- /dev/null +++ b/Demo/HelloVaf/model/app_module1.py @@ -0,0 +1,12 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") +app_module1.add_provided_interface("HelloWorldProvider", interface) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=500)) +app_module1.add_task(task=periodic_task) diff --git a/Demo/HelloVaf/model/app_module2.py b/Demo/HelloVaf/model/app_module2.py new file mode 100644 index 0000000..4dadef1 --- /dev/null +++ b/Demo/HelloVaf/model/app_module2.py @@ -0,0 +1,12 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) + +app_module2 = vafpy.ApplicationModule(name="AppModule2", namespace="demo") +app_module2.add_consumed_interface("HelloWorldConsumer", interface) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=1000)) +app_module2.add_task(task=periodic_task) diff --git a/Demo/HelloVaf/model/hello_interfaces.py b/Demo/HelloVaf/model/hello_interfaces.py new file mode 100644 index 0000000..72f624a --- /dev/null +++ b/Demo/HelloVaf/model/hello_interfaces.py @@ -0,0 +1,5 @@ +from vaf import BaseTypes, vafpy + +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) diff --git a/Demo/HelloVaf/model/hello_vaf.py b/Demo/HelloVaf/model/hello_vaf.py new file mode 100644 index 0000000..fe73d34 --- /dev/null +++ b/Demo/HelloVaf/model/hello_vaf.py @@ -0,0 +1,25 @@ +from datetime import timedelta + +from .application_modules import Instances, AppModule1, AppModule2 +from vaf import * + +# Create executable instances (or configure existing ones from the platform configuration) +executable = Executable("HelloVaf") + +# Add application modules to executable instances +executable.add_application_module( + AppModule1, + [(Instances.AppModule1.Tasks.PeriodicTask, timedelta(milliseconds=10), 0)], +) +executable.add_application_module( + AppModule2, + [(Instances.AppModule2.Tasks.PeriodicTask, timedelta(milliseconds=10), 1)], +) + +# Connect the internal application module instances +executable.connect_interfaces( + AppModule1, + Instances.AppModule1.ProvidedInterfaces.HelloWorldProvider, + AppModule2, + Instances.AppModule2.ConsumedInterfaces.HelloWorldConsumer, +) diff --git a/Demo/HelloVaf/src/app_module1/app_module1.cpp b/Demo/HelloVaf/src/app_module1/app_module1.cpp new file mode 100644 index 0000000..c5c0c97 --- /dev/null +++ b/Demo/HelloVaf/src/app_module1/app_module1.cpp @@ -0,0 +1,62 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file app_module1.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "demo/app_module1.h" + +namespace demo { + + +/* + Generated based on configuration in ../../model/app_module1.py + + Provider interfaces + =================== + Data element API example for Message of type vaf::string + - ::vaf::Result<::vaf::DataPtr<vaf::string>> Allocate_Message() + - ::vaf::Result<void> SetAllocated_Message(::vaf::DataPtr<vaf::string>&& data) + - ::vaf::Result<void> Set_Message(const vaf::string& data) + + - HelloWorldProvider_ : demo::HelloWorldIfProvider + - Data elements + - Message : vaf::string + - Operations + - void RegisterOperationHandler_SetMsgId(std::function<void(const std::uint8_t&)>&& f) +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +AppModule1::AppModule1(ConstructorToken&& token) + : AppModule1Base(std::move(token)) +{ + HelloWorldProvider_->RegisterOperationHandler_SetMsgId( + [this](const std::uint8_t& msg_id) { msg_id_ = static_cast<uint8_t>(msg_id); } + ); +} + +/********************************************************************************************************************** + 1 periodic task(s) +**********************************************************************************************************************/ +// Task with name PeriodicTask and a period of 500ms. +void AppModule1::PeriodicTask() { + std::string myMsg = "Hello, VAF! - MsgID: " + std::to_string(msg_id_); + HelloWorldProvider_->Set_Message(myMsg.c_str()); +} + + +} // namespace demo diff --git a/Demo/HelloVaf/src/app_module1/app_module1.h b/Demo/HelloVaf/src/app_module1/app_module1.h new file mode 100644 index 0000000..cb93026 --- /dev/null +++ b/Demo/HelloVaf/src/app_module1/app_module1.h @@ -0,0 +1,38 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file app_module1.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef DEMO_APP_MODULE1_H +#define DEMO_APP_MODULE1_H + +#include "demo/app_module1_base.h" + +namespace demo { + +class AppModule1 : public AppModule1Base { + public: + AppModule1(ConstructorToken&& token); + + void PeriodicTask() override; + + private: + uint8_t msg_id_; +}; + +} // namespace demo + +#endif // DEMO_APP_MODULE1_H diff --git a/Demo/HelloVaf/src/app_module2/app_module2.cpp b/Demo/HelloVaf/src/app_module2/app_module2.cpp new file mode 100644 index 0000000..9001bd9 --- /dev/null +++ b/Demo/HelloVaf/src/app_module2/app_module2.cpp @@ -0,0 +1,64 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file app_module2.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "demo/app_module2.h" +#include <iostream> + +namespace demo { + + +/* + Generated based on configuration in ../../model/app_module2.py + + Consumer interfaces + =================== + Data element API example for Message of type vaf::string + - ::vaf::Result<::vaf::ConstDataPtr<const vaf::string>> GetAllocated_Message() + - vaf::string Get_Message() + - void RegisterDataElementHandler_Message(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const vaf::string>)>&& f) + + - HelloWorldConsumer_ : demo::HelloWorldIfConsumer + - Data elements + - Message : vaf::string + - Operations + - ::vaf::Future<void> SetMsgId(const std::uint8_t& MsgId) +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +AppModule2::AppModule2(ConstructorToken&& token) + : AppModule2Base(std::move(token)) +{ + HelloWorldConsumer_->RegisterDataElementHandler_Message( + GetName(), + [](const auto& hello_text) { std::cout << "Received: " << *hello_text << std::endl; } + ); +} + +/********************************************************************************************************************** + 1 periodic task(s) +**********************************************************************************************************************/ +// Task with name PeriodicTask and a period of 1000ms. +void AppModule2::PeriodicTask() { + static uint8_t msg_id = 0; + HelloWorldConsumer_->SetMsgId(msg_id++); +} + + +} // namespace demo diff --git a/Demo/README.md b/Demo/README.md new file mode 100644 index 0000000..c6041eb --- /dev/null +++ b/Demo/README.md @@ -0,0 +1,14 @@ +# Demo + +Three examples are provided to illustrate the usage of the Vehicle Application Framework (VAF). +1. [HelloVaf](./HelloVaf/) is a simple one and the ideal starting point with the framework. It + introduces to the three different project types and the Configuration as Code user front-end. + Two application modules exchange information internal to one executable. +2. [Vss](./Vss) extends the previous example and illustrates how imported datatype and interface + information from the [COVESA Vehicle Signal Specification (VSS)](https://covesa.global/project/vehicle-signal-specification/) + can be used. +3. [SilKit](./SilKit/) is an example project with two executables that communicate via the [Vector + SIL Kit](https://github.com/vectorgrp/sil-kit). This illustrates the concept of middleware + abstraction and how to do system-level tests with a distributed application in the VAF. + + diff --git a/Demo/SilKit/README.md b/Demo/SilKit/README.md new file mode 100644 index 0000000..ea0fb6b --- /dev/null +++ b/Demo/SilKit/README.md @@ -0,0 +1,617 @@ +# ADAS demo using SIL Kit + +This example is inspired by an ADAS application and illustrates the workflow when using the Vehicle +Application Framework (VAF) with SIL Kit. The tutorial illustrates, how development of a distributed +application can be done, even if the middleware of the later target system is not known yet. In +other words, platform-specific design artifacts are not needed. Instead, modeling and configuration +is all done in the VAF. An appropriate platform abstraction for SIL Kit is automatically generated, +which facilitates rapid prototyping, quick development, and system-level testing. Still, the +migration path to other lower layer solutions is open as just another platform abstraction can be +attached in replacement for the SIL Kit one. + +The example starts with the creation of an architecture for the ADAS application in a modular way +using application modules. The ADAS application executable of this demo consists of two application +modules: (1) collision detection, and (2) sensor fusion. The collision detection receives the object +detection list from the sensor fusion application module. The sensor fusion module consumes camera +input (ImageService) (left/right), velocity service, and a steering angle service. From this +information, it computes the object list and sends it to the collision detection application module. +The collision detection module then commands the brake accordingly. + + + +For the architecture, the following interfaces are completely defined in the Configuration as Code +(CaC) environment of the VAF: + +| Service: ImageService | +| ------------------------- | +| DataElement: camera_image | +| Operation: GetImageSize | + +| Service: ObjectDetectionList | +| ---------------------------------- | +| DataElement: object_detection_list | + +| Service: BrakeService | +| ------------------------- | +| DataElement: brake_action | +| Operation: SumTwoSummands | + +| Service: SteeringAngleService | +| ----------------------------- | +| DataElement: steering_angle | + +| Service: VelocityService | +| ------------------------- | +| DataElement: car_velocity | + +Before starting, ensure that you have completed all [preparation +steps](../HelloVaf/README.md#prerequisites) as described in the `Hello, VAF!` demo. + +## Definition of datatypes and interfaces + +The first step is to define the interfaces as described above for further use in the application +module projects for collision detection and sensor fusion. For that purpose, an interface project is +used. To get started, create a project using the VAF command line tool and switch folders to the +just created project directory: + +``` bash +vaf project init interface +Enter the name of the project: Interfaces +? Enter the directory to store your project in . + +cd Interfaces +``` +Next step is the interface definition part. For that, open the template file `interfaces.py` within +the newly created interface project and add the following datatype and interface definitions: + +``` python +# Brake Service +brake_pressure = vafpy.datatypes.Struct(name="BrakePressure", namespace="datatypes") +brake_pressure.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +brake_pressure.add_subelement(name="value", datatype=BaseTypes.UINT8_T) + +brake_service = vafpy.ModuleInterface( + name="BrakeService", namespace="af::adas_demo_app::services" +) +brake_service.add_data_element(name="brake_action", datatype=brake_pressure) +brake_service.add_operation( + name="SumTwoSummands", + in_parameter={"summand_one": BaseTypes.UINT16_T, "summand_two": BaseTypes.UINT16_T}, + out_parameter={"sum": BaseTypes.UINT16_T}, +) + +# Object Detection List +od_struct = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +od_struct.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector( + name="ObjectDetectionList", + namespace="adas::interfaces", + datatype=od_struct, +) + +od_interface = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", + namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", +) +od_interface.add_data_element(name="object_detection_list", datatype=od_list) + +# ImageService +uint8_vector = vafpy.datatypes.Vector( + name="UInt8Vector", namespace="datatypes", datatype=BaseTypes.UINT8_T +) + +image = vafpy.datatypes.Struct(name="Image", namespace="datatypes") +image.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +image.add_subelement(name="height", datatype=BaseTypes.UINT16_T) +image.add_subelement(name="width", datatype=BaseTypes.UINT16_T) +image.add_subelement(name="R", datatype=uint8_vector) +image.add_subelement(name="G", datatype=uint8_vector) +image.add_subelement(name="B", datatype=uint8_vector) + +image_service = vafpy.ModuleInterface( + name="ImageService", namespace="af::adas_demo_app::services" +) +image_service.add_data_element(name="camera_image", datatype=image) +image_service.add_operation( + name="GetImageSize", + out_parameter={"width": BaseTypes.UINT16_T, "height": BaseTypes.UINT16_T}, +) + +# VelocityService +velocity = vafpy.datatypes.Struct(name="Velocity", namespace="datatypes") +velocity.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +velocity.add_subelement(name="value", datatype=BaseTypes.UINT16_T) + +velocity_service = vafpy.ModuleInterface( + name="VelocityService", namespace="af::adas_demo_app::services" +) +velocity_service.add_data_element(name="car_velocity", datatype=velocity) + +# Steering Angle +steering_angle = vafpy.datatypes.Struct(name="SteeringAngle", namespace="datatypes") +steering_angle.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +steering_angle.add_subelement(name="value", datatype=BaseTypes.UINT16_T) + +steering_angle_service = vafpy.ModuleInterface( + name="SteeringAngleService", namespace="af::adas_demo_app::services" +) +steering_angle_service.add_data_element(name="steering_angle", datatype=steering_angle) +``` + +Once complete, the configuration needs to be exported to JSON by using the following command: + +``` bash +vaf model generate +``` + +The exported JSON file gets stored to the subdirectory `./export` by default, along with its CaC +support file for later use in an application module project. + +## Configuration and implementation of app-modules + +Application modules are self-contained. That means, the corresponding VAF app-module project allows +to configure, implement, test, and maintain each module stand-alone and thus separate from the later +integration step. This brings flexibility in terms of project organization and further allows to use +app-modules in different integration projects. + +For the ADAS executable in this example, two application modules are needed. One for sensor fusion +and one for the collision detection part. + +### Sensor fusion application module + +Switch folders to the workspace directory and create a new app-module project for sensor fusion as +follows: + +``` bash +vaf project init app-module +Enter the name of the app-module: SensorFusion +Enter the namespace of the app-module: NsApplicationUnit::NsSensorFusion +? Enter the path to the output root directory . + +cd SensorFusion +``` + +In first place, the above-created data exchange file from the interface project needs to be imported +to make the model elements from there accessible in the app-module project. Use the following +command for that: + +```bash +vaf project import +? Please provide the path to the exported VAF model JSON file ../Interfaces/export/Interfaces.json +``` + +Next step is the configuration of the application module. For that, open the file +`SensorFusion/model/sensor_fusion.py`. To complete the import from the interface project, uncomment +the following line: + +``` python +from .imported_models import * +``` + +The configuration of the application module is done completely in this Configuration as Code file. +According to the illustration above, SensorFusion is supposed to consume the left/right camera +ImageService and therefore needs a corresponding consumer interface. Likewise, consumer interfaces +for the SteeringAngleService and VelocityService are required. For communication with +collision_detection it acts as provider of the earlier defined ObjectDetectionListInterface. + +``` python +sensor_fusion = vafpy.ApplicationModule( + name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion" +) +sensor_fusion.add_provided_interface( + "ObjectDetectionListModule", + interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface, +) +sensor_fusion.add_consumed_interface( + "ImageServiceConsumer1", interfaces.Af.AdasDemoApp.Services.image_service +) +sensor_fusion.add_consumed_interface( + "ImageServiceConsumer2", interfaces.Af.AdasDemoApp.Services.image_service +) +sensor_fusion.add_consumed_interface( + "SteeringAngleServiceConsumer", + interfaces.Af.AdasDemoApp.Services.steering_angle_service, +) +sensor_fusion.add_consumed_interface( + "VelocityServiceConsumer", interfaces.Af.AdasDemoApp.Services.velocity_service +) + +p_200ms = timedelta(milliseconds=200) +step1 = vafpy.Task(name="Step1", period=p_200ms, preferred_offset=0) +step2 = vafpy.Task(name="Step2", period=p_200ms, preferred_offset=0) +step3 = vafpy.Task(name="Step3", period=p_200ms, preferred_offset=0) + +sensor_fusion.add_task(task=step1) +sensor_fusion.add_task_chain(tasks=[step2, step3], run_after=[step1]) +sensor_fusion.add_task( + vafpy.Task(name="Step4", period=p_200ms, preferred_offset=0, run_after=[step1]) +) +``` + +### Collision detection application module + +The same workflow can now be applied to prepare the collision detection application module. Start +again from the level of the workspace directory. + +``` bash +vaf project init app-module +Enter the name of the app-module: CollisionDetection +Enter the namespace of the app-module: NsApplicationUnit::NsCollisionDetection +? Enter the path to the output root directory . + +cd CollisionDetection +``` + +Import from the interface project as previously done for the SensorFusion application module: + +```bash +vaf project import +Enter the path to the exported VAF model JSON file: ../Interfaces/export/Interfaces.json +``` + +Open the file `CollisionDetection/model/collision_detection.py`. To +complete the import from the interface project, uncomment the following line: + +``` python +from .imported_models import * +``` + +The collision_detection app-module acts as consumer counterpart for the ObjectDetectionListInterface +and towards the platform-side, needs a provider interface for BrakeService. Configure that by adding +the following lines to the CaC file: + +``` python +collision_detection = vafpy.ApplicationModule( + name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection" +) +collision_detection.add_provided_interface( + "BrakeServiceProvider", interfaces.Af.AdasDemoApp.Services.brake_service +) +collision_detection.add_consumed_interface( + "ObjectDetectionListModule", + interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface, +) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +collision_detection.add_task(task=periodic_task) +``` + +### Steps that apply for both application module projects + +Once complete, the configuration needs to be exported to the JSON data exchange format +(`model.json`), which is then used as input for the code generation step. Both steps can be executed +in a row with the following command that needs to be executed from each app-module project directory. + +``` bash +vaf project generate +``` + +The generated code can be divided into read-write and read-only parts. Former gets generated to the +`implementation` folder. This is user space, where the framework only provides implementation and +test stubs for the developer to start. In case of re-generation, a 3-way merge strategy based on +git-merge is applied to the files in this location. The read-only parts get generated to `src-gen` +and `test-gen`. Those folders are under control of the framework. Any user modification will be +overwritten in case of re-generation. + +The entry file for the user to add own code is located in +`SensorFusion/implementation/src/sensor_fusion.cpp` and +`CollisionDetection/implementation/src/collision_detection.cpp` respectively. Corresponding headers +are located in the corresponding `implementation/include` subdirectories. Some sample code for +reference is shipped as part of the container and located in: `/opt/vaf/Demo/SilKit/src`. Feel free +to copy this code to the app-module projects: + +```bash +cp -r /opt/vaf/Demo/SilKit/src/sensor_fusion/* SensorFusion/implementation/ +cp -r /opt/vaf/Demo/SilKit/src/collision_detection/* CollisionDetection/implementation/ +``` + +The application module project can now be built as library, which allows to see if added code passes +the compiler checks. To do so, execute the following step: + +``` bash +vaf make build +``` + +### Unit testing of app-modules + +The Vehicle Application Framework provides means for unit testing of application modules. Test mocks +for Googletest are generated to the `test-gen` folder in the app-module projects accordingly and +allow independent first-level testing. Custom test code can be added in the corresponding +`tests.cpp` file in the `implementation/test/unittest` folder. + +The resulting test binaries get stored in `build/Release/bin` for execution. + +## Executable integration + +Final integration of all application modules is done using a VAF integration project. This is +where the whole application, which potentially consists of multiple executables, gets integrated. In +practice, app-modules and platform modules (as provided by the framework) get instantiated and +connected. To start a new integration project, execute the following steps: + +``` bash +vaf project init integration +Enter your project name: SilKitDemo +? Enter the directory to store your project in . + +cd SilKitDemo +``` + +Continue by importing the above-created application module projects: + +```bash +vaf project import +? Enter the path to the application module project to be imported: ../SensorFusion + +vaf project import +? Enter the path to the application module project to be imported: ../CollisionDetection +``` + +The import command adds new files to `SilKitDemo/model/vaf/application_modules`. Those include +relevant path information but, most and foremost, the importer and CaC-support artifacts, which make +the model elements from the app-module accessible for the configuration in the integration project. + +The next step is the configuration of the integration project in `SilKitDemo/model/vaf/sil_kit_demo.py`. + +First step is to create a new executable for the ADAS demo: + +```python +# Create executable instances (or configure existing ones from the platform configuration) +executable = Executable("AdasDemoExecutable", timedelta(milliseconds=20)) +``` + +Next, add the application modules for Sensor Fusion and Collision Detection and specify the budget +and offset details for the execution of the application module tasks. + +```python +# Add application modules to executable instances +b_10ms = timedelta(milliseconds=10) +executable.add_application_module( + SensorFusion, + [ + (Instances.SensorFusion.Tasks.Step1, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step2, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step3, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step4, b_10ms, 0), + ], +) +executable.add_application_module( + CollisionDetection, + [(Instances.CollisionDetection.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)], +) +``` + +The two app-module instances can now be connected internal to the executable, on the one hand, and +with SIL Kit, on the other hand. The below configuration code snippet details the part for +executable-internal communication in this example project: + +``` python +# Connect the application module instances internally +executable.connect_interfaces( + SensorFusion, + Instances.SensorFusion.ProvidedInterfaces.ObjectDetectionListModule, + CollisionDetection, + Instances.CollisionDetection.ConsumedInterfaces.ObjectDetectionListModule, +) +``` + +The communication with a lower-layer platform is abstracted by platform modules. They deal with the +platform API towards the lower layer, i.e. the middleware stack, and with the VAF API towards the +upper, the application layer. The connection between application and platform modules is configured +as follows: + +``` python +# Connect the application module instances with middleware +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer1, + "Silkit_ImageService1", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer2, + "Silkit_ImageService2", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.SteeringAngleServiceConsumer, + "Silkit_SteeringAngleService", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.VelocityServiceConsumer, + "Silkit_VelocityService", +) + +executable.connect_provided_interface_to_silkit( + CollisionDetection, + Instances.CollisionDetection.ProvidedInterfaces.BrakeServiceProvider, + "Silkit_BrakeService", +) +``` + +With this step done, the integration project configuration part is complete. The next step is model +and code generation using: + +``` bash +vaf project generate +``` + +>**â„¹ï¸ Hint** +> Using `--mode PRJ` or `--mode ALL` allows to set the scope of this command to either, +> the current integration project only (PRJ), or to this and all related sub-projects (ALL). + +To complete the integration project, build and finally installation are missing: + +``` bash +vaf make install +``` + +The resulting binary is now available in `SilKitDemo/build/Release/install/opt`. + +## Test counterpart + +In order to run the ADAS demo application in a meaningful way, a counterpart is required that mimics +a counterpart that consumes/provides the necessary services from platform-side. This counterpart can +for example be realized as extra app-module that is created as part of the above integration project. + +``` bash +vaf project create app-module +Enter the name of the app-module: TestModule +Enter the namespace of the app-module: NsApplicationUnit::NsTestModule +? Enter the path to the project root directory . + +cd src/application_modules/test_module +``` + +To import the interface definitions to this app-module project use: +``` bash +vaf project import +? Please provide the path to the exported VAF model JSON file ../../../../Interfaces/export/Interfaces.json +``` + +Next, open the CaC file in `model/test_module.py` and complete it with the following configuration: +``` python +from .imported_models import * + +test_module = vafpy.ApplicationModule( + name="TestModule", namespace="NsApplicationUnit::NsTestModule" +) +test_module.add_consumed_interface( + instance_name="BrakeServiceConsumer", + interface=interfaces.Af.AdasDemoApp.Services.brake_service, +) +test_module.add_provided_interface( + instance_name="ImageServiceProvider1", + interface=interfaces.Af.AdasDemoApp.Services.image_service, +) +test_module.add_provided_interface( + instance_name="ImageServiceProvider2", + interface=interfaces.Af.AdasDemoApp.Services.image_service, +) +test_module.add_provided_interface( + instance_name="SteeringAngleServiceProvider", + interface=interfaces.Af.AdasDemoApp.Services.steering_angle_service, +) +test_module.add_provided_interface( + instance_name="VelocityServiceProvider", + interface=interfaces.Af.AdasDemoApp.Services.velocity_service, +) + +test_module.add_task( + task=vafpy.Task(name="BrakeTask", period=timedelta(milliseconds=100)) +) +test_module.add_task( + task=vafpy.Task(name="ImageTask", period=timedelta(milliseconds=100)) +) +test_module.add_task( + task=vafpy.Task(name="SteeringAngleTask", period=timedelta(milliseconds=1000)) +) +test_module.add_task( + task=vafpy.Task(name="VelocityTask", period=timedelta(milliseconds=1000)) +) +``` + +Trigger code generation using: +``` bash +vaf project generate +``` + +Afterwards, sample code as provided with the container can be integrated to the project using: +``` bash +cp -r /opt/vaf/Demo/SilKit/src/test_module/* ./implementation/ +``` + +Check for compilation issues and complete the TestModule with: +``` bash +vaf make build +``` + +Switch folders back to the level of the `SilKitDemo` integration project and trigger an update for +the newly added application module: +``` bash +vaf model update +? Choose one ore more application modules (Use arrow keys to move, <space> to select, <a> to toggle, <i> to invert) + â—‹ /workspaces/EclipseWorkspace/SilKitDemo/src/application_modules/sensor_fusion + â—‹ /workspaces/EclipseWorkspace/SilKitDemo/src/application_modules/collision_detection + » â— /workspaces/EclipseWorkspace/SilKitDemo/src/application_modules/test_module +``` + +Next step is to extend the existing CaC project configuration with a new executable to execute an +instance of the TestModule from above. Open `SilKitDemo/model/vaf/sil_kit_demo.py` and complete it +with the following content: +``` python +tester = Executable("AdasDemoTester", timedelta(milliseconds=20)) + +tester.add_application_module( + TestModule, + [ + (Instances.TestModule.Tasks.BrakeTask, b_10ms, 0), + (Instances.TestModule.Tasks.ImageTask, b_10ms, 0), + (Instances.TestModule.Tasks.SteeringAngleTask, b_10ms, 0), + (Instances.TestModule.Tasks.VelocityTask, b_10ms, 0), + ], +) + +tester.connect_consumed_interface_to_silkit( + TestModule, + Instances.TestModule.ConsumedInterfaces.BrakeServiceConsumer, + "Silkit_BrakeService", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.ImageServiceProvider1, + "Silkit_ImageService1", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.ImageServiceProvider2, + "Silkit_ImageService2", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.SteeringAngleServiceProvider, + "Silkit_SteeringAngleService", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.VelocityServiceProvider, + "Silkit_VelocityService", +) +``` + +Finally, complete the integration of the new module with: +``` bash +vaf project generate +vaf make install +``` + +## Execution of ADAS application with test counterpart + +Three executables need to be started for the distributed application to work: +1. The `sil-kit-registry` communication daemon from `SilKitDemo/build/Release/install/opt/silkit/bin` +2. The TestModule from `SilKitDemo/build/Release/install/opt/AdasDemoTester` +3. The ADAS demo from `SilKitDemo/build/Release/install/opt/AdasDemoExecutable` + +Use the following sequence to start them all from the `SilKitDemo` project directory: +``` bash +./build/Release/install/opt/silkit/bin/sil-kit-registry & +./build/Release/install/opt/AdasDemoTester/bin/AdasDemoTester & +./build/Release/install/opt/AdasDemoExecutable/bin/AdasDemoExecutable +``` + +The output should repeatedly look as follows: +``` bash +Received Velocity: 7 +SensorFusion::step +Received new images +SensorFusion sending detection list +Collision onObjectList +Received brake_action call with timestamp: 11 and value: 22 +... +``` + +To stop all running processes use `CTRL + c` and `fg` to bring the background processes to the +foreground again. diff --git a/Demo/SilKit/model/collision_detection.py b/Demo/SilKit/model/collision_detection.py new file mode 100644 index 0000000..41274d3 --- /dev/null +++ b/Demo/SilKit/model/collision_detection.py @@ -0,0 +1,18 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .imported_models import * + +collision_detection = vafpy.ApplicationModule( + name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection" +) +collision_detection.add_provided_interface( + "BrakeServiceProvider", interfaces.Af.AdasDemoApp.Services.brake_service +) +collision_detection.add_consumed_interface( + "ObjectDetectionListModule", + interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface, +) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +collision_detection.add_task(task=periodic_task) diff --git a/Demo/SilKit/model/interfaces.py b/Demo/SilKit/model/interfaces.py new file mode 100644 index 0000000..bbd4ea9 --- /dev/null +++ b/Demo/SilKit/model/interfaces.py @@ -0,0 +1,76 @@ +from vaf import BaseTypes, vafpy + +# Brake Service +brake_pressure = vafpy.datatypes.Struct(name="BrakePressure", namespace="datatypes") +brake_pressure.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +brake_pressure.add_subelement(name="value", datatype=BaseTypes.UINT8_T) + +brake_service = vafpy.ModuleInterface( + name="BrakeService", namespace="af::adas_demo_app::services" +) +brake_service.add_data_element(name="brake_action", datatype=brake_pressure) +brake_service.add_operation( + name="SumTwoSummands", + in_parameter={"summand_one": BaseTypes.UINT16_T, "summand_two": BaseTypes.UINT16_T}, + out_parameter={"sum": BaseTypes.UINT16_T}, +) + +# Object Detection List +od_struct = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +od_struct.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector( + name="ObjectDetectionList", + namespace="adas::interfaces", + datatype=od_struct, +) + +od_interface = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", + namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", +) +od_interface.add_data_element(name="object_detection_list", datatype=od_list) + +# ImageService +uint8_vector = vafpy.datatypes.Vector( + name="UInt8Vector", namespace="datatypes", datatype=BaseTypes.UINT8_T +) + +image = vafpy.datatypes.Struct(name="Image", namespace="datatypes") +image.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +image.add_subelement(name="height", datatype=BaseTypes.UINT16_T) +image.add_subelement(name="width", datatype=BaseTypes.UINT16_T) +image.add_subelement(name="R", datatype=uint8_vector) +image.add_subelement(name="G", datatype=uint8_vector) +image.add_subelement(name="B", datatype=uint8_vector) + +image_service = vafpy.ModuleInterface( + name="ImageService", namespace="af::adas_demo_app::services" +) +image_service.add_data_element(name="camera_image", datatype=image) +image_service.add_operation( + name="GetImageSize", + out_parameter={"width": BaseTypes.UINT16_T, "height": BaseTypes.UINT16_T}, +) + +# VelocityService +velocity = vafpy.datatypes.Struct(name="Velocity", namespace="datatypes") +velocity.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +velocity.add_subelement(name="value", datatype=BaseTypes.UINT16_T) + +velocity_service = vafpy.ModuleInterface( + name="VelocityService", namespace="af::adas_demo_app::services" +) +velocity_service.add_data_element(name="car_velocity", datatype=velocity) + +# Steering Angle +steering_angle = vafpy.datatypes.Struct(name="SteeringAngle", namespace="datatypes") +steering_angle.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T) +steering_angle.add_subelement(name="value", datatype=BaseTypes.UINT16_T) + +steering_angle_service = vafpy.ModuleInterface( + name="SteeringAngleService", namespace="af::adas_demo_app::services" +) +steering_angle_service.add_data_element(name="steering_angle", datatype=steering_angle) diff --git a/Demo/SilKit/model/sensor_fusion.py b/Demo/SilKit/model/sensor_fusion.py new file mode 100644 index 0000000..4b2d9c1 --- /dev/null +++ b/Demo/SilKit/model/sensor_fusion.py @@ -0,0 +1,36 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .imported_models import * + +sensor_fusion = vafpy.ApplicationModule( + name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion" +) +sensor_fusion.add_provided_interface( + "ObjectDetectionListModule", + interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface, +) +sensor_fusion.add_consumed_interface( + "ImageServiceConsumer1", interfaces.Af.AdasDemoApp.Services.image_service +) +sensor_fusion.add_consumed_interface( + "ImageServiceConsumer2", interfaces.Af.AdasDemoApp.Services.image_service +) +sensor_fusion.add_consumed_interface( + "SteeringAngleServiceConsumer", + interfaces.Af.AdasDemoApp.Services.steering_angle_service, +) +sensor_fusion.add_consumed_interface( + "VelocityServiceConsumer", interfaces.Af.AdasDemoApp.Services.velocity_service +) + +p_200ms = timedelta(milliseconds=200) +step1 = vafpy.Task(name="Step1", period=p_200ms, preferred_offset=0) +step2 = vafpy.Task(name="Step2", period=p_200ms, preferred_offset=0) +step3 = vafpy.Task(name="Step3", period=p_200ms, preferred_offset=0) + +sensor_fusion.add_task(task=step1) +sensor_fusion.add_task_chain(tasks=[step2, step3], run_after=[step1]) +sensor_fusion.add_task( + vafpy.Task(name="Step4", period=p_200ms, preferred_offset=0, run_after=[step1]) +) diff --git a/Demo/SilKit/model/sil_kit_demo.py b/Demo/SilKit/model/sil_kit_demo.py new file mode 100644 index 0000000..e354e0d --- /dev/null +++ b/Demo/SilKit/model/sil_kit_demo.py @@ -0,0 +1,96 @@ +from datetime import timedelta + +from .application_modules import TestModule, SensorFusion, Instances, CollisionDetection +from vaf import * + +# Create executable instances (or configure existing ones from the platform configuration) +executable = Executable("AdasDemoExecutable", timedelta(milliseconds=20)) +tester = Executable("AdasDemoTester", timedelta(milliseconds=20)) + +# Add application modules to executable instances +b_10ms = timedelta(milliseconds=10) +executable.add_application_module( + SensorFusion, + [ + (Instances.SensorFusion.Tasks.Step1, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step2, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step3, b_10ms, 0), + (Instances.SensorFusion.Tasks.Step4, b_10ms, 0), + ], +) +executable.add_application_module( + CollisionDetection, + [(Instances.CollisionDetection.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)], +) + +tester.add_application_module( + TestModule, + [ + (Instances.TestModule.Tasks.BrakeTask, b_10ms, 0), + (Instances.TestModule.Tasks.ImageTask, b_10ms, 0), + (Instances.TestModule.Tasks.SteeringAngleTask, b_10ms, 0), + (Instances.TestModule.Tasks.VelocityTask, b_10ms, 0), + ], +) + +# Connect the application module instances internally +executable.connect_interfaces( + SensorFusion, + Instances.SensorFusion.ProvidedInterfaces.ObjectDetectionListModule, + CollisionDetection, + Instances.CollisionDetection.ConsumedInterfaces.ObjectDetectionListModule, +) + +# Connect the application module instances with middleware +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer1, + "Silkit_ImageService1", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer2, + "Silkit_ImageService2", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.SteeringAngleServiceConsumer, + "Silkit_SteeringAngleService", +) +executable.connect_consumed_interface_to_silkit( + SensorFusion, + Instances.SensorFusion.ConsumedInterfaces.VelocityServiceConsumer, + "Silkit_VelocityService", +) + +executable.connect_provided_interface_to_silkit( + CollisionDetection, + Instances.CollisionDetection.ProvidedInterfaces.BrakeServiceProvider, + "Silkit_BrakeService", +) + +tester.connect_consumed_interface_to_silkit( + TestModule, + Instances.TestModule.ConsumedInterfaces.BrakeServiceConsumer, + "Silkit_BrakeService", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.ImageServiceProvider1, + "Silkit_ImageService1", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.ImageServiceProvider2, + "Silkit_ImageService2", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.SteeringAngleServiceProvider, + "Silkit_SteeringAngleService", +) +tester.connect_provided_interface_to_silkit( + TestModule, + Instances.TestModule.ProvidedInterfaces.VelocityServiceProvider, + "Silkit_VelocityService", +) diff --git a/Demo/SilKit/model/test_module.py b/Demo/SilKit/model/test_module.py new file mode 100644 index 0000000..654f098 --- /dev/null +++ b/Demo/SilKit/model/test_module.py @@ -0,0 +1,41 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .imported_models import * + +test_module = vafpy.ApplicationModule( + name="TestModule", namespace="NsApplicationUnit::NsTestModule" +) +test_module.add_consumed_interface( + instance_name="BrakeServiceConsumer", + interface=interfaces.Af.AdasDemoApp.Services.brake_service, +) +test_module.add_provided_interface( + instance_name="ImageServiceProvider1", + interface=interfaces.Af.AdasDemoApp.Services.image_service, +) +test_module.add_provided_interface( + instance_name="ImageServiceProvider2", + interface=interfaces.Af.AdasDemoApp.Services.image_service, +) +test_module.add_provided_interface( + instance_name="SteeringAngleServiceProvider", + interface=interfaces.Af.AdasDemoApp.Services.steering_angle_service, +) +test_module.add_provided_interface( + instance_name="VelocityServiceProvider", + interface=interfaces.Af.AdasDemoApp.Services.velocity_service, +) + +test_module.add_task( + task=vafpy.Task(name="BrakeTask", period=timedelta(milliseconds=100)) +) +test_module.add_task( + task=vafpy.Task(name="ImageTask", period=timedelta(milliseconds=100)) +) +test_module.add_task( + task=vafpy.Task(name="SteeringAngleTask", period=timedelta(milliseconds=1000)) +) +test_module.add_task( + task=vafpy.Task(name="VelocityTask", period=timedelta(milliseconds=1000)) +) diff --git a/Demo/SilKit/src/collision_detection/include/nsapplicationunit/nscollisiondetection/collision_detection.h b/Demo/SilKit/src/collision_detection/include/nsapplicationunit/nscollisiondetection/collision_detection.h new file mode 100644 index 0000000..0526901 --- /dev/null +++ b/Demo/SilKit/src/collision_detection/include/nsapplicationunit/nscollisiondetection/collision_detection.h @@ -0,0 +1,44 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file collision_detection.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H +#define NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H + +#include "nsapplicationunit/nscollisiondetection/collision_detection_base.h" + +namespace NsApplicationUnit { +namespace NsCollisionDetection { + +class CollisionDetection : public CollisionDetectionBase { + public: + CollisionDetection(ConstructorToken&& token); + + void PeriodicTask() override; + + ::datatypes::BrakePressure ComputeBrakePressure( + vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list); + void OnError(const vaf::Error& error) override; + void OnObjectList(vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list); + + private: +}; + +} // namespace NsCollisionDetection +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H diff --git a/Demo/SilKit/src/collision_detection/src/collision_detection.cpp b/Demo/SilKit/src/collision_detection/src/collision_detection.cpp new file mode 100644 index 0000000..7711dfb --- /dev/null +++ b/Demo/SilKit/src/collision_detection/src/collision_detection.cpp @@ -0,0 +1,97 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file collision_detection.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nscollisiondetection/collision_detection.h" + +namespace NsApplicationUnit { +namespace NsCollisionDetection { + +/* + Generated based on configuration in ../../model/collision_detection.py + + Consumer interfaces + =================== + Data element API example for object_detection_list of type adas::interfaces::ObjectDetectionList + - ::vaf::Result<::vaf::ConstDataPtr<const adas::interfaces::ObjectDetectionList>> + GetAllocated_object_detection_list() + - adas::interfaces::ObjectDetectionList Get_object_detection_list() + - void RegisterDataElementHandler_object_detection_list(std::string owner, std::function<void(const + ::vaf::ConstDataPtr<const adas::interfaces::ObjectDetectionList>)>&& f) + + - ObjectDetectionListModule_ : + nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceConsumer + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + Provider interfaces + =================== + Data element API example for brake_action of type datatypes::BrakePressure + - ::vaf::Result<::vaf::DataPtr<datatypes::BrakePressure>> Allocate_brake_action() + - ::vaf::Result<void> SetAllocated_brake_action(::vaf::DataPtr<datatypes::BrakePressure>&& data) + - ::vaf::Result<void> Set_brake_action(const datatypes::BrakePressure& data) + + - BrakeServiceProvider_ : af::adas_demo_app::services::BrakeServiceProvider + - Data elements + - brake_action : datatypes::BrakePressure + - Operations + - void + RegisterOperationHandler_SumTwoSummands(std::function<af::adas_demo_app::services::SumTwoSummands::Output(const + std::uint16_t&, const std::uint16_t&)>&& f) +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +CollisionDetection::CollisionDetection(ConstructorToken&& token) : CollisionDetectionBase(std::move(token)) { + ObjectDetectionListModule_->RegisterDataElementHandler_object_detection_list( + GetName(), [this](vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList> object_detection_list) { + OnObjectList(object_detection_list); + }); + BrakeServiceProvider_->RegisterOperationHandler_SumTwoSummands( + [](std::uint16_t const& summand_one, std::uint16_t const& summand_two) { + af::adas_demo_app::services::SumTwoSummands::Output output{}; + output.sum = summand_one + summand_two; + return output; + }); +} + +/********************************************************************************************************************** + 1 periodic task(s) +**********************************************************************************************************************/ +// Task with name PeriodicTask and a period of 200ms. +void CollisionDetection::PeriodicTask() { std::cout << "Collision detection is active\n"; } + +::datatypes::BrakePressure CollisionDetection::ComputeBrakePressure( + vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list) { + static_cast<void>(object_list); + return ::datatypes::BrakePressure{11, 22}; +} + +void CollisionDetection::OnError(const vaf::Error& error) { + static_cast<void>(error); + ReportError(vaf::ErrorCode::kDefaultErrorCode, "Unknown error", true); +} + +void CollisionDetection::OnObjectList(vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list) { + std::cout << "Collision onObjectList\n"; + ::datatypes::BrakePressure brake_pressure = ComputeBrakePressure(object_list); + BrakeServiceProvider_->Set_brake_action(brake_pressure); +} + +} // namespace NsCollisionDetection +} // namespace NsApplicationUnit diff --git a/Demo/SilKit/src/sensor_fusion/include/nsapplicationunit/nssensorfusion/sensor_fusion.h b/Demo/SilKit/src/sensor_fusion/include/nsapplicationunit/nssensorfusion/sensor_fusion.h new file mode 100644 index 0000000..5ebaf4c --- /dev/null +++ b/Demo/SilKit/src/sensor_fusion/include/nsapplicationunit/nssensorfusion/sensor_fusion.h @@ -0,0 +1,49 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + void Step1() override; + void Step2() override; + void Step3() override; + void Step4() override; + + void OnError(const vaf::Error& error) override; + void OnVelocity(vaf::ConstDataPtr<const ::datatypes::Velocity> velocity); + ::adas::interfaces::ObjectDetectionList DoDetection(const ::datatypes::Image&, const ::datatypes::Image&, + ::datatypes::SteeringAngle, ::datatypes::Velocity); + + private: + constexpr static uint16_t kMaxVelocity{100}; + bool is_enabled_{true}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/Demo/SilKit/src/sensor_fusion/src/sensor_fusion.cpp b/Demo/SilKit/src/sensor_fusion/src/sensor_fusion.cpp new file mode 100644 index 0000000..cdb29de --- /dev/null +++ b/Demo/SilKit/src/sensor_fusion/src/sensor_fusion.cpp @@ -0,0 +1,141 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +/* + Generated based on configuration in ../../model/sensor_fusion.py + + Consumer interfaces + =================== + Data element API example for camera_image of type datatypes::Image + - ::vaf::Result<::vaf::ConstDataPtr<const datatypes::Image>> GetAllocated_camera_image() + - datatypes::Image Get_camera_image() + - void RegisterDataElementHandler_camera_image(std::string owner, std::function<void(const + ::vaf::ConstDataPtr<const datatypes::Image>)>&& f) + + - ImageServiceConsumer1_ : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - Operations + - ::vaf::Future<af::adas_demo_app::services::GetImageSize::Output> GetImageSize() + - ImageServiceConsumer2_ : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - Operations + - ::vaf::Future<af::adas_demo_app::services::GetImageSize::Output> GetImageSize() + - SteeringAngleServiceConsumer_ : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + - VelocityServiceConsumer_ : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + Provider interfaces + =================== + Data element API example for object_detection_list of type adas::interfaces::ObjectDetectionList + - ::vaf::Result<::vaf::DataPtr<adas::interfaces::ObjectDetectionList>> Allocate_object_detection_list() + - ::vaf::Result<void> SetAllocated_object_detection_list(::vaf::DataPtr<adas::interfaces::ObjectDetectionList>&& + data) + - ::vaf::Result<void> Set_object_detection_list(const adas::interfaces::ObjectDetectionList& data) + + - ObjectDetectionListModule_ : + nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +SensorFusion::SensorFusion(ConstructorToken&& token) : SensorFusionBase(std::move(token)) { + VelocityServiceConsumer_->RegisterDataElementHandler_car_velocity( + GetName(), [this](vaf::ConstDataPtr<const ::datatypes::Velocity> velocity) { OnVelocity(std::move(velocity)); }); +} + +/********************************************************************************************************************** + 4 periodic task(s) +**********************************************************************************************************************/ +// Task with name Step1 and a period of 200ms. +void SensorFusion::Step1() { + if (is_enabled_) { + std::cout << "SensorFusion::step\n"; + bool no_new_image{false}; + + auto image1 = ImageServiceConsumer1_->GetAllocated_camera_image().InspectError( + [&no_new_image](const vaf::Error&) { no_new_image = true; }); + auto image2 = ImageServiceConsumer2_->GetAllocated_camera_image().InspectError( + [&no_new_image](const vaf::Error&) { no_new_image = true; }); + auto steering_angle = SteeringAngleServiceConsumer_->Get_steering_angle(); + auto velocity = VelocityServiceConsumer_->Get_car_velocity(); + + if (!no_new_image) { + std::cout << "Received new images" << "\n"; + ::adas::interfaces::ObjectDetectionList object_list = + DoDetection(*image1.Value(), *image2.Value(), steering_angle, velocity); + std::cout << "SensorFusion sending detection list\n"; + ObjectDetectionListModule_->Set_object_detection_list(object_list); + } + } +} + +// Task with name Step2 and a period of 200ms. +void SensorFusion::Step2() { + // Insert your code for periodic execution here... +} + +// Task with name Step3 and a period of 200ms. +void SensorFusion::Step3() { + // Insert your code for periodic execution here... +} + +// Task with name Step4 and a period of 200ms. +void SensorFusion::Step4() { + // Insert your code for periodic execution here... +} + +void SensorFusion::OnVelocity(vaf::ConstDataPtr<const ::datatypes::Velocity> velocity) { + std::cout << "Received Velocity: " << velocity->value << "\n"; + is_enabled_ = (velocity->value < kMaxVelocity); +} + +::adas::interfaces::ObjectDetectionList SensorFusion::DoDetection(const ::datatypes::Image& image1, + const ::datatypes::Image& image2, + ::datatypes::SteeringAngle, ::datatypes::Velocity) { + static_cast<void>(image1); + static_cast<void>(image2); + + vaf::Future<af::adas_demo_app::services::GetImageSize::Output> answer = ImageServiceConsumer1_->GetImageSize(); + if (vaf::is_future_ready(answer)) { + auto result = answer.GetResult(); + if (result.HasValue()) + std::cout << "GetImageSize() yields: " << result.Value().width << "x" << result.Value().height << "\n"; + } + return ::adas::interfaces::ObjectDetectionList{}; +} + +void SensorFusion::OnError(const vaf::Error& error) { + std::cout << "Error in sensor fusion: " << error.Message() << ", " << error.UserMessage() << "\n"; + ReportError(vaf::ErrorCode::kDefaultErrorCode, "Unknown error", true); +} + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/Demo/SilKit/src/test_module/include/nsapplicationunit/nstestmodule/test_module.h b/Demo/SilKit/src/test_module/include/nsapplicationunit/nstestmodule/test_module.h new file mode 100644 index 0000000..24e4d08 --- /dev/null +++ b/Demo/SilKit/src/test_module/include/nsapplicationunit/nstestmodule/test_module.h @@ -0,0 +1,43 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file test_module.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H +#define NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H + +#include "nsapplicationunit/nstestmodule/test_module_base.h" + +namespace NsApplicationUnit { +namespace NsTestModule { + +class TestModule : public TestModuleBase { + public: + TestModule(ConstructorToken&& token); + + void BrakeTask() override; + void ImageTask() override; + void SteeringAngleTask() override; + void VelocityTask() override; + + private: + datatypes::Image image{}; +}; + +} // namespace NsTestModule +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H diff --git a/Demo/SilKit/src/test_module/src/test_module.cpp b/Demo/SilKit/src/test_module/src/test_module.cpp new file mode 100644 index 0000000..c0d9cba --- /dev/null +++ b/Demo/SilKit/src/test_module/src/test_module.cpp @@ -0,0 +1,172 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file test_module.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nstestmodule/test_module.h" + +namespace NsApplicationUnit { +namespace NsTestModule { + +/* + Generated based on configuration in ../../model/test_module.py + + Consumer interfaces + =================== + Data element API example for brake_action of type datatypes::BrakePressure + - ::vaf::Result<::vaf::ConstDataPtr<const datatypes::BrakePressure>> GetAllocated_brake_action() + - datatypes::BrakePressure Get_brake_action() + - void RegisterDataElementHandler_brake_action(std::string owner, std::function<void(const + ::vaf::ConstDataPtr<const datatypes::BrakePressure>)>&& f) + + - BrakeServiceConsumer_ : af::adas_demo_app::services::BrakeServiceConsumer + - Data elements + - brake_action : datatypes::BrakePressure + - Operations + - ::vaf::Future<af::adas_demo_app::services::SumTwoSummands::Output> SumTwoSummands(const std::uint16_t& + summand_one, const std::uint16_t& summand_two) + + Provider interfaces + =================== + Data element API example for camera_image of type datatypes::Image + - ::vaf::Result<::vaf::DataPtr<datatypes::Image>> Allocate_camera_image() + - ::vaf::Result<void> SetAllocated_camera_image(::vaf::DataPtr<datatypes::Image>&& data) + - ::vaf::Result<void> Set_camera_image(const datatypes::Image& data) + + - ImageServiceProvider1_ : af::adas_demo_app::services::ImageServiceProvider + - Data elements + - camera_image : datatypes::Image + - Operations + - void + RegisterOperationHandler_GetImageSize(std::function<af::adas_demo_app::services::GetImageSize::Output()>&& f) + - ImageServiceProvider2_ : af::adas_demo_app::services::ImageServiceProvider + - Data elements + - camera_image : datatypes::Image + - Operations + - void + RegisterOperationHandler_GetImageSize(std::function<af::adas_demo_app::services::GetImageSize::Output()>&& f) + - SteeringAngleServiceProvider_ : af::adas_demo_app::services::SteeringAngleServiceProvider + - Data elements + - steering_angle : datatypes::SteeringAngle + - VelocityServiceProvider_ : af::adas_demo_app::services::VelocityServiceProvider + - Data elements + - car_velocity : datatypes::Velocity +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +TestModule::TestModule(ConstructorToken&& token) : TestModuleBase(std::move(token)) { + // Init image + image.height = 1080; + image.width = 1920; + image.timestamp = 0; + + image.R.push_back(10); + image.R.push_back(11); + image.R.push_back(12); + image.R.push_back(13); + + image.G.push_back(20); + image.G.push_back(21); + image.G.push_back(22); + image.G.push_back(23); + image.G.push_back(24); + + image.B.push_back(30); + image.B.push_back(31); + image.B.push_back(32); + image.B.push_back(33); + image.B.push_back(34); + image.B.push_back(35); + + ImageServiceProvider1_->RegisterOperationHandler_GetImageSize( + [this]() -> af::adas_demo_app::services::GetImageSize::Output { + af::adas_demo_app::services::GetImageSize::Output output{}; + std::cout << "ImageServiceProvider1::GetImageSize handler called" << std::endl; + output.width = image.width; + output.height = image.height; + return output; + }); + ImageServiceProvider2_->RegisterOperationHandler_GetImageSize( + [this]() -> af::adas_demo_app::services::GetImageSize::Output { + af::adas_demo_app::services::GetImageSize::Output output{}; + std::cout << "ImageServiceProvider2::GetImageSize handler called" << std::endl; + output.width = image.width; + output.height = image.height; + return output; + }); + + BrakeServiceConsumer_->RegisterDataElementHandler_brake_action( + GetName(), [this](vaf::ConstDataPtr<const datatypes::BrakePressure> brake_pressure) { + std::cout << "Received brake_action call with timestamp: " << brake_pressure->timestamp + << " and value: " << static_cast<int>(brake_pressure->value) << std::endl; + }); +} + +/********************************************************************************************************************** + 4 periodic task(s) +**********************************************************************************************************************/ +// Task with name BrakeTask and a period of 100ms. +void TestModule::BrakeTask() { + // Insert your code for periodic execution here... +} + +// Task with name ImageTask and a period of 100ms. +void TestModule::ImageTask() { + static uint64_t counter = 0; + static uint8_t step = 0; + + if (0 == step) { + image.timestamp = static_cast<uint64_t>( + std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()) + .count()); + ImageServiceProvider1_->Set_camera_image(image); + ImageServiceProvider2_->Set_camera_image(image); + } else { + counter++; + } + step = 1 - step; +} + +// Task with name SteeringAngleTask and a period of 1000ms. +void TestModule::SteeringAngleTask() { + static uint16_t counter = 0; + + auto steering_angle = datatypes::SteeringAngle(); + steering_angle.timestamp = static_cast<uint64_t>( + std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()) + .count()); + steering_angle.value = counter; + SteeringAngleServiceProvider_->Set_steering_angle(steering_angle); + + counter += 1000; +} + +// Task with name VelocityTask and a period of 1000ms. +void TestModule::VelocityTask() { + static uint16_t counter = 0; + + auto velocity = datatypes::Velocity(); + velocity.timestamp = static_cast<uint64_t>( + std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()) + .count()); + velocity.value = counter++; + VelocityServiceProvider_->Set_car_velocity(velocity); +} + +} // namespace NsTestModule +} // namespace NsApplicationUnit diff --git a/Demo/Vss/README.md b/Demo/Vss/README.md new file mode 100644 index 0000000..9e3783a --- /dev/null +++ b/Demo/Vss/README.md @@ -0,0 +1,183 @@ +# Demo based on input from the COVESA VSS catalogue + +The following tutorial guides you through an example with the Vehicle Application Framework (VAF), +where derived interfaces from the [COVESA Vehicle Signal Specification (VSS)] +(https://covesa.global/project/vehicle-signal-specification/) are used as input to the workflow. + +Plan in this demo is to develop one executable with two application modules that directly +communicate with each other. That means, they share an internal communication channel, which is +based on definitions from VSS. A high-level illustration of the setup is given below: + + + +Before starting, ensure that you have completed all [preparation +steps](../HelloVaf/README.md#prerequisites) as described in the `Hello, VAF!` demo. + +## Project setup + +First, enter the VAF workspace of your choice and create a new integration project and two +stand-alone application module projects using the VAF command line tool: + +``` bash +vaf project init integration +Enter your project name: DemoExecutable +? Enter the directory to store your project in . + +vaf project init app-module +Enter the name of the app-module: VssProvider +Enter the namespace of the app-module: demo +? Enter the path to the output root directory . + +vaf project init app-module +Enter the name of the app-module: VssConsumer +Enter the namespace of the app-module: demo +? Enter the path to the output root directory . +``` + +## Configuration and implementation of app-modules + +The following step applies for both application module projects alike. Switch folders and import the +VSS data catalogue to the project. The sample VSS catalogue is shipped as JSON file and already part +of the container. It is located in: `/opt/vaf/Demo/Vss/model/vss` +``` bash +cd VssProvider +vaf model import vss +Enter the path to the VSS catalogue file in JSON format /opt/vaf/Demo/Vss/model/vss/vss.json + +cd ../VssConsumer +vaf model import vss +Enter the path to the VSS catalogue file in JSON format /opt/vaf/Demo/Vss/model/vss/vss.json +``` + +The command adds two new files the `model` sub-folder of the project. `vss-derived-model.json` is +the VAF model file in JSON format. It contains all relevant information as imported from the VSS +catalogue. `vss.py` is the Configuration as Code (CaC) support file, which is needed to access the +model artifacts from the configuration in Python. + +Next step is the configuration of the app-modules in `VssProvider/model/vss_provider.py` and +`VssConsumer/model/vss_consumer.py` respectively. + +To import the VSS interfaces from the previous step, write: +``` python +from .vss import * +``` + +The app-module configuration template already contains the app-module object and a default periodic +task. On top, the following interface configuration needs to be added for the example. + +For the VssProvider use: +``` python +vss_provider.add_provided_interface("AccelerationProvider", interface=Vss.Vehicle.acceleration_if) +vss_provider.add_provided_interface("DriverProvider", interface=Vss.Vehicle.driver_if) +``` + +For the VssConsumer use: +``` python +vss_consumer.add_consumed_interface("AccelerationConsumer", interface=Vss.Vehicle.acceleration_if) +vss_consumer.add_consumed_interface("DriverConsumer", interface=Vss.Vehicle.driver_if) +``` + +Continue from here with model and code generation for each app-module project separately using the +following command: +``` bash +vaf project generate +``` + +Some sample code for VssProvider and VssConsumer app-modules is provided for reference in: +`/opt/vaf/Demo/Vss/src/vss_<consumer/provider>`. Feel free to use it as reference or simply copy the +snippets to the generated implementation stubs in `VssProvider/implementation/src/vss_provider.cpp` +and `VssConsumer/implementation/src/vss_consumer.cpp`. + +Finally, check if the app-module libraries compile using: +``` bash +vaf make build +``` + +With this part completed for both, the VssProvider and the VssConsumer, the final integration on +executable-level can be started. + +## Executable integration + +Back in the integration project, next step is to create one executable with one instance of the +above-created app-modules each. + +First of all, the stand-alone application module projects need to be imported to the scope of the +integration project. To do so, use the following commands: +``` bash +cd DemoExecutable +vaf project import +? Enter the path to the application module project to be imported: ../VssProvider + +vaf project import +? Enter the path to the application module project to be imported: ../VssConsumer +``` + +The configuration of the executable in `DemoExecutable/model/vaf/demo_executable.py`, can now be +started as follows: +``` python +# Create executable instances +executable = Executable("DemoExecutable", timedelta(milliseconds=10)) +``` + +Then, instantiating and mapping of app-modules follows: +``` python +# Add application modules to executable instances +executable.add_application_module( + VssProvider, + [(Instances.VssProvider.Tasks.PeriodicTask, timedelta(milliseconds=1), 0)], +) +executable.add_application_module( + VssConsumer, + [(Instances.VssConsumer.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)], +) +``` + +The second parameter, allows the definition of an integration-specific task mapping with execution +budget and order. In this example, the provider is configured to be executed before the consumer. + +The two app-modules instances now can be connected as follows: +``` python +# Connect the internal application module instances +executable.connect_interfaces( + VssProvider, + Instances.VssProvider.ProvidedInterfaces.AccelerationProvider, + VssConsumer, + Instances.VssConsumer.ConsumedInterfaces.AccelerationConsumer, +) +executable.connect_interfaces( + VssProvider, + Instances.VssProvider.ProvidedInterfaces.DriverProvider, + VssConsumer, + Instances.VssConsumer.ConsumedInterfaces.DriverConsumer, +) +``` + +With this, the configuration part in the integration project is complete. Model and integration code +can be generated in one step using: +``` bash +vaf project generate +``` + +To complete the demo, finish with compile, link, and install step as follows: +``` bash +vaf make install +``` + +## Running the application +To start the just created binary, switch folders to +`DemoExecutable/build/Release/install/opt/DemoExecutable` and execute: +``` bash +./bin/DemoExecutable +``` + +Some output similar to the following should be printed to the terminal window. +``` bash +... +Longitudinal acceleration: 4.6 m/s^2 +'Driver1' does not have the eyes on the road. +Longitudinal acceleration: 4.8 m/s^2 +'Driver1' does not have the eyes on the road. +Longitudinal acceleration: 5 m/s^2 +'Driver1' has the eyes on the road. +Longitudinal acceleration: 5.2 m/s^2 +``` diff --git a/Demo/Vss/model/vaf/demo_executable.py b/Demo/Vss/model/vaf/demo_executable.py new file mode 100644 index 0000000..88f5dcd --- /dev/null +++ b/Demo/Vss/model/vaf/demo_executable.py @@ -0,0 +1,31 @@ +from datetime import timedelta + +from .application_modules import * +from vaf import * + +# Create executable instances +executable = Executable("DemoExecutable", timedelta(milliseconds=10)) + +# Add application modules to executable instances +executable.add_application_module( + VssProvider, + [(Instances.VssProvider.Tasks.PeriodicTask, timedelta(milliseconds=1), 0)], +) +executable.add_application_module( + VssConsumer, + [(Instances.VssConsumer.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)], +) + +# Connect the internal application module instances +executable.connect_interfaces( + VssProvider, + Instances.VssProvider.ProvidedInterfaces.AccelerationProvider, + VssConsumer, + Instances.VssConsumer.ConsumedInterfaces.AccelerationConsumer, +) +executable.connect_interfaces( + VssProvider, + Instances.VssProvider.ProvidedInterfaces.DriverProvider, + VssConsumer, + Instances.VssConsumer.ConsumedInterfaces.DriverConsumer, +) diff --git a/Demo/Vss/model/vaf/vss_consumer.py b/Demo/Vss/model/vaf/vss_consumer.py new file mode 100644 index 0000000..a958d54 --- /dev/null +++ b/Demo/Vss/model/vaf/vss_consumer.py @@ -0,0 +1,13 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .vss import * + +vss_consumer = vafpy.ApplicationModule(name="VssConsumer", namespace="demo") +vss_consumer.add_consumed_interface( + "AccelerationConsumer", interface=Vss.Vehicle.acceleration_if +) +vss_consumer.add_consumed_interface("DriverConsumer", interface=Vss.Vehicle.driver_if) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +vss_consumer.add_task(task=periodic_task) diff --git a/Demo/Vss/model/vaf/vss_provider.py b/Demo/Vss/model/vaf/vss_provider.py new file mode 100644 index 0000000..4324682 --- /dev/null +++ b/Demo/Vss/model/vaf/vss_provider.py @@ -0,0 +1,13 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .vss import * + +vss_provider = vafpy.ApplicationModule(name="VssProvider", namespace="demo") +vss_provider.add_provided_interface( + "AccelerationProvider", interface=Vss.Vehicle.acceleration_if +) +vss_provider.add_provided_interface("DriverProvider", interface=Vss.Vehicle.driver_if) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +vss_provider.add_task(task=periodic_task) diff --git a/Demo/Vss/model/vss/vss.json b/Demo/Vss/model/vss/vss.json new file mode 100644 index 0000000..4d574f1 --- /dev/null +++ b/Demo/Vss/model/vss/vss.json @@ -0,0 +1,9201 @@ +{ + "Vehicle": { + "children": { + "ADAS": { + "children": { + "ABS": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if ABS is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Indicates if ABS is currently regulating brake pressure. True = Engaged. False = Not Engaged.", + "type": "sensor" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if ABS incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + } + }, + "description": "Antilock Braking System signals.", + "type": "branch" + }, + "ActiveAutonomyLevel": { + "allowed": [ + "SAE_0", + "SAE_1", + "SAE_2_DISENGAGING", + "SAE_2", + "SAE_3_DISENGAGING", + "SAE_3", + "SAE_4_DISENGAGING", + "SAE_4", + "SAE_5" + ], + "comment": "Follows https://www.sae.org/news/2019/01/sae-updates-j3016-automated-driving-graphic taxonomy. For SAE levels 3 and 4 the system is required to alert the driver before it will disengage. Level 4 systems are required to reach a safe state even if a driver does not take over. Only level 5 systems are required to not rely on a driver at all. While level 2 systems require the driver to be monitoring the system at all times, many level 2 systems, often termed \"level 2.5\" systems, do warn the driver shortly before reaching their operational limits, therefore we also support the DISENGAGING state for SAE_2.", + "datatype": "string", + "description": "Indicates the currently active level of autonomy according to SAE J3016 taxonomy.", + "type": "sensor" + }, + "CruiseControl": { + "children": { + "IsActive": { + "datatype": "boolean", + "description": "Indicates if cruise control system is active (i.e. actively controls speed). True = Active. False = Inactive.", + "type": "actuator" + }, + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if cruise control system is enabled (e.g. ready to receive configurations and settings) True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if cruise control system incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + }, + "SpeedSet": { + "datatype": "float", + "description": "Set cruise control speed in kilometers per hour.", + "type": "actuator", + "unit": "km/h" + } + }, + "description": "Signals from Cruise Control system.", + "type": "branch" + }, + "DMS": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if DMS is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if DMS incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + }, + "IsWarning": { + "datatype": "boolean", + "description": "Indicates if DMS has registered a driver alert condition.", + "type": "sensor" + } + }, + "description": "Driver Monitoring System signals.", + "type": "branch" + }, + "EBA": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if EBA is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Indicates if EBA is currently regulating brake pressure. True = Engaged. False = Not Engaged.", + "type": "sensor" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if EBA incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + } + }, + "description": "Emergency Brake Assist (EBA) System signals.", + "type": "branch" + }, + "EBD": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if EBD is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Indicates if EBD is currently regulating vehicle brakeforce distribution. True = Engaged. False = Not Engaged.", + "type": "sensor" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if EBD incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + } + }, + "description": "Electronic Brakeforce Distribution (EBD) System signals.", + "type": "branch" + }, + "ESC": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if ESC is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Indicates if ESC is currently regulating vehicle stability. True = Engaged. False = Not Engaged.", + "type": "sensor" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if ESC incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + }, + "IsStrongCrossWindDetected": { + "datatype": "boolean", + "description": "Indicates if the ESC system is detecting strong cross winds. True = Strong cross winds detected. False = No strong cross winds detected.", + "type": "sensor" + }, + "RoadFriction": { + "children": { + "LowerBound": { + "datatype": "float", + "description": "Lower bound road friction, as calculated by the ESC system. 5% possibility that road friction is below this value. 0 = no friction, 100 = maximum friction.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "MostProbable": { + "datatype": "float", + "description": "Most probable road friction, as calculated by the ESC system. Exact meaning of most probable is implementation specific. 0 = no friction, 100 = maximum friction.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "UpperBound": { + "datatype": "float", + "description": "Upper bound road friction, as calculated by the ESC system. 95% possibility that road friction is below this value. 0 = no friction, 100 = maximum friction.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Road friction values reported by the ESC system.", + "type": "branch" + } + }, + "description": "Electronic Stability Control System signals.", + "type": "branch" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "LaneDepartureDetection": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if lane departure detection system is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if lane departure system incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + }, + "IsWarning": { + "datatype": "boolean", + "description": "Indicates if lane departure detection registered a lane departure.", + "type": "sensor" + } + }, + "description": "Signals from Lane Departure Detection System.", + "type": "branch" + }, + "ObstacleDetection": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if obstacle sensor system is enabled (i.e. monitoring for obstacles). True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if obstacle sensor system incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + }, + "IsWarning": { + "datatype": "boolean", + "description": "Indicates if obstacle sensor system registered an obstacle.", + "type": "sensor" + } + }, + "description": "Signals form Obstacle Sensor System.", + "type": "branch" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "SupportedAutonomyLevel": { + "allowed": [ + "SAE_0", + "SAE_1", + "SAE_2", + "SAE_3", + "SAE_4", + "SAE_5" + ], + "datatype": "string", + "description": "Indicates the highest level of autonomy according to SAE J3016 taxonomy the vehicle is capable of.", + "type": "attribute" + }, + "TCS": { + "children": { + "IsEnabled": { + "datatype": "boolean", + "description": "Indicates if TCS is enabled. True = Enabled. False = Disabled.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Indicates if TCS is currently regulating traction. True = Engaged. False = Not Engaged.", + "type": "sensor" + }, + "IsError": { + "datatype": "boolean", + "description": "Indicates if TCS incurred an error condition. True = Error. False = No Error.", + "type": "sensor" + } + }, + "description": "Traction Control System signals.", + "type": "branch" + } + }, + "description": "All Advanced Driver Assist Systems data.", + "type": "branch" + }, + "Acceleration": { + "children": { + "Lateral": { + "datatype": "float", + "description": "Vehicle acceleration in Y (lateral acceleration).", + "type": "sensor", + "unit": "m/s^2" + }, + "Longitudinal": { + "datatype": "float", + "description": "Vehicle acceleration in X (longitudinal acceleration).", + "type": "sensor", + "unit": "m/s^2" + }, + "Vertical": { + "datatype": "float", + "description": "Vehicle acceleration in Z (vertical acceleration).", + "type": "sensor", + "unit": "m/s^2" + } + }, + "description": "Spatial acceleration. Axis definitions according to ISO 8855.", + "type": "branch" + }, + "AngularVelocity": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Vehicle rotation rate along Y (lateral).", + "type": "sensor", + "unit": "degrees/s" + }, + "Roll": { + "datatype": "float", + "description": "Vehicle rotation rate along X (longitudinal).", + "type": "sensor", + "unit": "degrees/s" + }, + "Yaw": { + "datatype": "float", + "description": "Vehicle rotation rate along Z (vertical).", + "type": "sensor", + "unit": "degrees/s" + } + }, + "description": "Spatial rotation. Axis definitions according to ISO 8855.", + "type": "branch" + }, + "AverageSpeed": { + "comment": "A new trip is considered to start when engine gets enabled (e.g. LowVoltageSystemState in ON or START mode). A trip is considered to end when engine is no longer enabled. The signal may however keep the value of the last trip until a new trip is started. Calculation of average speed may exclude periods when the vehicle for example is not moving or transmission is in neutral.", + "datatype": "float", + "description": "Average speed for the current trip.", + "type": "sensor", + "unit": "km/h" + }, + "Body": { + "children": { + "BodyType": { + "datatype": "string", + "description": "Body type code as defined by ISO 3779.", + "type": "attribute" + }, + "Hood": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "comment": "The hood is the hinged cover over the engine compartment of a motor vehicles. Depending on vehicle, it can be either in the front or back of the vehicle. Luggage compartments are in VSS called trunks, even if they are located at the front of the vehicle.", + "description": "Hood status. Start position for Hood is Closed.", + "type": "branch" + }, + "Horn": { + "children": { + "IsActive": { + "datatype": "boolean", + "description": "Horn active or inactive. True = Active. False = Inactive.", + "type": "actuator" + } + }, + "description": "Horn signals.", + "type": "branch" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "Lights": { + "children": { + "Backup": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Backup lights.", + "type": "branch" + }, + "Beam": { + "children": { + "High": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Beam lights.", + "type": "branch" + }, + "Low": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Beam lights.", + "type": "branch" + } + }, + "description": "Beam lights.", + "type": "branch" + }, + "Brake": { + "children": { + "IsActive": { + "allowed": [ + "INACTIVE", + "ACTIVE", + "ADAPTIVE" + ], + "datatype": "string", + "description": "Indicates if break-light is active. INACTIVE means lights are off. ACTIVE means lights are on. ADAPTIVE means that break-light is indicating emergency-breaking.", + "type": "actuator" + }, + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + } + }, + "description": "Brake lights.", + "type": "branch" + }, + "DirectionIndicator": { + "children": { + "Left": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsSignaling": { + "datatype": "boolean", + "description": "Indicates if light is signaling or off. True = signaling. False = Off.", + "type": "actuator" + } + }, + "description": "Indicator lights.", + "type": "branch" + }, + "Right": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsSignaling": { + "datatype": "boolean", + "description": "Indicates if light is signaling or off. True = signaling. False = Off.", + "type": "actuator" + } + }, + "description": "Indicator lights.", + "type": "branch" + } + }, + "description": "Indicator lights.", + "type": "branch" + }, + "Fog": { + "children": { + "Front": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Fog lights.", + "type": "branch" + }, + "Rear": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Fog lights.", + "type": "branch" + } + }, + "description": "Fog lights.", + "type": "branch" + }, + "Hazard": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsSignaling": { + "datatype": "boolean", + "description": "Indicates if light is signaling or off. True = signaling. False = Off.", + "type": "actuator" + } + }, + "description": "Hazard lights.", + "type": "branch" + }, + "IsHighBeamSwitchOn": { + "comment": "This signal indicates the status of the switch and does not indicate if low or high beam actually are on. That typically depends on vehicle logic and other signals like Lights.LightSwitch and Vehicle.LowVoltageSystemState.", + "datatype": "boolean", + "description": "Status of the high beam switch. True = high beam enabled. False = high beam not enabled.", + "type": "actuator" + }, + "LicensePlate": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "License plate lights.", + "type": "branch" + }, + "LightSwitch": { + "allowed": [ + "OFF", + "POSITION", + "DAYTIME_RUNNING_LIGHTS", + "AUTO", + "BEAM" + ], + "comment": "A vehicle typically does not support all alternatives. Which lights that actually are lit may vary according to vehicle configuration and local legislation. OFF is typically indicated by 0. POSITION is typically indicated by ISO 7000 symbol 0456. DAYTIME_RUNNING_LIGHTS (DRL) can be indicated by ISO 7000 symbol 2611. AUTO indicates that vehicle automatically selects suitable lights. BEAM is typically indicated by ISO 7000 symbol 0083.", + "datatype": "string", + "description": "Status of the vehicle main light switch.", + "type": "actuator" + }, + "Parking": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Parking lights.", + "type": "branch" + }, + "Running": { + "children": { + "IsDefect": { + "datatype": "boolean", + "description": "Indicates if light is defect. True = Light is defect. False = Light has no defect.", + "type": "sensor" + }, + "IsOn": { + "datatype": "boolean", + "description": "Indicates if light is on or off. True = On. False = Off.", + "type": "actuator" + } + }, + "description": "Daytime running lights (DRL).", + "type": "branch" + } + }, + "description": "Exterior lights.", + "type": "branch" + }, + "Mirrors": { + "children": { + "DriverSide": { + "children": { + "IsFolded": { + "datatype": "boolean", + "description": "Is mirror folded? True = Fully or partially folded. False = Fully unfolded.", + "type": "actuator" + }, + "IsHeatingOn": { + "datatype": "boolean", + "description": "Mirror Heater on or off. True = Heater On. False = Heater Off.", + "type": "actuator" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is mirror movement locked? True = Locked, mirror will not react to Tilt/Pan change. False = Unlocked.", + "type": "actuator" + }, + "Pan": { + "datatype": "int8", + "description": "Mirror pan as a percent. 0 = Center Position. 100 = Fully Left Position. -100 = Fully Right Position.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Tilt": { + "datatype": "int8", + "description": "Mirror tilt as a percent. 0 = Center Position. 100 = Fully Upward Position. -100 = Fully Downward Position.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + } + }, + "description": "All mirrors.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "IsFolded": { + "datatype": "boolean", + "description": "Is mirror folded? True = Fully or partially folded. False = Fully unfolded.", + "type": "actuator" + }, + "IsHeatingOn": { + "datatype": "boolean", + "description": "Mirror Heater on or off. True = Heater On. False = Heater Off.", + "type": "actuator" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is mirror movement locked? True = Locked, mirror will not react to Tilt/Pan change. False = Unlocked.", + "type": "actuator" + }, + "Pan": { + "datatype": "int8", + "description": "Mirror pan as a percent. 0 = Center Position. 100 = Fully Left Position. -100 = Fully Right Position.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Tilt": { + "datatype": "int8", + "description": "Mirror tilt as a percent. 0 = Center Position. 100 = Fully Upward Position. -100 = Fully Downward Position.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + } + }, + "description": "All mirrors.", + "type": "branch" + } + }, + "description": "All mirrors.", + "type": "branch" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "Raindetection": { + "children": { + "Intensity": { + "datatype": "uint8", + "description": "Rain intensity. 0 = Dry, No Rain. 100 = Covered.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Rain sensor signals.", + "type": "branch" + }, + "RearMainSpoilerPosition": { + "datatype": "float", + "description": "Rear spoiler position, 0% = Spoiler fully stowed. 100% = Spoiler fully exposed.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "RefuelPosition": { + "allowed": [ + "FRONT_LEFT", + "FRONT_RIGHT", + "MIDDLE_LEFT", + "MIDDLE_RIGHT", + "REAR_LEFT", + "REAR_RIGHT" + ], + "datatype": "string", + "deprecation": "v4.1 replaced with Vehicle.Powertrain.TractionBattery.Charging.ChargePortPosition and Vehicle.Powertrain.FuelSystem.RefuelPortPosition", + "description": "Location of the fuel cap or charge port.", + "type": "attribute" + }, + "Trunk": { + "children": { + "Front": { + "children": { + "IsLightOn": { + "comment": "V4.0 Moved from Vehicle.Cabin.Lights.IsTrunkOn because Trunk is not defined as part of the Cabin.", + "datatype": "boolean", + "description": "Is trunk light on", + "type": "actuator" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "comment": "A trunk is a luggage compartment in a vehicle. Depending on vehicle, it can be either in the front or back of the vehicle. Some vehicles may have trunks both at the front and at the rear of the vehicle.", + "description": "Trunk status. Start position for Trunk is Closed.", + "type": "branch" + }, + "Rear": { + "children": { + "IsLightOn": { + "comment": "V4.0 Moved from Vehicle.Cabin.Lights.IsTrunkOn because Trunk is not defined as part of the Cabin.", + "datatype": "boolean", + "description": "Is trunk light on", + "type": "actuator" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "comment": "A trunk is a luggage compartment in a vehicle. Depending on vehicle, it can be either in the front or back of the vehicle. Some vehicles may have trunks both at the front and at the rear of the vehicle.", + "description": "Trunk status. Start position for Trunk is Closed.", + "type": "branch" + } + }, + "comment": "A trunk is a luggage compartment in a vehicle. Depending on vehicle, it can be either in the front or back of the vehicle. Some vehicles may have trunks both at the front and at the rear of the vehicle.", + "description": "Trunk status. Start position for Trunk is Closed.", + "type": "branch" + }, + "Windshield": { + "children": { + "Front": { + "children": { + "IsHeatingOn": { + "datatype": "boolean", + "description": "Windshield heater status. False - off, True - on.", + "type": "actuator" + }, + "WasherFluid": { + "children": { + "IsLevelLow": { + "datatype": "boolean", + "description": "Low level indication for washer fluid. True = Level Low. False = Level OK.", + "type": "sensor" + }, + "Level": { + "datatype": "uint8", + "description": "Washer fluid level as a percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Windshield washer fluid signals", + "type": "branch" + }, + "Wiping": { + "children": { + "Intensity": { + "datatype": "uint8", + "description": "Relative intensity/sensitivity for interval and rain sensor mode as requested by user/driver. Has no significance if Windshield.Wiping.Mode is OFF/SLOW/MEDIUM/FAST 0 - wipers inactive. 1 - minimum intensity (lowest frequency/sensitivity, longest interval). 2/3/4/... - higher intensity (higher frequency/sensitivity, shorter interval). Maximum value supported is vehicle specific.", + "type": "actuator" + }, + "IsWipersWorn": { + "datatype": "boolean", + "description": "Wiper wear status. True = Worn, Replacement recommended or required. False = Not Worn.", + "type": "sensor" + }, + "Mode": { + "allowed": [ + "OFF", + "SLOW", + "MEDIUM", + "FAST", + "INTERVAL", + "RAIN_SENSOR" + ], + "datatype": "string", + "description": "Wiper mode requested by user/driver. INTERVAL indicates intermittent wiping, with fixed time interval between each wipe. RAIN_SENSOR indicates intermittent wiping based on rain intensity.", + "type": "actuator" + }, + "System": { + "children": { + "ActualPosition": { + "comment": "Default parking position might be used as reference position.", + "datatype": "float", + "description": "Actual position of main wiper blade for the wiper system relative to reference position. Location of reference position (0 degrees) and direction of positive/negative degrees is vehicle specific.", + "type": "actuator", + "unit": "degrees" + }, + "DriveCurrent": { + "comment": "May be negative in special situations.", + "datatype": "float", + "description": "Actual current used by wiper drive.", + "type": "sensor", + "unit": "A" + }, + "Frequency": { + "comment": "Examples - 0 = Wipers stopped, 80 = Wipers doing 80 cycles per minute (in WIPE mode).", + "datatype": "uint8", + "description": "Wiping frequency/speed, measured in cycles per minute. The signal concerns the actual speed of the wiper blades when moving. Intervals/pauses are excluded, i.e. the value corresponds to the number of cycles that would be completed in 1 minute if wiping permanently over default range.", + "type": "actuator", + "unit": "cpm" + }, + "IsBlocked": { + "datatype": "boolean", + "description": "Indicates if wiper movement is blocked. True = Movement blocked. False = Movement not blocked.", + "type": "sensor" + }, + "IsEndingWipeCycle": { + "comment": "In continuous wiping between A and B this sensor can be used a trigger to update TargetPosition.", + "datatype": "boolean", + "description": "Indicates if current wipe movement is completed or near completion. True = Movement is completed or near completion. Changes to RequestedPosition will be executed first after reaching previous RequestedPosition, if it has not already been reached. False = Movement is not near completion. Any change to RequestedPosition will be executed immediately. Change of direction may not be allowed.", + "type": "sensor" + }, + "IsOverheated": { + "datatype": "boolean", + "description": "Indicates if wiper system is overheated. True = Wiper system overheated. False = Wiper system not overheated.", + "type": "sensor" + }, + "IsPositionReached": { + "datatype": "boolean", + "description": "Indicates if a requested position has been reached. IsPositionReached refers to the previous position in case the TargetPosition is updated while IsEndingWipeCycle=True. True = Current or Previous TargetPosition reached. False = Position not (yet) reached, or wipers have moved away from the reached position.", + "type": "sensor" + }, + "IsWiperError": { + "datatype": "boolean", + "description": "Indicates system failure. True if wiping is disabled due to system failure.", + "type": "sensor" + }, + "IsWiping": { + "datatype": "boolean", + "description": "Indicates wiper movement. True if wiper blades are moving. Change of direction shall be considered as IsWiping if wipers will continue to move directly after the change of direction.", + "type": "sensor" + }, + "Mode": { + "allowed": [ + "STOP_HOLD", + "WIPE", + "PLANT_MODE", + "EMERGENCY_STOP" + ], + "datatype": "string", + "description": "Requested mode of wiper system. STOP_HOLD means that the wipers shall move to position given by TargetPosition and then hold the position. WIPE means that wipers shall move to the position given by TargetPosition and then hold the position if no new TargetPosition is requested. PLANT_MODE means that wiping is disabled. Exact behavior is vehicle specific. EMERGENCY_STOP means that wiping shall be immediately stopped without holding the position.", + "type": "actuator" + }, + "TargetPosition": { + "comment": "Default parking position might be used as reference position.", + "datatype": "float", + "description": "Requested position of main wiper blade for the wiper system relative to reference position. Location of reference position (0 degrees) and direction of positive/negative degrees is vehicle specific. System behavior when receiving TargetPosition depends on Mode and IsEndingWipeCycle. Supported values are vehicle specific and might be dynamically corrected. If IsEndingWipeCycle=True then wipers will complete current movement before actuating new TargetPosition. If IsEndingWipeCycle=False then wipers will directly change destination if the TargetPosition is changed.", + "type": "actuator", + "unit": "degrees" + } + }, + "comment": "These signals are typically not directly available to the user/driver of the vehicle. The overlay in overlays/extensions/dual_wiper_systems.vspec can be used to modify this branch to support two instances; Primary and Secondary.", + "description": "Signals to control behavior of wipers in detail. By default VSS expects only one instance.", + "type": "branch" + }, + "WiperWear": { + "datatype": "uint8", + "description": "Wiper wear as percent. 0 = No Wear. 100 = Worn. Replacement required. Method for calculating or estimating wiper wear is vehicle specific. For windshields with multiple wipers the wear reported shall correspond to the most worn wiper.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Windshield wiper signals.", + "type": "branch" + } + }, + "description": "Windshield signals.", + "type": "branch" + }, + "Rear": { + "children": { + "IsHeatingOn": { + "datatype": "boolean", + "description": "Windshield heater status. False - off, True - on.", + "type": "actuator" + }, + "WasherFluid": { + "children": { + "IsLevelLow": { + "datatype": "boolean", + "description": "Low level indication for washer fluid. True = Level Low. False = Level OK.", + "type": "sensor" + }, + "Level": { + "datatype": "uint8", + "description": "Washer fluid level as a percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Windshield washer fluid signals", + "type": "branch" + }, + "Wiping": { + "children": { + "Intensity": { + "datatype": "uint8", + "description": "Relative intensity/sensitivity for interval and rain sensor mode as requested by user/driver. Has no significance if Windshield.Wiping.Mode is OFF/SLOW/MEDIUM/FAST 0 - wipers inactive. 1 - minimum intensity (lowest frequency/sensitivity, longest interval). 2/3/4/... - higher intensity (higher frequency/sensitivity, shorter interval). Maximum value supported is vehicle specific.", + "type": "actuator" + }, + "IsWipersWorn": { + "datatype": "boolean", + "description": "Wiper wear status. True = Worn, Replacement recommended or required. False = Not Worn.", + "type": "sensor" + }, + "Mode": { + "allowed": [ + "OFF", + "SLOW", + "MEDIUM", + "FAST", + "INTERVAL", + "RAIN_SENSOR" + ], + "datatype": "string", + "description": "Wiper mode requested by user/driver. INTERVAL indicates intermittent wiping, with fixed time interval between each wipe. RAIN_SENSOR indicates intermittent wiping based on rain intensity.", + "type": "actuator" + }, + "System": { + "children": { + "ActualPosition": { + "comment": "Default parking position might be used as reference position.", + "datatype": "float", + "description": "Actual position of main wiper blade for the wiper system relative to reference position. Location of reference position (0 degrees) and direction of positive/negative degrees is vehicle specific.", + "type": "actuator", + "unit": "degrees" + }, + "DriveCurrent": { + "comment": "May be negative in special situations.", + "datatype": "float", + "description": "Actual current used by wiper drive.", + "type": "sensor", + "unit": "A" + }, + "Frequency": { + "comment": "Examples - 0 = Wipers stopped, 80 = Wipers doing 80 cycles per minute (in WIPE mode).", + "datatype": "uint8", + "description": "Wiping frequency/speed, measured in cycles per minute. The signal concerns the actual speed of the wiper blades when moving. Intervals/pauses are excluded, i.e. the value corresponds to the number of cycles that would be completed in 1 minute if wiping permanently over default range.", + "type": "actuator", + "unit": "cpm" + }, + "IsBlocked": { + "datatype": "boolean", + "description": "Indicates if wiper movement is blocked. True = Movement blocked. False = Movement not blocked.", + "type": "sensor" + }, + "IsEndingWipeCycle": { + "comment": "In continuous wiping between A and B this sensor can be used a trigger to update TargetPosition.", + "datatype": "boolean", + "description": "Indicates if current wipe movement is completed or near completion. True = Movement is completed or near completion. Changes to RequestedPosition will be executed first after reaching previous RequestedPosition, if it has not already been reached. False = Movement is not near completion. Any change to RequestedPosition will be executed immediately. Change of direction may not be allowed.", + "type": "sensor" + }, + "IsOverheated": { + "datatype": "boolean", + "description": "Indicates if wiper system is overheated. True = Wiper system overheated. False = Wiper system not overheated.", + "type": "sensor" + }, + "IsPositionReached": { + "datatype": "boolean", + "description": "Indicates if a requested position has been reached. IsPositionReached refers to the previous position in case the TargetPosition is updated while IsEndingWipeCycle=True. True = Current or Previous TargetPosition reached. False = Position not (yet) reached, or wipers have moved away from the reached position.", + "type": "sensor" + }, + "IsWiperError": { + "datatype": "boolean", + "description": "Indicates system failure. True if wiping is disabled due to system failure.", + "type": "sensor" + }, + "IsWiping": { + "datatype": "boolean", + "description": "Indicates wiper movement. True if wiper blades are moving. Change of direction shall be considered as IsWiping if wipers will continue to move directly after the change of direction.", + "type": "sensor" + }, + "Mode": { + "allowed": [ + "STOP_HOLD", + "WIPE", + "PLANT_MODE", + "EMERGENCY_STOP" + ], + "datatype": "string", + "description": "Requested mode of wiper system. STOP_HOLD means that the wipers shall move to position given by TargetPosition and then hold the position. WIPE means that wipers shall move to the position given by TargetPosition and then hold the position if no new TargetPosition is requested. PLANT_MODE means that wiping is disabled. Exact behavior is vehicle specific. EMERGENCY_STOP means that wiping shall be immediately stopped without holding the position.", + "type": "actuator" + }, + "TargetPosition": { + "comment": "Default parking position might be used as reference position.", + "datatype": "float", + "description": "Requested position of main wiper blade for the wiper system relative to reference position. Location of reference position (0 degrees) and direction of positive/negative degrees is vehicle specific. System behavior when receiving TargetPosition depends on Mode and IsEndingWipeCycle. Supported values are vehicle specific and might be dynamically corrected. If IsEndingWipeCycle=True then wipers will complete current movement before actuating new TargetPosition. If IsEndingWipeCycle=False then wipers will directly change destination if the TargetPosition is changed.", + "type": "actuator", + "unit": "degrees" + } + }, + "comment": "These signals are typically not directly available to the user/driver of the vehicle. The overlay in overlays/extensions/dual_wiper_systems.vspec can be used to modify this branch to support two instances; Primary and Secondary.", + "description": "Signals to control behavior of wipers in detail. By default VSS expects only one instance.", + "type": "branch" + }, + "WiperWear": { + "datatype": "uint8", + "description": "Wiper wear as percent. 0 = No Wear. 100 = Worn. Replacement required. Method for calculating or estimating wiper wear is vehicle specific. For windshields with multiple wipers the wear reported shall correspond to the most worn wiper.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Windshield wiper signals.", + "type": "branch" + } + }, + "description": "Windshield signals.", + "type": "branch" + } + }, + "description": "Windshield signals.", + "type": "branch" + } + }, + "description": "All body components.", + "type": "branch" + }, + "Cabin": { + "children": { + "Convertible": { + "children": { + "Status": { + "allowed": [ + "UNDEFINED", + "CLOSED", + "OPEN", + "CLOSING", + "OPENING", + "STALLED" + ], + "datatype": "string", + "description": "Roof status on convertible vehicles.", + "type": "sensor" + } + }, + "description": "Convertible roof.", + "type": "branch" + }, + "Door": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "IsChildLockActive": { + "datatype": "boolean", + "description": "Is door child lock active. True = Door cannot be opened from inside. False = Door can be opened from inside.", + "type": "sensor" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Shade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Side window shade. Open = Retracted, Closed = Deployed. Start position for Shade is Open/Retracted.", + "type": "branch" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + }, + "Window": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Door window status. Start position for Window is Closed.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "IsChildLockActive": { + "datatype": "boolean", + "description": "Is door child lock active. True = Door cannot be opened from inside. False = Door can be opened from inside.", + "type": "sensor" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Shade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Side window shade. Open = Retracted, Closed = Deployed. Start position for Shade is Open/Retracted.", + "type": "branch" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + }, + "Window": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Door window status. Start position for Window is Closed.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "IsChildLockActive": { + "datatype": "boolean", + "description": "Is door child lock active. True = Door cannot be opened from inside. False = Door can be opened from inside.", + "type": "sensor" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Shade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Side window shade. Open = Retracted, Closed = Deployed. Start position for Shade is Open/Retracted.", + "type": "branch" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + }, + "Window": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Door window status. Start position for Window is Closed.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "IsChildLockActive": { + "datatype": "boolean", + "description": "Is door child lock active. True = Door cannot be opened from inside. False = Door can be opened from inside.", + "type": "sensor" + }, + "IsLocked": { + "datatype": "boolean", + "description": "Is item locked or unlocked. True = Locked. False = Unlocked.", + "type": "actuator" + }, + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Shade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Side window shade. Open = Retracted, Closed = Deployed. Start position for Shade is Open/Retracted.", + "type": "branch" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + }, + "Window": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Door window status. Start position for Window is Closed.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + } + }, + "description": "All doors, including windows and switches.", + "type": "branch" + }, + "DoorCount": { + "datatype": "uint8", + "default": 4, + "description": "Number of doors in vehicle.", + "type": "attribute" + }, + "DriverPosition": { + "allowed": [ + "LEFT", + "MIDDLE", + "RIGHT" + ], + "comment": "Some signals use DriverSide and PassengerSide as instances. If this signal specifies that DriverPosition is LEFT or MIDDLE, then DriverSide refers to left side and PassengerSide to right side. If this signal specifies that DriverPosition is RIGHT, then DriverSide refers to right side and PassengerSide to left side.", + "datatype": "string", + "description": "The position of the driver seat in row 1.", + "type": "attribute" + }, + "HVAC": { + "children": { + "AmbientAirTemperature": { + "datatype": "float", + "description": "Ambient air temperature inside the vehicle.", + "type": "sensor", + "unit": "celsius" + }, + "IsAirConditioningActive": { + "datatype": "boolean", + "description": "Is Air conditioning active.", + "type": "actuator" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "IsFrontDefrosterActive": { + "datatype": "boolean", + "description": "Is front defroster active.", + "type": "actuator" + }, + "IsRearDefrosterActive": { + "datatype": "boolean", + "description": "Is rear defroster active.", + "type": "actuator" + }, + "IsRecirculationActive": { + "datatype": "boolean", + "description": "Is recirculation active.", + "type": "actuator" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "Station": { + "children": { + "Row1": { + "children": { + "Driver": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Passenger": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Row2": { + "children": { + "Driver": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Passenger": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Row3": { + "children": { + "Driver": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Passenger": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Row4": { + "children": { + "Driver": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + }, + "Passenger": { + "children": { + "AirDistribution": { + "allowed": [ + "UP", + "MIDDLE", + "DOWN" + ], + "datatype": "string", + "description": "Direction of airstream", + "type": "actuator" + }, + "FanSpeed": { + "datatype": "uint8", + "description": "Fan Speed, 0 = off. 100 = max", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Temperature": { + "datatype": "int8", + "description": "Temperature", + "type": "actuator", + "unit": "celsius" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "HVAC for single station in the vehicle", + "type": "branch" + } + }, + "description": "Climate control", + "type": "branch" + }, + "Infotainment": { + "children": { + "HMI": { + "children": { + "Brightness": { + "comment": "The value 0 does not necessarily correspond to a turned off HMI, as it may not be allowed/supported to turn off the HMI completely.", + "datatype": "float", + "description": "Brightness of the HMI, relative to supported range. 0 = Lowest brightness possible. 100 = Maximum Brightness possible.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "CurrentLanguage": { + "datatype": "string", + "description": "ISO 639-1 standard language code for the current HMI", + "type": "sensor" + }, + "DateFormat": { + "allowed": [ + "YYYY_MM_DD", + "DD_MM_YYYY", + "MM_DD_YYYY", + "YY_MM_DD", + "DD_MM_YY", + "MM_DD_YY" + ], + "datatype": "string", + "description": "Date format used in the current HMI", + "type": "actuator" + }, + "DayNightMode": { + "allowed": [ + "DAY", + "NIGHT" + ], + "datatype": "string", + "description": "Current display theme", + "type": "actuator" + }, + "DisplayOffDuration": { + "comment": "Display shall be turned off at HMI.LastActionTime + HMI.DisplayOffDuration, unless HMI.IsScreenAlwaysOn==True.", + "datatype": "uint16", + "description": "Duration in seconds before the display is turned off. Value shall be 0 if screen never shall turn off.", + "type": "actuator", + "unit": "s" + }, + "DistanceUnit": { + "allowed": [ + "MILES", + "KILOMETERS" + ], + "datatype": "string", + "description": "Distance unit used in the current HMI", + "type": "actuator" + }, + "EVEconomyUnits": { + "allowed": [ + "MILES_PER_KILOWATT_HOUR", + "KILOMETERS_PER_KILOWATT_HOUR", + "KILOWATT_HOURS_PER_100_MILES", + "KILOWATT_HOURS_PER_100_KILOMETERS", + "WATT_HOURS_PER_MILE", + "WATT_HOURS_PER_KILOMETER" + ], + "datatype": "string", + "description": "EV fuel economy unit used in the current HMI", + "type": "actuator" + }, + "EVEnergyUnits": { + "allowed": [ + "WATT_HOURS", + "AMPERE_HOURS", + "KILOWATT_HOURS" + ], + "comment": "Ampere hours is by definition not an energy unit, but can be used as a measurement of energy if the voltage, like nominal voltage of the battery, is known.", + "datatype": "string", + "description": "EV energy unit used in the current HMI", + "type": "actuator" + }, + "FontSize": { + "allowed": [ + "STANDARD", + "LARGE", + "EXTRA_LARGE" + ], + "datatype": "string", + "description": "Font size used in the current HMI", + "type": "actuator" + }, + "FuelEconomyUnits": { + "allowed": [ + "MPG_UK", + "MPG_US", + "MILES_PER_LITER", + "KILOMETERS_PER_LITER", + "LITERS_PER_100_KILOMETERS" + ], + "datatype": "string", + "description": "Fuel economy unit used in the current HMI", + "type": "actuator" + }, + "FuelVolumeUnit": { + "allowed": [ + "LITER", + "GALLON_US", + "GALLON_UK" + ], + "datatype": "string", + "description": "Fuel volume unit used in the current HMI", + "type": "actuator" + }, + "IsScreenAlwaysOn": { + "datatype": "boolean", + "description": "Used to prevent the screen going black if no action placed.", + "type": "actuator" + }, + "LastActionTime": { + "datatype": "string", + "description": "Time for last hmi action, formatted according to ISO 8601 with UTC time zone.", + "type": "sensor", + "unit": "iso8601" + }, + "SpeedUnit": { + "allowed": [ + "METERS_PER_SECOND", + "MILES_PER_HOUR", + "KILOMETERS_PER_HOUR" + ], + "datatype": "string", + "description": "Speed unit used in the current HMI", + "type": "actuator" + }, + "TemperatureUnit": { + "allowed": [ + "C", + "F" + ], + "datatype": "string", + "description": "Temperature unit used in the current HMI", + "type": "actuator" + }, + "TimeFormat": { + "allowed": [ + "HR_12", + "HR_24" + ], + "datatype": "string", + "description": "Time format used in the current HMI", + "type": "actuator" + }, + "TirePressureUnit": { + "allowed": [ + "PSI", + "KPA", + "BAR" + ], + "datatype": "string", + "description": "Tire pressure unit used in the current HMI", + "type": "actuator" + } + }, + "description": "HMI related signals", + "type": "branch" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "Media": { + "children": { + "Action": { + "allowed": [ + "UNKNOWN", + "STOP", + "PLAY", + "FAST_FORWARD", + "FAST_BACKWARD", + "SKIP_FORWARD", + "SKIP_BACKWARD" + ], + "datatype": "string", + "description": "Tells if the media was", + "type": "actuator" + }, + "DeclinedURI": { + "datatype": "string", + "description": "URI of suggested media that was declined", + "type": "sensor" + }, + "Played": { + "children": { + "Album": { + "datatype": "string", + "description": "Name of album being played", + "type": "sensor" + }, + "Artist": { + "datatype": "string", + "description": "Name of artist being played", + "type": "sensor" + }, + "PlaybackRate": { + "comment": "The normal playback rate is multiplied by this value to obtain the current rate, so a value of 1.0 indicates normal speed. Values of lower than 1.0 make the media play slower than normal. Values of higher than 1.0 make the media play faster than normal.", + "datatype": "float", + "description": "Current playback rate of media being played.", + "type": "actuator" + }, + "Source": { + "allowed": [ + "UNKNOWN", + "SIRIUS_XM", + "AM", + "FM", + "DAB", + "TV", + "CD", + "DVD", + "AUX", + "USB", + "DISK", + "BLUETOOTH", + "INTERNET", + "VOICE", + "BEEP" + ], + "datatype": "string", + "description": "Media selected for playback", + "type": "actuator" + }, + "Track": { + "datatype": "string", + "description": "Name of track being played", + "type": "sensor" + }, + "URI": { + "datatype": "string", + "description": "User Resource associated with the media", + "type": "sensor" + } + }, + "description": "Collection of signals updated in concert when a new media is played", + "type": "branch" + }, + "SelectedURI": { + "datatype": "string", + "description": "URI of suggested media that was selected", + "type": "actuator" + }, + "Volume": { + "datatype": "uint8", + "description": "Current Media Volume", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "All Media actions", + "type": "branch" + }, + "Navigation": { + "children": { + "DestinationSet": { + "children": { + "Latitude": { + "datatype": "double", + "description": "Latitude of destination in WGS 84 geodetic coordinates.", + "max": 90, + "min": -90, + "type": "actuator", + "unit": "degrees" + }, + "Longitude": { + "datatype": "double", + "description": "Longitude of destination in WGS 84 geodetic coordinates.", + "max": 180, + "min": -180, + "type": "actuator", + "unit": "degrees" + } + }, + "description": "A navigation has been selected.", + "type": "branch" + }, + "GuidanceVoice": { + "allowed": [ + "STANDARD_MALE", + "STANDARD_FEMALE", + "ETC" + ], + "comment": "ETC indicates a voice alternative not covered by the explicitly listed alternatives.", + "datatype": "string", + "description": "Navigation guidance state that was selected.", + "type": "actuator" + }, + "Map": { + "children": { + "IsAutoScaleModeUsed": { + "comment": "If true, then auto-scaling mode is used. If false, then manual-scaling mode is used.", + "datatype": "boolean", + "description": "Used to select auto-scaling mode. This feature dynamically adjusts the zoom level of the map to provide an optimal view based on the current speed of the vehicle", + "type": "actuator" + } + }, + "description": "All map actions", + "type": "branch" + }, + "Mute": { + "allowed": [ + "MUTED", + "ALERT_ONLY", + "UNMUTED" + ], + "datatype": "string", + "description": "Navigation mute state that was selected.", + "type": "actuator" + }, + "Volume": { + "datatype": "uint8", + "description": "Current navigation volume", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "All navigation actions", + "type": "branch" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "SmartphoneProjection": { + "children": { + "Active": { + "allowed": [ + "NONE", + "ACTIVE", + "INACTIVE" + ], + "comment": "NONE indicates that projection is not supported.", + "datatype": "string", + "description": "Projection activation info.", + "type": "actuator" + }, + "Source": { + "allowed": [ + "USB", + "BLUETOOTH", + "WIFI" + ], + "comment": "Smartphone projection exposes or controls specific applications on the Smartphone on the vehicle infotainment system.", + "datatype": "string", + "description": "Connectivity source selected for projection.", + "type": "actuator" + }, + "SupportedMode": { + "allowed": [ + "ANDROID_AUTO", + "APPLE_CARPLAY", + "MIRROR_LINK", + "OTHER" + ], + "datatype": "string[]", + "description": "Supportable list for projection.", + "type": "attribute" + } + }, + "comment": "Smartphone projection exposes or controls specific applications on the Smartphone on the vehicle infotainment system.", + "description": "All smartphone projection actions.", + "type": "branch" + }, + "SmartphoneScreenMirroring": { + "children": { + "Active": { + "allowed": [ + "NONE", + "ACTIVE", + "INACTIVE" + ], + "comment": "NONE indicates that mirroring is not supported.", + "datatype": "string", + "description": "Mirroring activation info.", + "type": "actuator" + }, + "Source": { + "allowed": [ + "USB", + "BLUETOOTH", + "WIFI" + ], + "datatype": "string", + "description": "Connectivity source selected for mirroring.", + "type": "actuator" + } + }, + "comment": "Smartphone screen mirroring mirrors the whole screen of the Smartphone on the vehicle infotainment system.", + "description": "All smartphone screen mirroring actions.", + "type": "branch" + } + }, + "description": "Infotainment system.", + "type": "branch" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "IsWindowChildLockEngaged": { + "comment": "Window child lock refers to the functionality to disable the move window button next to most windows, so that they only can be operated by the driver.", + "datatype": "boolean", + "description": "Is window child lock engaged. True = Engaged. False = Disengaged.", + "type": "actuator" + }, + "Light": { + "children": { + "AmbientLight": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + } + }, + "description": "Decorative coloured light inside the cabin, usually mounted on the door, ceiling, etc.", + "type": "branch" + }, + "InteractiveLightBar": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Effect": { + "comment": "Default and allowed values are OEM-specific and should be defined accordingly (e.g. with the use of overlays).", + "datatype": "string", + "description": "Light effect selection from a predefined set of allowed values.", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Decorative coloured light bar that supports effects, usually mounted on the dashboard (e.g. BMW i7 Interactive bar).", + "type": "branch" + }, + "IsDomeOn": { + "datatype": "boolean", + "description": "Is central dome light on", + "type": "actuator" + }, + "IsGloveBoxOn": { + "datatype": "boolean", + "description": "Is glove box light on", + "type": "actuator" + }, + "PerceivedAmbientLight": { + "comment": "V4.0 named changed from \"AmbientLight\" to \"PerceivedAmbientLight\". This is a read-only property that refers to the pre-existing light (e.g., natural light). If you are looking for the in-cabin decorative lights that sometimes are also called \"AmbientLights\", please refer to the branch Vehicle.Cabin.Light.AmbientLight.", + "datatype": "uint8", + "description": "The percentage of ambient light that is measured (e.g., by a sensor) inside the cabin. 0 = No ambient light. 100 = Full brightness.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "Spotlight": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "Row3": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "Row4": { + "children": { + "DriverSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Color": { + "comment": "For example; \"#C0C0C0\" = Silver, \"#FFD700\" = Gold, \"#000000\" = Black, \"#FFFFFF\" = White, etc.", + "datatype": "string", + "description": "Hexadecimal color code represented as a 3-byte RGB (i.e. Red, Green, and Blue) value preceded by a hash symbol \"#\". Allowed range \"#000000\" to \"#FFFFFF\".", + "type": "actuator" + }, + "Intensity": { + "comment": "Minimum value cannot be zero as on/off is controlled by the actuator IsLightOn. V4.0 moved from Cabin.Lights.AmbientLight.Intensity to enable individual control of lights via the SingleConfigurableLight.vspec.", + "datatype": "uint8", + "description": "How much of the maximum possible brightness of the light is used. 1 = Maximum attenuation, 100 = No attenuation (i.e. full brightness).", + "max": 100, + "min": 1, + "type": "actuator", + "unit": "percent" + }, + "IsLightOn": { + "datatype": "boolean", + "description": "Indicates whether the light is turned on. True = On, False = Off.", + "type": "actuator" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "description": "Spotlight for a specific area in the vehicle.", + "type": "branch" + } + }, + "comment": "V4.0 branch renamed from \"Lights\" to \"Light\" to comply with singular naming of entities. Use SingleConfigurableLight.vspec to describe interior lights that can be configured.", + "description": "Light that is part of the Cabin.", + "type": "branch" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "RearShade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Rear window shade. Open = Retracted, Closed = Deployed. Start position for RearShade is Open/Retracted.", + "type": "branch" + }, + "RearviewMirror": { + "children": { + "DimmingLevel": { + "datatype": "uint8", + "description": "Dimming level of rear-view mirror. 0 = Undimmed. 100 = Fully dimmed.", + "max": 100, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Rear-view mirror.", + "type": "branch" + }, + "Seat": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Middle": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Middle": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + }, + "SeatPosCount": { + "comment": "Default value corresponds to two seats in front row and 3 seats in second row.", + "datatype": "uint8[]", + "default": [ + 2, + 3 + ], + "description": "Number of seats across each row from the front to the rear.", + "type": "attribute" + }, + "SeatRowCount": { + "comment": "Default value corresponds to two rows of seats.", + "datatype": "uint8", + "default": 2, + "description": "Number of seat rows in vehicle.", + "type": "attribute" + }, + "Sunroof": { + "children": { + "Position": { + "datatype": "int8", + "description": "Sunroof position. 0 = Fully closed 100 = Fully opened. -100 = Fully tilted.", + "max": 100, + "min": -100, + "type": "sensor", + "unit": "percent" + }, + "Shade": { + "children": { + "IsOpen": { + "datatype": "boolean", + "description": "Is item open or closed? True = Fully or partially open. False = Fully closed.", + "type": "actuator" + }, + "Position": { + "comment": "Relationship between Open/Close and Start/End position is item dependent.", + "datatype": "uint8", + "description": "Item position. 0 = Start position 100 = End position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or blind.", + "type": "actuator" + } + }, + "description": "Sun roof shade status. Open = Retracted, Closed = Deployed. Start position for Sunroof.Shade is Open/Retracted.", + "type": "branch" + }, + "Switch": { + "allowed": [ + "INACTIVE", + "CLOSE", + "OPEN", + "ONE_SHOT_CLOSE", + "ONE_SHOT_OPEN", + "TILT_UP", + "TILT_DOWN" + ], + "datatype": "string", + "description": "Switch controlling sliding action such as window, sunroof, or shade.", + "type": "actuator" + } + }, + "description": "Sun roof status.", + "type": "branch" + } + }, + "description": "All in-cabin components, including doors.", + "type": "branch" + }, + "CargoVolume": { + "datatype": "float", + "description": "The available volume for cargo or luggage. For automobiles, this is usually the trunk volume.", + "min": 0, + "type": "attribute", + "unit": "l" + }, + "Chassis": { + "children": { + "Accelerator": { + "children": { + "PedalPosition": { + "datatype": "uint8", + "description": "Accelerator pedal position as percent. 0 = Not depressed. 100 = Fully depressed.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Accelerator signals", + "type": "branch" + }, + "Axle": { + "children": { + "Row1": { + "children": { + "AxleWidth": { + "comment": "Corresponds to SAE J1100-2009 W113.", + "datatype": "uint16", + "description": "The lateral distance between the wheel mounting faces, measured along the spindle axis.", + "type": "attribute", + "unit": "mm" + }, + "SteeringAngle": { + "comment": "Single track two-axle model steering angle refers to the angle that a centrally mounted wheel would have.", + "datatype": "float", + "description": "Single track two-axle model steering angle. Angle according to ISO 8855. Positive = degrees to the left. Negative = degrees to the right.", + "type": "sensor", + "unit": "degrees" + }, + "TireAspectRatio": { + "datatype": "uint8", + "description": "Aspect ratio between tire section height and tire section width, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "percent" + }, + "TireDiameter": { + "datatype": "float", + "description": "Outer diameter of tires, in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + }, + "TireWidth": { + "datatype": "uint16", + "description": "Nominal section width of tires, in mm, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "mm" + }, + "TrackWidth": { + "comment": "Corresponds to SAE J1100-2009 W102.", + "datatype": "uint16", + "description": "The lateral distance between the centers of the wheels, measured along the spindle, or axle axis. If there are dual rear wheels, measure from the midway points between the inner and outer tires.", + "type": "attribute", + "unit": "mm" + }, + "TreadWidth": { + "comment": "Corresponds to SAE J1100-2009 W101.", + "datatype": "uint16", + "description": "The lateral distance between the centerlines of the base tires at ground, including camber angle. If there are dual rear wheels, measure from the midway points between the inner and outer tires.", + "type": "attribute", + "unit": "mm" + }, + "Wheel": { + "children": { + "Left": { + "children": { + "AngularSpeed": { + "comment": "Positive if wheel is trying to drive vehicle forward. Negative if wheel is trying to drive vehicle backward.", + "datatype": "float", + "description": "Angular (Rotational) speed of a vehicle's wheel.", + "type": "sensor", + "unit": "degrees/s" + }, + "Brake": { + "children": { + "FluidLevel": { + "datatype": "uint8", + "description": "Brake fluid level as percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "IsBrakesWorn": { + "datatype": "boolean", + "description": "Brake pad wear status. True = Worn. False = Not Worn.", + "type": "sensor" + }, + "IsFluidLevelLow": { + "datatype": "boolean", + "description": "Brake fluid level status. True = Brake fluid level low. False = Brake fluid level OK.", + "type": "sensor" + }, + "PadWear": { + "datatype": "uint8", + "description": "Brake pad wear as percent. 0 = No Wear. 100 = Worn.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Brake signals for wheel", + "type": "branch" + }, + "Speed": { + "datatype": "float", + "description": "Linear speed of a vehicle's wheel.", + "type": "sensor", + "unit": "km/h" + }, + "Tire": { + "children": { + "IsPressureLow": { + "datatype": "boolean", + "description": "Tire Pressure Status. True = Low tire pressure. False = Good tire pressure.", + "type": "sensor" + }, + "Pressure": { + "datatype": "uint16", + "description": "Tire pressure in kilo-Pascal.", + "type": "sensor", + "unit": "kPa" + }, + "Temperature": { + "datatype": "float", + "description": "Tire temperature in Celsius.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Tire signals for wheel.", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + }, + "Right": { + "children": { + "AngularSpeed": { + "comment": "Positive if wheel is trying to drive vehicle forward. Negative if wheel is trying to drive vehicle backward.", + "datatype": "float", + "description": "Angular (Rotational) speed of a vehicle's wheel.", + "type": "sensor", + "unit": "degrees/s" + }, + "Brake": { + "children": { + "FluidLevel": { + "datatype": "uint8", + "description": "Brake fluid level as percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "IsBrakesWorn": { + "datatype": "boolean", + "description": "Brake pad wear status. True = Worn. False = Not Worn.", + "type": "sensor" + }, + "IsFluidLevelLow": { + "datatype": "boolean", + "description": "Brake fluid level status. True = Brake fluid level low. False = Brake fluid level OK.", + "type": "sensor" + }, + "PadWear": { + "datatype": "uint8", + "description": "Brake pad wear as percent. 0 = No Wear. 100 = Worn.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Brake signals for wheel", + "type": "branch" + }, + "Speed": { + "datatype": "float", + "description": "Linear speed of a vehicle's wheel.", + "type": "sensor", + "unit": "km/h" + }, + "Tire": { + "children": { + "IsPressureLow": { + "datatype": "boolean", + "description": "Tire Pressure Status. True = Low tire pressure. False = Good tire pressure.", + "type": "sensor" + }, + "Pressure": { + "datatype": "uint16", + "description": "Tire pressure in kilo-Pascal.", + "type": "sensor", + "unit": "kPa" + }, + "Temperature": { + "datatype": "float", + "description": "Tire temperature in Celsius.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Tire signals for wheel.", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + }, + "WheelCount": { + "datatype": "uint8", + "description": "Number of wheels on the axle", + "type": "attribute" + }, + "WheelDiameter": { + "datatype": "float", + "description": "Diameter of wheels (rims without tires), in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + }, + "WheelWidth": { + "datatype": "float", + "description": "Width of wheels (rims without tires), in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + } + }, + "description": "Axle signals", + "type": "branch" + }, + "Row2": { + "children": { + "AxleWidth": { + "comment": "Corresponds to SAE J1100-2009 W113.", + "datatype": "uint16", + "description": "The lateral distance between the wheel mounting faces, measured along the spindle axis.", + "type": "attribute", + "unit": "mm" + }, + "SteeringAngle": { + "comment": "Single track two-axle model steering angle refers to the angle that a centrally mounted wheel would have.", + "datatype": "float", + "description": "Single track two-axle model steering angle. Angle according to ISO 8855. Positive = degrees to the left. Negative = degrees to the right.", + "type": "sensor", + "unit": "degrees" + }, + "TireAspectRatio": { + "datatype": "uint8", + "description": "Aspect ratio between tire section height and tire section width, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "percent" + }, + "TireDiameter": { + "datatype": "float", + "description": "Outer diameter of tires, in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + }, + "TireWidth": { + "datatype": "uint16", + "description": "Nominal section width of tires, in mm, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "mm" + }, + "TrackWidth": { + "comment": "Corresponds to SAE J1100-2009 W102.", + "datatype": "uint16", + "description": "The lateral distance between the centers of the wheels, measured along the spindle, or axle axis. If there are dual rear wheels, measure from the midway points between the inner and outer tires.", + "type": "attribute", + "unit": "mm" + }, + "TreadWidth": { + "comment": "Corresponds to SAE J1100-2009 W101.", + "datatype": "uint16", + "description": "The lateral distance between the centerlines of the base tires at ground, including camber angle. If there are dual rear wheels, measure from the midway points between the inner and outer tires.", + "type": "attribute", + "unit": "mm" + }, + "Wheel": { + "children": { + "Left": { + "children": { + "AngularSpeed": { + "comment": "Positive if wheel is trying to drive vehicle forward. Negative if wheel is trying to drive vehicle backward.", + "datatype": "float", + "description": "Angular (Rotational) speed of a vehicle's wheel.", + "type": "sensor", + "unit": "degrees/s" + }, + "Brake": { + "children": { + "FluidLevel": { + "datatype": "uint8", + "description": "Brake fluid level as percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "IsBrakesWorn": { + "datatype": "boolean", + "description": "Brake pad wear status. True = Worn. False = Not Worn.", + "type": "sensor" + }, + "IsFluidLevelLow": { + "datatype": "boolean", + "description": "Brake fluid level status. True = Brake fluid level low. False = Brake fluid level OK.", + "type": "sensor" + }, + "PadWear": { + "datatype": "uint8", + "description": "Brake pad wear as percent. 0 = No Wear. 100 = Worn.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Brake signals for wheel", + "type": "branch" + }, + "Speed": { + "datatype": "float", + "description": "Linear speed of a vehicle's wheel.", + "type": "sensor", + "unit": "km/h" + }, + "Tire": { + "children": { + "IsPressureLow": { + "datatype": "boolean", + "description": "Tire Pressure Status. True = Low tire pressure. False = Good tire pressure.", + "type": "sensor" + }, + "Pressure": { + "datatype": "uint16", + "description": "Tire pressure in kilo-Pascal.", + "type": "sensor", + "unit": "kPa" + }, + "Temperature": { + "datatype": "float", + "description": "Tire temperature in Celsius.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Tire signals for wheel.", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + }, + "Right": { + "children": { + "AngularSpeed": { + "comment": "Positive if wheel is trying to drive vehicle forward. Negative if wheel is trying to drive vehicle backward.", + "datatype": "float", + "description": "Angular (Rotational) speed of a vehicle's wheel.", + "type": "sensor", + "unit": "degrees/s" + }, + "Brake": { + "children": { + "FluidLevel": { + "datatype": "uint8", + "description": "Brake fluid level as percent. 0 = Empty. 100 = Full.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "IsBrakesWorn": { + "datatype": "boolean", + "description": "Brake pad wear status. True = Worn. False = Not Worn.", + "type": "sensor" + }, + "IsFluidLevelLow": { + "datatype": "boolean", + "description": "Brake fluid level status. True = Brake fluid level low. False = Brake fluid level OK.", + "type": "sensor" + }, + "PadWear": { + "datatype": "uint8", + "description": "Brake pad wear as percent. 0 = No Wear. 100 = Worn.", + "max": 100, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Brake signals for wheel", + "type": "branch" + }, + "Speed": { + "datatype": "float", + "description": "Linear speed of a vehicle's wheel.", + "type": "sensor", + "unit": "km/h" + }, + "Tire": { + "children": { + "IsPressureLow": { + "datatype": "boolean", + "description": "Tire Pressure Status. True = Low tire pressure. False = Good tire pressure.", + "type": "sensor" + }, + "Pressure": { + "datatype": "uint16", + "description": "Tire pressure in kilo-Pascal.", + "type": "sensor", + "unit": "kPa" + }, + "Temperature": { + "datatype": "float", + "description": "Tire temperature in Celsius.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Tire signals for wheel.", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + } + }, + "description": "Wheel signals for axle", + "type": "branch" + }, + "WheelCount": { + "datatype": "uint8", + "description": "Number of wheels on the axle", + "type": "attribute" + }, + "WheelDiameter": { + "datatype": "float", + "description": "Diameter of wheels (rims without tires), in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + }, + "WheelWidth": { + "datatype": "float", + "description": "Width of wheels (rims without tires), in inches, as per ETRTO / TRA standard.", + "type": "attribute", + "unit": "inch" + } + }, + "description": "Axle signals", + "type": "branch" + } + }, + "description": "Axle signals", + "type": "branch" + }, + "AxleCount": { + "datatype": "uint8", + "default": 2, + "description": "Number of axles on the vehicle", + "type": "attribute" + }, + "Brake": { + "children": { + "IsDriverEmergencyBrakingDetected": { + "comment": "Detection of emergency braking can trigger Emergency Brake Assist (EBA) to engage.", + "datatype": "boolean", + "description": "Indicates if emergency braking initiated by driver is detected. True = Emergency braking detected. False = Emergency braking not detected.", + "type": "sensor" + }, + "PedalPosition": { + "datatype": "uint8", + "description": "Brake pedal position as percent. 0 = Not depressed. 100 = Fully depressed.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Brake system signals", + "type": "branch" + }, + "ParkingBrake": { + "children": { + "IsAutoApplyEnabled": { + "datatype": "boolean", + "description": "Indicates if parking brake will be automatically engaged when the vehicle engine is turned off.", + "type": "actuator" + }, + "IsEngaged": { + "datatype": "boolean", + "description": "Parking brake status. True = Parking Brake is Engaged. False = Parking Brake is not Engaged.", + "type": "actuator" + } + }, + "description": "Parking brake signals", + "type": "branch" + }, + "SteeringWheel": { + "children": { + "Angle": { + "datatype": "int16", + "description": "Steering wheel angle. Positive = degrees to the left. Negative = degrees to the right.", + "type": "sensor", + "unit": "degrees" + }, + "Extension": { + "datatype": "uint8", + "description": "Steering wheel column extension from dashboard. 0 = Closest to dashboard. 100 = Furthest from dashboard.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Tilt": { + "datatype": "uint8", + "description": "Steering wheel column tilt. 0 = Lowest position. 100 = Highest position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Steering wheel signals", + "type": "branch" + }, + "Wheelbase": { + "datatype": "uint16", + "default": 0, + "description": "Overall wheelbase, in mm.", + "type": "attribute", + "unit": "mm" + } + }, + "description": "All data concerning steering, suspension, wheels, and brakes.", + "type": "branch" + }, + "Connectivity": { + "children": { + "IsConnectivityAvailable": { + "comment": "This signal can be used by onboard vehicle services to decide what features that shall be offered to the driver, for example disable the 'check for update' button if vehicle does not have connectivity.", + "datatype": "boolean", + "description": "Indicates if connectivity between vehicle and cloud is available. True = Connectivity is available. False = Connectivity is not available.", + "type": "sensor" + } + }, + "description": "Connectivity data.", + "type": "branch" + }, + "CurbWeight": { + "datatype": "uint16", + "default": 0, + "description": "Vehicle curb weight, including all liquids and full tank of fuel, but no cargo or passengers.", + "type": "attribute", + "unit": "kg" + }, + "CurrentLocation": { + "children": { + "Altitude": { + "datatype": "double", + "description": "Current altitude relative to WGS 84 reference ellipsoid, as measured at the position of GNSS receiver antenna.", + "type": "sensor", + "unit": "m" + }, + "GNSSReceiver": { + "children": { + "FixType": { + "allowed": [ + "NONE", + "TWO_D", + "TWO_D_SATELLITE_BASED_AUGMENTATION", + "TWO_D_GROUND_BASED_AUGMENTATION", + "TWO_D_SATELLITE_AND_GROUND_BASED_AUGMENTATION", + "THREE_D", + "THREE_D_SATELLITE_BASED_AUGMENTATION", + "THREE_D_GROUND_BASED_AUGMENTATION", + "THREE_D_SATELLITE_AND_GROUND_BASED_AUGMENTATION" + ], + "datatype": "string", + "description": "Fix status of GNSS receiver.", + "type": "sensor" + }, + "MountingPosition": { + "children": { + "X": { + "datatype": "int16", + "description": "Mounting position of GNSS receiver antenna relative to vehicle coordinate system. Axis definitions according to ISO 8855. Origin at center of (first) rear axle. Positive values = forward of rear axle. Negative values = backward of rear axle.", + "type": "attribute", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Mounting position of GNSS receiver antenna relative to vehicle coordinate system. Axis definitions according to ISO 8855. Origin at center of (first) rear axle. Positive values = left of origin. Negative values = right of origin. Left/Right is as seen from driver perspective, i.e. by a person looking forward.", + "type": "attribute", + "unit": "mm" + }, + "Z": { + "datatype": "int16", + "description": "Mounting position of GNSS receiver on Z-axis. Axis definitions according to ISO 8855. Origin at center of (first) rear axle. Positive values = above center of rear axle. Negative values = below center of rear axle.", + "type": "attribute", + "unit": "mm" + } + }, + "description": "Mounting position of GNSS receiver antenna relative to vehicle coordinate system. Axis definitions according to ISO 8855. Origin at center of (first) rear axle.", + "type": "branch" + } + }, + "description": "Information on the GNSS receiver used for determining current location.", + "type": "branch" + }, + "Heading": { + "datatype": "double", + "description": "Current heading relative to geographic north. 0 = North, 90 = East, 180 = South, 270 = West.", + "max": 360, + "min": 0, + "type": "sensor", + "unit": "degrees" + }, + "HorizontalAccuracy": { + "datatype": "double", + "description": "Accuracy of the latitude and longitude coordinates.", + "type": "sensor", + "unit": "m" + }, + "Latitude": { + "datatype": "double", + "description": "Current latitude of vehicle in WGS 84 geodetic coordinates, as measured at the position of GNSS receiver antenna.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Longitude": { + "datatype": "double", + "description": "Current longitude of vehicle in WGS 84 geodetic coordinates, as measured at the position of GNSS receiver antenna.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Timestamp": { + "datatype": "string", + "description": "Timestamp from GNSS system for current location, formatted according to ISO 8601 with UTC time zone.", + "type": "sensor", + "unit": "iso8601" + }, + "VerticalAccuracy": { + "datatype": "double", + "description": "Accuracy of altitude.", + "type": "sensor", + "unit": "m" + } + }, + "description": "The current latitude and longitude of the vehicle.", + "type": "branch" + }, + "CurrentOverallWeight": { + "datatype": "uint16", + "description": "Current overall Vehicle weight. Including passengers, cargo and other load inside the car.", + "type": "sensor", + "unit": "kg" + }, + "Diagnostics": { + "children": { + "DTCCount": { + "datatype": "uint8", + "description": "Number of Diagnostic Trouble Codes (DTC)", + "type": "sensor" + }, + "DTCList": { + "datatype": "string[]", + "description": "List of currently active DTCs formatted according OBD II (SAE-J2012DA_201812) standard ([P|C|B|U]XXXXX )", + "type": "sensor" + } + }, + "description": "Diagnostics data.", + "type": "branch" + }, + "Driver": { + "children": { + "AttentiveProbability": { + "datatype": "float", + "description": "Probability of attentiveness of the driver.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "DistractionLevel": { + "datatype": "float", + "description": "Distraction level of the driver, which can be evaluated by multiple factors e.g. driving situation, acoustical or optical signals inside the cockpit, ongoing phone calls.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "FatigueLevel": { + "datatype": "float", + "description": "Fatigue level of the driver, which can be evaluated by multiple factors e.g. trip time, behaviour of steering, eye status.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "HeartRate": { + "datatype": "uint16", + "description": "Heart rate of the driver.", + "type": "sensor", + "unit": "bpm" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "IsEyesOnRoad": { + "datatype": "boolean", + "description": "Has driver the eyes on road or not?", + "type": "sensor" + }, + "IsHandsOnWheel": { + "datatype": "boolean", + "description": "Are the driver's hands on the steering wheel or not?", + "type": "sensor" + } + }, + "description": "Driver data.", + "type": "branch" + }, + "EmissionsCO2": { + "datatype": "int16", + "description": "The CO2 emissions.", + "type": "attribute", + "unit": "g/km" + }, + "Exterior": { + "children": { + "AirTemperature": { + "datatype": "float", + "description": "Air temperature outside the vehicle.", + "type": "sensor", + "unit": "celsius" + }, + "Humidity": { + "datatype": "float", + "description": "Relative humidity outside the vehicle. 0 = Dry, 100 = Air fully saturated.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "LightIntensity": { + "comment": "Mapping to physical units and calculation method is sensor specific.", + "datatype": "float", + "description": "Light intensity outside the vehicle. 0 = No light detected, 100 = Fully lit.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Information about exterior measured by vehicle.", + "type": "branch" + }, + "GrossWeight": { + "datatype": "uint16", + "default": 0, + "description": "Curb weight of vehicle, including all liquids and full tank of fuel and full load of cargo and passengers.", + "type": "attribute", + "unit": "kg" + }, + "Height": { + "datatype": "uint16", + "default": 0, + "description": "Overall vehicle height.", + "type": "attribute", + "unit": "mm" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "IsBrokenDown": { + "comment": "Actual criteria and method used to decide if a vehicle is broken down is implementation specific.", + "datatype": "boolean", + "description": "Vehicle breakdown or any similar event causing vehicle to stop on the road, that might pose a risk to other road users. True = Vehicle broken down on the road, due to e.g. engine problems, flat tire, out of gas, brake problems. False = Vehicle not broken down.", + "type": "sensor" + }, + "IsMoving": { + "datatype": "boolean", + "description": "Indicates whether the vehicle is stationary or moving.", + "type": "sensor" + }, + "Length": { + "datatype": "uint16", + "default": 0, + "description": "Overall vehicle length.", + "type": "attribute", + "unit": "mm" + }, + "LowVoltageBattery": { + "children": { + "CurrentCurrent": { + "datatype": "float", + "description": "Current current flowing in/out of the low voltage battery. Positive = Current flowing in to battery, e.g. during charging or driving. Negative = Current flowing out of battery, e.g. when using the battery to start a combustion engine.", + "type": "sensor", + "unit": "A" + }, + "CurrentVoltage": { + "datatype": "float", + "description": "Current Voltage of the low voltage battery.", + "type": "sensor", + "unit": "V" + }, + "NominalCapacity": { + "datatype": "uint16", + "description": "Nominal capacity of the low voltage battery.", + "type": "attribute", + "unit": "Ah" + }, + "NominalVoltage": { + "comment": "Nominal voltage typically refers to voltage of fully charged battery when delivering rated capacity.", + "datatype": "uint16", + "description": "Nominal Voltage of the battery.", + "type": "attribute", + "unit": "V" + } + }, + "description": "Signals related to low voltage battery.", + "type": "branch" + }, + "LowVoltageSystemState": { + "allowed": [ + "UNDEFINED", + "LOCK", + "OFF", + "ACC", + "ON", + "START" + ], + "datatype": "string", + "description": "State of the supply voltage of the control units (usually 12V).", + "type": "sensor" + }, + "MaxTowBallWeight": { + "datatype": "uint16", + "default": 0, + "description": "Maximum vertical weight on the tow ball of a trailer.", + "type": "attribute", + "unit": "kg" + }, + "MaxTowWeight": { + "datatype": "uint16", + "default": 0, + "description": "Maximum weight of trailer.", + "type": "attribute", + "unit": "kg" + }, + "OBD": { + "children": { + "AbsoluteLoad": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 43 - Absolute load value", + "type": "sensor", + "unit": "percent" + }, + "AcceleratorPositionD": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 49 - Accelerator pedal position D", + "type": "sensor", + "unit": "percent" + }, + "AcceleratorPositionE": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 4A - Accelerator pedal position E", + "type": "sensor", + "unit": "percent" + }, + "AcceleratorPositionF": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 4B - Accelerator pedal position F", + "type": "sensor", + "unit": "percent" + }, + "AirStatus": { + "datatype": "string", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 12 - Secondary air status", + "type": "sensor" + }, + "AmbientAirTemperature": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 46 - Ambient air temperature", + "type": "sensor", + "unit": "celsius" + }, + "BarometricPressure": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 33 - Barometric pressure", + "type": "sensor", + "unit": "kPa" + }, + "Catalyst": { + "children": { + "Bank1": { + "children": { + "Temperature1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3C - Catalyst temperature from bank 1, sensor 1", + "type": "sensor", + "unit": "celsius" + }, + "Temperature2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3E - Catalyst temperature from bank 1, sensor 2", + "type": "sensor", + "unit": "celsius" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Catalyst bank 1 signals", + "type": "branch" + }, + "Bank2": { + "children": { + "Temperature1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3D - Catalyst temperature from bank 2, sensor 1", + "type": "sensor", + "unit": "celsius" + }, + "Temperature2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3F - Catalyst temperature from bank 2, sensor 2", + "type": "sensor", + "unit": "celsius" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Catalyst bank 2 signals", + "type": "branch" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Catalyst signals", + "type": "branch" + }, + "CommandedEGR": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2C - Commanded exhaust gas recirculation (EGR)", + "type": "sensor", + "unit": "percent" + }, + "CommandedEVAP": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2E - Commanded evaporative purge (EVAP) valve", + "type": "sensor", + "unit": "percent" + }, + "CommandedEquivalenceRatio": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 44 - Commanded equivalence ratio", + "type": "sensor", + "unit": "ratio" + }, + "ControlModuleVoltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 42 - Control module voltage", + "type": "sensor", + "unit": "V" + }, + "CoolantTemperature": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 05 - Coolant temperature", + "type": "sensor", + "unit": "celsius" + }, + "DTCList": { + "datatype": "string[]", + "deprecation": "v5.0 replaced with Vehicle.Diagnostics.DTCList", + "description": "List of currently active DTCs formatted according OBD II (SAE-J2012DA_201812) standard ([P|C|B|U]XXXXX )", + "type": "sensor" + }, + "DistanceSinceDTCClear": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 31 - Distance traveled since codes cleared", + "type": "sensor", + "unit": "km" + }, + "DistanceWithMIL": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 21 - Distance traveled with MIL on", + "type": "sensor", + "unit": "km" + }, + "DriveCycleStatus": { + "children": { + "DTCCount": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Number of sensor Trouble Codes (DTC)", + "type": "sensor" + }, + "IgnitionType": { + "allowed": [ + "SPARK", + "COMPRESSION" + ], + "datatype": "string", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Type of the ignition for ICE - spark = spark plug ignition, compression = self-igniting (Diesel engines)", + "type": "sensor" + }, + "IsMILOn": { + "datatype": "boolean", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Malfunction Indicator Light (MIL) - False = Off, True = On", + "type": "sensor" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 41 - OBD status for the current drive cycle", + "type": "branch" + }, + "EGRError": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2D - Exhaust gas recirculation (EGR) error", + "type": "sensor", + "unit": "percent" + }, + "EVAPVaporPressure": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 32 - Evaporative purge (EVAP) system pressure", + "type": "sensor", + "unit": "Pa" + }, + "EVAPVaporPressureAbsolute": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 53 - Absolute evaporative purge (EVAP) system pressure", + "type": "sensor", + "unit": "kPa" + }, + "EVAPVaporPressureAlternate": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 54 - Alternate evaporative purge (EVAP) system pressure", + "type": "sensor", + "unit": "Pa" + }, + "EngineLoad": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 04 - Engine load in percent - 0 = no load, 100 = full load", + "type": "sensor", + "unit": "percent" + }, + "EngineSpeed": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0C - Engine speed measured as rotations per minute", + "type": "sensor", + "unit": "rpm" + }, + "EthanolPercent": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 52 - Percentage of ethanol in the fuel", + "type": "sensor", + "unit": "percent" + }, + "FreezeDTC": { + "datatype": "string", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 02 - DTC that triggered the freeze frame", + "type": "sensor" + }, + "FuelInjectionTiming": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 5D - Fuel injection timing", + "type": "sensor", + "unit": "degrees" + }, + "FuelLevel": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2F - Fuel level in the fuel tank", + "type": "sensor", + "unit": "percent" + }, + "FuelPressure": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0A - Fuel pressure", + "type": "sensor", + "unit": "kPa" + }, + "FuelRailPressureAbsolute": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 59 - Absolute fuel rail pressure", + "type": "sensor", + "unit": "kPa" + }, + "FuelRailPressureDirect": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 23 - Fuel rail pressure direct inject", + "type": "sensor", + "unit": "kPa" + }, + "FuelRailPressureVac": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 22 - Fuel rail pressure relative to vacuum", + "type": "sensor", + "unit": "kPa" + }, + "FuelRate": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 5E - Engine fuel rate", + "type": "sensor", + "unit": "l/h" + }, + "FuelStatus": { + "datatype": "string", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 03 - Fuel status", + "type": "sensor" + }, + "FuelType": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 51 - Fuel type", + "max": 23, + "min": 0, + "type": "attribute" + }, + "HybridBatteryRemaining": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 5B - Remaining life of hybrid battery", + "type": "sensor", + "unit": "percent" + }, + "IntakeTemp": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0F - Intake temperature", + "type": "sensor", + "unit": "celsius" + }, + "IsPTOActive": { + "datatype": "boolean", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1E - Auxiliary input status (power take off)", + "type": "sensor" + }, + "LongTermFuelTrim1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 07 - Long Term (learned) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer", + "type": "sensor", + "unit": "percent" + }, + "LongTermFuelTrim2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 09 - Long Term (learned) Fuel Trim - Bank 2 - negative percent leaner, positive percent richer", + "type": "sensor", + "unit": "percent" + }, + "LongTermO2Trim1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 56 (byte A) - Long term secondary O2 trim - Bank 1", + "type": "sensor", + "unit": "percent" + }, + "LongTermO2Trim2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 58 (byte A) - Long term secondary O2 trim - Bank 2", + "type": "sensor", + "unit": "percent" + }, + "LongTermO2Trim3": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 56 (byte B) - Long term secondary O2 trim - Bank 3", + "type": "sensor", + "unit": "percent" + }, + "LongTermO2Trim4": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 58 (byte B) - Long term secondary O2 trim - Bank 4", + "type": "sensor", + "unit": "percent" + }, + "MAF": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 10 - Grams of air drawn into engine per second", + "type": "sensor", + "unit": "g/s" + }, + "MAP": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0B - Intake manifold pressure", + "type": "sensor", + "unit": "kPa" + }, + "MaxMAF": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 50 - Maximum flow for mass air flow sensor", + "type": "sensor", + "unit": "g/s" + }, + "O2": { + "children": { + "Sensor1": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor2": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor3": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor4": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor5": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor6": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor7": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "Sensor8": { + "children": { + "ShortTermFuelTrim": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte B) - Short term fuel trim", + "type": "sensor", + "unit": "percent" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1x (byte A) - Sensor voltage", + "type": "sensor", + "unit": "V" + } + }, + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Oxygen sensors (PID 14 - PID 1B)", + "type": "branch" + }, + "O2WR": { + "children": { + "Sensor1": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor2": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor3": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor4": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor5": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor6": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor7": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "Sensor8": { + "children": { + "Current": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 3x (byte CD) - Current for wide range/band oxygen sensor", + "type": "sensor", + "unit": "A" + }, + "Lambda": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte AB) and PID 3x (byte AB) - Lambda for wide range/band oxygen sensor", + "type": "sensor" + }, + "Voltage": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 2x (byte CD) - Voltage for wide range/band oxygen sensor", + "type": "sensor", + "unit": "V" + } + }, + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Wide range/band oxygen sensors (PID 24 - 2B and PID 34 - 3B)", + "type": "branch" + }, + "OBDStandards": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1C - OBD standards this vehicle conforms to", + "type": "attribute" + }, + "OilTemperature": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 5C - Engine oil temperature", + "type": "sensor", + "unit": "celsius" + }, + "OxygenSensorsIn2Banks": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 13 - Presence of oxygen sensors in 2 banks. [A0..A3] == Bank 1, Sensors 1-4. [A4..A7] == Bank 2, Sensors 1-4", + "type": "sensor" + }, + "OxygenSensorsIn4Banks": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1D - Presence of oxygen sensors in 4 banks. Similar to PID 13, but [A0..A7] == [B1S1, B1S2, B2S1, B2S2, B3S1, B3S2, B4S1, B4S2]", + "type": "sensor" + }, + "PidsA": { + "allowed": [ + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "0A", + "0B", + "0C", + "0D", + "0E", + "0F", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "1A", + "1B", + "1C", + "1D", + "1E", + "1F", + "20" + ], + "datatype": "string[]", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 00 - Array of the supported PIDs 01 to 20 in Hexadecimal.", + "type": "attribute" + }, + "PidsB": { + "allowed": [ + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "2A", + "2B", + "2C", + "2D", + "2E", + "2F", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "3A", + "3B", + "3C", + "3D", + "3E", + "3F", + "40" + ], + "datatype": "string[]", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 20 - Array of the supported PIDs 21 to 40 in Hexadecimal.", + "type": "attribute" + }, + "PidsC": { + "allowed": [ + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "4A", + "4B", + "4C", + "4D", + "4E", + "4F", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "5A", + "5B", + "5C", + "5D", + "5E", + "5F", + "60" + ], + "datatype": "string[]", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 40 - Array of the supported PIDs 41 to 60 in Hexadecimal.", + "type": "attribute" + }, + "RelativeAcceleratorPosition": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 5A - Relative accelerator pedal position", + "type": "sensor", + "unit": "percent" + }, + "RelativeThrottlePosition": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 45 - Relative throttle position", + "type": "sensor", + "unit": "percent" + }, + "RunTime": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 1F - Engine run time", + "type": "sensor", + "unit": "s" + }, + "RunTimeMIL": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 4D - Run time with MIL on", + "type": "sensor", + "unit": "min" + }, + "ShortTermFuelTrim1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 06 - Short Term (immediate) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer", + "type": "sensor", + "unit": "percent" + }, + "ShortTermFuelTrim2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 08 - Short Term (immediate) Fuel Trim - Bank 2 - negative percent leaner, positive percent richer", + "type": "sensor", + "unit": "percent" + }, + "ShortTermO2Trim1": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 55 (byte A) - Short term secondary O2 trim - Bank 1", + "type": "sensor", + "unit": "percent" + }, + "ShortTermO2Trim2": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 57 (byte A) - Short term secondary O2 trim - Bank 2", + "type": "sensor", + "unit": "percent" + }, + "ShortTermO2Trim3": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 55 (byte B) - Short term secondary O2 trim - Bank 3", + "type": "sensor", + "unit": "percent" + }, + "ShortTermO2Trim4": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 57 (byte B) - Short term secondary O2 trim - Bank 4", + "type": "sensor", + "unit": "percent" + }, + "Speed": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0D - Vehicle speed", + "type": "sensor", + "unit": "km/h" + }, + "Status": { + "children": { + "DTCCount": { + "datatype": "uint8", + "deprecation": "v5.0 replaced with Vehicle.Diagnostics.DTCCount", + "description": "Number of Diagnostic Trouble Codes (DTC)", + "type": "sensor" + }, + "IgnitionType": { + "allowed": [ + "SPARK", + "COMPRESSION" + ], + "datatype": "string", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Type of the ignition for ICE - spark = spark plug ignition, compression = self-igniting (Diesel engines)", + "type": "attribute" + }, + "IsMILOn": { + "datatype": "boolean", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "Malfunction Indicator Light (MIL) False = Off, True = On", + "type": "sensor" + } + }, + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 01 - OBD status", + "type": "branch" + }, + "ThrottleActuator": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 4C - Commanded throttle actuator", + "type": "sensor", + "unit": "percent" + }, + "ThrottlePosition": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 11 - Throttle position - 0 = closed throttle, 100 = open throttle", + "type": "sensor", + "unit": "percent" + }, + "ThrottlePositionB": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 47 - Absolute throttle position B", + "type": "sensor", + "unit": "percent" + }, + "ThrottlePositionC": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 48 - Absolute throttle position C", + "type": "sensor", + "unit": "percent" + }, + "TimeSinceDTCCleared": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 4E - Time since trouble codes cleared", + "type": "sensor", + "unit": "min" + }, + "TimingAdvance": { + "datatype": "float", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 0E - Time advance", + "type": "sensor", + "unit": "degrees" + }, + "WarmupsSinceDTCClear": { + "datatype": "uint8", + "deprecation": "v5.0 OBD-branch is deprecated.", + "description": "PID 30 - Number of warm-ups since codes cleared", + "type": "sensor" + } + }, + "description": "OBD data.", + "type": "branch" + }, + "Occupant": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "Middle": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "Middle": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "HeadPosition": { + "children": { + "Pitch": { + "datatype": "float", + "description": "Head pitch angle, measured as angle from vehicle sprung mass XY-plane as defined by ISO 23150:2023 to the head X-axis. 0 = Head in normal position. Positive values = Head leaning up. Negative values = Head leaning down.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Roll": { + "datatype": "float", + "description": "Head roll angle about the head X-axis (right-hand rule). 0 = Head in normal position. Positive values = Head leaning to the right. Negative values = Head leaning to the left.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "X": { + "datatype": "int16", + "description": "Longitudinal position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = forward of (first) rear-axle. Negative values = backward of (first) rear-axle.", + "type": "sensor", + "unit": "mm" + }, + "Y": { + "datatype": "int16", + "description": "Lateral position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = left of rear-axle center. Negative values = right of rear-axle center.", + "type": "sensor", + "unit": "mm" + }, + "Yaw": { + "datatype": "float", + "description": "Head yaw angle, measured from the vehicle sprung mass X-axis as defined by ISO 23150:2023 to the head X-axis, around the vehicle Z-axis (right-hand rule). 0 = Head in normal position. Positive values = Head turned left. Negative values = Head turned right.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Z": { + "datatype": "int16", + "description": "Height position of head center measured as mid eye position on X-axis of the vehicle rear-axle coordinate system as defined by ISO 23150:2023 section 3.7.12 Mid eye position refers to the center of a line drawn between the center of the drivers eyes. Positive values = above center of rear-axle reference point. Negative values = below center of rear-axle reference point.", + "type": "sensor", + "unit": "mm" + } + }, + "description": "The current position of the driver head on vehicle axis according to ISO 23150:2023.", + "type": "branch" + }, + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + }, + "MidEyeGaze": { + "children": { + "Azimuth": { + "datatype": "float", + "description": "Mid eye azimuth gaze (right-hand rule) on vehicle sprung mass Z-axis as defined by ISO 23150:2023 0 = Driver looking forward. Positive values = Driver looking at something on the left side of driver. Negative values = Driver looking at something on the right side of driver.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + }, + "Elevation": { + "datatype": "float", + "description": "Elevation to observed object measured as angle between vehicle sprung mass XY-plane as defined by ISO 23150:2023 at driver mid eye position and object. 0 = Driver looking at something at same height as mid eye position. Positive values = Driver looking at something above mid eye position. Negative values = Driver looking at something below mid eye position.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + } + }, + "description": "Direction from mid eye position to object driver is looking at.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + } + }, + "description": "Occupant (Driver or Passenger) data.", + "type": "branch" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "Powertrain": { + "children": { + "AccumulatedBrakingEnergy": { + "datatype": "float", + "description": "The accumulated energy from regenerative braking over lifetime.", + "type": "sensor", + "unit": "kWh" + }, + "CombustionEngine": { + "children": { + "AspirationType": { + "allowed": [ + "UNKNOWN", + "NATURAL", + "SUPERCHARGER", + "TURBOCHARGER" + ], + "datatype": "string", + "default": "UNKNOWN", + "description": "Type of aspiration (natural, turbocharger, supercharger etc).", + "type": "attribute" + }, + "Bore": { + "datatype": "float", + "description": "Bore in millimetres.", + "type": "attribute", + "unit": "mm" + }, + "CompressionRatio": { + "datatype": "string", + "description": "Engine compression ratio, specified in the format 'X:1', e.g. '9.2:1'.", + "type": "attribute" + }, + "Configuration": { + "allowed": [ + "UNKNOWN", + "STRAIGHT", + "V", + "BOXER", + "W", + "ROTARY", + "RADIAL", + "SQUARE", + "H", + "U", + "OPPOSED", + "X" + ], + "datatype": "string", + "default": "UNKNOWN", + "description": "Engine configuration.", + "type": "attribute" + }, + "DieselExhaustFluid": { + "children": { + "Capacity": { + "datatype": "float", + "description": "Capacity in liters of the Diesel Exhaust Fluid Tank.", + "type": "attribute", + "unit": "l" + }, + "IsLevelLow": { + "datatype": "boolean", + "description": "Indicates if the Diesel Exhaust Fluid level is low. True if level is low. Definition of low is vehicle dependent.", + "type": "sensor" + }, + "Level": { + "datatype": "uint8", + "description": "Level of the Diesel Exhaust Fluid tank as percent of capacity. 0 = empty. 100 = full.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "Range": { + "datatype": "uint32", + "description": "Remaining range in meters of the Diesel Exhaust Fluid present in the vehicle.", + "type": "sensor", + "unit": "m" + } + }, + "comment": "In retail and marketing other names are typically used for the fluid.", + "description": "Signals related to Diesel Exhaust Fluid (DEF). DEF is called AUS32 in ISO 22241.", + "type": "branch" + }, + "DieselParticulateFilter": { + "children": { + "DeltaPressure": { + "datatype": "float", + "description": "Delta Pressure of Diesel Particulate Filter.", + "type": "sensor", + "unit": "Pa" + }, + "InletTemperature": { + "datatype": "float", + "description": "Inlet temperature of Diesel Particulate Filter.", + "type": "sensor", + "unit": "celsius" + }, + "OutletTemperature": { + "datatype": "float", + "description": "Outlet temperature of Diesel Particulate Filter.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Diesel Particulate Filter signals.", + "type": "branch" + }, + "Displacement": { + "datatype": "uint16", + "description": "Displacement in cubic centimetres.", + "type": "attribute", + "unit": "cm^3" + }, + "ECT": { + "datatype": "int16", + "deprecation": "v5.0 moved to EngineCoolant.Temperature", + "description": "Engine coolant temperature.", + "type": "sensor", + "unit": "celsius" + }, + "EOP": { + "datatype": "uint16", + "description": "Engine oil pressure.", + "type": "sensor", + "unit": "kPa" + }, + "EOT": { + "datatype": "int16", + "deprecation": "v5.0 moved to EngineOil.Temperature", + "description": "Engine oil temperature.", + "type": "sensor", + "unit": "celsius" + }, + "EngineCode": { + "comment": "For hybrid vehicles the engine code may refer to the combination of combustion and electric engine.", + "datatype": "string", + "description": "Engine code designation, as specified by vehicle manufacturer.", + "type": "attribute" + }, + "EngineCoolant": { + "children": { + "Capacity": { + "datatype": "float", + "description": "Engine coolant capacity in liters.", + "type": "attribute", + "unit": "l" + }, + "Level": { + "allowed": [ + "CRITICALLY_LOW", + "LOW", + "NORMAL" + ], + "datatype": "string", + "description": "Engine coolant level.", + "type": "sensor" + }, + "LifeRemaining": { + "comment": "In addition to this a signal a vehicle can report remaining time to service (including e.g. coolant change) by Vehicle.Service.TimeToService.", + "datatype": "int32", + "description": "Remaining engine coolant life in seconds. Negative values can be used to indicate that lifetime has been exceeded.", + "type": "sensor", + "unit": "s" + }, + "Temperature": { + "datatype": "float", + "description": "Engine coolant temperature.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Signals related to the engine coolant", + "type": "branch" + }, + "EngineCoolantCapacity": { + "datatype": "float", + "deprecation": "v5.0 moved to EngineCoolant.Capacity", + "description": "Engine coolant capacity in liters.", + "type": "attribute", + "unit": "l" + }, + "EngineHours": { + "datatype": "float", + "description": "Accumulated time during engine lifetime with 'engine speed (rpm) > 0'.", + "type": "sensor", + "unit": "h" + }, + "EngineOil": { + "children": { + "Capacity": { + "datatype": "float", + "description": "Engine oil capacity in liters.", + "type": "attribute", + "unit": "l" + }, + "Level": { + "allowed": [ + "CRITICALLY_LOW", + "LOW", + "NORMAL", + "HIGH", + "CRITICALLY_HIGH" + ], + "datatype": "string", + "description": "Engine oil level.", + "type": "sensor" + }, + "LifeRemaining": { + "comment": "In addition to this a signal a vehicle can report remaining time to service (including e.g. oil change) by Vehicle.Service.TimeToService.", + "datatype": "int32", + "description": "Remaining engine oil life in seconds. Negative values can be used to indicate that lifetime has been exceeded.", + "type": "sensor", + "unit": "s" + }, + "Temperature": { + "datatype": "float", + "description": "EOT, Engine oil temperature.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Signals related to the engine oil", + "type": "branch" + }, + "EngineOilCapacity": { + "datatype": "float", + "deprecation": "v5.0 moved to EngineOil.Capacity", + "description": "Engine oil capacity in liters.", + "type": "attribute", + "unit": "l" + }, + "EngineOilLevel": { + "allowed": [ + "CRITICALLY_LOW", + "LOW", + "NORMAL", + "HIGH", + "CRITICALLY_HIGH" + ], + "datatype": "string", + "deprecation": "v5.0 moved to EngineOil.Level", + "description": "Engine oil level.", + "type": "sensor" + }, + "IdleHours": { + "comment": "Vehicles may calculate accumulated idle time for an engine. It might be based on engine speed (rpm) below a certain limit or any other mechanism.", + "datatype": "float", + "description": "Accumulated idling time during engine lifetime. Definition of idling is not standardized.", + "type": "sensor", + "unit": "h" + }, + "IsRunning": { + "datatype": "boolean", + "description": "Engine Running. True if engine is rotating (Speed > 0).", + "type": "sensor" + }, + "MAF": { + "datatype": "uint16", + "description": "Grams of air drawn into engine per second.", + "type": "sensor", + "unit": "g/s" + }, + "MAP": { + "datatype": "uint16", + "description": "Manifold absolute pressure possibly boosted using forced induction.", + "type": "sensor", + "unit": "kPa" + }, + "MaxPower": { + "datatype": "uint16", + "default": 0, + "description": "Peak power, in kilowatts, that engine can generate.", + "type": "attribute", + "unit": "kW" + }, + "MaxTorque": { + "datatype": "uint16", + "default": 0, + "description": "Peak torque, in newton meter, that the engine can generate.", + "type": "attribute", + "unit": "Nm" + }, + "NumberOfCylinders": { + "datatype": "uint16", + "description": "Number of cylinders.", + "type": "attribute" + }, + "NumberOfValvesPerCylinder": { + "datatype": "uint16", + "description": "Number of valves per cylinder.", + "type": "attribute" + }, + "OilLifeRemaining": { + "comment": "In addition to this a signal a vehicle can report remaining time to service (including e.g. oil change) by Vehicle.Service.TimeToService.", + "datatype": "int32", + "deprecation": "v5.0 moved to EngineOil.LifeRemaining", + "description": "Remaining engine oil life in seconds. Negative values can be used to indicate that lifetime has been exceeded.", + "type": "sensor", + "unit": "s" + }, + "Power": { + "datatype": "uint16", + "description": "Current engine power output. Shall be reported as 0 during engine breaking.", + "type": "sensor", + "unit": "kW" + }, + "Speed": { + "datatype": "uint16", + "description": "Engine speed measured as rotations per minute.", + "type": "sensor", + "unit": "rpm" + }, + "StrokeLength": { + "datatype": "float", + "description": "Stroke length in millimetres.", + "type": "attribute", + "unit": "mm" + }, + "TPS": { + "datatype": "uint8", + "description": "Current throttle position.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "Torque": { + "comment": "During engine breaking the engine delivers a negative torque to the transmission. This negative torque shall be ignored, instead 0 shall be reported.", + "datatype": "uint16", + "description": "Current engine torque. Shall be reported as 0 during engine breaking.", + "type": "sensor", + "unit": "Nm" + } + }, + "description": "Engine-specific data, stopping at the bell housing.", + "type": "branch" + }, + "ElectricMotor": { + "children": { + "CoolantTemperature": { + "datatype": "int16", + "deprecation": "v5.0 moved to EngineCoolant.Temperature", + "description": "Motor coolant temperature (if applicable).", + "type": "sensor", + "unit": "celsius" + }, + "EngineCode": { + "datatype": "string", + "description": "Engine code designation, as specified by vehicle manufacturer.", + "type": "attribute" + }, + "EngineCoolant": { + "children": { + "Capacity": { + "datatype": "float", + "description": "Engine coolant capacity in liters.", + "type": "attribute", + "unit": "l" + }, + "Level": { + "allowed": [ + "CRITICALLY_LOW", + "LOW", + "NORMAL" + ], + "datatype": "string", + "description": "Engine coolant level.", + "type": "sensor" + }, + "LifeRemaining": { + "comment": "In addition to this a signal a vehicle can report remaining time to service (including e.g. coolant change) by Vehicle.Service.TimeToService.", + "datatype": "int32", + "description": "Remaining engine coolant life in seconds. Negative values can be used to indicate that lifetime has been exceeded.", + "type": "sensor", + "unit": "s" + }, + "Temperature": { + "datatype": "float", + "description": "Engine coolant temperature.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Signals related to the engine coolant (if applicable).", + "type": "branch" + }, + "MaxPower": { + "datatype": "uint16", + "default": 0, + "description": "Peak power, in kilowatts, that motor(s) can generate.", + "type": "attribute", + "unit": "kW" + }, + "MaxRegenPower": { + "datatype": "uint16", + "default": 0, + "description": "Peak regen/brake power, in kilowatts, that motor(s) can generate.", + "type": "attribute", + "unit": "kW" + }, + "MaxRegenTorque": { + "datatype": "uint16", + "default": 0, + "description": "Peak regen/brake torque, in newton meter, that the motor(s) can generate.", + "type": "attribute", + "unit": "Nm" + }, + "MaxTorque": { + "datatype": "uint16", + "default": 0, + "description": "Peak power, in newton meter, that the motor(s) can generate.", + "type": "attribute", + "unit": "Nm" + }, + "Power": { + "datatype": "int16", + "description": "Current motor power output. Negative values indicate regen mode.", + "type": "sensor", + "unit": "kW" + }, + "Speed": { + "datatype": "int32", + "description": "Motor rotational speed measured as rotations per minute. Negative values indicate reverse driving mode.", + "type": "sensor", + "unit": "rpm" + }, + "Temperature": { + "datatype": "int16", + "description": "Motor temperature.", + "type": "sensor", + "unit": "celsius" + }, + "TimeInUse": { + "comment": "Vehicles may define their READY state.", + "datatype": "float", + "description": "Accumulated time during engine lifetime when the vehicule state's is 'READY'.", + "type": "sensor", + "unit": "h" + }, + "Torque": { + "datatype": "int16", + "description": "Current motor torque. Negative values indicate regen mode.", + "type": "sensor", + "unit": "Nm" + } + }, + "description": "Electric Motor specific data.", + "type": "branch" + }, + "FuelSystem": { + "children": { + "AbsoluteLevel": { + "datatype": "float", + "description": "Current available fuel in the fuel tank expressed in liters.", + "type": "sensor", + "unit": "l" + }, + "AverageConsumption": { + "datatype": "float", + "description": "Average consumption in liters per 100 km.", + "min": 0, + "type": "sensor", + "unit": "l/100km" + }, + "ConsumptionSinceStart": { + "comment": "A new trip is considered to start when engine gets enabled (e.g. LowVoltageSystemState in ON or START mode). A trip is considered to end when engine is no longer enabled. The signal may however keep the value of the last trip until a new trip is started.", + "datatype": "float", + "description": "Fuel amount in liters consumed since start of current trip.", + "type": "sensor", + "unit": "l" + }, + "HybridType": { + "allowed": [ + "UNKNOWN", + "NOT_APPLICABLE", + "STOP_START", + "BELT_ISG", + "CIMG", + "PHEV" + ], + "datatype": "string", + "default": "UNKNOWN", + "description": "Defines the hybrid type of the vehicle.", + "type": "attribute" + }, + "InstantConsumption": { + "datatype": "float", + "description": "Current consumption in liters per 100 km.", + "min": 0, + "type": "sensor", + "unit": "l/100km" + }, + "IsEngineStopStartEnabled": { + "datatype": "boolean", + "description": "Indicates whether eco start stop is currently enabled.", + "type": "sensor" + }, + "IsFuelLevelLow": { + "datatype": "boolean", + "description": "Indicates that the fuel level is low (e.g. <50km range).", + "type": "sensor" + }, + "IsFuelPortFlapOpen": { + "datatype": "boolean", + "description": "Status of the fuel port flap(s). True if at least one is open.", + "type": "actuator" + }, + "Range": { + "datatype": "uint32", + "description": "Remaining range in meters using only liquid fuel.", + "type": "sensor", + "unit": "m" + }, + "RefuelPortPosition": { + "allowed": [ + "FRONT_LEFT", + "FRONT_MIDDLE", + "FRONT_RIGHT", + "REAR_LEFT", + "REAR_MIDDLE", + "REAR_RIGHT", + "LEFT_FRONT", + "LEFT_MIDDLE", + "LEFT_REAR", + "RIGHT_FRONT", + "RIGHT_MIDDLE", + "RIGHT_REAR" + ], + "datatype": "string[]", + "description": "Position of refuel port(s). First part indicates side of vehicle, second part relative position on that side.", + "type": "attribute" + }, + "RelativeLevel": { + "datatype": "uint8", + "description": "Level in fuel tank as percent of capacity. 0 = empty. 100 = full.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "SupportedFuel": { + "allowed": [ + "E5_95", + "E5_98", + "E10_95", + "E10_98", + "E85", + "B7", + "B10", + "B20", + "B30", + "B100", + "XTL", + "LPG", + "CNG", + "LNG", + "H2", + "OTHER" + ], + "comment": "RON 95 is sometimes referred to as Super, RON 98 as Super Plus.", + "datatype": "string[]", + "description": "Detailed information on fuels supported by the vehicle. Identifiers originating from DIN EN 16942:2021-08, appendix B, with additional suffix for octane (RON) where relevant.", + "type": "attribute" + }, + "SupportedFuelTypes": { + "allowed": [ + "GASOLINE", + "DIESEL", + "E85", + "LPG", + "CNG", + "LNG", + "H2", + "OTHER" + ], + "comment": "If a vehicle also has an electric drivetrain (e.g. hybrid) that will be obvious from the PowerTrain.Type signal.", + "datatype": "string[]", + "description": "High level information of fuel types supported", + "type": "attribute" + }, + "TankCapacity": { + "datatype": "float", + "description": "Capacity of the fuel tank in liters.", + "type": "attribute", + "unit": "l" + }, + "TimeRemaining": { + "datatype": "uint32", + "description": "Time remaining in seconds before the fuel tank is empty.", + "type": "sensor", + "unit": "s" + } + }, + "description": "Fuel system data.", + "type": "branch" + }, + "IsAutoPowerOptimize": { + "datatype": "boolean", + "description": "Auto Power Optimization Flag When set to 'true', the system enables automatic power optimization, dynamically adjusting the power optimization level based on runtime conditions or features managed by the OEM. When set to 'false', manual control of the power optimization level is allowed.", + "type": "actuator" + }, + "PowerOptimizeLevel": { + "datatype": "uint8", + "description": "Power optimization level for this branch/subsystem. A higher number indicates more aggressive power optimization. Level 0 indicates that all functionality is enabled, no power optimization enabled. Level 10 indicates most aggressive power optimization mode, only essential functionality enabled.", + "max": 10, + "min": 0, + "type": "actuator" + }, + "Range": { + "datatype": "uint32", + "description": "Remaining range in meters using all energy sources available in the vehicle.", + "type": "sensor", + "unit": "m" + }, + "TimeRemaining": { + "datatype": "uint32", + "description": "Time remaining in seconds before all energy sources available in the vehicle are empty.", + "type": "sensor", + "unit": "s" + }, + "TractionBattery": { + "children": { + "AccumulatedChargedEnergy": { + "datatype": "float", + "description": "The accumulated energy delivered to the battery during charging over lifetime of the battery.", + "type": "sensor", + "unit": "kWh" + }, + "AccumulatedChargedThroughput": { + "datatype": "float", + "description": "The accumulated charge throughput delivered to the battery during charging over lifetime of the battery.", + "type": "sensor", + "unit": "Ah" + }, + "AccumulatedConsumedEnergy": { + "datatype": "float", + "description": "The accumulated energy leaving HV battery for propulsion and auxiliary loads over lifetime of the battery.", + "type": "sensor", + "unit": "kWh" + }, + "AccumulatedConsumedThroughput": { + "datatype": "float", + "description": "The accumulated charge throughput leaving HV battery for propulsion and auxiliary loads over lifetime of the battery.", + "type": "sensor", + "unit": "Ah" + }, + "BatteryConditioning": { + "children": { + "IsActive": { + "comment": "This signal is typically true when mode is not INACTIVE and time is within defined start/end times.", + "datatype": "boolean", + "description": "Indicates if battery conditioning is active (i.e. actively monitors battery temperature). True = Active. False = Inactive.", + "type": "sensor" + }, + "IsOngoing": { + "comment": "When battery conditioning is active, but temperature is already within acceptable range so that no cooling or heating is needed then IsOngoing shall report False.", + "datatype": "boolean", + "description": "Indicating if battery conditioning is currently ongoing. Battery conditioning is considered ongoing when the battery conditioning system is actively heating or cooling the battery, or requesting heating or cooling.", + "type": "sensor" + }, + "RequestedMode": { + "allowed": [ + "INACTIVE", + "FAST_CHARGING_PREPARATION", + "DRIVING_PREPARATION" + ], + "comment": "The Mode and TargetTime can be used to calculate TargetTemperature and StartTime", + "datatype": "string", + "description": "Defines requested mode for battery conditioning. INACTIVE - Battery conditioning inactive. FAST_CHARGING_PREPARATION - Battery conditioning for fast charging. DRIVING_PREPARATION - Battery conditioning for driving.", + "type": "actuator" + }, + "StartTime": { + "comment": "If the vehicle is asleep, this is the time the vehicle and the battery conditioning system must wake up and start monitoring the battery and if necessary start heating/cooling of the battery.", + "datatype": "string", + "description": "Start time for battery conditioning, formatted according to ISO 8601 with UTC time zone.", + "type": "actuator", + "unit": "iso8601" + }, + "TargetTemperature": { + "comment": "Target temperature possibly differs between different modes as well as other factors. Allowed deviation from target temperature is implementation dependent.", + "datatype": "float", + "description": "Target temperature for battery conditioning.", + "type": "actuator", + "unit": "celsius" + }, + "TargetTime": { + "comment": "For FAST_CHARGING mode this is typically the time when charging is supposed to start. For DRIVING mode this is typically the expected departure time. Battery conditioning will be deactivated when this time has passed.", + "datatype": "string", + "description": "Target time when conditioning shall be finished, formatted according to ISO 8601 with UTC time zone.", + "type": "actuator", + "unit": "iso8601" + } + }, + "description": "Properties related to preparing the vehicle battery for charging or driving.", + "type": "branch" + }, + "CellVoltage": { + "children": { + "CellVoltages": { + "comment": "Cells are identified by relative position in array.", + "datatype": "float[]", + "description": "Array of cell voltages. Length or array shall correspond to number of cells in vehicle.", + "type": "sensor" + }, + "IdMax": { + "comment": "Identifier is supposed to be relative index of the cell, starting with 0 the first cell.", + "datatype": "uint16", + "description": "Identifier of the battery cell with highest voltage.", + "type": "sensor" + }, + "IdMin": { + "comment": "Identifier is supposed to be relative index of the cell, starting with 0 the first cell.", + "datatype": "uint16", + "description": "Identifier of the battery cell with lowest voltage.", + "type": "sensor" + }, + "Max": { + "datatype": "float", + "description": "Current voltage of the battery cell with highest voltage.", + "type": "sensor", + "unit": "V" + }, + "Min": { + "datatype": "float", + "description": "Current voltage of the battery cell with lowest voltage.", + "type": "sensor", + "unit": "V" + } + }, + "description": "Voltage information for cells in the battery pack.", + "type": "branch" + }, + "Charging": { + "children": { + "AveragePower": { + "datatype": "float", + "description": "Average charging power of last or current charging event.", + "type": "sensor", + "unit": "kW" + }, + "ChargeCurrent": { + "children": { + "DC": { + "datatype": "float", + "description": "Current DC charging current at inlet. Negative if returning energy to grid.", + "type": "sensor", + "unit": "A" + }, + "Phase1": { + "datatype": "float", + "description": "Current AC charging current (rms) at inlet for Phase 1. Negative if returning energy to grid.", + "type": "sensor", + "unit": "A" + }, + "Phase2": { + "datatype": "float", + "description": "Current AC charging current (rms) at inlet for Phase 2. Negative if returning energy to grid.", + "type": "sensor", + "unit": "A" + }, + "Phase3": { + "datatype": "float", + "description": "Current AC charging current (rms) at inlet for Phase 3. Negative if returning energy to grid.", + "type": "sensor", + "unit": "A" + } + }, + "description": "Current charging current.", + "type": "branch" + }, + "ChargeLimit": { + "datatype": "uint8", + "default": 100, + "description": "Target charge limit (state of charge) for battery.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "ChargePlugType": { + "allowed": [ + "IEC_TYPE_1_AC", + "IEC_TYPE_2_AC", + "IEC_TYPE_3_AC", + "IEC_TYPE_4_DC", + "IEC_TYPE_1_CCS_DC", + "IEC_TYPE_2_CCS_DC", + "TESLA_ROADSTER", + "TESLA_HPWC", + "TESLA_SUPERCHARGER", + "GBT_AC", + "GBT_DC", + "OTHER" + ], + "comment": "A vehicle may have multiple charging inlets. The signal Charging.ChargePlugPosition can be used to indicate position of the charge plug. IEC_TYPE_1_AC refers to Type 1 as defined in IEC 62196-2. Also known as Yazaki or J1772 connector. IEC_TYPE_2_AC refers to Type 2 as defined in IEC 62196-2. Also known as Mennekes connector. IEC_TYPE_3_AC refers to Type 3 as defined in IEC 62196-2. Also known as Scame connector. IEC_TYPE_4_DC refers to AA configuration as defined in IEC 62196-3. Also known as Type 4 or CHAdeMO connector. IEC_TYPE_1_CCS_DC refers to EE Configuration as defined in IEC 62196-3. Also known as CCS1 or Combo1 connector. IEC_TYPE_2_CCS_DC refers to FF Configuration as defined in IEC 62196-3. Also known as CCS2 or Combo2 connector. TESLA_ROADSTER, TESLA_HPWC (High Power Wall Connector) and TESLA_SUPERCHARGER refer to non-standardized charging inlets/methods used by Tesla. GBT_AC refers to connector specified in GB/T 20234.2. GBT_DC refers to connector specified in GB/T 20234.3. Also specified as BB Configuration in IEC 62196-3. OTHER shall be used if the vehicle has a charging connector, but not one of the connectors listed above. For additional information see https://en.wikipedia.org/wiki/IEC_62196.", + "datatype": "string[]", + "deprecation": "V4.1 renamed to Charging.ChargePortType", + "description": "Type of charge plugs (charging inlet) available on the vehicle. A charge plug type may occur multiple times in the list if there are multiple instances of that charge plug type. IEC types refer to IEC 62196, GBT refers to GB/T 20234.", + "type": "attribute" + }, + "ChargePortFlap": { + "allowed": [ + "OPEN", + "CLOSED" + ], + "datatype": "string", + "deprecation": "V4.1 - Replaced with Charging.IsChargePortFlapOpen", + "description": "Status of the charge port cover(s), can potentially be controlled manually. OPEN if at least one is open.", + "type": "actuator" + }, + "ChargePortPosition": { + "allowed": [ + "FRONT_LEFT", + "FRONT_MIDDLE", + "FRONT_RIGHT", + "REAR_LEFT", + "REAR_MIDDLE", + "REAR_RIGHT", + "LEFT_FRONT", + "LEFT_MIDDLE", + "LEFT_REAR", + "RIGHT_FRONT", + "RIGHT_MIDDLE", + "RIGHT_REAR" + ], + "comment": "Example - If this signal is [LEFT_FRONT, RIGHT_FRONT] and Charging.ChargePortType is [IEC_TYPE_2_AC, GBT_AC] that means that there is Mennekes port on the left side of the vehicle near the front, and a GB/T AC port on the right side, near the front.", + "datatype": "string[]", + "description": "Location of the charge port(s). First part indicates side of vehicle, second part relative position on that side. If supported, the list in this attribute shall have the same length as Charging.ChargePortType, and use same the relative order.", + "type": "attribute" + }, + "ChargePortType": { + "allowed": [ + "IEC_TYPE_1_AC", + "IEC_TYPE_2_AC", + "IEC_TYPE_3_AC", + "IEC_TYPE_4_DC", + "IEC_TYPE_1_CCS_DC", + "IEC_TYPE_2_CCS_DC", + "TESLA_ROADSTER", + "TESLA_HPWC", + "TESLA_SUPERCHARGER", + "GBT_AC", + "GBT_DC", + "OTHER" + ], + "comment": "A vehicle may have multiple charging ports. The signal Charging.ChargePortPosition can be used to indicate position of the charge port. IEC_TYPE_1_AC refers to Type 1 as defined in IEC 62196-2. Also known as Yazaki or J1772 connector. IEC_TYPE_2_AC refers to Type 2 as defined in IEC 62196-2. Also known as Mennekes connector. IEC_TYPE_3_AC refers to Type 3 as defined in IEC 62196-2. Also known as Scame connector. IEC_TYPE_4_DC refers to AA configuration as defined in IEC 62196-3. Also known as Type 4 or CHAdeMO connector. IEC_TYPE_1_CCS_DC refers to EE Configuration as defined in IEC 62196-3. Also known as CCS1 or Combo1 connector. IEC_TYPE_2_CCS_DC refers to FF Configuration as defined in IEC 62196-3. Also known as CCS2 or Combo2 connector. TESLA_ROADSTER, TESLA_HPWC (High Power Wall Connector) and TESLA_SUPERCHARGER refer to non-standardized charging ports/methods used by Tesla. GBT_AC refers to connector specified in GB/T 20234.2. GBT_DC refers to connector specified in GB/T 20234.3. Also specified as BB Configuration in IEC 62196-3. OTHER shall be used for charging ports not included in the list above. For additional information see https://en.wikipedia.org/wiki/IEC_62196.", + "datatype": "string[]", + "description": "Type of charge ports (charging inlet) available on the vehicle. A charge port type may occur multiple times in the list if there are multiple instances of that charge port type. IEC types refer to IEC 62196, GBT refers to GB/T 20234.", + "type": "attribute" + }, + "ChargeRate": { + "datatype": "float", + "description": "Current charging rate, as in kilometers of range added per hour.", + "type": "sensor", + "unit": "km/h" + }, + "ChargeVoltage": { + "children": { + "DC": { + "datatype": "float", + "description": "Current DC charging voltage at charging inlet.", + "type": "sensor", + "unit": "V" + }, + "Phase1": { + "datatype": "float", + "description": "Current AC charging voltage (rms) at inlet for Phase 1.", + "type": "sensor", + "unit": "V" + }, + "Phase2": { + "datatype": "float", + "description": "Current AC charging voltage (rms) at inlet for Phase 2.", + "type": "sensor", + "unit": "V" + }, + "Phase3": { + "datatype": "float", + "description": "Current AC charging voltage (rms) at inlet for Phase 3.", + "type": "sensor", + "unit": "V" + } + }, + "description": "Current charging voltage, as measured at the charging inlet.", + "type": "branch" + }, + "EvseId": { + "comment": "Length of id between 7 and 37 characters. ZZ00000 to be used if SECC cannot provide id", + "datatype": "string", + "description": "EVSE charging point ID (without separators) of last or current charging event according to ISO 15118-2 Annex H.", + "type": "sensor" + }, + "IsChargePortFlapOpen": { + "datatype": "boolean", + "description": "Status of the charge port flap(s), can potentially be controlled manually. True if at least one is open.", + "type": "actuator" + }, + "IsCharging": { + "datatype": "boolean", + "description": "True if charging is ongoing. Charging is considered to be ongoing if energy is flowing from charger to vehicle.", + "type": "sensor" + }, + "IsChargingCableConnected": { + "datatype": "boolean", + "description": "Indicates if a charging cable is physically connected to the vehicle or not.", + "type": "sensor" + }, + "IsChargingCableLocked": { + "comment": "Locking of charging cable can be used to prevent unintentional removing during charging.", + "datatype": "boolean", + "description": "Is charging cable locked to prevent removal.", + "type": "actuator" + }, + "IsDischarging": { + "datatype": "boolean", + "description": "True if discharging (vehicle to grid) is ongoing. Discharging is considered to be ongoing if energy is flowing from vehicle to charger/grid.", + "type": "sensor" + }, + "Location": { + "children": { + "Altitude": { + "datatype": "double", + "description": "Altitude relative to WGS 84 reference ellipsoid of last or current charging event.", + "type": "sensor", + "unit": "m" + }, + "Latitude": { + "datatype": "double", + "description": "Latitude of last or current charging event in WGS 84 geodetic coordinates.", + "max": 90, + "min": -90, + "type": "sensor", + "unit": "degrees" + }, + "Longitude": { + "datatype": "double", + "description": "Longitude of last or current charging event in WGS 84 geodetic coordinates.", + "max": 180, + "min": -180, + "type": "sensor", + "unit": "degrees" + } + }, + "comment": "This may depending on implementation represent the location of (the charge port of) the vehicle during charging, or the actual location of the charger/load connected to the vehicle.", + "description": "Location of last or current charging event.", + "type": "branch" + }, + "MaxPower": { + "datatype": "float", + "description": "Maximum charging power of last or current charging event.", + "type": "sensor", + "unit": "kW" + }, + "MaximumChargingCurrent": { + "children": { + "DC": { + "datatype": "float", + "description": "Maximum DC charging current at inlet that can be accepted by the system.", + "type": "sensor", + "unit": "A" + }, + "Phase1": { + "datatype": "float", + "description": "Maximum AC charging current (rms) at inlet for Phase 1 that can be accepted by the system.", + "type": "sensor", + "unit": "A" + }, + "Phase2": { + "datatype": "float", + "description": "Maximum AC charging current (rms) at inlet for Phase 2 that can be accepted by the system.", + "type": "sensor", + "unit": "A" + }, + "Phase3": { + "datatype": "float", + "description": "Maximum AC charging current (rms) at inlet for Phase 3 that can be accepted by the system.", + "type": "sensor", + "unit": "A" + } + }, + "description": "Maximum charging current that can be accepted by the system, as measured at the charging inlet.", + "type": "branch" + }, + "Mode": { + "allowed": [ + "DEACTIVATED", + "AUTOMATIC", + "TRIGGERED", + "TIMER", + "PROFILE", + "EXTERNAL_ENTITY", + "MANUAL", + "GRID" + ], + "comment": "EXTERNAL_ENTITY is the only mode where discharge may occur. The mechanism to provide a profile to the vehicle is currently not covered by VSS.", + "datatype": "string", + "deprecation": "V4.1 - MANUAL and GRID are deprecated, please use AUTOMATIC/TRIGGERED or EXTERNAL_ENITY instead.", + "description": "Describes how the charging process is controlled. DEACTIVATED means that charging and discharging is deactivated, nothing will happen if charger is connected. AUTOMATIC means charging will be initiated as soon as charger is connected. TRIGGERED means charging will be initiated when triggered by user. TIMER means charging is timer-based. PROFILE means charging is controlled by profile downloaded to vehicle. EXTERNAL_ENTITY means charging/discharging is controlled by the external entity connected to the vehicle. This includes GRID-controlled charging (e.g. ISO 15118), but also other cases where vehicle is connected to an arbitrary load that is powered by the vehicle. MANUAL means manually initiated (plug-in event, companion app, etc). GRID means grid-controlled (e.g. ISO 15118).", + "type": "actuator" + }, + "PowerLoss": { + "datatype": "float", + "description": "Electrical energy lost by power dissipation to heat inside the AC/DC converter.", + "type": "sensor", + "unit": "W" + }, + "StartStopCharging": { + "allowed": [ + "START", + "STOP" + ], + "datatype": "string", + "description": "Start or stop the charging process.", + "type": "actuator" + }, + "Temperature": { + "datatype": "float", + "description": "Current temperature of AC/DC converter converting grid voltage to battery voltage.", + "type": "sensor", + "unit": "celsius" + }, + "TimeToComplete": { + "comment": "Shall consider time set by Charging.Timer.Time. E.g. if charging shall start in 3 hours and 2 hours of charging is needed, then Charging.TimeToComplete shall report 5 hours.", + "datatype": "uint32", + "description": "The time needed for the current charging process to reach Charging.ChargeLimit. 0 if charging is complete or no charging process is active or planned.", + "type": "sensor", + "unit": "s" + }, + "Timer": { + "children": { + "Mode": { + "allowed": [ + "INACTIVE", + "START_TIME", + "END_TIME" + ], + "datatype": "string", + "description": "Defines timer mode for charging: INACTIVE - no timer set, charging may start as soon as battery is connected to a charger. START_TIME - charging shall start at Charging.Timer.Time. END_TIME - charging shall be finished (reach Charging.ChargeLimit) at Charging.Timer.Time. When charging is completed the vehicle shall change mode to 'inactive' or set a new Charging.Timer.Time. Charging shall start immediately if mode is 'starttime' or 'endtime' and Charging.Timer.Time is a time in the past.", + "type": "actuator" + }, + "Time": { + "datatype": "string", + "description": "Time for next charging-related action, formatted according to ISO 8601 with UTC time zone. Value has no significance if Charging.Timer.Mode is 'inactive'.", + "type": "actuator", + "unit": "iso8601" + } + }, + "description": "Properties related to timing of battery charging sessions.", + "type": "branch" + } + }, + "description": "Properties related to battery charging.", + "type": "branch" + }, + "CurrentCurrent": { + "datatype": "float", + "description": "Current current flowing in/out of battery. Positive = Current flowing in to battery, e.g. during charging. Negative = Current flowing out of battery, e.g. during driving.", + "type": "sensor", + "unit": "A" + }, + "CurrentPower": { + "datatype": "float", + "description": "Current electrical energy flowing in/out of battery. Positive = Energy flowing in to battery, e.g. during charging. Negative = Energy flowing out of battery, e.g. during driving.", + "type": "sensor", + "unit": "W" + }, + "CurrentVoltage": { + "datatype": "float", + "description": "Current Voltage of the battery.", + "type": "sensor", + "unit": "V" + }, + "DCDC": { + "children": { + "PowerLoss": { + "datatype": "float", + "description": "Electrical energy lost by power dissipation to heat inside DC/DC converter.", + "type": "sensor", + "unit": "W" + }, + "Temperature": { + "datatype": "float", + "description": "Current temperature of DC/DC converter converting battery high voltage to vehicle low voltage (typically 12 Volts).", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Properties related to DC/DC converter converting high voltage (from high voltage battery) to vehicle low voltage (supply voltage, typically 12 Volts).", + "type": "branch" + }, + "ErrorCodes": { + "comment": "Error code format is not defined, it may be DTCs according to OBD II (SAE-J2012DA_201812) standard ([P|C|B|U]XXXXX ) or any other format.", + "datatype": "string[]", + "description": "Current error codes related to the battery, if any.", + "type": "sensor" + }, + "GrossCapacity": { + "datatype": "uint16", + "description": "Gross capacity of the battery.", + "type": "attribute", + "unit": "kWh" + }, + "Id": { + "comment": "This could be serial number, part number plus serial number, UUID, or any other identifier that the OEM want to use to uniquely identify the battery individual.", + "datatype": "string", + "description": "Battery Identification Number as assigned by OEM.", + "type": "attribute" + }, + "IsGroundConnected": { + "comment": "It might be possible to disconnect the traction battery used by an electric powertrain. This is achieved by connectors, typically one for plus and one for minus.", + "datatype": "boolean", + "description": "Indicating if the ground (negative terminator) of the traction battery is connected to the powertrain.", + "type": "sensor" + }, + "IsPowerConnected": { + "comment": "It might be possible to disconnect the traction battery used by an electric powertrain. This is achieved by connectors, typically one for plus and one for minus.", + "datatype": "boolean", + "description": "Indicating if the power (positive terminator) of the traction battery is connected to the powertrain.", + "type": "sensor" + }, + "MaxVoltage": { + "datatype": "uint16", + "description": "Max allowed voltage of the battery, e.g. during charging.", + "type": "attribute", + "unit": "V" + }, + "NetCapacity": { + "datatype": "uint16", + "description": "Total net capacity of the battery considering aging.", + "type": "sensor", + "unit": "kWh" + }, + "NominalVoltage": { + "comment": "Nominal voltage typically refers to voltage of fully charged battery when delivering rated capacity.", + "datatype": "uint16", + "description": "Nominal Voltage of the battery.", + "type": "attribute", + "unit": "V" + }, + "PowerLoss": { + "datatype": "float", + "description": "Electrical energy lost by power dissipation to heat inside the battery.", + "type": "sensor", + "unit": "W" + }, + "ProductionDate": { + "datatype": "string", + "description": "Production date of battery in ISO8601 format, e.g. YYYY-MM-DD.", + "type": "attribute", + "unit": "iso8601" + }, + "Range": { + "datatype": "uint32", + "description": "Remaining range in meters using only battery.", + "type": "sensor", + "unit": "m" + }, + "StateOfCharge": { + "children": { + "Current": { + "datatype": "float", + "description": "Physical state of charge of the high voltage battery, relative to net capacity. This is not necessarily the state of charge being displayed to the customer.", + "max": 100.0, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "CurrentEnergy": { + "comment": "Current energy could be calculated as .StateOfCharge.Current * .NetCapacity.", + "datatype": "float", + "description": "Physical state of charge of high voltage battery expressed in kWh.", + "type": "sensor", + "unit": "kWh" + }, + "Displayed": { + "datatype": "float", + "description": "State of charge displayed to the customer.", + "max": 100.0, + "min": 0, + "type": "sensor", + "unit": "percent" + } + }, + "description": "Information on the state of charge of the vehicle's high voltage battery.", + "type": "branch" + }, + "StateOfHealth": { + "comment": "Exact formula is implementation dependent. Could be e.g. current capacity at 20 degrees Celsius divided with original capacity at the same temperature.", + "datatype": "float", + "description": "Calculated battery state of health at standard conditions.", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent" + }, + "Temperature": { + "children": { + "Average": { + "datatype": "float", + "description": "Current average temperature of the battery cells.", + "type": "sensor", + "unit": "celsius" + }, + "CellTemperature": { + "comment": "Cells are identified by relative position in array.", + "datatype": "float[]", + "description": "Array of cell temperatures. Length or array shall correspond to number of cells in vehicle.", + "type": "sensor" + }, + "Max": { + "datatype": "float", + "description": "Current maximum temperature of the battery cells, i.e. temperature of the hottest cell.", + "type": "sensor", + "unit": "celsius" + }, + "Min": { + "datatype": "float", + "description": "Current minimum temperature of the battery cells, i.e. temperature of the coldest cell.", + "type": "sensor", + "unit": "celsius" + } + }, + "description": "Temperature Information for the battery pack.", + "type": "branch" + }, + "TimeRemaining": { + "datatype": "uint32", + "description": "Time remaining in seconds before the battery is empty.", + "type": "sensor", + "unit": "s" + } + }, + "description": "Battery Management data.", + "type": "branch" + }, + "Transmission": { + "children": { + "ClutchEngagement": { + "datatype": "float", + "description": "Clutch engagement. 0% = Clutch fully disengaged. 100% = Clutch fully engaged.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "ClutchWear": { + "datatype": "uint8", + "description": "Clutch wear as a percent. 0 = no wear. 100 = worn.", + "max": 100, + "type": "sensor", + "unit": "percent" + }, + "CurrentGear": { + "datatype": "int8", + "description": "The current gear. 0=Neutral, 1/2/..=Forward, -1/-2/..=Reverse.", + "type": "sensor" + }, + "DiffLockFrontEngagement": { + "datatype": "float", + "description": "Front Diff Lock engagement. 0% = Diff lock fully disengaged. 100% = Diff lock fully engaged.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "DiffLockRearEngagement": { + "datatype": "float", + "description": "Rear Diff Lock engagement. 0% = Diff lock fully disengaged. 100% = Diff lock fully engaged.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "DriveType": { + "allowed": [ + "UNKNOWN", + "FORWARD_WHEEL_DRIVE", + "REAR_WHEEL_DRIVE", + "ALL_WHEEL_DRIVE" + ], + "datatype": "string", + "default": "UNKNOWN", + "description": "Drive type.", + "type": "attribute" + }, + "GearChangeMode": { + "allowed": [ + "MANUAL", + "AUTOMATIC" + ], + "datatype": "string", + "description": "Is the gearbox in automatic or manual (paddle) mode.", + "type": "actuator" + }, + "GearCount": { + "datatype": "int8", + "default": 0, + "description": "Number of forward gears in the transmission. -1 = CVT.", + "type": "attribute" + }, + "IsElectricalPowertrainEngaged": { + "comment": "In some hybrid solutions it is possible to disconnect/disengage the electrical powertrain mechanically to avoid induced voltage reaching a too high level when driving at high speed.", + "datatype": "boolean", + "description": "Is electrical powertrain mechanically connected/engaged to the drivetrain or not. False = Disconnected/Disengaged. True = Connected/Engaged.", + "type": "actuator" + }, + "IsLowRangeEngaged": { + "comment": "The possibility to switch between low and high gear range is typically only available in heavy vehicles and off-road vehicles.", + "datatype": "boolean", + "description": "Is gearbox in low range mode or not. False = Normal/High range engaged. True = Low range engaged.", + "type": "actuator" + }, + "IsParkLockEngaged": { + "datatype": "boolean", + "description": "Is the transmission park lock engaged or not. False = Disengaged. True = Engaged.", + "type": "actuator" + }, + "PerformanceMode": { + "allowed": [ + "NORMAL", + "SPORT", + "ECONOMY", + "SNOW", + "RAIN" + ], + "datatype": "string", + "description": "Current gearbox performance mode.", + "type": "actuator" + }, + "SelectedGear": { + "datatype": "int8", + "description": "The selected gear. 0=Neutral, 1/2/..=Forward, -1/-2/..=Reverse, 126=Park, 127=Drive.", + "type": "actuator" + }, + "Temperature": { + "datatype": "int16", + "description": "The current gearbox temperature.", + "type": "sensor", + "unit": "celsius" + }, + "TorqueDistribution": { + "datatype": "float", + "description": "Torque distribution between front and rear axle in percent. -100% = Full torque to front axle, 0% = 50:50 Front/Rear, 100% = Full torque to rear axle.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "TravelledDistance": { + "datatype": "float", + "description": "Odometer reading, total distance travelled during the lifetime of the transmission.", + "type": "sensor", + "unit": "km" + }, + "Type": { + "allowed": [ + "UNKNOWN", + "SEQUENTIAL", + "H", + "AUTOMATIC", + "DSG", + "CVT" + ], + "datatype": "string", + "default": "UNKNOWN", + "description": "Transmission type.", + "type": "attribute" + } + }, + "description": "Transmission-specific data, stopping at the drive shafts.", + "type": "branch" + }, + "Type": { + "allowed": [ + "COMBUSTION", + "HYBRID", + "ELECTRIC" + ], + "comment": "For vehicles with a combustion engine (including hybrids) more detailed information on fuels supported can be found in FuelSystem.SupportedFuelTypes and FuelSystem.SupportedFuels.", + "datatype": "string", + "description": "Defines the powertrain type of the vehicle.", + "type": "attribute" + } + }, + "description": "Powertrain data for battery management, etc.", + "type": "branch" + }, + "RoofLoad": { + "datatype": "int16", + "description": "The permitted total weight of cargo and installations (e.g. a roof rack) on top of the vehicle.", + "type": "attribute", + "unit": "kg" + }, + "Service": { + "children": { + "DistanceToService": { + "datatype": "float", + "description": "Remaining distance to service (of any kind). Negative values indicate service overdue.", + "type": "sensor", + "unit": "km" + }, + "IsServiceDue": { + "datatype": "boolean", + "description": "Indicates if vehicle needs service (of any kind). True = Service needed now or in the near future. False = No known need for service.", + "type": "sensor" + }, + "TimeToService": { + "datatype": "int32", + "description": "Remaining time to service (of any kind). Negative values indicate service overdue.", + "type": "sensor", + "unit": "s" + } + }, + "description": "Service data.", + "type": "branch" + }, + "Speed": { + "datatype": "float", + "description": "Vehicle speed.", + "type": "sensor", + "unit": "km/h" + }, + "StartTime": { + "comment": "This signal is supposed to be set whenever a new trip starts. A new trip is considered to start when engine gets enabled (e.g. LowVoltageSystemState in ON or START mode). A trip is considered to end when engine is no longer enabled. The default value indicates that the vehicle never has been started, or that latest start time is unknown.", + "datatype": "string", + "default": "0000-01-01T00:00Z", + "description": "Start time of current or latest trip, formatted according to ISO 8601 with UTC time zone.", + "type": "attribute", + "unit": "iso8601" + }, + "Trailer": { + "children": { + "IsConnected": { + "datatype": "boolean", + "description": "Signal indicating if trailer is connected or not.", + "type": "sensor" + } + }, + "description": "Trailer signals.", + "type": "branch" + }, + "TraveledDistance": { + "datatype": "float", + "description": "Odometer reading, total distance traveled during the lifetime of the vehicle.", + "type": "sensor", + "unit": "km" + }, + "TraveledDistanceSinceStart": { + "comment": "A new trip is considered to start when engine gets enabled (e.g. LowVoltageSystemState in ON or START mode). A trip is considered to end when engine is no longer enabled. The signal may however keep the value of the last trip until a new trip is started.", + "datatype": "float", + "description": "Distance traveled since start of current trip.", + "type": "sensor", + "unit": "km" + }, + "TripDuration": { + "comment": "This signal is not assumed to be continuously updated, but instead set to 0 when a trip starts and set to the actual duration of the trip when a trip ends. A new trip is considered to start when engine gets enabled (e.g. LowVoltageSystemState in ON or START mode). A trip is considered to end when engine is no longer enabled.", + "datatype": "float", + "description": "Duration of latest trip.", + "type": "sensor", + "unit": "s" + }, + "TripMeterReading": { + "comment": "The trip meter is an odometer that can be manually reset by the driver", + "datatype": "float", + "description": "Trip meter reading.", + "type": "actuator", + "unit": "km" + }, + "TurningDiameter": { + "datatype": "uint16", + "description": "Minimum turning diameter, Wall-to-Wall, as defined by SAE J1100-2009 D102.", + "type": "attribute", + "unit": "mm" + }, + "VehicleIdentification": { + "children": { + "AcrissCode": { + "datatype": "string", + "description": "The ACRISS Car Classification Code is a code used by many car rental companies.", + "type": "attribute" + }, + "BodyType": { + "datatype": "string", + "description": "Indicates the design and body style of the vehicle (e.g. station wagon, hatchback, etc.).", + "type": "attribute" + }, + "Brand": { + "datatype": "string", + "description": "Vehicle brand or manufacturer.", + "type": "attribute" + }, + "DateVehicleFirstRegistered": { + "datatype": "string", + "description": "The date in ISO 8601 format of the first registration of the vehicle with the respective public authorities.", + "type": "attribute", + "unit": "iso8601" + }, + "KnownVehicleDamages": { + "datatype": "string", + "description": "A textual description of known damages, both repaired and unrepaired.", + "type": "attribute" + }, + "LicensePlate": { + "comment": "Depending on the context, this attribute might not be up to date or might be misconfigured, and therefore should be considered untrustworthy in the absence of another method of verification.", + "datatype": "string", + "description": "The license plate of the vehicle.", + "type": "attribute" + }, + "MeetsEmissionStandard": { + "datatype": "string", + "description": "Indicates that the vehicle meets the respective emission standard.", + "type": "attribute" + }, + "Model": { + "datatype": "string", + "description": "Vehicle model.", + "type": "attribute" + }, + "OptionalExtras": { + "comment": "Allowed values are not standardized, each OEM can specify detail descriptions of array elements.", + "datatype": "string[]", + "description": "Optional extras refers to all car equipment options that are not installed as standard by the manufacturer.", + "type": "attribute" + }, + "ProductionDate": { + "datatype": "string", + "description": "The date in ISO 8601 format of production of the item, e.g. vehicle.", + "type": "attribute", + "unit": "iso8601" + }, + "PurchaseDate": { + "datatype": "string", + "description": "The date in ISO 8601 format of the item e.g. vehicle was purchased by the current owner.", + "type": "attribute", + "unit": "iso8601" + }, + "VIN": { + "datatype": "string", + "description": "17-character Vehicle Identification Number (VIN) as defined by ISO 3779.", + "type": "attribute" + }, + "VehicleConfiguration": { + "datatype": "string", + "description": "A short text indicating the configuration of the vehicle, e.g. '5dr hatchback ST 2.5 MT 225 hp' or 'limited edition'.", + "type": "attribute" + }, + "VehicleExteriorColor": { + "datatype": "string", + "description": "The main color of the exterior within the basic color palette (eg. red, blue, black, white, ...).", + "type": "attribute" + }, + "VehicleInteriorColor": { + "datatype": "string", + "description": "The color or color combination of the interior of the vehicle.", + "type": "attribute" + }, + "VehicleInteriorType": { + "datatype": "string", + "description": "The type or material of the interior of the vehicle (e.g. synthetic fabric, leather, wood, etc.).", + "type": "attribute" + }, + "VehicleModelDate": { + "datatype": "string", + "description": "The release date in ISO 8601 format of a vehicle model (often used to differentiate versions of the same make and model).", + "type": "attribute", + "unit": "iso8601" + }, + "VehicleSeatingCapacity": { + "datatype": "uint16", + "description": "The number of passengers that can be seated in the vehicle, both in terms of the physical space available, and in terms of limitations set by law.", + "type": "attribute" + }, + "VehicleSpecialUsage": { + "datatype": "string", + "description": "Indicates whether the vehicle has been used for special purposes, like commercial rental, driving school.", + "type": "attribute" + }, + "WMI": { + "datatype": "string", + "description": "3-character World Manufacturer Identification (WMI) as defined by ISO 3780.", + "type": "attribute" + }, + "Year": { + "datatype": "uint16", + "description": "Model year of the vehicle.", + "type": "attribute" + } + }, + "description": "Attributes that identify a vehicle.", + "type": "branch" + }, + "VersionVSS": { + "children": { + "Label": { + "comment": "COVESA VSS project typically use dev for latest master, and empty string for released versions.", + "datatype": "string", + "description": "Label to further describe the version.", + "type": "attribute" + }, + "Major": { + "datatype": "uint32", + "default": 4, + "description": "Supported Version of VSS - Major version.", + "type": "attribute" + }, + "Minor": { + "datatype": "uint32", + "default": 2, + "description": "Supported Version of VSS - Minor version.", + "type": "attribute" + }, + "Patch": { + "datatype": "uint32", + "default": 0, + "description": "Supported Version of VSS - Patch version.", + "type": "attribute" + } + }, + "description": "Supported Version of VSS.", + "type": "branch" + }, + "Width": { + "datatype": "uint16", + "default": 0, + "deprecation": "v4.1 replaced with WidthExcludingMirrors and WidthIncludingMirrors", + "description": "Overall vehicle width.", + "type": "attribute", + "unit": "mm" + }, + "WidthExcludingMirrors": { + "datatype": "uint16", + "default": 0, + "description": "Overall vehicle width excluding mirrors, as defined by SAE J1100-2009 W103.", + "type": "attribute", + "unit": "mm" + }, + "WidthFoldedMirrors": { + "datatype": "uint16", + "description": "Overall vehicle width with mirrors folded, as defined by SAE J1100-2009 W145.", + "type": "attribute", + "unit": "mm" + }, + "WidthIncludingMirrors": { + "datatype": "uint16", + "description": "Overall vehicle width including mirrors, as defined by SAE J1100-2009 W144.", + "type": "attribute", + "unit": "mm" + } + }, + "description": "High-level vehicle data.", + "type": "branch" + } +} diff --git a/Demo/Vss/src/vss_consumer/vss_consumer.cpp b/Demo/Vss/src/vss_consumer/vss_consumer.cpp new file mode 100644 index 0000000..963cf8d --- /dev/null +++ b/Demo/Vss/src/vss_consumer/vss_consumer.cpp @@ -0,0 +1,79 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file vss_consumer.cpp + * \brief + * + *********************************************************************************************************************/ + + #include "demo/vss_consumer.h" + #include <iostream> + + namespace demo { + + + /* + Generated based on configuration in ../../model/vss_consumer.py + + Consumer interfaces + =================== + Data element API example for Lateral of type float + - ::vaf::Result<::vaf::ConstDataPtr<const float>> GetAllocated_Lateral() + - float Get_Lateral() + - void RegisterDataElementHandler_Lateral(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const float>)>&& f) + + - AccelerationConsumer_ : vss::vehicle::Acceleration_IfConsumer + - Data elements + - Lateral : float + - Longitudinal : float + - Vertical : float + - DriverConsumer_ : vss::vehicle::Driver_IfConsumer + - Data elements + - AttentiveProbability : float + - DistractionLevel : float + - FatigueLevel : float + - HeartRate : std::uint16_t + - Identifier : vss::vehicle::driver::Identifier + - IsEyesOnRoad : bool + - IsHandsOnWheel : bool + */ + + /********************************************************************************************************************** + Constructor + **********************************************************************************************************************/ + VssConsumer::VssConsumer(ConstructorToken&& token) + : VssConsumerBase(std::move(token)) + { + // Insert your code here... + } + + /********************************************************************************************************************** + 1 periodic task(s) + **********************************************************************************************************************/ + // Task with name PeriodicTask and a period of 200ms. + void VssConsumer::PeriodicTask() { + auto acceleration = AccelerationConsumer_->Get_Longitudinal(); + auto isEyesOnRoad = DriverConsumer_->Get_IsEyesOnRoad(); + auto driverId = DriverConsumer_->Get_Identifier(); + + std::cout << "Longitudinal acceleration: " << acceleration << " m/s^2" << std::endl; + if (isEyesOnRoad) { + std::cout << "'" << driverId.Subject << "' has the eyes on the road." << std::endl; + } else { + std::cout << "'" << driverId.Subject << "' does not have the eyes on the road." << std::endl; + } + } + + + } // namespace demo + \ No newline at end of file diff --git a/Demo/Vss/src/vss_provider/vss_provider.cpp b/Demo/Vss/src/vss_provider/vss_provider.cpp new file mode 100644 index 0000000..a1e5261 --- /dev/null +++ b/Demo/Vss/src/vss_provider/vss_provider.cpp @@ -0,0 +1,91 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file vss_provider.cpp + * \brief + * + *********************************************************************************************************************/ + + #include "demo/vss_provider.h" + + namespace demo { + + + /* + Generated based on configuration in ../../model/vss_provider.py + + Provider interfaces + =================== + Data element API example for Lateral of type float + - ::vaf::Result<::vaf::DataPtr<float>> Allocate_Lateral() + - ::vaf::Result<void> SetAllocated_Lateral(::vaf::DataPtr<float>&& data) + - ::vaf::Result<void> Set_Lateral(const float& data) + + - AccelerationProvider_ : vss::vehicle::Acceleration_IfProvider + - Data elements + - Lateral : float + - Longitudinal : float + - Vertical : float + - DriverProvider_ : vss::vehicle::Driver_IfProvider + - Data elements + - AttentiveProbability : float + - DistractionLevel : float + - FatigueLevel : float + - HeartRate : std::uint16_t + - Identifier : vss::vehicle::driver::Identifier + - IsEyesOnRoad : bool + - IsHandsOnWheel : bool + */ + + /********************************************************************************************************************** + Constructor + **********************************************************************************************************************/ + VssProvider::VssProvider(ConstructorToken&& token) + : VssProviderBase(std::move(token)) + { + // Insert your code here... + } + + /********************************************************************************************************************** + 1 periodic task(s) + **********************************************************************************************************************/ + // Task with name PeriodicTask and a period of 200ms. + void VssProvider::PeriodicTask() { + // Acceleration + static float value = 0; + static float diff = 0.2f; + AccelerationProvider_->Set_Lateral(value); + AccelerationProvider_->Set_Longitudinal(value); + AccelerationProvider_->Set_Vertical(value); + + if (value >= 10) { + diff = -0.2f; + } else if (value <= -10) { + diff = 0.2f; + } + value += diff; + + // Driver + vss::vehicle::driver::Identifier driverId = {"Issuer", "Driver1"}; + DriverProvider_->Set_Identifier(driverId); + + if (value > 5) { + DriverProvider_->Set_IsEyesOnRoad(true); + } else { + DriverProvider_->Set_IsEyesOnRoad(false); + } + } + + + } // namespace demo + \ No newline at end of file diff --git a/Demo/figures/hello.drawio.svg b/Demo/figures/hello.drawio.svg new file mode 100644 index 0000000..b291d85 --- /dev/null +++ b/Demo/figures/hello.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="411px" height="126px" viewBox="-0.5 -0.5 411 126" content="<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2"> <diagram id="qchfyPlCbnvhXIaJ2EZ1" name="Page-1"> <mxGraphModel dx="624" dy="567" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="2" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;HelloVaf&amp;nbsp;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;align=right;verticalAlign=top;spacingRight=3;spacing=1;" parent="1" vertex="1"> <mxGeometry x="80" y="160" width="280" height="110" as="geometry" /> </mxCell> <mxCell id="35" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="4" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="36" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="3" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="34" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=0;" parent="1" vertex="1"> <mxGeometry x="210" y="212" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="n_8MEDxsc1R7JmpyKjgA-36" value="" style="endArrow=none;dashed=1;html=1;strokeWidth=1;rounded=0;" edge="1" parent="1"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="370" y="170" as="sourcePoint" /> <mxPoint x="410" y="160" as="targetPoint" /> <Array as="points"> <mxPoint x="410" y="160" /> </Array> </mxGeometry> </mxCell> <mxCell id="n_8MEDxsc1R7JmpyKjgA-37" value="Executable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;fontSize=14;" vertex="1" parent="1"> <mxGeometry x="410" y="145" width="80" height="30" as="geometry" /> </mxCell> <mxCell id="3" value="AppModule1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="99" y="192" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="4" value="AppModule2" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="250" y="192" width="90" height="60" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> "><defs/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="2"><g><rect x="0" y="15" width="280" height="110" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 277px; height: 1px; padding-top: 21px; margin-left: -1px;"><div style="box-sizing: border-box; font-size: 0; text-align: right; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 14px;">HelloVaf </font></div></div></div></foreignObject><text x="276" y="33" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="end">HelloVaf </text></switch></g></g></g><g data-cell-id="35"><g><path d="M 150 77 L 170 77" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="36"><g><path d="M 130 77 L 109 77" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="34"><g><ellipse cx="137" cy="77" rx="7" ry="7" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(0, 0, 0);"/><path d="M 140 67 Q 150 67 150 77 Q 150 87 140 87" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="n_8MEDxsc1R7JmpyKjgA-36"><g><path d="M 290 25 L 330 15" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="n_8MEDxsc1R7JmpyKjgA-37"><g><rect x="330" y="0" width="80" height="30" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 70px; height: 1px; padding-top: 15px; margin-left: 336px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; max-height: 26px; overflow: hidden; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Executable</div></div></div></foreignObject><text x="336" y="19" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px">Executable</text></switch></g></g></g><g data-cell-id="3"><g><rect x="19" y="47" width="90" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(65, 149, 201);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 77px; margin-left: 20px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">AppModule1</div></div></div></foreignObject><text x="64" y="81" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">AppModule1</text></switch></g></g></g><g data-cell-id="4"><g><rect x="170" y="47" width="90" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(65, 149, 201);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 77px; margin-left: 171px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">AppModule2</div></div></div></foreignObject><text x="215" y="81" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">AppModule2</text></switch></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/Demo/figures/silkit.drawio.svg b/Demo/figures/silkit.drawio.svg new file mode 100644 index 0000000..3959aeb --- /dev/null +++ b/Demo/figures/silkit.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="301px" height="271px" viewBox="-0.5 -0.5 301 271" content="<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.0.9 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="26.0.9"> <diagram id="qchfyPlCbnvhXIaJ2EZ1" name="Page-1"> <mxGraphModel dx="1232" dy="971" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="2" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;&amp;nbsp; Executable&amp;nbsp;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;align=left;verticalAlign=top;" parent="1" vertex="1"> <mxGeometry x="80" y="160" width="280" height="110" as="geometry" /> </mxCell> <mxCell id="29" value="" style="edgeStyle=none;sketch=0;jumpStyle=none;html=1;shadow=0;strokeColor=#000000;strokeWidth=1;endArrow=none;endFill=0;endSize=6;sourcePerimeterSpacing=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="18" target="3" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="30" style="edgeStyle=none;sketch=0;jumpStyle=none;html=1;shadow=0;strokeColor=#000000;strokeWidth=1;endArrow=none;endFill=0;endSize=6;sourcePerimeterSpacing=0;" parent="1" source="18" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="145" y="290" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="18" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=90;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="1" vertex="1"> <mxGeometry x="135" y="260" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="32" value="" style="edgeStyle=none;sketch=0;jumpStyle=none;html=1;shadow=0;strokeColor=#000000;strokeWidth=1;endArrow=none;endFill=0;endSize=6;sourcePerimeterSpacing=0;entryX=0.112;entryY=0.995;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="31" target="4" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="33" value="" style="edgeStyle=none;sketch=0;jumpStyle=none;html=1;shadow=0;strokeColor=#000000;strokeWidth=1;endArrow=none;endFill=0;endSize=6;sourcePerimeterSpacing=0;" parent="1" source="31" target="8" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="260" y="290" /> </Array> </mxGeometry> </mxCell> <mxCell id="31" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=-90;" parent="1" vertex="1"> <mxGeometry x="250" y="260" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="35" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="4" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="36" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="3" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="34" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=-180;" parent="1" vertex="1"> <mxGeometry x="210" y="210" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-40" value="Object &lt;br&gt;list" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=14;" parent="1" vertex="1"> <mxGeometry x="190" y="165" width="60" height="50" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-41" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=-90;" parent="1" vertex="1"> <mxGeometry x="320" y="260" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="3" value="Collision detection" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="100" y="190" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;endArrow=none;endFill=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-41" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="330" y="250" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;endArrow=none;endFill=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-41" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="330" y="290" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-44" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=90;" parent="1" vertex="1"> <mxGeometry x="245" y="150" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-47" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=90;" parent="1" vertex="1"> <mxGeometry x="315" y="150" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-49" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.945;entryY=1.004;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-44" target="hdpQ5ZzZvHVYTLjAbtzv-37" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-50" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.55;entryY=0.978;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-47" target="hdpQ5ZzZvHVYTLjAbtzv-38" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-37" value="Camera (left)&lt;br&gt;service" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#7f7f7f;" parent="1" vertex="1"> <mxGeometry x="170" y="80" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-38" value="Camera (right)&lt;br&gt;service" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#7f7f7f;" parent="1" vertex="1"> <mxGeometry x="270" y="80" width="100" height="60" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-51" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.054;entryY=0.012;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-44" target="4" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;endArrow=none;endFill=0;entryX=0.833;entryY=-0.007;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="hdpQ5ZzZvHVYTLjAbtzv-47" target="4" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="280" y="190" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="4" value="Sensor &lt;br&gt;fusion" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="250" y="190" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="7" value="Brake&lt;br&gt;service" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#7f7f7f;" parent="1" vertex="1"> <mxGeometry x="70" y="290" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="8" value="Steering angle&lt;br&gt;service" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#7f7f7f;" parent="1" vertex="1"> <mxGeometry x="170" y="290" width="100" height="60" as="geometry" /> </mxCell> <mxCell id="hdpQ5ZzZvHVYTLjAbtzv-36" value="Velocity&lt;br&gt;service" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#7f7f7f;" parent="1" vertex="1"> <mxGeometry x="280" y="290" width="90" height="60" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> "><defs/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="2"><g><rect x="10" y="80" width="280" height="110" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 87px; margin-left: 12px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 14px;"> Executable </font></div></div></div></foreignObject><text x="12" y="99" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px"> Executable </text></switch></g></g></g><g data-cell-id="29"><g><path d="M 75 180 L 75 170" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="30"><g><path d="M 75 200 L 75 210" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="18"><g><ellipse cx="72" cy="190" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(90,75,190)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 75 180 Q 85 180 85 190 Q 85 200 75 200" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(90,75,190)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="32"><g><path d="M 190.04 180 L 190.08 169.7" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="33"><g><path d="M 190 200 L 190 210" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="31"><g><ellipse cx="187" cy="190" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(-90,190,190)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 190 180 Q 200 180 200 190 Q 200 200 190 200" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(-90,190,190)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="35"><g><path d="M 160 140 L 180 140" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="36"><g><path d="M 140 140 L 120 140" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="34"><g><ellipse cx="147" cy="140" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(-180,150,140)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 150 130 Q 160 130 160 140 Q 160 150 150 150" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(-180,150,140)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-40"><g><rect x="120" y="85" width="60" height="50" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 110px; margin-left: 150px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: nowrap; ">Object <br />list</div></div></div></foreignObject><text x="150" y="114" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Object...</text></switch></g></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-41"><g><ellipse cx="257" cy="190" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(-90,260,190)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 260 180 Q 270 180 270 190 Q 270 200 260 200" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(-90,260,190)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="3"><g><rect x="30" y="110" width="90" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(65, 149, 201), rgb(65, 149, 201));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 140px; margin-left: 31px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Collision detection</div></div></div></foreignObject><text x="75" y="144" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Collision det...</text></switch></g></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-42"><g><path d="M 260 180 L 260 170" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-43"><g><path d="M 260 200 L 260 210" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-44"><g><ellipse cx="182" cy="80" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(90,185,80)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 185 70 Q 195 70 195 80 Q 195 90 185 90" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(90,185,80)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-47"><g><ellipse cx="252" cy="80" rx="7" ry="7" fill="#ffffff" stroke="#000000" transform="rotate(90,255,80)" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/><path d="M 255 70 Q 265 70 265 80 Q 265 90 255 90" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(90,255,80)" pointer-events="all" style="stroke: light-dark(rgb(0, 0, 0), rgb(0, 0, 0));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-49"><g><path d="M 185 70 L 185.05 60.24" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-50"><g><path d="M 255 70 L 255 58.68" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-37"><g><rect x="100" y="0" width="90" height="60" fill="#ffffff" stroke="#7f7f7f" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(127, 127, 127), rgb(127, 127, 127));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 30px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Camera (left)<br />service</div></div></div></foreignObject><text x="145" y="34" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Camera (left)...</text></switch></g></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-38"><g><rect x="200" y="0" width="100" height="60" fill="#ffffff" stroke="#7f7f7f" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(127, 127, 127), rgb(127, 127, 127));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 30px; margin-left: 201px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Camera (right)<br />service</div></div></div></foreignObject><text x="250" y="34" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Camera (right)...</text></switch></g></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-51"><g><path d="M 185 90 L 184.86 110.72" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-52"><g><path d="M 255 90 L 254.97 109.58" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="4"><g><rect x="180" y="110" width="90" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(65, 149, 201), rgb(65, 149, 201));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 140px; margin-left: 181px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Sensor <br />fusion</div></div></div></foreignObject><text x="225" y="144" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Sensor...</text></switch></g></g></g><g data-cell-id="7"><g><rect x="0" y="210" width="90" height="60" fill="#ffffff" stroke="#7f7f7f" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(127, 127, 127), rgb(127, 127, 127));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 240px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Brake<br />service</div></div></div></foreignObject><text x="45" y="244" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Brake...</text></switch></g></g></g><g data-cell-id="8"><g><rect x="100" y="210" width="100" height="60" fill="#ffffff" stroke="#7f7f7f" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(127, 127, 127), rgb(127, 127, 127));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 240px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Steering angle<br />service</div></div></div></foreignObject><text x="150" y="244" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Steering angle...</text></switch></g></g></g><g data-cell-id="hdpQ5ZzZvHVYTLjAbtzv-36"><g><rect x="210" y="210" width="90" height="60" fill="#ffffff" stroke="#7f7f7f" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(127, 127, 127), rgb(127, 127, 127));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 240px; margin-left: 211px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Velocity<br />service</div></div></div></foreignObject><text x="255" y="244" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">Velocity...</text></switch></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/Demo/figures/vscode-remote-window.png b/Demo/figures/vscode-remote-window.png new file mode 100644 index 0000000000000000000000000000000000000000..fdac0388af5b2c3a881e9d3e0428e82791955024 GIT binary patch literal 4594 zcmV<O5e@E%P)<h;3K|Lk000e1NJLTq005!@002e^0ssI2z(v^D00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D01|XXSaefwW^{L9 za%BKVa%E+1b7*gLUR4MM000qbNkl<ZcwX(B=~q)%+lTY*`S|`pwv`Uji4M|%v`T!d zu_|?-T4|S9m1>I<Rt-2VO;yrraYC)p5)lGI97q+SNI(cOXq9TEeSG}*UOD&XcnF6i zO5iE4=ePD^-DmG}_H^z0-usZm_S<j2UAS=J+_`gpzkl=Q&5!;`>gnlGmZg!&!u(9g z!u(9g!u(9g!u(9g!u(7q#h8yDKmLh9Zns+%Je4fWsZt6s|MABk%6jz3<#Iu{prByY zs#P;*&Ro8Hxhi<{=-$11%1T-m=2R&j=Kmz2g9i`JnKP%dvQjP=E?hWk)~tsQA7Zaw zy?Vxs8Grrt7j}Jp{k(be_U+rJ-Ic7myStTTDQPKqgJptQ-98|g4W~ng4*l<dHf-1s z4u>&Tu3Ral9*>91hK7c1+qP-9L{(Z^Dy7M&tE)>{mXeSHHXs2kip4B<sOKI&{P$q} zZP1Y;N2X1iwqU`6rlzLi;$rOS)2H)y&z?PULv?kvp1Ew<GH(0&>#wmPEjJ`oXJ@Cf zEDa+CW<Uy?0l7J5xk;W;HU0fJfmc_*CN|pn^XEGpj=H)!$*HNSnLBqb6l-g1C8wjK z!|8OgRqx-w|Ni~^<TN)o^T_Pkvv1wHCHKS^H7LuHnG_OD3e^C3;i!`~!7PB~Vd{FI z>CYhoXLfdWettejFv(#nZEI^2TLjLQmKJsK=br?29;v9PP}hlc<HikTS&A!Rq=OgO zM$)mEwFMDntfR#d@m&PY7;&ziI&~^RSY5|eRaF%?uU)%VT_>T|)>dU%8eT#NOu`Fr zLK+Ed6U^Kp9^BsEe);m{fTeLIkg?P0o(*a7=~&DZvm&^aeH24Ba7*JwAOjpOiUCU9 zp<^+#5O9AoEym+ifWxPOs7G%|$6}_KaF6?|hb)alfe(l}X%ozB=6!vA7Upp+@BtB& zc(yonEM`{0ojZ3d%;Q?%10pE(9Xb{>tKj$Ff44A?vAVmvm6ZyC4~U?YxNU;@?%lh$ zZ{L2FF*7g98ks69E2mGNt}f!LuCDI=_up3+sSx;p2uk9%Y|kc`Z{50;5cA2CCmjyQ z#EBE%e*5k3zyCf}Q<G3vuU<`0PoFSh0)L%OXGKMYDoBx5uU@@<`*w8^S5u};Idtfd zx)`k7+}z!}ck@<r;J^Wu6<17t$}s~`Fw6EFi<y|75cA=~hhKd0MUTgG{rYv*?1vwI z$iP(DC@UBYzVy;dL?ogdOKsAmNf$3(RAs5qs#U9!#JqIr(xRdwv1@8--g)O8W>YTT zefQn!>T0o*(I{cow`X(Ay}iA0FcawCc;gM@I*mjkFTC&qHDIq<vxWh)2(q)Y&zw0U zH}HDCW5<rS-g=9oAAkIj9L@!we)=i(@F0=x#*G_tr-)L9otBoy-xz-d^UE*4tS%ls zTDWlG)~#DHSh>rWFUQ3{{`h0*yxs)M;`7fxFD@>ob?l8BH)@YYKX1k7CQqJBK%x@f zI>-bwp#o)QW^y^ST3x$#?fUGq&%`DMJonslwY9a_Ji_B$U0r9-p2g$IxpL*o)TvXc zglS=MuwQBqJ^JOBU+5C~%z%!W^}$oGzWQo@em<+2oQ#YNnOm7>#)Vy0RyKF;+~@;l zqN_k05oS8gFnC^FYhu7Wi}A@Pp8&G6vlEYp6ET*|BS(%f3|#-xrAx28^2)Vq*9az5 z(%9J8(b2JN*|MR*psA^e-DTgteXqUtng9?PF>?=7Am2k;v0}v+Uwna!v;M%wz@!N} zARm;?o;|y{xf$1oG(+H#<HwKVcI42FtgI}86PaM%wrv|NN~1%oB~!$7(KoSKE0A8d zZXGsLN3Sq+%oq&+=FOW7oE+&evjKGi60x0?Cz$Cf-8*sO1nd6GFTc#o%Oi8ik|jHL z?!;hOFd}9Ed*#ZNl4+{Mm{~#bF%zJS{v;|WDEQ`^Z!o}o`t)hZ#1F)ESOoj`@0ZN4 zzWNGy!T^xuFv~1nDUA_xjh7ftp$w7-Uw{2|<_Lq?Av$pzrvxTW?xB=AjZLufaA+x| zGb}p{yg|?+kaN_)Fa~YYYQ;v>O#Of%bK10N;c!?20Ha&9Xc2}Hvlxg{fyZKEDkPK1 z7tD}bym+x>vMi{d*zohuKhK{(pBz>aQDN`iz1ZB3&uBNANHBv^f2Vq4%n7|&$4sYL zi5MSz@Bz^V=SCPVm&?ci*T>eLP-2AmH_;5Ypon0l3I_IOZlD`%%u+;z<Tj}v(F9{L zHgW9OF}zu;AiB<kE=LM|TfwKrHI0}}tCb=Vk^I!DQ)~xpNnBE4Lqh{$dC#6bT$*C0 zCpkGe7&NqD!v@LJF@O8*w|XX`MTtfX8B`yA^pVf!W4)4tV@SL)RSGau`<rjRIdpI4 ztpMAInUSntzaE1r76;O0WFX5{@<qf3#Oa;>F~2dG^;p6(63^hc@ci@76a6G#WNZRw zoi%Hg<m;GOnz}bL`{K=bOi4+JWSUlM6i2YNYu7@krKN>S9wcrPz}Zc>G{sC$1T&o% zr$?sVEUO=H#%4VoJa~{Tobb!!6B5|z<Tg{K05gJ_oU~bMoV3~4^pFT<W{Ty;*w}{U z7|eMAho%+6ujItXOtc3xBjmIa2Q$6r2vb#6h0TG5;}`*!*^yaJh#9o(&4fPV-i#y8 zm@$JEWeXfytx+^hM3MD@xQ$B=eH`w%jE|Ys!yGa*#EkOta=}cdac|a<6X6LqECOu$ zj~)L_GBucy*XuQXZw50P6(NO<iZMtgCvCd;-h1ycFa`{O_?X+;+Gft2N#%^$Znx7P zRWKMc`st^iIMOq%tO<@wtaK)tut`xu%yQC(G_L?#wrr6Y$ne2HKXD*tXK1xX(F9>k zLbQmnvogevj~OxN+)rDq4Bb2Bq|Jt<pR^Iw84E{9Yz|^fFMX3DQzgcn@T47I#-MHK zza_yuq8F<8vM~P>loaM<{@H2ipDget_%9f{k%f7@OE80y)5EZsIks4s$F;x*M8RzS z36*@_OeU*9J!ENI32@*8V!Y3riRQ%g*49?*o1NoPAOjru^o^OfDHF`Nxi~bpQiS`P zN<Nc_5t*vk(tk-H3x~tv%KFA^f*Chw703?Fp}f1hyQ{0Kv$HdzsY6qHdwVb#q&kIH z6PIN2B2Q_m)X>nNEK3Fn1(9$85SV}kGTD`ZC=naX{~r3yP6~9=ED8>6JlWIJBfQZ~ zP1Gw3M`z3>nNpf6UAb~aS(eNsL_h-|FaZl>F^q9#6U>BiJY7iR_=I?#WPwnHAlF6J zmoHxiFv5_QQmarXq%2FrNVot9Ouzz}FxGcv7@Pd+LLxJfp-mGzG!$DjT^|seyy)7s zYnL=(s4PokB?aU9b)f?$U<ow|?0PUqQOp-FUaYID6U?^kU$k_>HuacFQ_5{qjz-hR zCh1>}a#BoY!o-TRlqzx5LgK+lkJY*>t6xM8!t6Ntm~<5O@yEPVm!w0MQYFwLqBMZ@ z{TRT)co@u&N$W{N{uum76CJWNatTzCxGw^53}ep7Hcn52F?+S7!8YNYnxuM^gznwG zdGq!?bunVyYrAlvEoHSO(!JZ}JtzORGDj?ds!Ql10gU8TXb@(X%VnE(YJjw!29U>3 z^DdQydp}(`B;PElzQj@Yr6cPWWM@sz%FdoKBYX1XtOeg5X}qHfpH}Vr=1iKHy{l1O zj;^|YU6QrnNVmE&=uXvg3fk3G3Z=jfNC1lz=KA{jnwlDgSx>RNhfnhwwzS^cvhhr8 z{xC^(WEeeYC|!^>XZ^{RyDEdMp8C?oSy_vZwmeWd26a??H{;ET6DLldv$?)U<(cSi z#ggnLM^Ap2z4&OHyZ-Z_<>-oRs+*LxxU}JM51v#F>$B&SwlwXYv*e_)lBUfIR#Y?{ zU68e+I%XtEjv}EH*ujco=8ec4bCPL(aBJKBt(z)i^M_BWaZ~kr^XxgEu*sKTdVK|U zdr>f^BvO`>ZZGhKBcbyA%#1v5pURI_$mOJ3YAMfk6b6R<j!oF@NOu(ZBaxsdHzPC7 zjqw#Ka^#gqeEIf#A06rqc#4YL{^)nwBA%QaPl$rTK_3DpJBp{2?aGxaU=9QVU@k5$ zj^SaR76oT*s#3PIzOe1V6EP;K#!b{8D75F4Mdzb8;0p{4wm<Cmg_!U@Uw)>P>WY*( z({jq>+hS2fx#lxugd1`>ay)}7d90Ajo}TBE`+`N883q2Q;@r<#Eeg_5ZaLiv6lUfW zxpM6VQL<#_dqZxgRx+R@NAc8(Vs2<?0CR0^ZL*l>oG)yC@Y5C{T{Elkf!9<2FXIh~ zl4^XY`uzo&YAHv&`3`4MlytZp|8_?)N2eZFHzEoYWMpX5hx&baY4)O!To}dTVZwW( zQ;dT~SBpdQvLOObn%$*p=q<}ha}Kv25=e8`u*a!AAFXJ@1mV~pC~y?`gD%G)k4<V6 zBap4Ju@TJY&z}c#Nl8fzk71LMwDTOK&;DHhKgJv4Ce`>*MVJ`3{*g!ozK+}+yVDgM zn36tku09`{eEI2_MbR(YM&&O^&lnsGH4!Ks8oN-DU7iMj<ix12JSWXDK(^nTo91}j zn<o-YI^Cg=+X3x}H!maC?as|)X+_F#YJVtNYOFY!QH(^krlzJ~Fev};+_Gg$43Bte z1f*5tL&dr`j-Lt2OiOpT9`DDv8-Y|^M3vYN48E&l*8Mw1Df4D_i9CD0Hxlytd~Rn3 z?aPJ}WGf2$2R0^MqwdXM*8fAYb?ep`9tqN-=CgNu-*IX-qyyd477e~(n4}svQ9uvc z(G!=$QRt6^aR5#&`o21N<`eE}+7oK!^!hz+pL*K-D5mYrs)}IYQ}4}DMal~by}kX^ zk{11$5K7nZ_4!=|Wic^g)c594D5M{@pA2)<oA0~T4*g_FHEtrdu1t+ef6$dz=#zo> zhdg-&UTtF=;s*)NsDokl`rIzBKEuWZpescu?E&=>ee@pFnP}jai@_T0llIlCSM^ia z6JVZy@%y$1Psf;~8aGvhxgboNjI-BYV0R38q2dW&p)(^bEiE(0<sTe|V?%R)Bp3)k zu9-M0FFZ!|hs*OFRF`hg^O*JGiNslhO(!=`DVK_e+XjXoMG9oQcI_IcFxj5BZ{Hrn z!#rt>2Ts~glT_ows4r0D%&_Ns0!BUoPo6!x*{O`A1m%phj7<CR%1BGkSFcZ_p#JE4 zfjgjmB(D^7=a{Y3(Uz^bxmn+yckI{^!^1o+3Qp7Co1ZGF#^WgB_vAY>Gcp~{oE)da zZg=Drc|$3VWTURWfTt`LX@9WHqyIl(%w)TM{kk5vckbL7!()_^YCN&}`+9qO`^J3n z|G$%sKtkLWhu*boR}7C)N~&>7V<lT_Yby@Tc^ik`y?b{Ik5NjhaZ6(*+l?DHbcg=o zhaX~ij8amKTN*3b+S}X3q1mDL?%f;1W0aC=+|pRd7Kuc}p*eDwmX_|>v&Zdrvq^It z<Nb;^>5`I?;^N{>n>KCSxN*aV4Mjyo>({Sew{G29O>5SyS*@v1(|1W|>C&ajvNTq* zb#``kbab?}wY9Xg5V~cP<~5r4tMlj2*VWb4*4Fy{{;H~~%F0Tg&sR}Var*S>Q>RXO zz21{2PyV9m#EBEf4LTNAEGA`H8Y|hlwBOE1=#C+M>C&YO7cSJ-*PlCguBN62*wxk5 zXV0F6_n9+i1o^MO{t9&guZtBBM+XiZP?n{!lC7tw2hxOYoix!K(v6LcmoH!DWm?=i z5D188!&^s=i$h(&3;Ser`0!z6SsE+ZdbQuf-Mo2INK5pFG$%67-ncdI)4&$bhBwX) zZ~PnNI&~53lMzu}S(e61Hu+^#3~5eeoV_K0<JJP3FfPt5yv4<#F5rz~5yTNYy0R>d cjn19>Kgsgmglhh6vH$=807*qoM6N<$g2oT@0RR91 literal 0 HcmV?d00001 diff --git a/Demo/figures/vscode-reopen-container.png b/Demo/figures/vscode-reopen-container.png new file mode 100644 index 0000000000000000000000000000000000000000..38eb61c1cdf5cbc37427142caec7382ef02337de GIT binary patch literal 19058 zcma&OWmp|eyQUr7-911c3y0tyY%PMjJ3#{kch`l71b26LcMI<B1b25B$g`h!_VIl) zbL=0mx}m7*s_w4)y3V?bU^y8O3L+umyLazUzKDw|yn6?!|9YGN5BvJvr059u^#j6A z0VMpcbcA^C^#s~PNLuLKyNXDpM}3&ra|CN~b-Q=(P`lo~Ao{-Ne|`5(0`7~bkdm{` z(K4Ev(rgRo{dWpvLbzcm3MmVGH*EGyTr2GT->27K%@xvr{{S*0{88#RYi|`Ul{kNY zf-*r$CF}DM=K;DIB|C4;4pJJPkOb?)c-TjnU!VC>%pCH0oPUwS!G*CZ_vS-!+|*rL zeEs}P3pVpia}=z+Nu75qsd3WMozY=k**<e_g*6Og>BVm<u!?*6`gUZ<i4ny7`Vm&~ z#X4zl>;8TqhVJ%Z^@Wk4MG&cO)sxq%>4?MqiCwVbZ*d}&s1(<i<WEK+(Rr>fmrr-K zRVJgJ%S5fNc!Gk00Bl5PXlQZ48`8g3hoQ(K>s(!4uAOfU?j9c><8|K$d^+n~k!P*| zhb!jE1Sk~vx3vkv{nI`R`uvx#fT)~q@7V7nn4$eT1`W$jS<b)kA(}QLc>i?$Q|f@~ zQ;c&V0NCr!8mE>WRbCW)c)gg@{ni7P-rgYmHB2b&)&$7`?G{0>C^fkH-(U2rw5S(x zIw4G`DqUKkhvK9B9S6frk*{>C#Z=-6gHBL?f0D%2+HkO6jtBQPHenUPn@Kg@qjfcP zb&|R>w8lrF!G=!D4sp#*Z7O{(e3eh5w?osE-}T?R`*3|%YL0kq2@lFQ4s161YBHJ{ zL%kDvr@wK~o_(T^LoNl)jL{v4q>p6x4A!L@5>vR;azT1)bgoX;p^N5Gu;zvASp%Kn zJAwLl_yZI@1A;61$5CxnF7LN%In<Q>lX2$!so$>iZ(pr^ee61K9{_((s3HEniOdb; z#Z5>l*E06Mi(W6^9z$Du`F!-X5$eT1fy@sN&R0%wdTkw^84pBbWytgfZp(wWV!;S0 z=l8dJt=n1_zRT4_W5Izxb<_3Av~|dmW;k_w2YVII310`}H+4`sR{ns@)w45yqlSLr zQbY-pRcEd=(*_<4mGk6bw37@yhOwu*QEPx-&@Pv5cM-}{-vcCGaeL*~1v;QCGSrHd z*6WOj*fehT#m9lHsFR5!_@U$^wWyF+ro`hHi5He8l4F*#4hd2LD$_G+nocw)a>l_X zX0uv3o@1kC^<dok1CsK2YQ_5Z+t=&S9IOxXPjEWwhKR!rtQl1dswWj>EpFdPw+Y7+ z+24CMc4Y9m$i!$94mCT!uixFnczIFTZE(imA27PDThgWAym2Y^;DcO_O#v(#wf*)< zUeJ0rD}Fo~H^3cf_XMtdZWJi#o+(l0+Exs9Jo8o8Sc390RqYmOJKcV)>%lj)FwlOg zRH=A<<dN@;N)%^FJ7;lN&NaLonA*UGp|hI-_3vFm%R<XJ4|`VvH@TL@)<v3-BR}?u z?1MC%^bbZP)nbyudY-FSmV;%TPI@y89qV0lH&U&keiqm%hk8ua)Os}%HK7uVBo)Ca zDu<ql0zW}Y!vHMpgYnR*TGLtyinf0jVe;<Rs%~tuT4`lI-OzjD%NFbS%-au@8h+n! z>fN+<7#HA4qy5Ta@GI@JzlLWK(~iyIvSoLaqRH4MCz72i{;BAa@QHZrg`(0CpZBJT zmOZf`z+_m=d1(`@S)6O780L@DIY&(bbBffJsGGZ%8hCVjRe{t0TZ^1z)1V09J0X$v z#wFElK{b4&2XP?yz3U79fXkWU<8d527kQb%@n*laWFJ}SAr!K1gmyj~X_r}CQiRCX zSm0(xABr032krOfL5B9JJZduXyizFvJ!pbH({#p@ZcXEjH_C^#$v%S~!7Ga|JeQo8 zSLY6AldI$}?exXN!9gl3+idblo}cgtsx3K6oaD6~<+Wu}8ldyHH#$E4%$N<CTST2K zQZ_Yp>hLIl^Bh3;XG#l7RY8hKbIdT==T{?+3!5Hnxx&54nXe~$V948T&Hlsy4qQjz z-wqZbDeGi<?h-b-O1xUTSb0GWv_R4=ake|~O21eq{#yFu7}EW|$$cvMROB{M>x1Nr zJeU5$^Eb85SwlYoxdks%N7xj@Yw(SjQyxJt=S|lH&_Q9vPyKo7d4c`*=1;)Hb4KY^ zj;yYj5J}C^wz9&aqaw*gk@wg86Z;In&&yRyyeFrmji-}XmfqF?E6I|+996RDSs-<5 zvGVRyrpj4P$>t}_T4x``(#WDyY8ZwcZ+&p6@jhV1$zWyws(<*7pf!>*-*r-IdHC~` zJkbkO(@_<Aod6y;fek#Lj$ff{Gg>?&X;H_CW1XSnp@zl4uuyMeP<o7_|ElkY$4`P} zcXv=w@ytl8vbi#nVewyg_u_&0k<Mf&j!w0kLsMI~>N1SBoFyGMPmvk9+nYiHfX^w{ zBPr#2FrL@$jHxg4h-;H6w<%vz$G5D4p285(%2q}D)FVH}Lc|t+n$k`=+zvwTqNXK_ ziGrMCCyBc-JX~^tkHZ!4xoQ~QG(m&eP#X4X2ef%zZhgS6v?s`9FvWnd$gX@KtRQww z&b2LG7Tr>7gGGZ)Z9i81W-Zkif0Vzd4s%cqmt$M1%T9FEOFQ)?66m(ZV@Jpz`s>Wy zijkwl1HVv(a+%3*7)*5Uijvn<gp)>`^@E!oU9ktYP;z<%_L5#U!;nAn4~#aKoLRR` z0j)OI@(Rq+=ICZzLsB`%0$Crby7w--S{mg{-g<q7OljOrYcV$lIA~_#O8W&GSBFRR z=+b62OO}P=<FeP?ITJ-!O+eXvyrkLLP=Vvg?sAV|`P@mzO<cj4IrsYVj0d6PtkO`b z#}N}(*9zV;wy~4Kd$jCNV^^-vCTNDGQ_Pk6r4DOLF!2t*BUBoEO(GU;_7r#n)K6UV zQf5q;0%M_G=l<m%HVFC)x5&lpLp?pRtKDT@>fWkO9wCkeP)%UNv}A8xXX1_R0u}~2 zq$iQkb(6Y{=sMk#Ne{?0HAVxWWQfq|NpvnZZc?4n&OO7tU4VUZWF*8OvKkHx(SG}9 zX!$&QhYx*`&nG8n_b=~rg-Ei2Yiu?{Cx$&*g7&o!_RpTQ`Mb_O`z~NlYx2hhS$RAj z?<YfdTVQBV8aPme1iprYP?oQ_CqY&KxQe}3AXm7{xBs4g>SGsk9TJF8#)VfQ7_ho# zWUsNy<wJMsyd(?_Q<$OMN@#<`*tzlWJRYsMeey9)vN){pP$!EKj^rb=DXB`aC-FL0 zV5FEv#)aB09~xn-q2n4GG($vJh?^FdLvvZlQ||a(0jl{C;%*ldjr$xN!X~8_6B&Q0 z?CCy}r;l#4_&T5sIY_4H^r;>P9ZD!Ald;egKeNW3o*lQBAKVZpvp#2b;#R<BFBszX zbHBlWpxPdd#;?0&OFL~@WF6!mvGOocPB>_y*x-vxacqNFm)R<SHP(ES=57NT$JLok zPvJ%4w`b@nU?i<-XFPs@>!NY@48h8@k*V9TM+>M~S#R|TY-E!0LJSQZC^rwdX;d`T z;A&zDKyfRXMyil=fc+=~=GuYQrXEV14wzBQ?9}FR*g!s3=W`m1QhHSbS)4Ly5!oYO zUHB9@EPz(MBJg}QL}e--5?<O)>r$#{OKH)+vGUDmcp;r+@fcB)#qEN1JoYe)dF{$t zuQ`K8(swes5J~!A@_kDUg>7eTrj)Hf9ZWjip-kJG!&q_M?L+C0c{D5~c|>?{(A~$3 zv_4bwzlp@tC1BbZ@nB!N1!02KeReaRS|SSqH*Muj@*3ehYA%98WH_cCf@pX2dKIoK zVxgX^n3Hst#CCp+OxhtfU2GjR(~$Mnl4{watUwNYMufJ<(z2uJwQhNgUKiJSfz(lJ zBh;6m>Qph&n-)HyZ(=Nz9Nl}mbvW^e(+tPr$J^r|${v5r)lbyrT>j>9ph)AWfaP{F zm})kKDzK++p2b+dbbkNN&@43F1shY_ac+-4meO%Zr#9Yq#lXKvW_@#0+j`+>H<2CB z4#eUzcGHS(RL{27_(1rqG1|KU<6|ng5)!KY(Rzp<&jxKI;NX_VUYjq%@Tki4MQ`+w zz%VSlhby35U~-r9ZW?V^Y_!0z+(~f<XBRHUiXRaP=^-|5#^A19MvM=b$b+-~61)0R zLv#tBDM!hJrJ6Tr^7Z$iEV5rPx8?c$=e~oL?mq1)^_^z_IGuqWtWb}%-(eAL_-4B{ zLYJB?jarPC(1qw+yStj4M{V$euDU1luB9|CX`c&h^Tv6rq?>i^e|p+Kvc$|pE(j<8 z&SQBS@VG9R#t-qpom0Ho(eDr{FB3Zp<3Fp+^U0Gt!uMS7WX00iXzPfJkTvFRh-|b_ z6*3t;$zd(dX(aX6+XgR+d%gE@cAcUYI(F{ASYpG+C=_eCy@VGq9IGRj=<-Hr3iRY1 zY0zuZD=4CO#*O+u{gTz^_9XPN!;{EzGhA;uPI)SADvK(u;h;dClu_5KAQs7UWWlA^ z3Y$N|CC+kaq9qQ6OM3qOs+**Gsr*U4n|e3YkjUg=ja+YXod%Qe7rxJbgsO0!*V5vv zL~@H9_hb=XvjDlBbXS;pp5{e#dIq}6yuhec%%Sz|J9b$(No3KDTszuJq|lP=JYXM2 z;Onz3=4^sJHkf^?3Rp8nIwoZLj<aWVC->xT0QbwOR`$9lA8Bgn&;<q~ZdNV4muY|> z3Cj;Wc#S>0dZxdu?{fQL^@+|Wn{u82mk|UDA0T<y9cIi0lUX#IPhtj-=m5zPlUFQ` zvm|-vlMjL=88@;bT+=R6Q60L{`ZY*-Lwzk<rcRk|Y({b6g~Z33Tr&$_`cAsfS{%wR zhk8D-+-GYuhOZFMJ+Wx)QGgGeJaoI=JZ9;bJH3OH`^p!cwOqRis-3xyxh*@be&vS( z(3VZ?Bf|)m<5tnq0<n4t5x>~$I+B7&rYj_?i^PG2>T*|e`Yejtd&EZ@fh3Zex8E>0 z@VMli-kEHdwj12VVL9B|4%L#i`zZRTm8-cA>4jw<coLqdCRl6HLd7hb+`4pslXied z;`3>|S!7{KKHh8(fKRgoX)hz>cj75Zy&68ptX#gA$BVYdS4W6i0iM5iTCxdhE^2%9 zNL!B+M2MNae>mLaakt(@7hrzEdv^ZwfpMt@JCYwG=x#Faz1}s&(8UX}G~E8#u^ZXi zX%rS$k&gevNeZJUNzf|ZFxS*>XY(#qe4QSK@$+cfsm_yU^GydiamE^lhbQ*488v!( z#wK+2`sDr1*|85=_Ln&)My-fDJ3s4(0$J;|<(t#>G?}%DmciY+%hp}n8-5{cb%D>z ztxkLKC|sWUJZzz{hIfK68yhBMn^~+k6g>Mn&|thY-iScTIP`lxXg0;{x<N=5ua1`6 z{W7xl+hb2Q4Xt>BD`?OA)8y70b}ygODqQ!|QiS0&h>H!+5PvW)OTaT8HZeGY@+2c- z|7ARw(KHtLd3xRM*zCrDg(`D1=-`yG<wZ6x&v4xEH?#k6x|1RDR&uc3w7ME<OVAUX zKxYN(WQFzJjrEJQ(G7cu?c?}%Zvz&}+{+5cw1JHXP2dXKp3wY+hLz<;0A=K93yOHI zjSLQzq*u3f*T-?5Vu?Qo?#SyNJq-r9?sI35ZSsTXcVLrFtLwsxKbov`-}!EU(l>oV zU%$q&#}N=$-7W<Elxf9olULsvnwU1~+St0_dR3Wkg?&Nbh!d_Cw>@%Q&<hf7==-Z1 z*4x1#hSRJovGc|)IV8wurV0U={V|yO(9$Eflfy1IvXt(vHL|tfKQ93%;6;l@*g~Yf z({(qcoj}13RKy(p7ymnv+5kWilNap^jr;9RsG7MmGDZs%e0}J1*F8FjiLsM1k{%Yv z@A7-!`Uz5_3ErfG;Jo+Esz=<wDT0i4GJ<8d?Glr~_@~Yq+?(e8bKTRvQQ_16O$?>u zclpnrh(X0ZYIogjYb)QZNMHT7<K0c2X4JRa(q@jzP`s8%bE~$e>!QJWcd?$jR1YRZ z9S8F3I2!Qopx29acA59-od(LAk6zr5y$eBnbN4J99DJDn90338;2Nce{LRc8T409p z_<N`x1?>m^HNS5z{a3%ps<QTl%?%6DRWkG9-i7lYPF(lnMv8v{00xv|@5_T*yw@nQ z%V0lj5*Eik`rrC{OVMP9Ox`MP60?T?2Q)wv|6}C;w|8&<x9R_9k&3fFj_t-y19WfX zV2sOu`F$klSs&YCYY#kH9H6c9Vr-jPzz0`wR-xAL3D<@C)qT=`$c^iwZrj)<w1!xs z{zFBbS#E}mw;jl(HxvRgFHqK~BD(m|kVRl+7XDhNxa%K5&~~7UEDEi_y@Jlmc2c=l zZNFs+=x#)VE%C@&$Y*U#9DgR8oJNAOZG-xpYfMQqBBj@Oj)(DGA-aDcQMr{NWM}mG zw^F|nKAZ$gnz<%1S$5)tMXk{NS~2lY{_C(ZygXP+Ch?(B@w0*czFPRzhyZK}=fkV~ zT4+jga!B(#BhCPTq`;4d8K7u?5&*VCX$9U(1T(YmOy%1GVdRS)cwv0D*}=JG=$(@X z6@3SSI9RSrCndsO5^{wWoN)VX2>$`sZvC{>mDuK4TO%nm9(7t<DE_4-2MjOYDZ9WE z(Yo*5aL2@Te-~#xeo~LPg>1SFT+7Ixk7sQAdMKK|5QKF>+Jz;V`+G6a4kiMZwN)-q z-=*JF$Lm{z*^5O~QvrU0dX6ay$NQ#i<Tj>7-|ADO{NX`SofZ+#>0yH)7A6vxUL<(g zMc<#Zx}f=36McB3z;mG6?+Ro;3?os<2`k{cq;?)&4bAnL{R}k4$%<&~&U~E=7V)Ne z2&wezwrfPw3|XSpcQfA_8S&WJ**yk1pxCh6L<}dg-@QIkoTE5exoz*-swhbJ1U-mf z2+O)E-I~s3p&aIn?rf2>B(qMZcbrXbgxt^T2;gV?*7mx&_;Q=jRvQ$3-rZ5n7VU&Q zcI8X?7>`$e|N4$-06NTnUM{r}H}_OG%fe8!t(`m^b1G0zvd37I#xj4HMz~};A_8eS zp0pW0D$pb<YHButcX)cPwF|x~-Y_dzSi+G5Gh09T`Q%D9;5{u3(LBN|EO8wT+V23F zY^CV;`sESxhCv1PyaUoI_Ri7qd6J!hMOk89X?-e*VKq%W-AKWRk*(*r9D(z4DG7e& zNl196i+tLIwwyhmCG~sclY*yu@s;FvN*t#Qzv)oXD{-oFI-HVYFc%L3HKMiL8nj}< zRk)VS3$jL+^YdhM{g)K}95Hunqwm1?X2Iah;g56TavG%2G|q+f%;{JPhbo3C?Ek3L zr!)}mVF@g&%I})w)yU3z_dK?BELQswEx2YKKqr|AFPdzu^nKN5Ay?&Idzg&Y0bqYn zt7llPVO}*9QQbP;l`GthM^i3FIE=Yo0Y7a_l#;aYfe*@P(Lj$$1{C!hVitz>fP#N! z%jz<a{%qytg0#kGw%Nohvho8Q;$~?2obaqLawLkA2dEKNpj%u`z_!B4F1k4<j_8Uz zI6qZ2Fof->hEl&v3-mg1c<Odu20>Xbw;>kcUOqi}Wla0OJf2d-@;@8WxBcR{Ocs$e zWQ}ltrW(<eUpsCXJpEyXI%UQBZ0E##eBeQHm#L4pV#6e2en^~V?EsVZGD~`Rl<YSh z$>e8TPF`Ee;XY?7G`M$B|H%lp)o%4^3^d$}TygUK<JkzDio4A*B%i8Pkgy9U?w<Xv z4|ev_t^KTy`xI}u<3P*pnXK2l;T@EGvqwnn32@TM0l(>d8xm-W<#rZ;GkryQXeod) z+ap;o+}CP2L;P6gb!S5V<6u&=^jF?;eQ~@`!_5mTsYbSM8oqp0y!Bc>(hk#v?(^hv zk4P|2zKn-I)XNi0YcpWPjp_1iT+KSjz1YUu4%m4(Z0ZOtVzNut4$VNdD^~|YZFc?x zi=zlCgTN@iz=dRSCZJ0>#jjbzr8l|@{MfAFjI1elrUGN@AfvP$(@Brw0lwj>Ff|Og zT=|KzULLoTHNnf!7X-H*NbO943?`rmQ<JolGerOnaPX+8b6l26{P{CGN#Gwfx>+{Z zliJ8LMS=|>WikFaO<UM##V_$Ec0L2P<33zM{!wj4PpOcEIu1!w*!~XC(vyZT`(D05 ztU*J#yz~!)Qt&1l9>wY|iI{y|O?x3&NNAe$uwWrDy1ez}9jKJGr7Z)Ud#gmPI%1)< z5c&YOCX+1>9c4l^SAL4y9ZCn!p>#2l!FAOR$#H6XD}4sbZ>f@y=b58Bzo67ID}idu zd)gw;&3B|F57B6zq8NZ4TMa{{{9RvG8UmR)!xSX4noKtxc}iD64@cwu1!Jrae%5L3 z8#8HOTf}QjT*)0(2XiYv2P*2y{Y)=E6Wb(@=P_AJ+f*f|@}$Z25)#@hyX4$Wxe?|) z;ycXiIe^A{I_xOs7J>rSwRQ(HF|HrOWca}`pQ&9w0h2`mq+i^LU+%2|*5@M4hBhuv zZX=sR4SToGn~|HVsbM0A#Ap$TiQ}#g`NxjXW#GOS84t{tB*-~Fp1w=B*o~+@Rr062 z$c+p)ruE$*V|Vhlg;|_BB*q@C;>?R@%}mmDPu;c8n_uqm>}Y47fyoN~<j=pAoy`Lf zbv>8BT?(j;kh6PC<8~*AkKb%5Y6hR;?Y6L=Z_m`1O5CCcDhXc*iF~*>@!JDGJ(CaZ zrK8HA9O=oLOm$TEg(GeFREk0<m*bk(z-Ek_^~)dxl*|C6PaW9^^`}4RrI2Hr=fKL- zAb``~&F->3XckQLpGf<XPX))u`lKXr;iZV>G*Y8W@EK1fE`eQD!XU>hs^!HOen5xM z!~Yu10P;i%XPhQr<@y69%T#GIP{TX2))BcZL>w9=^7AvM%o#F&=6j~%s)@qp*b)?I zHL??cC!8azfMq`6m`~HELYA5GbQ#&U1rJ;482eHWL^tfh8M;AXrsLNdq9zvJI^$rE za1S9fB?r>@Hs~abnp(MRi}ZVOhe`1)@2ro<2;-jSruoOd3RwYx3yKA(em=)=ky+BH zzkLCH=tcz7S0o#R$Qzv*eBHghu5q`b*c|=5fu9l&`tc1ne}5-Djt6=@xjP{2n)Qv3 z^2cK}AYU9S>D_BzV6dwOGYJZY57rYQ9jCzd6-=&-o!2?KAGZ=+>>xW&&2B~+uPm`x zo|3|(e6-m}MwAz<N4tTQ=?Zf@?h?6KMNu83xvy!Q#a_xt4&3u$W!ZUtI8C8re3Wgg z2&Or`zzS`4?UNcpRC@pZbFho#aS!q+OnvLm8x%GpTFAZT$rEH?_swxfbQK9UQ7`~+ z+GIYYA>JVfa^FR=LiDKj#ob26HE9jxkSO$!3rCB=95BM!1Esp-;x4w8;Q7(=mo8^i zub_Xh+-L2f^t1`5#{3H<gGTdH9d#^B$bd;2Z7w*H^rkCzzA9TPl@KaMvhZaqF1VwX ze81d>t|MYDf1#bsBht8Ur!u3<5OJVz^l(`hHf*c>Xunvm{)=1m$c^)fC}Jj_15s>t zopwFexYCT|h&@Et96&x`HUNq1GL-B4vYGlr5XZtXsn`y`a7uyIR5!M`d(dxyg}kX_ z2+1tISc-=;F^M&;@MmswcteS=-9CX6#MvKv72R9~1Lhb`2*%aQ%1+qvyX}{ON=i!3 zah0FGBD;U$9z)T7izKN0cxN%r$&P(W_egh`BW{g0`|U)|TQ#(1cU=`1^|terFigX~ zZZ@EuopQx?8_#EMEg?H*r?uV4w41o4GREtO_^a7T2LxT|1R4F;Ws=;<)f`1eo%VnZ z>RcG9oN_yuxS(VtM;H?scYn@rj{1EkFW#y*soi&USxH>mc+4mes*N@YBXltb5+6~O zT@IcGzPX+Cv3m7wm6E&u@aA?tUC)WPxi@^wa~`;qCmI=SqMo=7Vz&H1!ER~FmRJ@{ z>i7$T!-&g1<2(=|xfIoT%G^vQULz~;CDXzAX-$Z@x$&@vUC}l$=W{$GB=hVI(R`x> z0dh=dFh`K=7ZTL{>mdABn6;E}sj}*tICvp{6wwh|_%zq{!tnI~_|gznBrjCpYu<<` zc(0ryyNqVw^#u|J92F*KQb@$klI*yef;uP4jKyp9!*`(cvVM(_!U)h^zKkynUaW=^ zqlUq(RhD-<783(PKW=$sc3}I-jKpd8UA4HPz;2dhB7?|fG^XTG9}H|oW}{vgEsr}3 zHg6vXQsUiC*zS=mX`c-CBJWsaHyTWSJ;W-9=6K=?*;Ra=_lX@{Je$SBJ571mMn3=2 z*TllvPo`VDU=3W^7-X`hJ+8Nf*zo`sGS)M#4Y1wkIF9wjJ>5xX%xw`>Hp+BP%^@iN ziTv?Aq^L$j28+{TT>J>|hm~r8LwlOaTdB?lt}?W3XiT0opjAYcbdDO}LFN%wyzF+r zH1a{DMIeh!G=ehnM@3X@_=h-ni5=;rwz&HX>?vp&P{t+ha;9+VI5<1DtvmHgKxR2O zgdWJ<Q?zE!@g;<d-;(s4c-9>k^s&C^hfUp^L}k8)vyW)gC@OOWShb5orupB!wJ{+4 zbb@ndL-Z@T0r6mjt!Zmf{B$BQCK^)SPGe!pn8CgBD>7}2b-l2()Mg2c0Q?ll+*t|z zN`;1{DFH{GXTV92{sA(TedPXHhPC2?UeK?FnhbkhDN+*BY3&x~Stcp8l!Y*f#%qp7 zE14u1<21){dJX8D8r&EZ4zBL}ydo!!r!iMe`D&9k+-ZN|ql)$qvt1nJK31pqI%sF6 z(N@NDqViU!JfGg|5g(q-dQm8sS1r`XL;+E0LpWpl2x0&D<YP`E$!)2Qg2<$?iM?3e z8>-~EmJ=K@fM%sQOrMumSex^)P<L{NXH~MVOO)gpNga;cDz|U!BqLYT$hwpX(euPT z6(ihmpKk&qo5!uH`?y%2;FBux?Fmzc2AdOhn}v*s-WqnjzymSr*-8~-^2x9v_E71i zR>QNb%SdAA9X7Mz-RXzc+ayy;&g7JxQqLa;g#1=qGLxP>JJ@GPZ0rF$MJyin7mZS% z;i01CiR3F8P%ah<qtfn>Q)Nbl8jN_5H6_Z8+AVBMF241D(GJhEqg@YK@@JqqXHKAo z&_u)p4B?P_T$%I5CI>ufgpO*Z%PYtMmQ;Mhqe$axciunk<wd0``={jMB0?aFe#O>P zbcP$KQmEkJC!<zIM6@*ovMXd{m;b^w2kk9Pi|5{`XfA`r=il+0N5v2a)z^z+t4EKS z_YqoQgBR4i!$TM35=6FK=?V6@dB?bR`)A$<maxX~x?&+tY-bpOcvQ+{`XXXo`T=u) zup+*{gGmcxAi`LY|6=+1=%;EpE+UBnSCnHOIj0zuq&#(M?g1?+Q(+fC>Wf=h&J@4o zm31cH6N~vM*N3=;Y<a+*X(E2HWV+#&px?B;7xpw-@{oh!?2W7GCBhh;R6mnddb_jV z+xr^G1_N=4r{C9ivL;yQxGA`5COVn0SRwiXPysD7c*)LT4~_3-pz%b?UY}gFTD@Q- z?<e5~5L}#eCDX;BGsis>oB!D#c|a#C>v9)^Lv7QIoL$Wq8GgV`e%yd$RQ%z#roRA3 zwBiyP@zRPC{{qE_S^9I8j~LPU2Ba6!7oz<geDe(R!fM3mY26mGuN+hv!g=~~T)RQH zg}lTvGtS)BboRLz)vk;f^mM$ebmK9%Y)!0-8ne&nxY6&`5+q?W!YSa-e=5L-FQB-> zZ9{!Hr~#UpdMSdQ6GX1-f{2V4mlfnax|&N>4gJBO-2X#>f8dpscswjsGkr5!HFk`5 z{7TNwf?*R$MZw>OQCQ6&zWL@z!>(9^DgP!y7_OrJ7fo>tt=D$vj2_(jiTf9WINB{S zwh~F?D17;w_kiETeQWdKZwADNwSPbf2LhM>8-59shD80RvR~dJZ>Xks?!OmVw&god z%Ua_gXJWw!kT!Hidn;jufQ8;!43LfxGcO>patV!da!WPyh4kwJC*Q`XH7L+mfMumX zGc)FFb04?etu*;V>?We{C3ix@LAI`_Aw<OID+hlv<Z#j=Y?GP=Ft_-24KdRvY5$<S zahr$S`1Gi9tLmcxk=8R<k>ByoYu7_vie<+gsfo1F*nCJWo&K4Z_R)zCeH}zw9C(zh zRoD!)P?eINk+Xxf<h(SP`Vu*hAqS!^<E*(u`2hk92;+n<F>ifc#mB<#e8hOBBq82% z0o0+!&@Pn|AVnn*N2;;>j8=@G&YL?XVHqquL6Je7GVZ0Qs^uKx)*lKHbFI<VxykWP z^!=ew63D@Z7%071PSxwDy-2s0{|N*ok%LjJ)=iyjSTs(}|IVJU3Oz|{;f7~UK1F7W zSt8(EU*ziA<8;@q!txh{e1?W;bq09s<9q5(qRyomjXyabDOAGxsZ27a{?y<97@z+P z!N`trW&mwTHO*UuU%dz-dM;NX9Um;rTW}pyN)GA1RXaIg4ISrPoAK{_Rf|bIqonbJ ztWk;LM>H!$N#M&8;GBEns#$5SE!AX0fmVS_e$91l1xatS)Cb9(bPsi)xx?QZpN)`& zl?xtdk7c6@yX!F}{Q7=CTK_{{GgRZ@r)FhkZ|EsXucqKkbpQn(jo!CPSHI9E7+g(G zi&)%~P3cG+<0QiMb&U!RNGb|sSAVX=aRC2D*1MRv$lkp#b1GN3103|i-^>JP&C+-j zg5>gGVpl9cf}D#rU}V)nqOaG+Y`nf1tfJ%NaO>%=f0Q~)MuF<mFts_*Sq;oP=J;3k z)t$MoeoYz0Tqn<!j!?c{+rLDI+<AYRXKH$SeXSNhpGGZ^%2Eg+#_3<X)#VLp@r5HP z!3H=q<mVT398j6To6(5LmuQg(VcfaYoZ{D}Z<HYZ*-y?Nq6<)`jfGOFBFP}Y$)8sY zsI=gBwtj_j_(^J5Tr9c}CFFQSB1!T}OKVu4pg9TOB)=E#7Ystcw7$4AEheHJQ~)F* z$vDPmNmeoHsD?zn=^?+s=V;sL8Ult8Ytg`v7<swLvpsjKD2?JP=7p{wKQn?<O8hx^ zU=Z|C**F#D#&^?a7xc}qBOthwi1erTGl=4^mQV{r2@@gai{r8?aE+xgIX;MubF;yR z&x1{9PN#^5RY6_pQ)3U)N^FHUw1sukhb4>3uRzb^qB)w7fo%d_7auuL&Y9Q}YN0Ap zSfG}g4fYEU`=PC~0~=uh308T;N?Go#XwHZCot9Bu1?k?jY9bH2Er~?##cvZ&1%|X9 zJl52h$@kCoM!dDNPL~1bA?PwDoIKb3J06GBu{*1NgLV*jyJ7?4B%R3ymjh6mSuhL! zCK-x#>EjXy!?^Wb4q*HvE&Du@5i3OIXga<T)cbkg%;|G()zV%^NzNr13`MrF9{)}& zbAPb<Fg0DZD@iHA_pEnWxla+~3O~AJc-gT1|2SY+u|?1Ekuav+KcKIN?DOvm1Vf?Z zaEs$b5*ThqX_$-EHJf~ph{EP4-J8qQS}rMDPguE*7z7#C5h+Z+t{$>DPD)$DQx2F~ z3`O{tR1*)Y^14$^NqG75UD2YF^3By9GJOui_m>9>lac%WK%fpKZ0v{M?ey6OYJ9h+ zR3H-@H)dNhEwmH`iGQ%qzz&+C&3~edYU<lbu2wSg|57%yYlv=K7WDhoY!>0dKE03R zt67IvbxN;TG5I<e1eEOPTR%-u+{#e?h}}`xF?iS%<*71u;1PMiar8Ori;ush@?4u2 z6YVF8HKr3HBzBljFJcF$jj}Chq)Va0^5;lz)3BqWwEJrp@{x-}FVi=Dn<30a2{YH& zjz7Ejp`hjw$poQrfWAMbui;=p1XW;PA(BwABl_=Au4g!8@e;Ghi-<9!CCji3Y<n*+ zcrSF)|55aIu@^zij>j?f)-eRSRA8tyVOhDBEE}J=Rp-rgp|5|o^rW)5)L2f(%If?P zef^&A;rxfP1{!P2>Uw$Cj8dd)6&7I%gnop%MVXav%78vA&Snje$^aRI5)LHB>^m)^ z23X@3C9zmRcxoxxhyvA=2E{@e=Z6m{(+yDV%NW(7T**yBDB7SR9<*HiKI|>&r@InR zxK=BQic^iSd2Xk9?euktouY6&{$0pOzqeImv&7WB1$H(}S0yD<K@pjVtt+YHz(oag z&au4Qp)UvU#Nz`#E>y}rq$MZvGe9B3Utv5%kgtxgNHvdw^@N?xm7=1e7@BBHmH{$D zoUT9M*!T8w!<?^{hd^Bnc<B)nkJ+f~3efuTOl+`#7vsS?;2Gn;7Ax_`NWd>oaWbl^ z3!IB8K}`r%i=F-1j8>Q@hO(#`Dk=%_2QG&JG$r=wOwVWifsV<I7GA>jDgMy#D4FOy z!NB_ZzdENcDT`Y}FcF$o6%zX@Q%mXQD`I|4Z0oy)NGy&}90m?fZ3r~t8Qgfyh3p2S z;|N@}k`i=fqqp#T)l|~b@^p}zN(!cW|Nh<IEXdHmp*lS1H3w9}>;CTU%V0E(qScJ} z-++yO@t>uX|L1zfTOAgd|AQirB7w}2iwHYc&yurmA=!|#BRhb3G@aax@24VG$gfFx zvlvy-sq~O}?YVuo$xJ6>nHOtVM$Ym-D;~kW*j{H7FD)#>&co?FHG-sIji6>BV>($e z_tpZhItxaifdS3X`F^)udpu4kah9SE868pKq+x~amV{YwxGd0BhGpN<%H^edT(q|x zy$ask#e=WG@(M8W1!O=!O~*m{dygAng>MbfXI?z3!i{zx54~HB=<=3VdL3!9AsnBF zFdf~ROJ|W^!f}J9<%i-oUYo>!%yMhGWa_e(-Hg+^?r=D-=oj)+>q9_wCL0~u)ojuM z@C!kdH=784^!dHBjiTDX5WQIFfcN3g)y=C)%YK;<(fD)NQMT=GMgL7wJixK(lMk6K z1ONj_=LzJkL(|}p(H%IqDP;)7Bt&gavP5PD_?RN;b5uivEJ@jL@+eqz!nk@UxvTJ7 z{XSWJW2iNzevSU3RJmDGON-M@`m_>2_u{$KkY)`!O9ClQ`bAYYP?bSlrjW(?oIdS{ za3z<C1;s?&OefFKTCDKvBVP~*B!czmB^2!p1BL>EplT8-`p*f>s$!@qIb=y8>|Zgy z>nBV@v1J2{v_!x2+?82ZJ;qT{bAx6j&hOk|<-e!xri>{#2H{VNX#Q+xyA9ISbhY2} zjL9YXDVYhT1YMiNpuzWG5*5~+_<_<wEt8PJh|>xw!WbE{pQZdc{e!PZB=L@<`@W0_ z7yP!l;u?WPv@Qr%NRphTeHAZFqw%GdScsc@tv>=s0>2}5ys47l1BL|_v>H{W_%}_` zU};KLGmjFn_x7M|8v6?4!z5_1PPsy5UI}LEO+aTAyqx}c&4qE>-<NYbWw1d0#aZa- zuN!RX04E=tor8kt|0)8$Ol!_5D!zk~0xXQLq2Q0W{@GFL#7PaWOe9pY7z7HNo@~;= zQ0#gbDYF9>(NW!8p3&{PA1h3k5A0ich?m+3#;4XbY09xRe4{E$AlZ%P$C_xPe(5s7 zrLNcOb53V%`9e<S4JHL{{)?N<%?ExI*=2FGVWTM2pQdL`!=ly5!%QDt{bcj6j?T<? zELYc)nJbo|Ul89aaUr34+CM0f_1v`ofDL}au_tX`SP*i9E$7Ud$3RXYH$TPTKn%}p zS#}*?!I_K24BHk)j8Hj=;v*?3r!kQGY^ihM3W13o4p=&#v@&d{eF_`HMWsByFkfe} z5bDv)^!!WNlln-?6OZ7B(;H6;gw<<F`RZQ>^iYL`g?z}^f4o#oN(yjQBM%;@(Px>_ zWsTCxkdsqA44vuWNDG$;$0f|clyLYj`Jm8u%uJv^^Fd!k1H0Os1rtZ2?4lJ!48jpU zsMaP*ffmWfVqox#^l={jm^NkzEcqRtZ^B7ItpruWf%t{!XF3bfL*%~Jbolnh*Y3VP z3db!&XX+Ppz9=*C5W*uZYAPiS_P@{-6MfyxrzbB8TOwQuPTCatr@i?c1A|D|?s$}v zlFlm&ZoSI6$3I8`ODw{R#5=VCSw-iUP|a0&X3?>RiNkAFu4OQfq<4b<OCEUur~jN6 zvg?bh;UEM|BPTU~qn~wT7O4ry8iy~UhB(-LGIy0$LafPJ^zAMBnCnI!zt0Gyd$4*l zL>3d$pW!dsE!a9T!hLj*o#j5_V`TXi){yqLlDb4UM@~%iWaZB}XUA<=%;jVt-<r zVi`OT!HPtBja%EibW0@GE>rMlD6|vY$>nH?sE-(_D!w5hh}eAWXp=kqp_VYP;?tyb zTlP|_&T9k|Ml@nPgwsp3Y4-{qJfa@LKnwvudwxOcn+g(P``mV|GFC{KiaNVygt<Oo zryqZg>R}1mSj7ED?GW6_?+nztvpF{9+_}Dmj1r4Sk$4cFt9{0zPQ>M{bNA%WcvUpK z1-*R|c8o6aOOZCzL=GBQf8;tdxDYAC4;Dq8&rfdhQ5ZrMeUc1320@#F+qdBSt+SMr zGUPysb<w0QlO%go_G*zZbed>`50ZZ1XbXI~@FP_+0^0O!EUq94cE8hL&rOknOmS*o z<+fPTWDer>eN?s?G!EUc^Egv)&!eM%_0Q3({vjQ#AwjYsyJgY{nnfe+?kF16v55Go z+x{BBmNR?#{Tql@MXEj$A4n8tV`Q#u%@zr-nHR@x@0(T=wi^p)4Syl;*(NcX_zR4t z^nxbMf`*St26m6?#njG^x@+$7{TFC1qdD7w`fK|(K<V%`J($CAYPG#5RH78s|Hi!5 zs*~hfS_mWHq3kJ98fb*0DuvKMTaNfS*_pk~VuV~$)A@LPwhG=2^I5D)X=HoYrtT%! zC{tWAK{&Co8H6;*U(C=ttC-N#bL>;{`H4{*QKhf)Ie9b23DCFGuS=~m9UaHE=z70} zOLXH?08t|in`;fpm*F@tJjEK4twT2_J=nS6q<Xjk#W%1<O*VAr5=7ac^j1OEw<z0H zA5`9ZPYtjyLdT*7f?e@YC@?Y6kFB~}sX3!xdES4~9GOv2%`ICJHS7T<Tlt??it<|> zkQt#+;D$>?nF5gYLbkE75ofIV64{<Dqx;L70p^Pw$9K^7<OY|EbBPPRc0Qy$4FT9* zl`?cCE%k;lk>tM<q{IPZg`D*FoW@F6jX3%=;-Tdk?m=JnheQ-@qbl-Iwi09wulAL& z+3C=00nUHMK3PSBSL$KR5^)dvrD7KrOz~_$ET#lg_rrh(WlUd9+NiiU<|PdpL8VOO z>Aqr-bIbcHrlzU>Bc?(Y!mbt~0_@2?e3oY#s3D9TKfCzGAmUH+(E^uF!@>&DgOsb7 zfw`_)sQBt>=<SIie%mMFwLCcq^|mKqt+eU*r&EO&G-+PE^-0RdZ5s{wq%^e9R%j}O zS$4ZOQ)f84emGw>k>=^?Iq}J802@{RW!GXlp}(j$V^f&(QJEY(mZPT~Ncw1W`Sv~y zcm10nf{fcqz3ui-{>WVU{|K49HTQp_D)mOf@qI_c+p9-*U3;x7UK<G&-wDx@ITnXs z;8tH<%d%1(5Z;b3>Q{V_Yf!U*cLOs{L5{J@5!v`IRBoSE*w=9t!@IhH??R+*{I$6s zU#C@xVkw58;bs4gKcasUsIv^97FQt*Rrr?eR9rkZuG&ha0mDNgCE5$GJ17pxru+k$ z-5hvSdW|z3!PX94#Mmnv1z30_cLQqOA9E?cePbs)#9}eu_E}bnXuf=%xF_xmu%Z%` z!S_T*fPxEYDf%8$%3R?rKXPECn1o9gwB6#qeDbdd(SngP@mHv6(-p2G_i?`tFUv>= zcHsK3BlRb?KW)tz0cLtyUaYR&FK4O#P+3rev`$=p1)%qxpA2PLBo>I_Q;yrTQ*hr* zZjzVw>nKRK1|#XGQY$ImCzh6H)GqJ^R-{&(wjU(~<>}-^H0L5x!Hf!*F=qhyNpiN& z++#O=N_dd=0>V!t)q{L1XU`sfYVj4J`RxN=$SopGEG%DBCKMKi@8If}vC&ysCC4*A zy>I$+<J@9FRQZbnBe!`xThDL0RFo?Km4QUE06S*<HK_u@wd4ke6NOzs+ZO^GKKzS_ za5prxuveq5Zh?@r^oc@1xP0{!wT|lRjjjtsK+>0)WMreg>>mO9YCbM8VKwNN42!rL z6g$~d<>9tMNsu-n^r)|3<jr;4AC@EI<zvf*Mri$iIFikk{?9CkoC#BzV*BP2U=p@_ zaxZ;1b=-AJgoJzwX(;`sH^=~$vQ~8gL#%Hl89ki2Bya@B$J7r({#-A3Q6rRZ?@WV! z<5!iOxo!XY0F<2zwF1^=OXSMyJ#3wZPx{_>vJkYh6%}=9K92d15KUb$p{kKJW+_D# zn3sqmP6~oGGs-q>(r3k`U`@D|JkpBDT`A<20t{u_fiW0)K&}pL8Sf4LgR-!uS(T8& zIj}MAp}R$$MdrpFa%(Nq-^C^FlCWbt^wYu~9dFvKx9qey#FBzsivc;dR#z%vTz`dS z0ZKQ(gtl^Ei+NQ^{Gi7pE657V)<AJ<oF1)s`qk$<<Qn!-TLlDLk>#1u{oGSiP*=2* z^Q<BF=XlgF(TXj01<waxaaV{loV3u<_)8uER?89s^4k{rv+7%)#-1c@%vXhPO6QhN z8d2GX9PBwV_k?^<lLzhULM5_4bSc#_<IMW*nFM7_&|gH1LZ^1O-Q{=-jGN-^ZK z={cnZaVRk^0j4Tc8R?m@I56MP1#%$}{sX(NK-kph=i^-b2#bX)!t;S*rVPU%sv||v zKKg!j`^4hx#OSai0|i|2*!&WF5(Q@DejosxMS8~_V|`F1ucGK<Nz-A<m>sb~>uP|; zqd{}IXDctS=r=1lfj*%SLb3Xq7fZIT>fn%H#0#$c!1C%r)h2MG<y>y2u-o5Zg*dXw zsq&4T_Bkq|573-=M=acx6heOR9%xwp!ymDT7%Cl}{hF!(B7m8N5Rv;Awz-IOe(st{ zkeC^lu*CKAEhL<3mf2BZ%d~ES=W0>99WN72Ij}CLK*@LldIQAe-wl3Gj_~(IoEkf` zbMUUI@w*P|_Tva8IPSMF|HYqA`}^|;<<BIkzP^=pr!%BHD)m@3Vle`d-Xf<{MYig- zJ$h@(j-1#EytM}7JT`5yddrzAh*troKL~BHXK!FpoJdNh7xgdk%a0gnUo@%uNu5dF zrol>TYXA8#W`+3RV1yjLw-qQ%T*DT=g)Pyl3WR}p2l3De;gXs6Qh32dRo{z&@x&P7 zznR}lWd%~R5jOr1GHf5)jhEQZTvA|CmNi1i+T6=frppMI5fYAv8Xi_63`cckfax_p zK@W%5R4E~Cgm{YAe9bd0Al;CU`u|Zk2bn3N2huLuXhPGeOaT`0OlFh1>RW$W7;MCf z{vy$Wabe2v(|`^=_<+9gZ7jWeqQ^Naw&QR9!Y}kcDf0Puxe#Q<g!Qew@63P7Q>Yc? zdTcyF(e5~o-R;JUY>miICD4+`NS0*Sm1Wv#4r2#DI3MtdXSohB&+uZz)M5lOn>)!1 z45Nn&LI?a@h%Bv3q<z24Z_ZFnc($wPmk-^Dw`94yJDV;Ny=Bf@Dgvyo*R27M%)R3e z81NA2YU<L}C0k|y$cBp*<HzJs2~@oRPHSFMPb6ro`piU<CMjctc&DUa(cfV#D+Kuv zRMj|i5C<@IHS4oz7;2#kqKE<-eXEu5*TfDtr^rc|JYkq=^pux;t|M#5P*hdoGC$AS zbkmy0db2Hai#q!*21KE8S&-298{8xQ2kyZ}Pyu>;l4axsIRQZ_u68I6o#&1DRe}3E zd)8Mlm}C<2H~KriE@VA9p&+e_71=$9K{w!plLc*A6%olp>aPRo!HbiQtp;x-k+ga= zhh1}?Ktu2!&KaK2(2Q)m$n7a>r}VBYV1M~*axCbli(VNMF!s_p+E-SE{ctKhi`Ul_ z6t#YDPJ5grXKtJ~#{$+bD|_KHvoFi+Y>KuFZrJub_<nnkFFo(8wG5;5YQ<Tq(18c( z<B_kk1cT}SMN|I-e(C1J9}m76COglOgA+N*kZ}f&czv~Eo94)*{D8^Bf}W=$bVL@s z#1Ch4s<)~TgF)S*krgQv-$F`lN4a03fe)KNP>LGqKQkG2pWDI96|SPxFEm~d7o?IR z2VDe64D;4W#~;&glIE5Bs_<T46X*J5H8dm){&w&ID2q@tK}IgyvQV}HcZ2udxZYw? zk|@I30gmth?nSOA{(vtQf-omUf(ddhoh9&^F5Ox;{XIolWVd`|=7uq}pr&u#^-14~ z<(IK*j(k%u+J~{A^OZ80M%@Q4J**C?Lwr`4CrAq5^&c_*i5~oQ9@=WK%%X2d9c{V3 z4xPls0O;w9=4;&h^=(NczUhpg&8@SdG<$#l`-8#VRUvvk;eq}&Aj3@wZt6S8rX_|) z<6b(A=c4G0njRLm1Sdvp+O(2)-H~UE<!~$<L>Of~ad0>TJB4dZo(4ITMWpb)r<fV) zl8|*EG`w7*&#u#|N)eAq@jxGJozBsQ$>DmGzABN<u19j^94@8~VB_cjl2mqC`OPau zQtv0R^FVbHPtWNrL-WRT8PonN!beCG<q%VF;|cSnWOzvy7cpDduaS8TIEdLPP~@!% zozj~-fJcY9j<p@z_($Xan|(^mhA#}Qr=PP=XRRDISMWrNV)*=P2<(TGQR(Oz1PZi> ze3%0WYGO8)HWqk6rdh2mEk`ajVIg|ZMJeTSbM|1jevZ>PsFSDt3_UGc-K@ZgBW4$S zXC=-=HaGt6EP2ia4KelCchV{;1~MZ_C(oZlO2lUc<*cRGaZ}|_42SqlL!U-CAI3;` z$(BWCdM!?kh?ni_Hsv|#PsilN6|D$}%e3A8*Pi#1^n{`xKD=LA275?b0kSyt7kjPk zmA2nIT$vY-eCj0OLF-UR!wt!XWQo#rpYDFcpg1`y?48{gX+GEz0GyKBE<1Z<S8d~! zZ>E=`28QYg90O@<SbdWJfYT3YTsogBL&A0+Xj%5Zs_tc23*FnDR-jN(aK!3qF7Vk; z;gVk@<ek~O;)a+L<uq`O;g{#Uhmlakm?$7t-y#7oDS20y%Xec)BhOHo>izbDE&8<= zf8_{p7&S1=#@gD8Bxhtq{hh<HC%>xJ6|RvM?pv*==J-{fS1|C;CEsE6PFr}OMjL@q zn}o2nB-Qz+w2sMwz5aQ9QAN0`ZBB(93>u6U8>9&~hPkK&sjZP9`9?i#ne1g(i~b0o z&ge*!?x$Zm2tke*!a)O~nc<Vd<Bj|{k@9Z6d8%C*2(fKC{+-)AHpRqz4Eq&XXNlYz z8=eg5-&QLrQ;w_b4^0z-!hEH{srkr(@c2K4^_fQFTFV`F4*;!AR=l=9dpv%Eha^7Q z6VQMaoY%^0+m|M&pKLdeO?{>p5N+nytVD|DArJDqxL&bnu&t(>+runBKR>$U=g;qs z8xI&=@C<+TZDLnly6#-5|Hrv>jiwvCdJ!wJx9#oEmlqemVrdj}U+HZfwWb60d7<TQ z{TPauGCYMnjoL?nbskbE%Qx#H-TObZE_zCKovqLJ-`uaJRVTi6zwKPdH!L2ttXrlY zzG{5^M*!JraE-^@`V`&{PEL03UfF6dK9PUFI0aqs5SvC8qP_w2-#-aM`A(l;rbHeF zdNcDZy+DrGp>C{;*GT@l75+cF<=e?E&_TND!8t_()(Sdp%342Ph}DT`f5jRYJ!80} zytQ4Ihybq-Iva?@`<yjC_6g1|7P!$@kaX5NZg>8ysoP)4?tK2+2>$16U-ktvZPl-G z+dask1Xei7EU&OBRn#oS6%P*{`37@{pL8I%Xmz#gUmwr@po#qXyV$vGPW|3rySL#Y zE`!OU_iS_6bnZ%%56>0(?#sbhZ#Y#{lJPbaO@9tL$19Dl8R04R_<+E)C>-^?&q!>_ z<-MP2&xigAiuF&NR@&fYTSa^bmFzaflg~j&)Y~95Ay6OMd~F{hi05X7C%=dzXXL~Z z^ha<A+JZBWli4^LJ~tir6)#@U3gS2+wM77}_V*Twv;3@n7gbdG+P@Vz8<2cLBW9H3 zj$VW@Dz4}={<p#V$WJM}kBBqRT$o7RfT@8R0Pn=>CPQqa3Aera3HW6R*Aon64uM&f zYeRZ9<vo6@MIyDAO;dVpW)R`LCSi*IBO0vauQ==5ExyCFsKEWg66bRts(7+bWRj$} z2oqkF{stI(kMHi30&|o&Y@Vl71$OBkz&j0LT}iDwB>GzAxDE!2np6suaS{$kx@mUK zybcimE4~In`BuK-eW2P|w;8LVy=|hQHjQ4j8FhUPPRH?<E0WGF+I0OJN99MKmvE#k z6+fnPh*7;ck#yc~&VVLkj4^ggy9sl`&f(<SdvN4Dg)(V4h{DQC&mj9qC|-QG8O^(1 zz^wi2vA)uq3eMGS!ZVwXV)2%D(A@kEwk$r1&ChJY2U6$XiT^&*iTk%Up!v@Y*j4xd z&b*R})G~SY76qA~r|!h%Cx4Fy+W)G)4KM%vC3v%6Cyq()JxK3u#ydsJV0&pjULI-M z)VY&5ax4Td9Bjs)|9k+yiM@=S>tDhL*G$klhB{Lx7C)JSB~s!V=p<fA{W<motU*OX zGa4$^AYkXu`^r9w^E^=4jL$y%42~18B2H|W6^9qAM1B5@16!Bi*h|^iImkq|%WX$+ zWX2j)H`B2js<9^EZLH6JLk@sP@ygntWB<(OP}Tfryt8Eqj&7!QIV!yqZHG-bum26T z=b!0XZN&p)9v)<jF~-<nCMbkmhABG|OBaaItcCbrKYtsSA9w+oKcsYW=`h}S`yBMo zy@(%%%tX+VC-K~x5FFWmnBv+wnBJ%Zp4^J9aq|%rG#_zWx8h0EVW+8g2xcl~28GbR z5G?s&E`IX@g^!(YP?VqyR#%C`p=<DB$`S<448a30JO}-`!>BvveP`c$gRms-IXt<n z4M&dn4han*U<QIhf~4~N@VPa3;PMe1w#oah>O?1{nxLRr^7;TrcH)g=%kaY16fC1- zg)B?K))y!U%4L@fd!7JknL5=c;Y|&~{P{tcIddlF|6~pHL2WpCO}V@Rrp`bJ)jKF; z8Pd~!h=8Mqz2`mhhE%TSUi=B>i{r$-fHg~OIDELbT>=mg5`qxgC(6bdj4{R-8y^!C z!UFKXi|^oI!$DN1-H#dfzksUh6wDX9&YwXiEqi{x(EEssmPcNu<Z$jB&Qp+SYrBk) zP~QpVAqWk*jLx>f9s$zc`5~Cm*(QzZbhe$r<^O&e56Q=!v+(EGf0>Ru=p!@=JTn4t z`SLYGTEi2MSpzQP{CRo(DiNNj44r4>_5LnVLhGDCVa8{gRuF}o0J-ef81g)Q&K;@5 z`c>i)<^n8Onu<3%M>%thg5u2cm!x@SqFim4O~{Uv+iXrG@{Z7D8lt@!V~jC2J|=KZ zm<T0eG^z;Cp$wZU<>zEGW?@FaEUc+Mj?X{;yl;6oo#K{wPXO9%{U$8I))pX*!VE@) zv-6aG#0bp{3KsznY(azXaX<eHe)B``YbVxX=pUGYV{gAb=vP}z6{Aq++u)mRI@{W) z?4s5q384Q`WV-AdvW{YBb{<aNUxb5yK7kX>6?ig4jFyd({8Fi0Gh*?ZKl`@X=V;iv z%=-ey7-Ni0h>4#QHgyTow*Ca2FKvP}?Q7}-NcqWByq%wiw~w}=^IRv|P98;@G+H$i zv1|0e8=JAY?j$-pPvV2koACzXutwkeAnY7$AAEqLlxEtFyn)TH97bsDlMs<%{!i%7 zqb1l}b{Ho+&*5BW8;+j5StB}A@xvEhzyobBBRT06ynW;(+9+h5Jn{kFc>4%0iLbp_ zd;~9VuEY_k?3LL3@)0av^CXtYM;O`+goMn%(fxHeB1W!`Qrpnhs{?$OFUb?>ufwt@ z@mR=Vyqx!jRIYP$Jx<c`2OT_Qj4{U8xVZ@v^C_Mzdk!x=a1t-)zfGO{R6MYy3PsD> z@N!Z#A{RztWpdutPwUN$`wf0CCYk3wg2>26u<6(mZ2f&9e&{n9sq^qlcxGiJqABd0 z(f<a&eL;>fAu0H+nDGAgdOQ-j5Z{abG1iwH8T@hIM4<Ek{@vf=u^Dw#w}%iN9gRnR z{t^YUPMpDfJXi5sthu}ssnJw+@d1K0zePp5^pJK06!0>05qItttok0c*Uw*usci|K z+xh~6OlzqPzl((nlkhe|5i;gUTT75z@f*aRE5pyJO&5MI8p+u^aqPNN9b=3!#zy0| z_V)I##lQG1mVkf&+;!Jo@~%FA``h2-pC;P}Sif`=0$y!K(F5`(#u#Iav0KQUcit)g z)aUHkv(le_etyz2Wy+MBGZMxaV~jDz`um2BgfYe#V~pL}#&sm@w%cx#e`1U=#u#Hm z8B1mwRR|M_jWNa;V~h=NESYIkA?%Jj?ts6)KaYqp#u#Ia4MJojk(ESd8m&>y3H$o% zui<vP(cRrG{md9+j4{Ug^oB5{QaR|L)nIeNMis&sV~jDz*!APDs9=mS#u&RL0RKOl WR-gSv73}>00000<MNUMnLSTX@1?yG- literal 0 HcmV?d00001 diff --git a/Demo/figures/vss.drawio.svg b/Demo/figures/vss.drawio.svg new file mode 100644 index 0000000..bb9445d --- /dev/null +++ b/Demo/figures/vss.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="291px" height="116px" viewBox="-0.5 -0.5 291 116" content="<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2"> <diagram id="qchfyPlCbnvhXIaJ2EZ1" name="Page-1"> <mxGraphModel dx="437" dy="397" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="2" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;DemoExecutable&amp;nbsp;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;align=right;verticalAlign=top;spacing=1;spacingRight=3;" parent="1" vertex="1"> <mxGeometry x="80" y="154" width="290" height="115" as="geometry" /> </mxCell> <mxCell id="3" value="VssProvider" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="100" y="190" width="90" height="60" as="geometry" /> </mxCell> <mxCell id="4" value="VssConsumer" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;" parent="1" vertex="1"> <mxGeometry x="250" y="190" width="100" height="60" as="geometry" /> </mxCell> <mxCell id="35" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="4" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="36" value="" style="edgeStyle=none;html=1;endArrow=none;endFill=0;" parent="1" source="34" target="3" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="34" value="" style="shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=0;" parent="1" vertex="1"> <mxGeometry x="210" y="210" width="20" height="20" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> "><defs/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="2"><g><rect x="0" y="0" width="290" height="115" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 287px; height: 1px; padding-top: 6px; margin-left: -1px;"><div style="box-sizing: border-box; font-size: 0; text-align: right; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 14px;">DemoExecutable </font></div></div></div></foreignObject><text x="286" y="18" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="end">DemoExecutable </text></switch></g></g></g><g data-cell-id="3"><g><rect x="20" y="36" width="90" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(65, 149, 201);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 66px; margin-left: 21px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">VssProvider</div></div></div></foreignObject><text x="65" y="70" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">VssProvider</text></switch></g></g></g><g data-cell-id="4"><g><rect x="170" y="36" width="100" height="60" fill="#ffffff" stroke="#4195c9" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(65, 149, 201);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 66px; margin-left: 171px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 14px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">VssConsumer</div></div></div></foreignObject><text x="220" y="70" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="14px" text-anchor="middle">VssConsumer</text></switch></g></g></g><g data-cell-id="35"><g><path d="M 150 66 L 170 66" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="36"><g><path d="M 130 66 L 110 66" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="34"><g><ellipse cx="137" cy="66" rx="7" ry="7" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: rgb(0, 0, 0);"/><path d="M 140 56 Q 150 56 150 66 Q 150 76 140 76" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 0000000..617ee8b --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,20 @@ +# IDE's +## Jetbrains IDE's +.DS_Store +.idea + +## Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Sphinx API documentation +doc/_api/ + +## General documentation +**/_build/ +**/_release/ +**/_temp/ diff --git a/Documentation/README.md b/Documentation/README.md new file mode 100644 index 0000000..9bd38c0 --- /dev/null +++ b/Documentation/README.md @@ -0,0 +1,11 @@ +**Table of contents** +[1. Introduction](contents/10_introduction.md) +[2. Building blocks](contents/20_building_blocks.md) +[3. Glossary](contents/30_glossary.md) + +# Documentation + +The following documentation introduces to motivation and concept of this project, i.e., an +Application Framework for automotive HPC projects. It further provides technical details of the +building blocks it is made of. A glossary section finally lists terms and abbreviations that are +used in this project. diff --git a/Documentation/contents/10_introduction.md b/Documentation/contents/10_introduction.md new file mode 100644 index 0000000..f721fe9 --- /dev/null +++ b/Documentation/contents/10_introduction.md @@ -0,0 +1,53 @@ +# Introduction + +This project addresses application development and integration for µP-based Electronic Control Units +(ECU) in the automotive domain. + +The starting point for the project is illustrated by the below stack view on a µP-based ECU. From +bottom to top, hardware gets abstracted by an optional hypervisor but definitely by some POSIX +operating system (OS). Distributed communication is then realized an top and covered by middleware +solutions, for example based on SOME/IP or DDS. The application layer sits on top and directly +interfaces with the services or mechanisms of the lower layer middleware respectively. + +<img src="./figures/stack-today.svg" alt="Schematic illustration of HPC stack according to state-of-the-art." width="340"/><br> + +For applications that get developed according to the AUTOSAR Adaptive standard, the middleware stack +and its ara::com interface is given. The model-driven workflow related to the solution, however, +comes with extensive front loading. All details need to be modeled, which makes it difficult to +implement agile work modes in bigger projects at the side of an OEM or Tier-1. Architecture and +modeling work is often separated from the development teams, which makes efficient and constructive +collaboration a difficult endeavor. + +Another group of applications is based on graphical engineering and development tools. Modeling in +graphical UML tools as well as GUI-supported development (for example in MATLAB Simulink) cover the +development and test journey to a large extent. Integration with a middleware stack below, instead, +is often cumbersome and far from straight-forward. Also tool lock-in is a problem. Applications or +algorithms that once got developed and tested in such an environment are hard to migrate to +different eco-systems. This keeps especially the suppliers in the automotive field from reaching +their goal, namely *Software as a product*. In other words, applications that are developed in a +middleware-agnostic way and ready to be sold, no matter what middleware stack is running in the +target system. + +The last application type represents code-first development. That is, algorithms and logic that is +developed irrespective of automotive standards and independent of commercial tools. This modern +approach comes natural to engineers and computer scientists without automotive background. +Programming language skills and an IDE with helpful plugins is all they need. When starting in +automotive projects, this target group is confronted with automotive-specific terms and APIs for +established communication patters as for example pub-sub messaging or remote procedure calls. + +In sum, different workflows, patterns, file formats and models exist. The complete field of +application development for high-performance machines in the automotive sector is extremely dynamic. +Terms that are used all over the place are linked with varying definitions. Even the term +*Application* has different meaning for different people, which makes discussions on the topic +troublesome and fruitless. In the end, integration of software building blocks and especially the +reuse are complicated. Productivity decreases, integration in and migration to series projects +remains a hard task. + +<img src="./figures/stack-new.svg" alt="HPC stack with Application Framework included." width="340"/><br> + +This situation in mind lead to the idea of an *Application Framework* and finally to this project. +The concept can be shortly summarized as follows: Plan is to introduce a new, thin, modeled and +generated layer to the µP stack that also comes with a complete workflow and corresponding tool to +work with it. This way, lower-layer independent design, implementation, and test of distributed +applications shall become easier and more straight-forward for either of the above-mentioned target +groups. diff --git a/Documentation/contents/20_building_blocks.md b/Documentation/contents/20_building_blocks.md new file mode 100644 index 0000000..672ab4e --- /dev/null +++ b/Documentation/contents/20_building_blocks.md @@ -0,0 +1,26 @@ +**Table of contents** +[1. SW architecture](21_sw_architecture.md) +[2. Workflow](22_workflow.md) +[3. Model](23_model.md) +[4. API](24_api.md) +[5. Configuration](25_configuration.md) +[6. Platform support](26_platform_support.md) +[7. Code generation](27_code_generation.md) +[8. SW library](28_sw_library.md) +[9. Testing](29_testing.md) + +# Building blocks + +The *Application Framework* is a compile-time solution that puts the focus on the executable. The +essential building blocks of the framework are illustrated below. The workflow covers all steps, +from project creation over modeling and configuration, import of design artifacts, generation, +build, and test. The software architecture on executable-level is completely modular as illustrated +on the right-hand side. Generated and static code artifacts that are provided by the framework go +hand in hand with code that is added or integrated by the developer in the scope of so-called +application modules. + +<img src="./figures/af-concept.svg" alt="Application Framework building blocks and executable architecture." width="1200"/> + +> **The definition of *Application* in this project is clear and unambiguous:** +> An *Application* is of distributed kind and considered a thematic bracket. On technical level it +> can consist of 1..N executables. Each executable in turn can consist of 1..M application modules. diff --git a/Documentation/contents/21_sw_architecture.md b/Documentation/contents/21_sw_architecture.md new file mode 100644 index 0000000..c315ced --- /dev/null +++ b/Documentation/contents/21_sw_architecture.md @@ -0,0 +1,108 @@ +# Software architecture + +The following subsection describes the software architecture on executable-level as implemented by the Vehicle Application Framework (VAF). + +A VAF executable consists of application modules whose tasks are orchestrated by the VAF control +module. Each application module can access platform and internal communication provider and consumer +modules to handle communication with the outside world of the application module. The communication +contract between an application module and a communication module - either platform or internal +communication - is defined by a module interface. This ensures a clean separation between +application modules and communication modules, be it platform or internal communication. + +The individual components are described in more detail below. + +## Module interface + +A module interface is a communication contract between application modules and respective deployable +communication modules. A concrete module consists of a set of DataElements and a set of Operations. +Here, a DataElement is used to exchange data that is modeled by a datatype, whereby the datatype can +be either a basic type or a modeled complex type. Operations, on the other hand, provide the +communication pattern of a remote procedure call. Here too, both the return value and the parameters +of the procedure call can be either a basic type or modeled as complex type. Each module interface +belongs to one of the following categories. It is either a *Consumer* interface, i.e., it consumes +data elements and operations, or it is a *Provider* interface, i.e., it provides data elements and +operations. +Depending on the consumer or provider role, the module interface contains corresponding API +methods for each DataElement and each Operation of a module interface. These API methods are +described in more detail in the [VAF API](24_api.md) section. + +The overall structure of consumer and provider module interfaces is given below: +<img src="./figures/arch-module-if.svg" alt="arch-module-if" width="800"/><br> + +## Application module + +An application module is the place where the user's business logic is to be implemented. Interaction +between application modules and the *outside world* takes place via consumer and provider +communication modules. There exist two flavors of the those modules, internal communication modules +and platform-related modules. The application module itself is separated into a base class and a +specialization. The specialization contains pre-generated method stubs that a software developer can +implement. Helper comments are generated to those stubs as to guide users of the framework. The base +class is used to hide all aspects that a software developer does not necessarily have to deal with. +For each communication module in use, the base class provides a shared pointer of the respective +module interface type. By that, an application module does not dependent on a concrete communication +module deployment. Concrete deployments instead can be injected on start up via the control module +using the pattern of *dependency injection*. The base class is also derived from the control +interface. Control interface methods are used by the control module to manage and orchestrate the +application modules at startup and during execution. + +The overall structure of an application module is given below: +<img src="./figures/arch-app-module.svg" alt="arch-app-module" width="800"/><br> + +## Internal communication module + +The internal communication module handles the communication between application modules within one +executable for a given module interface. Both categories, *Consumer* and *Provider* communication, +are implemented by one internal communication module. Thus, the internal communication module class +is a specialization of a provider and consumer module interface. The internal communication module +class is also derived from the control interface. Control interface methods are used by the control +module to manage and orchestrate the internal communication modules at startup and during execution. + +The overall structure of an internal communication module is given below: +<img src="./figures/arch-internal-com-module.svg" alt="arch-internal-com-module" width="800"/><br> + +## Platform provider module + +The platform provider module handles communication between application modules and a platform +middleware in the role of a *Provider*. The platform provider module class is therefore a +specialization of a provider module interface. It acts as glue for a specific middleware that +uses it, such as SIL Kit for example. The platform provider module class is also derived from the +control interface. Control interface methods are used by the control module to manage and +orchestrate the platform provider modules at startup and during execution. + +The overall structure of a platform provider module is given below: +<img src="./figures/arch-provider-module.svg" alt="arch-provider-module" width="800"/><br> + +## Platform consumer module + +The platform consumer module handles communication between application modules and a platform +middleware in the role of *Consumer*. The platform consumer module class is therefore a +specialization of a consumer module interface. It acts as glue code for a specific middleware that +uses it, such as SIL Kit for example. The platform consumer module class is also derived from the +control interface. Control interface methods are used by the control module to manage and +orchestrate the platform consumer modules at startup and during execution. + +The overall structure of a platform consumer module is given below: +<img src="./figures/arch-consumer-module.svg" alt="arch-consumer-module" width="800"/><br> + +## Control module + +The control module is the core component of a VAF executable. It manages the creation of the +contained application and communication modules, their initialization, starting, and stopping. It is +also responsible for the periodic processing of tasks that belong to application modules in an +execution thread. The basis of the control module is the class `ExecutableControllerBase` and its +specialization `ExecutableController`, which is generated according to the given model. The +specialization must be instantiated in a main function and its member method `Run` must be executed. +A corresponding main function is also generated by the VAF code generators and does not have to be +created by the user. The `Run` method triggers the initialization and start of the contained +modules. In addition, a user-implementable call-out, the `UserController`, is triggered in the +initial phase so that a user can add specific code artifacts there. +The `UserController` is a specialization of the `UserControllerInterface` and a stub is generated +for it, which does not need to be modified if no special need by the user is given. The +specialization `ExecutableController` also contains the `Executor` class, which holds the `Executor +Thread` and manages the periodic processing of the tasks. All tasks of one module are additionally +managed by the class `ModuleExecutor`, inherited via its parent class `ControlInterface`, such that +all tasks of one module can be activated or deactivated together. Within the control module, a task +itself is stored in the class `RunnableHandle` + +The overall structure of the control module is given below: +<img src="./figures/arch-control-module.svg" alt="arch-control-module" width="800"/><br> diff --git a/Documentation/contents/22_workflow.md b/Documentation/contents/22_workflow.md new file mode 100644 index 0000000..8922f74 --- /dev/null +++ b/Documentation/contents/22_workflow.md @@ -0,0 +1,32 @@ +# Workflow (vaf-cli) + +According to the introduction, the Vehicle Application Framework (VAF) is not only a layer in the µP +stack but also a tool and associated workflow that facilitates the work with this stack layer. +The workflow can be divided in three parts, each one represented by a specific project type. The +below figure illustrates the optional and mandatory steps on interface, app-module, and integration +line. + +<img src="./figures/vaf-map.svg" alt="vaf-map" width="600"/><br> + +The interface project marks the optional starting point. This project type allows the consolidation +of available design artifacts, for example provided in an Interface Description Language (IDL) or a +signal/service catalogue representation. Imported information from there can be modified or extended +by using the Configuration as Code (CaC) solution in Python that comes with the framework. Last step +on this line is the export of created design artifacts to the VAF model data exchange format. + +The next line covers design/implementation/test of application modules. Interface definitions can be +imported but not necessarily have to. The complete functionality from the interface line is also +available for the app-module projects. Also here, CaC plays a central role for modeling and +configuration of the application module. Model exchange format creation directly based on that the +code generation step provide the necessary code, build environment, and test files and stubs to +start development and test of the application module. + +Final workflow step is the integration of application modules on executable-level. Application +module projects can be imported or created in place. Again CaC is in place as user front-end for +instantiation and mapping in this project type. The flow ends with model plus code generation +followed by compile and link step that eventually produce one or more binaries for execution. + +The complete workflow is covered by a command-line tool. Please find a tree representation of all +included commands below. + +<img src="./figures/vaf-cli.drawio.svg" alt="vaf-cli-commands" width="700"/><br> diff --git a/Documentation/contents/23_model.md b/Documentation/contents/23_model.md new file mode 100644 index 0000000..599f2f7 --- /dev/null +++ b/Documentation/contents/23_model.md @@ -0,0 +1,354 @@ +# Model (vafmodel) + +The underlying data model that is used as sole input for all generation steps is available in form +of a [Pydantic](https://docs.pydantic.dev/latest/) model named *vafmodel*. A JSON schema can also be +generated from this representation to enable the import and export of JSON files to and from a given +vafmodel instance. In the following, the basic structure of the vafmodel is presented. + +## MainModel + +The root of each instance of a vafmodel is given by the **class MainModel**. It consists of the +following members: +- **schema_reference**: Is an optional string with field alias "$schema", where the string should + contain the location of the JSON schema file if set, to help other tools that allow schema + validation to do this with the exported JSON. +- **BaseTypes**: Is a list of BaseTypes. The class BaseType is presented below. +- **DataTypeDefinitions**: Is a list of DataTypeDefinitions. The class DataTypeDefinition is + presented below. +- **ModuleInterfaces**: Is a list of ModuleInterfaces. The class ModuleInterface is presented below. +- **ApplicationModules**: Is a list of ApplicationModules. The class ApplicationModule is presented + below. +- **PlatformConsumerModules**: Is a list of PlatformModules. Here, in the role of a module interface + consumer from the perspective of an application module that uses this module. The class + PlatformModule is presented below. +- **PlatformProviderModules**: Is a list of PlatformModules. Here, in the role of a module interface + provider from the perspective of an application module that uses this module. The class + PlatformModule is presented below. +- **Executables**: Is a list of Executables. The class Executable is presented below. +- **SILKITAdditionalConfiguration**: Is an optional member that contains the necessary information + for the provision of the SIL Kit consumer and provider modules. The class + SILKITAdditionalConfigurationType is presented below. + +## BaseType + +The **class BaseType** is an enum type with which can take the following values: +- "int8_t" +- "int16_t" +- "int32_t" +- "int64_t" +- "uint8_t" +- "uint16_t" +- "uint32_t" +- "uint64_t" +- "float" +- "double" +- "bool" + +Each of these literals stands for an intrinsic datatype of the target language C++. + +## DataTypeDefinition + +The **class DataTypeDefinition** is a container for complex datatypes with the same namespace. It +consists of the following members: +- **Namespace**: A string value containing the namespace as value. +- **Strings**: Is a list of Strings. The class String is presented below. +- **Enums**: Is a list of VafEnums. The class VafEnum is presented below. +- **Arrays**: Is a list of Arrays. The class Array is presented below. +- **Maps**: Is a list of Maps. The class Map is presented below. +- **TypeRefs**: Is a list of TypeRefs. The class TypeRef is presented below. +- **Structs**: Is a list of Structs. The class Struct is presented below. +- **Vectors**: Is a list of Vectors. The class Vector is presented below. + +## Strings + +The **class String** defines a string type. It has only one member: +- **Name**: A string value containing the name of the string type as value. + +## VafEnum + +The **class VafEnum** defines an enum type. It consists of the following members: +- **Name**: A string value containing the name of the enum type as value. +- **BaseType**: Is an optional DataTypeRef. The class DataTypeRef is presented below. +- **Literals**: Is a list of EnumLiterals. The class EnumLiteral is presented below. + +## EnumLiteral + +The **class EnumLiteral** defines a literal of an enum datatype. It consists of the following +members: +- **Label**: A string value containing the name of the label as value. +- **Value**: An integer value containing the value of the enumeration for given label. + +## Arrays + +The **class Array** defines an array type. It consists of the following members: +- **Name**: A string value containing the name of the array type as value. +- **TypeRef**: A DataTypeRef referencing to the base type of the array. The class DataTypeRef is + presented below. +- **Size**: An integer value containing the size of the array. + +## Maps + +The **class Map** defines a map type. It consists of the following members: +- **Name**: A string value containing the name of the map type as value. +- **MapKeyTypeRef**: A DataTypeRef referencing to the key type of the map. The class DataTypeRef is + presented below. +- **MapValueTypeRef**: A DataTypeRef referencing to the value type of the map. The class DataTypeRef + is presented below. + +## TypeRefs + +The **class TypeRef** defines a typeref type. It consists of the following members: +- **Name**: A string value containing the name of the typeref type as value. +- **TypeRef**: A DataTypeRef referencing to the referenced type of the typeref. The class + DataTypeRef is presented below. + +## Structs + +The **class Struct** defines a struct type. It consists of the following members: +- **Name**: A string value containing the name of the struct type as value. +- **SubElements**: Is a list of SubElements. The class SubElement is presented below. + +## SubElement + +The **class SubElement** defines a sub element of a struct. It consists of the following members: +- **Name**: A string value containing the name of the struct sub element as value. +- **TypeRef**: A DataTypeRef referencing to the base type of the sub element. The class DataTypeRef + is presented below. +- **Min**: An optional floating point value representing the minimum value that the sub element can + have as a value. +- **Max**: An optional floating point value representing the maximum value that the sub element can + have as a value. + +## Vectors + +The **class Vector** defines a vector type. It consists of the following members: +- **Name**: A string value containing the name of the vector type as value. +- **TypeRef**: A DataTypeRef referencing to the base type of the vector. The class DataTypeRef is + presented below. +- **Size**: An optional integer value containing the initial size of the vector. + +## Executable + +The **class Executable** defines an executable. It consists of the following members: +- **Name**: A string value containing the name of the executable as value. +- **ExecutorPeriod**: A string value containing main executor period of the executable as value. +- **InternalCommunicationModules**: Is a list of PlatformModules defining internal communication. + The class PlatformModule is presented below. +- **ApplicationModules**: Is a list of ExecutableApplicationModuleMappings. The class + ExecutableApplicationModuleMapping is presented below. + +## ExecutableApplicationModuleMapping + +The **class ExecutableApplicationModuleMapping** defines a mapping of an application module to the +executable. The mapping includes in particular the concrete instantiation of the abstract +instantiations of the provided and consumed module interfaces of the application module. +- **ApplicationModuleRef**: A ApplicationModuleRefType referencing to the application module. The + class ApplicationModuleRefType is presented below. +- **InterfaceInstanceToModuleMappings**: Is a list of InterfaceInstanceToModuleMappings. The class + InterfaceInstanceToModuleMapping is presented below. +- **TaskMapping**: Is a list of ExecutableTaskMappings. The class ExecutableTaskMapping is presented + below. + +## InterfaceInstanceToModuleMapping + +The **class InterfaceInstanceToModuleMapping** defines the concrete instantiation of the abstract +instantiation of an application module with an platform module. It consists of the following +members: +- **InstanceName**: A string value containing the instance name of the provided or consumed + interface of the application module as value. +- **ModuleRef**: A PlatformModuleRefType referencing to the platform module. The class + PlatformModuleRefType is presented below. + +## ExecutableTaskMapping + +The **class ExecutableTaskMapping** defines the mapping of an task of an application module to an +executable. It consists of the following members: +- **TaskName**: A string value containing the task name as value. +- **Offset**: An optional integer value containing the execution offset as value. +- **Budget**: An optional string value containing the budget of the task value. + +## ApplicationModuleRefType + +The **class ApplicationModuleRefType** is an annotated ApplicationModule for resolving the +referenced ApplicationModule, which is referenced in the JSON representation via a string value that +contains the namespace path to the referenced ApplicationModule . The class ApplicationModule is +presented below. + +## ApplicationModule + +The **ApplicationModule** class defines an application module that consists of tasks to be executed +in an executable, as well as provided and consumed module interfaces that are used by the tasks for +data exchange and remote operation calls. It consists of the following members: +- **Name**: A string value containing the name of the application module as value. +- **Namespace**: A string value containing the namespace of the application module as value. +- **ConsumedInterfaces**: Is a list of ApplicationModuleConsumedInterfaces. The class + ApplicationModuleConsumedInterface is presented below. +- **ProvidedInterfaces**: Is a list of ApplicationModuleProvidedInterfaces. The class + ApplicationModuleProvidedInterface is presented below. +- **ImplementationProperties**: An optional class of implementation properties for the application + module. The class ImplementationProperty is presented below. +- **Tasks**: Is a list of ApplicationModuleTasks. The class ApplicationModuleTask is presented below. + +## ApplicationModuleProvidedInterface + +The **class ApplicationModuleProvidedInterface** defines an abstract instantiation of a provided +module interface within an application module. It consists of the following members: +- **InstanceName**: A string value containing the instance name of the provided interface of the + application module as value. +- **ModuleInterfaceRef**: A ModuleInterfaceRef referencing to the module interface of the provided + interface of the application module. The class ModuleInterfaceRefType is presented below. + +## ApplicationModuleConsumedInterface + +The **class ApplicationModuleConsumedInterface** defines an abstract instantiation of a consumed +module interface within an application module. It consists of the following members: +- **InstanceName**: A string value containing the instance name of the application module consumed + interface as value. +- **ModuleInterfaceRef**: A ModuleInterfaceRef referencing to the module interface of the + application module consumed interface. The class ModuleInterfaceRefType is presented below. +- **IsOptional**: A boolean value with value "TRUE" if the application module consumed interface is + optional otherwise "FALSE". + +## ImplementationProperty + +The **class ImplementationProperty** defines the implementation properties of an application +module. It consists of the following members: +- **GenerateUnitTestStubs**: A optional boolean value with value "TRUE" if unit test stubs shall be + generated for the application module otherwise "FALSE". If it is not set, no unit test stubs are + generated. +- **InstallationPath**: An optional string value containing the installation path within an + integration project of the application module as value. + +## ApplicationModuleTasks + +The **class ApplicationModuleTasks** defines a task within an application module. It consists of the +following members: +- **Name**: A string value containing the name of the application module task as value. +- **Period**: A string value containing the period of the application module task as value. +- **PreferredOffset**: An optional integer value containing the preferred offset of the application + module task as value. +- **RunAfter**: A list of string values, each containing the name of an application module to run + after as value. + +## PlatformModule + +The **class PlatformModule** defines a realization of a module interface via a specific platform. It +consists of the following members: +- **Name**: A string value containing the name of the platform module as value. +- **Namespace**: A string value containing the namespace of the platform module as value. +- **ModuleInterfaceRef**: A ModuleInterfaceRef referencing to the module interface of the platform + module. The class ModuleInterfaceRefType is presented below. +- **OriginalEcoSystem*: An optional OriginalEcoSystemEnum indicating the platform type. The class + OriginalEcoSystemEnum is presented below. If not platform type is given it is defined to be + internal communication. +- **ConnectionPointRef**: An optional ConnectionPointRefType referencing to the connection point of + the platform module. The class ConnectionPointRefType is presented below. + +## OriginalEcoSystemEnum + +The **class OriginalEcoSystemEnum** is an enum type which indicates the platform type of the +platform module. Supported is: +- "SILKIT" + +## ConnectionPointRefType + +The **class ConnectionPointRefType** is an annotated SILKITConnectionPoint for resolving the +referenced *ConnectionPoint, which is referenced in the JSON representation via a string value that +contains the namespace path to the referenced *ConnectionPoint. The class SILKITConnectionPoint is +presented below. + +## ModuleInterfaceRefType + +The **class ModuleInterfaceRefType** is an annotated ModuleInterface for resolving the referenced +ModuleInterface, which is referenced in the JSON representation via a string value that contains the +namespace path to the referenced ModuleInterface . The class ModuleInterface is presented below. + +## ModuleInterface + +The **class ModuleInterface** defines an interface consisting of data elements and operations. It +consists of the following members: +- **Name**: A string value containing the name of the module interface as value. +- **Namespace**: A string value containing the namespace of the module interface as value. +- **OperationOutputNamespace**: An optional string value containing the operation output datatype + namespace as value. +- **DataElements**: Is a list of DataElements. The class DataElement is presented below. +- **Operations** : Is a list of Operations. The class Operation is presented below. + +## DataElement + +The **class DataElement** defines an element with message semantics in a module interface. It +consists of the following members: +- **Name**: A string value containing the name of the data element as value. +- **TypeRef**: A DataTypeRef referencing to the base type of the vector. The class DataTypeRef is + presented below. +- **InitialValue**: An optional string value containing the initial value definition in C++ style as + value. +- **Min**: An optional floating point value representing the minimum value that the data element can + have as a value. +- **Max**: An optional floating point value representing the maximum value that the data element can + have as a value. + +## Operation + +The **class Operation** defines an element with remote procedure call semantics in a module +interface. It consists of the following members: +- **Name**: A string value containing the name of the operation as value. +- **Parameters**: Is a list of Parameters. The class Parameter is presented below. + +## Parameter + +The **class Parameter** defines an in or out parameter of an operation. It consists of the following +members: +- **Name**: A string value containing the name of the parameter as value. +- **TypeRef**: A DataTypeRef referencing to the base type of the parameter. The class DataTypeRef is + presented below. +- **Direction**: A ParameterDirection defining the direction of the parameter. The class + ParameterDirection is presented below. + +## ParameterDirection + +The **class ParameterDirection** is an enum type which indicates the direction of the parameter. It +can take following values: +- "IN" +- "OUT" +- "INOUT" + +## DataTypeRef + +The **class DataTypeRef** is an annotated Datatype for resolving the referenced Datatype, which is +referenced in the JSON representation via a string value that contains the namespace path to the +referenced Datatype . The class Datatype is presented below. + +## DataType + +The **class DataType** represents a datatype by its name and namespace of a datatype. It consists +of the following members: +- **Name**: A string value containing the name of the represented datatype. +- **Namespace**: A string value containing the namespace of the represented datatype. + +## OperationRefType + +The **class OperationRefType** is an annotated Operation for resolving the referenced Operation, +which is referenced in the JSON representation via a string value that contains the path to the +referenced Operation. The class Operation is presented above. + +## DataElementRefType + +The **class DataElementRefType** is an annotated DataElement for resolving the referenced +DataElement, which is referenced in the JSON representation via a string value that contains the +path to the referenced DataElement. The class Operation is presented above. + +## SILKITAdditionalConfigurationType + +The **class SILKITAdditionalConfigurationType** contains all additional configuration information +needed for the SILKIT platform. It consists of the following members: +- **ConnectionPoints**: Is a list of SILKITConnectionPoints. The class SILKITConnectionPoint is + presented below. + +## SILKITConnectionPoint + +The **class SILKITConnectionPoint** contains the information of a SILKIT connection point. It +consists of the following members: +- **Name**: A string value containing the name of the connection point as value. +- **ServiceInterfaceName**: A string value containing the instance name of the connection point as + value. diff --git a/Documentation/contents/24_api.md b/Documentation/contents/24_api.md new file mode 100644 index 0000000..dc8da46 --- /dev/null +++ b/Documentation/contents/24_api.md @@ -0,0 +1,80 @@ +# VAF API + +## Communication + +In the following, the basic API methods for *data elements* and *operations* of a module interface +are presented in dependence of the role, i.e., consumer or provider. + +Each *data element* with name `{DataElementName}` and type `{DataElementType}` of a module interface +of consumer type makes the following interface methods available to the consumer module interface: +``` C++ +vaf::Result<vaf::ConstDataPtr<const {DataElementType}>> GetAllocated_{DataElementName}() + +{DataElementType} Get_{DataElementName}() + +void RegisterDataElementHandler_{DataElementName}(std::string owner, std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&& f) +``` + +`GetAllocated_{DataElementName}()` differs from `Get_{DataElementName}()`. In the former case, a +``vaf::Result`` with a contained `vaf::ConstDataPtr` or a `vaf::Error` is returned if no *data +element* has been received yet. Currently, `vaf::ConstDataPtr` contains a `std::unique_ptr` of +datatype `const {DataElementType}`, but further extensions are easily possible if needed to support +other middlewares. In the latter case, a copy is returned from the Non-Allocatee API if a value is +present, and if no data element has been received yet, a default value is returned. + +The associated call sequence is shown below on the example of a SIL Kit consumer module. + +When a data element is received, the generic receive handler stores the value of the data element in +`cached_{DataElementName}_` from where it is accessible via a `vaf::ConstDataPtr` of type ` +DataElementType`. It also calls the registered *data element* handlers. +The process of registering the *data element* handlers is shown in (Registration of *data element* +callback handler methods). The process of the respective getters is shown in (Allocate API) and +(Non-Allocate API). + +<img src="./figures/arch-consumer_get_register_api.svg" alt="arch-consumer_get_register_api" width="800"/><br> + +On the other hand, each *data element* with name `{DataElementName}` and type `{DataElementType}` of +a module interface of provider type makes the following interface methods available to the provider +module interface: +``` C++ +vaf::Result<vaf::DataPtr<{DataElementType}>> Allocate_{DataElementName}() + +vaf::Result<void> SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&) + +vaf::Result<void> Set_{DataElementName}(const {data: DataElementType}&) +``` + +Here, one can distinguish between an *Allocatee API* and a *Non-Allocatee API*. With the Allocatee +API, a `vaf::DataPtr` of a specific datatype must be instantiated first before the actual data value +can be assigned. The `SetAllocated_{DataElementName}()` method then takes the allocated +`vaf::DataPtr` to pass it over to the middleware provider module. The specific middleware module, +again, is then responsible for the processing of the released `vaf::DataPtr`. It can either make a +copy of it and send it out, or, implement a zero-copy mechanism, which is currently prepared but not +supported. + +The associated call sequence is shown below in the case of a SIL Kit provider module +for both, the Allocate API and Non-Allocate API case. + +<img src="./figures/arch-provider_allocate_set_api.svg" alt="arch-provider_allocate_set_api" width="580"/><br> + +Similar for *operations*. An *operation* with name `{OperationName}` and parameters +`{OperationParameters}` provides the following interface method in the case of a consumer module +interface: +- `vaf::Future<{OperationOutput}> {OperationName}({OperationParameters})` + +This is just the *operation* call, which returns a `vaf::Future` of type `{OperationOutput}` with +common future semantics. The associated call sequence is presented below in the case of a +SIL Kit consumer module. + +<img src="./figures/arch-consumer_operation_api.svg" alt="arch-consumer_operation_api" width="420"/><br> + +And last, an *operation* with name `{OperationName}` and parameters `{OperationParameters}` provides +the following interface method in the case of a provider module interface: +- ` void RegisterOperationHandler_{OperationName}(std::function<{OperationOutput}({OperationParameters})>&& f)` + +This is the registration of a specific *operation* implementation that must be specified by the +user. The associated call sequence is shown below in (Registration of the *operation* handler +method). The sequence of *operation* response to *operation* request in the case of a SIL Kit +provider module is illustrated in (Operation response on request). + +<img src="./figures/arch-provider_operation_api.svg" alt="arch-provider_operation_api" width="800"/><br> diff --git a/Documentation/contents/25_configuration.md b/Documentation/contents/25_configuration.md new file mode 100644 index 0000000..9e86a87 --- /dev/null +++ b/Documentation/contents/25_configuration.md @@ -0,0 +1,74 @@ +# Configuration + +A code-based approach in Python is used to configure applications in the Vehicle Application +Framework (VAF). By default, there are two types of configuration levels, the foundation level +(using `vafmodel`) and the abstraction level (using `vafpy`). The user is encouraged to use the +abstraction level of the vafpy package, as this hides a lot of work that needs to be done to make +the internal runtime function. If more advanced features are needed, the vafmodel API still can be +used for customization. + +## Abstraction level (vafpy) + +The following section describes the classes in the vafpy package that are used to build a VAF +executable. To simplify the diagrams, only the vafpy-based parameters are shown in the method +descriptions. Each vafpy class supports full instantiation without the use of a convenience +function. For this, the constructor supports optional vafmodel-based parameters to instantiate the +classes. To allow advanced modifications, each vafpy object allows access to its internal +vafmodel instance. + +The following figure shows a simplified overview of the Configuration as Code (CaC) +architecture. + +<img src="./figures/cac-overview.svg" alt="cac-overview" width="280"/><br> + +### Executable + +Each VAF application consists of at least one executable. The executable contains an executor that +is responsible for scheduling the tasks of added application modules. The period of the executor and +the name of the executable are set in the constructor of this class. + +Application modules can be added to an executable using the `add_application_module()` method. The +interfaces of the application modules must be bound to an appropriate counterpart. The executable +API provides several methods to bind interfaces to supported platforms. + +<img src="./figures/cac-cd_executable.svg" alt="cac-cd_executable" width="700"/><br> + +### Application Module + +An application module is the entity in which the business logic is implemented by the user. Each +application module has a unique name in its namespace and can be added to multiple executables. To +communicate with other modules, module interfaces are used. Those can be added to the application +module as either provided or consumed interfaces. Consumed interfaces can be marked as optional, +which allows the application module to start before the a corresponding provider is available. + +Tasks are used to execute the business logic functionality. They can be added to the application +module either individually or as a task chain. The latter ensures that the tasks are executed in a +specific order. + +<img src="./figures/cac-cd_app_module.svg" alt="cac-cd_app_module" width="460"/><br> + +### Module Interface + +A module interface is an interface description. It contains data elements and operations; the name +must be unique in the specified namespace. Module interfaces can be reused across multiple +application modules. Custom datatypes for data elements and operations can be defined using the +classes in the `vafpy.datatypes` module. + +<img src="./figures/cac-cd_module_interface.svg" alt="cac-cd_module_interface" width="380"/><br> + +### Task + +Tasks defined in the CaC result in method stubs that are generated in the application module code. +Their names must be unique for each executable. The period parameter defines the period cycle in +which the method is called. The `referred_offset` parameter allows the user to specify a task order +to be used when tasks have the same period. + +<img src="./figures/cac-cd_task.svg" alt="cac-cd_task" width="410"/><br> + +### Datatypes + +If custom datatypes are needed in module interfaces, they can be created in the CaC. The supported +datatypes are shown in the following figure. A `TypeRef` is implemented as a `using` statement in +the generated C++ code. + +<img src="./figures/cac-cd_datatypes.svg" alt="cac-cd_datatypes" width="900"/><br> diff --git a/Documentation/contents/26_platform_support.md b/Documentation/contents/26_platform_support.md new file mode 100644 index 0000000..6eb2265 --- /dev/null +++ b/Documentation/contents/26_platform_support.md @@ -0,0 +1,23 @@ +# Platform support + +## Model import + +### VSS import (vafvssimport) + +The `vafvssimport` package allows to import a VSS-based data catalogue into module interfaces and +datatypes of the internal Vehicle Application Framework (VAF) model. The importer requires the JSON +data export from VSS. + +Each branch of the tree-like VSS model is converted to a nested module interface. The +parent branches are used as namespace for the current interface. All child elements of a branch are +represented as data elements of that interface. If these elements are branches by themselves, they +are imported as structs, while leaves result in primitive types. +With this structure, the user is able to either access individual leafs of the VSS +catalogue by using one of the nested interfaces, or complete branches by working with the structs of +interfaces that sit higher in the hierarchy. + +VSS supports restrictions on input values of parameters. For numeric datatypes, a range can be +specified, while string parameters support a list of allowed values. The numeric ranges are imported +into the VAF model as is, while the allowed string values are converted to enums for better +usability. VSS allows a maximum size to be specified for array types. Parameters with this attribute +set are imported as fixed-size arrays, while those without are imported as vectors. diff --git a/Documentation/contents/27_code_generation.md b/Documentation/contents/27_code_generation.md new file mode 100644 index 0000000..fa2f714 --- /dev/null +++ b/Documentation/contents/27_code_generation.md @@ -0,0 +1,267 @@ +# Code generation (vafgeneration) + +The Vehicle Application Framework (VAF) relies heavily on generated code and configuration files. +This section lists all the generators and the corresponding generated files. They are implemented in +the Python package `vafgeneration`. + +## Convenience Modules + +This section contains all Python modules that do not directly generate files, but provide +convenience functionality to either the caller or the code generator. + +### generation + +Contains helper functions relevant to the following generator modules. + +### vaf_generate_application_module + +Module that calls the generators needed for application module projects. + +### vaf_generate_common + +Contains helper functions relevant to the following generator modules. Implements the 3-way merge +strategy. + +### vaf_generate_project + +Module that calls the generators needed for integration projects. + +## Code generators + +Modules that actually generate code and similar required files are listed below. + +### vaf_application_communication + +Generates C++ source code and CMake files for the communication module, which allows +executable-internal communication between application modules. + +Generated files: + +``` text +<project>/src-gen/libs/platform_vaf +├── <module_name> +| ├── include/application_communication +| | └── <interface_name>.h +| ├── src/application_communication +| | └── <interface_name>.cpp +│ └── CMakeLists.txt +└── CMakeLists.txt +``` + +### vaf_application_module + +Generates C++ source code and CMake files for application module projects. This includes base +classes as well as business logic and unit test stubs. Each module is built as a separate library. + +Generated files: + +``` text +<project> +├── src-gen/libs/application_module_base +│ ├── <module_name> +│ | ├── src/<name>/<space> +│ | | └── <module_name>_base.cpp +│ | ├── include/<name>/<space> +│ | | └── <module_name>_base.h +│ | └── CMakeLists.txt +│ └── CMakeLists.txt +├── src/application_modules/<module_name>/implementation +│ ├── src +│ | └── <module_name>.cpp +│ ├── include/<name>/<space> +│ | └── <module_name>.h +│ ├── test +│ | ├── unittest +│ | | ├── src +| │ | | ├── main.cpp +| │ | | ├── test.cpp +| │ | | └── <name>/<space> +| | │ | | └── <module_name>_base.cpp +│ | | ├── include/<name>/<space> +| │ | | └── <module_name>_base.h +│ | | └── CMakeLists.txt +│ | └── CMakeLists.txt +| └── CMakeLists.txt +└── test-gen/mocks/interfaces + ├── include/<name>/<space> + | └── <interface_name>_mock.h + └── CMakeLists.txt +``` + +### vaf_cac_support + +Generates a Python file containing classes and attributes that allow imported model artifacts to be +used on Configuration as Code (CaC) level. This includes the VSS support as well as interface +project exports. + +Generated files: + +``` text +<project> +├── model +│ └── vss.py +└── export + └── interfaces.py +``` + +### vaf_cmake_common + +This generator is responsible for creating CMake files that add subdirectories as well as the CMake +file for the `vaf_data_types` target. + +Generated files: + +``` text +<project> +├── src-gen +| ├── executables +| │ └── CMakeLists.txt +| ├── libs +| | ├── data_types +| | │ └── CMakeLists.txt +| │ └── CMakeLists.txt +│ └── CMakeLists.txt +├── src +| ├── executables +| │ └── CMakeLists.txt +│ └── CMakeLists.txt +└── test-gen + ├── mocks + │ └── CMakeLists.txt + └── CMakeLists.txt +``` + +### vaf_conan + +Based on the dependencies used in the project, a Conan dependency list with the required Conan +packages is generated. This generator is executed for app-module and integration projects. + +Generated files: + +``` text +<project>/src-gen +└── conan_deps.list +``` + +### vaf_controller + +Generates source code and CMake files for the controller and executable entry point. Also creates +stubs for the user controller. + +Generated files: + +``` text +<project> +├── src-gen/executables/<executable_name> +| ├── include +| | └── executable_controller +| | └── executable_controller.cpp +| ├── src +| | ├── executable_controller +| | | └── executable_controller.cpp +| | └── main.cpp +│ └── CMakeLists.txt +└── src/executables/<executable_name> + ├── include + | └── user_controller.h + ├── src + | └── user_controller.cpp + └── CMakeLists.txt +``` + +### vaf_core_support + +Generates source code, CMake, and configuration files to initialize executable-level core +functionality. + +Generated files: + +``` text +<project> +└── src-gen/libs/core_support + ├── config/<executable_name>/etc + | └── logging_config.json + ├── src + | └── initialization.cpp + └── CMakeLists.txt +``` + +### vaf_interface + +Generates header and CMake files to support the module interfaces configured in CaC. + +Generated files: + +``` text +<project> +├── src-gen/libs/interfaces +│ ├── include/<name>/<space> +│ | ├── <interface_name>.h +│ | └── internal/methods +| | └── <method_name>.h +│ └── CMakeLists.txt +└── test-gen/mocks/interfaces + ├── include/<name>/<space> + | └── <interface_name>_mock.h + └── CMakeLists.txt +``` + +### vaf_protobuf_serdes + +Creates `.proto` files for the configured datatypes and platform interfaces. These are used to +serialize data when using SIL Kit as communication platform. It also provides helper functions +(transformers) to easily convert between VAF datatypes and protobuf. + +Generated files: + +``` text +<project>/src-gen/libs/protobuf_serdes +├── proto +│ ├── protobuf_<namespace>.proto +│ └── CMakeLists.txt +└── transformer + ├── include/protobuf + | └── <name>/<space> + | └── protobuf_transformer.h + └── CMakeLists.txt +``` + +### vaf_silkit + +Generates the C++ source code and CMake files for platform provider and consumer modules that +communicate with SIL Kit. Each module is built as a separate library. This generator is only used in +integration projects. + +Generated files: + +``` text +<project>/src-gen/libs/platform_silkit +├── platform_consumer_modules +│ ├── <consumer_module> +│ | ├── src +│ | | └── <consumer_module>.cpp +│ | ├── include +│ | | └── <consumer_module>.h +│ | └── CMakeLists.txt +│ └── CMakeLists.txt +└── platform_provider_modules + ├── <provider_module> + | ├── src + | | └── <provider_module>.cpp + | ├── include + | | └── <provider_module>.h + | └── CMakeLists.txt + └── CMakeLists.txt +``` + +### vaf_std_data_types + +Generates header files for all used VAF datatypes. Uses primitive types and the C++ standard +library. + +Generated files: + +``` text +<project>/src-gen/libs/datatypes/include/<name>/<space> +└── impl_type_<typename>.h +``` diff --git a/Documentation/contents/28_sw_library.md b/Documentation/contents/28_sw_library.md new file mode 100644 index 0000000..35f6e6f --- /dev/null +++ b/Documentation/contents/28_sw_library.md @@ -0,0 +1,204 @@ +# VAF software library (vafcpp) + +The vafcpp library is the core library and static code part of the Vehicle Application Framework +(VAF). It covers abstraction of required primitives such as future, promise, data pointer, error, +and logging. Beyond that, it contains the basic framework for the execution of application and +platform communication modules. The execution framework is mainly divided into an executor (see +[executor.h](../../SwLibraries//vaf_core_library/lib/include/vaf/executor.h)) and an executable +controller class (see +[executable_controller_base.h](../../SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h)). + +An instance of the executable controller class is created in the main function of every VAF +executable, where it acts as entry point for execution. An instance of the executor class, which +manages the periodic execution of the tasks of application and communication modules, is a direct +member of this executable controller. All tasks that shall be scheduled by an executor are +accessible via so-called task handles. All tasks of one module are linked to a corresponding module +executor. The overall structure of the executor and executable controller is given below: + +<img src="./figures/arch-executor-module.svg" alt="arch-module-if" width="800"/><br> + +## Executor + +The executor ensures periodic task execution (see +[executor.h](../../SwLibraries/vaf_core_library/lib/include/vaf/executor.h)). The period can be +configured with the *ExecutorPeriod* parameter in the executable configuration. Tasks are processed +while considering module dependencies. That is, if an application module A depends from application +module B, the tasks of module B are always executed before the ones of module A in one time slot. +Since the executor works with time slots, it maps the tasks deterministically into the same slot. To +avoid situations, where many tasks are mapped to the same time slot, it is possible to configure +tasks with an offset. + +## Runtime monitoring + +Each task can have a budget assigned to it. The executor will monitor the execution time of a +task and log any violation of its budget. Also the runtime of the executor time slot is monitored +and if tasks in one slot exceed their budget, a warning is logged. + +**Example** + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +classDiagram + ApplicationModule1 --> CommunicationModule + CommunicationModule --> ApplicationModule2 + CommunicationModule --> ApplicationModule3 + + ApplicationModule1: task1() @ 20ms + ApplicationModule2: task2() @ 40ms + ApplicationModule3: task3() @ 40ms +``` + +Consider the example with three application modules with one task each and an executor period of +20ms (see figure below). + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline +20ms: task1 +40ms: task1 & task2 & task3 +60ms: task1 +80ms: task1 & task2 & task3 +100ms: task1 +120ms: task1 & task2 & task3 +``` + +Every second cycle, the executor has to execute all three tasks in one time slot. For a better load +distribution, one can add an offset of 1 (cycle) to task3 as depicted in the next figure. + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline +20ms: task1 +40ms: task1 & task2 +60ms: task1 & task3 +80ms: task1 & task2 +100ms: task1 & task3 +120ms: task1 & task2 +``` +## Future/Promise + +The abstraction of *Future* and *Promise* primitives is encapsulated by the `vaf::Future` and +`vaf::Promise` namespaces respectively. For details see +[future.h](../../SwLibraries/vaf_core_library/lib/include/vaf/future.h). + +## Data pointer + +Two types of data pointers are used in VAF. First one is `vaf::DataPtr`, a data pointer type where +the data can be changed. Second one is `vaf::ConstDataPtr`, where the data is fixed. The underlying +type of a `vaf::DataPtr` or a `vaf::ConstDataPtr` is not fixed. For the `vaf::DataPtr` case the +underlying type can be a platform-specific type, for example `std::unique_ptr`. Same holds for the +`vaf::ConstDataPtr` case, which also maps to `std::unique_ptr` for example. See +[data_ptr.h](../../SwLibraries/vaf_core_library/lib/include/vaf/data_ptr.h) for the details. + +## Error + +The abstraction of error codes, i.e., `vaf::Error`, is implemented in +[error_domain.h](../../SwLibraries/vaf_core_library/lib/include/vaf/error_domain.h). + +### Error reporting + +Modules can report errors via `ReportError(ErrorCode error_code, std::string msg, bool critical = false)`. See +[controller_interface.h](../../SwLibraries/vaf_core_library/lib/include/vaf/controller_interface.h). +If `critical` is set to *true*, the state of the module changes to *not operational*. Errors are +further propagated to other modules that depend on the module in question. + +## ExecutableController + +The executable controller manages the states of the application and communication modules (see +[executable_controller_base.h](../../SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h)). +The following state machine defines the *states and *state transitions* of a module: + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +stateDiagram + [*] --> NotInitialized + NotOperational --> Shutdown: DeInit() + Shutdown --> [*] + NotInitialized --> NotOperational : Init() + NotOperational --> Starting: Start() + Starting --> Operational: ReportOperational() + Operational --> NotOperational: ReportError(..., "..." true) or Stop() + Starting --> NotOperational: ReportError(..., "..." true) or Stop() +``` + +The following methods trigger a ***state transition***: +- Init() + - Called at startup. +- DeInit() + - Called at shutdown. +- Start() + - Called when all required modules are operational. + - Will enable executor tasks. +- Stop() + - Called when the module reports an error or before shutdown. + - Will disable executor tasks and receive handlers. +- ReportOperational() + - Called by the module, if starting was successful or an error was recovered. + - Will enable receive handler. +- ReportError(..., "..." true) + - Called if the module detects an error (makes the module unusable for other modules). + - Will disable executor tasks and receive handlers. + - Will call OnError() on all modules that depend on the module. + +The following sequence diagram shows the ***startup*** of communication and application modules by +the executable controller: +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +sequenceDiagram + Controller ->> PlatformModule: Init() + Controller ->> Controller: change state of MM to NotOperational + Controller ->> ApplicationModule: Init() + Controller ->> Controller: change state of AM to NotOperational + Controller ->> PlatformModule: Start() + Controller ->> Controller: change state of MM to Starting + PlatformModule ->> Controller: ReportOperational() + Controller ->> Controller: change state of MM to Operational + Controller ->> ApplicationModule: Start() + Controller ->> Controller: change state of AM to Starting + ApplicationModule ->> Controller: ReportOperational() + Controller ->> Controller: change state of AM to Operational +``` + +The following sequence diagram shows the ***shutdown*** of platform and application modules by +the executable controller: + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +sequenceDiagram + Controller ->> ApplicationModule: Stop() + Controller ->> Controller: change state of AM to NotOperational + Controller ->> PlatformModule: Stop() + Controller ->> Controller: change state of MM to NotOperational + Controller ->> ApplicationModule: DeInit() + Controller ->> Controller: change state of AM to Shutdown + Controller ->> PlatformModule: DeInit() + Controller ->> Controller: change state of MM to Shutdown +``` + +The following sequence diagram shows the ***normal operation*** of platform and application +modules in interaction with the executable controller: + +``` mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +sequenceDiagram + PlatformModule ->> Controller: ReportError(kConnectionLost, true) + Controller ->> Controller: change state of MM to NotOperational + Controller ->> PlatformModule: Stop() + Controller ->> ApplicationModule: OnError(error) + opt is error critical + ApplicationModule ->> Controller: ReportError(kRequiredModuleNotOperational, true) + Controller ->> Controller: change state of AM to NotOperational + Controller ->> ApplicationModule: Stop() + end + Controller ->> PlatformModule: Start() + PlatformModule ->> Controller: ReportOperational() + Controller ->> Controller: change state of MM to Operational + opt is ApplicationModule not operational + Controller ->> ApplicationModule: Start() + end +``` + +## Logging + +Logging functionality is encapsulated by the `vaf::Logger` namespace. For details see +[logging.h](../../SwLibraries/vaf_core_library/lib/include/vaf/logging.h). diff --git a/Documentation/contents/29_testing.md b/Documentation/contents/29_testing.md new file mode 100644 index 0000000..e15c471 --- /dev/null +++ b/Documentation/contents/29_testing.md @@ -0,0 +1,76 @@ +# Testing + +## Unit tests (GoogleTest) + +The Vehicle Application Framework (VAF) assist with GoogleTest-based unit testing of application +modules by generating test skeletons and mocks for all used interfaces. The idea is that the writer +of a unit test can mock any input/output of the interfaces to produce test cases that verify the +actual application code without having to connect to real or simulated external test communication +partners. The generated test project builds together with generated test-specific base code, which +vastly simplifies the writing of the unit test. + +Unit tests are activated by default but can be disabled with the following flag that needs to be +passed to the preset stage: +``` +vaf make preset -d -DVAF_BUILD_TESTS=OFF +``` + +The test code, which can be edited and extended by the user is located in the file: +`<app-module project directory>/implementation/test/unittest/src/tests.cpp` + +One example skeleton test case is generated for reference. It is up to the user to adapt it and add +further tests. Writing a test case consists of 4 steps: + +1. Test case creation. +``` +TEST_F(AppModule1UnitTest, Test_1) { +``` +2. Create mock objects of interfaces as used by the application. +``` +auto HvacStatusConsumerMock = std::make_shared<demo::HvacStatusConsumerMock>(); +auto DataExchangeProviderMock = std::make_shared<demo::DataExchangeInterfaceProviderMock>(); +``` +3. Write expected outcome of the test, i.e., what you want to test. +``` +EXPECT_CALL(*DataExchangeProviderMock, RegisterOperationHandler_MyFunction(_)).Times(1); +``` +4. Create an application module object using above created interface mocks. +``` +auto AppModule1 = std::make_shared<demo::AppModule1>( demo::AppModule1 ::ConstructorToken { + HvacStatusConsumerMock, + DataExchangeProviderMock}); +} +``` + +## SIL tests (SIL Kit) + +Software In the Loop (SIL) testing is supported using [Vector SIL +Kit](https://github.com/vectorgrp/sil-kit). Any interface modeled in Configuration as Code (CaC) can +be selected to be routed via SIL Kit. SIL Kit uses a registry application, which acts as a message +broker. In other words, all messages must go through that router. The connection to SIL Kit in the +VAF is configured using CaC and is done similar to other interface connections. Only difference, one +has to connect to the SIL Kit registry by specifying the registry URI and instance name of the +communication interface. Providers and consumers that want to connect should configure the same +instance name and URI. + +CaC snippet connecting an interface to an application module using SIL Kit: +``` python +demo_app.connect_consumed_interface_to_silkit( + Appmodule1, # The application module + Appmodule1.ConsumedInterfaces.VelocityServiceConsumer, # The connected interface + "Silkit_VelocityService", # Instance name used to identify the interface in SIL Kit registry + "silkit://192.168.128.129:8500" # URI of the running SIL Kit registry to connect to +) +demo_app.connect_provided_interface_to_silkit( + Appmodule2, # The application module + Appmodule2.ProvidedInterfaces.VelocityServiceProvider, # The connected interface + "Silkit_VelocityService", # Instance name used to identify the interface in SIL Kit registry + "silkit://192.168.128.129:8500" # URI of the running SIL Kit registry to connect to +) +``` + +VAF utilizes [Protobuf](https://protobuf.dev/) to serialize the data such that communication +partners on any type of platform easily can serialize or deserialize the payload. Proto files are +generated for all defined datatypes and interfaces. These proto files are then compiled using the +protoc compiler. Further, transformers get generated for each type to enable easy translation +between protobuf types and VAF types. diff --git a/Documentation/contents/30_glossary.md b/Documentation/contents/30_glossary.md new file mode 100644 index 0000000..c7abe28 --- /dev/null +++ b/Documentation/contents/30_glossary.md @@ -0,0 +1,103 @@ +# Glossary +```{glossary} + +ADAS + Advanced Driver-Assistance System + +API + Application Programming Interface + +ASIL + Automotive Safety Integrity Level + +CaC + Configuration as Code + +E/E Architecture + Electrical and Electronic Architecture + +ECU + Electronic Control Unit + +FOSS + Free and Open Source Software + +HAL + Hardware Abstraction Layer + +HPC + High-Performance Computing + +IDL + Interface Definition Language + +IFEX + Interface Exchange Framework + +IPC + Inter-Process Communication + +IT + Information Technology + +IVI + In-Vehicle Infotainment + +JSON + JavaScript Object Notation + +OEM + Original Equipment Manufacturer + +OS + Operating System + +POSIX + Portable Operating System Interface + +QoS + Quality of Service + +RPC + Remote Procedure Call + +SDK + Software Development Kit + +SDV + Software-Defined Vehicle + +SIL + Software In the Loop + +SHM + Shared Memory + +SOME/IP + Scalable Service-Oriented Middleware over IP + +TCP/IP + Transmission Control Protocol/Internet Protocol + +UDP + User Datagram Protocol + +UDS + Unix Domain Sockets + +VAF + Vehicle Application Framework + +VISS + Vehicle Information Service Specification + +VSS + Vehicle Signal Specification + +XML + Extensible Markup Language + +YAML + YAML Ain't Markup Language + +``` diff --git a/Documentation/contents/figures/af-concept.svg b/Documentation/contents/figures/af-concept.svg new file mode 100644 index 0000000..e74c6dc --- /dev/null +++ b/Documentation/contents/figures/af-concept.svg @@ -0,0 +1 @@ +<svg width="4184" height="1213" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><defs><clipPath id="clip0"><rect x="56" y="923" width="4184" height="1213"/></clipPath><image width="170" height="215" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAADXCAMAAAC9FDqvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAA/UExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALMlgi8AAAAUdFJOUwAIECAwOEBIWGB4j5efr7e/z9ffW4FgUgAAAAlwSFlzAAAywAAAMsABKGRa2wAAAkRJREFUeF7t3e1O40AMRuEpW9gCBUK393+tq+5ahI+mHRvO2JHe82sUaernTxJVipJ26uZuXNt/E2NtHv4cR3bY2WB/k/3EuF42NtrZzvaPLGh9tu1Di1kPtntsIevYc+qtiDWJGrFmUQPWNKrfOlMnuFeb85bXOlPtANadzZlzWjOpTmsq1WfNpbqsyVSPNZvqsKZT+60Z1NePl9heawZ1uglZU6gtZM2hhqxJ1Ig1ixqwplH91jyq25pI/WK1w0tlUj9bn+zwQqlUnzWX6rImUz3WbKrDmk7tt+ZTu60FqL3WCtROawlqn7UGtctahNpjrULtsJahXrfWoV61FqK2XzPm1GdrJeoVaynqZWst6kVrMeolazXqBWs56rK1HnXRWpC6ZK1IXbCWpJ631qSetWZQA52sK6EeH9dDPW7XQ90PpG5tTrBpIHVjc4KNpH7zOamh1HsbFGsote1tUqix1PZ7b4/cdDf/iR1M9ff+bizqTyUqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSiQqkahEohKJSnSeam89r9X5d7AXT1SiVVG/98GJgb20Z1uV77HtbFW+29YmWxbv9H2jzcMKzqzD/f+bl/rZWvsL4/NjXTHhNkkAAAAASUVORK5CYII=" preserveAspectRatio="none" id="img1"></image></defs><g clip-path="url(#clip0)" transform="translate(-56 -923)"><rect x="2851.5" y="950.5" width="1386" height="807" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="none"/><rect x="2817.5" y="981.5" width="1387" height="807" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3944.75 1048)">Executable</text><rect x="2872.5" y="1121.5" width="864" height="145" stroke="#B70032" stroke-width="4.58333" stroke-miterlimit="8" fill="none"/><rect x="3780" y="1121" width="364" height="617" fill="#B70032"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3886.73 1418)">Control</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3885.29 1467)">module</text><path d="M0 0 25.2961 0 25.2961 62.6794 50.5921 62.6794" stroke="#028FC3" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd" transform="matrix(1 0 0 -1 2970.5 1226.18)"/><path d="M3073.5 1163.5 3249.75 1163.5 3249.75 1200.41" stroke="#028FC3" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3306.39 1041)">Application </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3306.39 1090)">modules</text><rect x="2817.5" y="1823.5" width="65" height="65" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 2931.36 1872)">Domain of middleware stack</text><rect x="2817" y="1901" width="65" height="65" fill="#B70032"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 2934.56 1949)">Domain of Framework</text><rect x="2817" y="2056" width="65" height="65" fill="#028FC3"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 2923.1 2102)">Domain of developer</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 2926.77 2026)">Shared between Framework and developer</text><path d="M2944.5 1251.5 2944.5 1345.79" stroke="#028FC3" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M3249.5 1251.72 3249.5 1334.22 3604.8 1334.22 3604.8 1251.5" stroke="#028FC3" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><rect x="2872" y="1307" width="864" height="431" fill="#B70032"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3068.02 1361)">Middleware abstraction module</text><rect x="2905.5" y="1438.5" width="795" height="118" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3087.36 1489)">Middleware interface </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 2970.19 1538)">(e.g., </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3098.52 1538)">ara</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3165.55 1538)">::com proxy/skeleton)</text><rect x="2905.5" y="1587.5" width="795" height="119" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="41" transform="matrix(1 0 0 1 3021.46 1663)">IPC (e.g., via UDS or SHM)</text><rect x="3223" y="1199" width="52" height="51.9999" fill="#028FC3"/><rect x="3021" y="1137" width="52.0002" height="51.9999" fill="#028FC3"/><rect x="3578" y="1199" width="52" height="51.9999" fill="#028FC3"/><rect x="2918" y="1199" width="52" height="51.9999" fill="#028FC3"/><path d="M3089.93 1099.21 3099.25 1091.66 3107.82 1086.28 3117.58 1081.28 3123.03 1078.92 3128.86 1076.67 3135.11 1074.55 3141.83 1072.55 3149.02 1070.69 3156.66 1068.96 3164.72 1067.35 3173.18 1065.84 3191.14 1063.13 3210.32 1060.75 3230.48 1058.63 3251.36 1056.72 3272.72 1054.93 3294.32 1053.22 3294.68 1057.78 3273.09 1059.5 3273.1 1059.5 3251.75 1061.28 3251.77 1061.28 3230.91 1063.2 3230.94 1063.19 3210.82 1065.3 3210.87 1065.3 3191.74 1067.67 3191.8 1067.67 3173.9 1070.37 3173.96 1070.36 3165.55 1071.86 3165.6 1071.85 3157.59 1073.45 3157.64 1073.44 3150.06 1075.16 3150.13 1075.14 3143.02 1076.98 3143.09 1076.96 3136.46 1078.93 3136.54 1078.9 3130.37 1081 3130.46 1080.97 3124.72 1083.18 3124.81 1083.14 3119.47 1085.46 3119.6 1085.39 3110 1090.31 3110.17 1090.22 3101.8 1095.47 3102.03 1095.31 3092.81 1102.77ZM3104.05 1108.01 3074.5 1116.5 3085.44 1087.76Z" fill="#343739"/><rect x="2817.5" y="1979.5" width="65" height="65" stroke="#B70032" stroke-width="4.58333" stroke-miterlimit="8" fill="none"/><path d="M3522.71 1060.22 3530.18 1060.89 3537.64 1061.79 3545.01 1063.11 3552.21 1065.09 3559.14 1067.95 3565.69 1071.92 3571.7 1077.16 3574.54 1080.38 3577.17 1083.96 3579.62 1087.94 3581.91 1092.31 3585.98 1101.97 3589.55 1112.85 3592.69 1124.72 3595.5 1137.38 3598.06 1150.64 3598.9 1155.52 3594.38 1156.3 3593.55 1151.44 3593.55 1151.49 3591 1138.28 3591.02 1138.34 3588.23 1125.76 3588.25 1125.85 3585.13 1114.09 3585.17 1114.22 3581.65 1103.49 3581.72 1103.67 3577.72 1094.18 3577.8 1094.35 3575.59 1090.14 3575.67 1090.27 3573.31 1086.45 3573.42 1086.6 3570.9 1083.18 3571.03 1083.34 3568.36 1080.3 3568.57 1080.51 3562.83 1075.5 3563.15 1075.74 3556.91 1071.96 3557.22 1072.12 3550.59 1069.38 3550.86 1069.47 3543.9 1067.56 3544.1 1067.6 3536.9 1066.31 3537.03 1066.33 3529.67 1065.45 3529.74 1065.46 3522.29 1064.78ZM3609.42 1149.08 3600.5 1178.5 3582.31 1153.71Z" fill="#343739"/><rect x="619.5" y="1692.5" width="1628" height="259" stroke="#000000" stroke-width="6.875" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="55" transform="matrix(1 0 0 1 652.414 1763)">Data model </text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 652.414 1838)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 743.394 1838)">The foundation</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 652.414 1911)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 743.394 1911)">Model packages for agnostic and middleware</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1781.52 1911)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1802.14 1911)">related aspects</text><path d="M243 2006.5 328.317 1957 328.317 1983.67 2537.68 1983.67 2537.68 1957 2623 2006.5 2537.68 2056 2537.68 2029.33 328.317 2029.33 328.317 2056Z" fill="#B70032" fill-rule="evenodd"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1187.43 2096)">Tooling and workflow</text><rect x="619.5" y="1387.5" width="883" height="260" stroke="#000000" stroke-width="6.875" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="55" transform="matrix(1 0 0 1 652.415 1459)">Configuration as Code </text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 652.415 1534)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 743.394 1534)">Model abstraction</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 652.415 1607)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 743.394 1607)">Text</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 844.227 1607)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 864.852 1607)">based user front</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1244.7 1607)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1265.32 1607)">end</text><rect x="241.5" y="1083.5" width="779" height="259" stroke="#000000" stroke-width="6.875" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="55" transform="matrix(1 0 0 1 273.865 1154)">Model import</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 273.865 1229)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 364.844 1229)">Import from COVESA VSS</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 273.865 1302)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 364.844 1302)">Others ...</text><path d="M303.79 1381.4 305.239 1415.91 305.237 1415.88 307.151 1449.86 307.148 1449.81 308.425 1466.45 308.421 1466.4 309.989 1482.71 309.983 1482.66 311.899 1498.57 311.89 1498.5 314.213 1513.96 314.199 1513.88 316.987 1528.82 316.967 1528.72 320.278 1543.07 320.249 1542.96 324.141 1556.65 324.101 1556.52 328.632 1569.5 328.575 1569.35 333.803 1581.54 333.724 1581.37 339.708 1592.72 339.601 1592.54 346.399 1602.96 346.259 1602.77 353.929 1612.22 353.755 1612.03 362.335 1620.46 362.148 1620.29 371.6 1627.74 371.412 1627.6 381.677 1634.14 381.497 1634.03 392.519 1639.72 392.352 1639.64 404.071 1644.54 403.921 1644.48 416.279 1648.66 416.148 1648.62 429.087 1652.15 428.973 1652.12 442.435 1655.06 442.338 1655.04 456.265 1657.46 456.184 1657.45 470.518 1659.41 470.451 1659.4 485.133 1660.97 485.079 1660.96 500.053 1662.21 499.995 1662.2 530.581 1663.97 530.541 1663.97 538.693 1664.29 538.51 1668.87 530.337 1668.55 499.702 1666.78 484.673 1665.53 469.93 1663.95 455.522 1661.98 441.506 1659.55 427.938 1656.59 414.876 1653.03 402.377 1648.8 390.5 1643.83 379.305 1638.06 368.854 1631.41 359.213 1623.81 350.451 1615.21 342.625 1605.57 335.704 1594.95 329.627 1583.43 324.331 1571.08 319.751 1557.97 315.825 1544.15 312.49 1529.7 309.686 1514.68 307.352 1499.15 305.429 1483.18 303.857 1466.82 302.577 1450.14 300.66 1416.12 299.21 1381.6ZM534.572 1652.66 561.5 1667.5 533.472 1680.14Z" fill="#343739"/><rect x="1844.5" y="1083.5" width="591" height="259" stroke="#000000" stroke-width="6.875" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="55" transform="matrix(1 0 0 1 1877.34 1154)">User library</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 1877.34 1229)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1968.32 1229)">Runtime aspects</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 1877.34 1302)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1968.32 1302)">Log, err, states, …</text><rect x="1553.5" y="1387.5" width="882" height="260" stroke="#000000" stroke-width="6.875" stroke-miterlimit="8" fill="none"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="55" transform="matrix(1 0 0 1 1585.76 1459)">Generators</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 1585.76 1534)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1676.74 1534)">API for com and persistency</text><text fill="#B70032" font-family="Wingdings 3,Wingdings 3_MSFontService,sans-serif" font-weight="400" font-size="34" transform="matrix(1 0 0 1 1585.76 1607)">ïµ</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1676.74 1607)">Build environment, testing</text><use width="100%" height="100%" xlink:href="#img1" fill="none" transform="translate(1345 923)"></use><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 305.869 1927)">Project </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 482.901 1927)">init</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 2272.14 1925)">Build and test</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 180.843 1643)">Input</text><path d="M1101.6 1334.55 1100.7 1295.89 1100.22 1257.82 1100.26 1239.18 1100.56 1220.92 1101.17 1203.1 1102.14 1185.8 1103.53 1169.09 1105.38 1153.06 1107.76 1137.76 1110.71 1123.28 1114.29 1109.68 1118.56 1097.04 1123.58 1085.43 1129.41 1074.94 1136.08 1065.63 1143.55 1057.46 1151.76 1050.39 1160.65 1044.34 1170.15 1039.22 1180.2 1034.97 1190.75 1031.49 1201.74 1028.72 1213.12 1026.56 1224.84 1024.95 1236.85 1023.79 1249.12 1023.02 1276.53 1022.34 1276.64 1026.93 1249.27 1027.6 1249.36 1027.59 1237.18 1028.36 1237.25 1028.36 1225.33 1029.51 1225.42 1029.49 1213.8 1031.1 1213.92 1031.08 1202.66 1033.21 1202.79 1033.18 1191.95 1035.92 1192.1 1035.87 1181.72 1039.29 1181.9 1039.22 1172.03 1043.4 1172.23 1043.31 1162.93 1048.31 1163.13 1048.19 1154.45 1054.11 1154.66 1053.95 1146.65 1060.85 1146.84 1060.66 1139.55 1068.62 1139.72 1068.41 1133.21 1077.5 1133.35 1077.28 1127.64 1087.56 1127.74 1087.36 1122.8 1098.77 1122.87 1098.6 1118.66 1111.07 1118.7 1110.92 1115.16 1124.38 1115.19 1124.25 1112.26 1138.62 1112.28 1138.52 1109.92 1153.72 1109.93 1153.63 1108.09 1169.58 1108.09 1169.51 1106.71 1186.15 1106.72 1186.09 1105.75 1203.33 1105.75 1203.28 1105.14 1221.05 1105.14 1221.01 1104.84 1239.24 1104.84 1239.21 1104.8 1257.81 1104.8 1257.78 1105.29 1295.82 1105.29 1295.8 1106.18 1334.45ZM1271.92 1010.91 1299.5 1024.5 1272.08 1038.41Z" fill="#343739"/><path d="M-1.42595 287.143-1.79315 271.392-2.28024 233.319-2.23869 214.68-1.93766 196.416-1.32494 178.598-0.348118 161.298 1.04549 144.593 2.909 128.555 5.29617 113.257 8.26165 98.7734 11.8615 85.1754 16.1534 72.5361 21.1978 60.9293 27.0555 50.4345 33.7624 41.1212 41.2737 32.9608 49.5261 25.8886 58.4563 19.8332 68.0017 14.7186 78.1025 10.4654 88.7022 6.99261 99.7467 4.21899 111.184 2.06395 122.964 0.447843 135.035-0.708065 147.358-1.48235 172.487-2.19063 197.991-2.29165 198.009 2.29165 172.533 2.39256 172.588 2.39167 147.527 3.09805 147.606 3.09445 135.36 3.8639 135.434 3.85797 123.447 5.00584 123.54 4.99501 111.864 6.59698 111.977 6.57862 100.663 8.71037 100.797 8.68099 89.897 11.4182 90.0523 11.3733 79.6188 14.7917 79.7946 14.726 69.879 18.9012 70.072 18.8091 60.7261 23.8169 60.9299 23.6936 52.2054 29.6095 52.4105 29.4529 44.3592 36.3527 44.5541 36.1646 37.2278 44.124 37.4014 43.9112 30.8519 53.0059 30.9934 52.7836 25.2553 63.0639 25.356 62.8604 20.3947 74.2761 20.4629 74.0995 16.2267 86.5747 16.2721 86.4243 12.709 99.8834 12.7388 99.7565 9.79719 114.124 9.81636 114.017 7.44444 129.217 7.45653 129.128 5.60248 145.085 5.60987 145.011 4.2219 161.649 4.22619 161.588 3.25253 178.831 3.25482 178.78 2.64367 196.553 2.64472 196.512 2.34429 214.74 2.3446 214.707 2.30312 233.312 2.30294 233.278 2.78965 271.322 2.78921 271.298 3.15613 287.036ZM14.5045 282.187 1.39921 310-12.988 282.828Z" fill="#343739" transform="matrix(-1 0 0 1 1762.5 1024.5)"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1050.48 1005)">yields</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1687.81 1005)">uses</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1172.66 1193)">Data exchange format </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 1226.24 1248)">(model database)</text><path d="M2476.55 1151.46 2758.66 1296.31 2756.57 1300.39 2474.45 1155.54ZM2759.82 1284.02 2778 1308.82 2747.26 1308.49Z"/><path d="M1.04672-2.03865 283.16 142.81 281.067 146.887-1.04672 2.03865ZM284.317 130.523 302.5 155.315 271.756 154.987Z" transform="matrix(1 0 0 -1 2475.5 1520.82)"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 2561.59 1106)">Static </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 2573.62 1161)">code</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 2507.76 1580)">Generated </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="46" transform="matrix(1 0 0 1 2574.22 1635)">code</text></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/arch-app-module.svg b/Documentation/contents/figures/arch-app-module.svg new file mode 100644 index 0000000..31a584d --- /dev/null +++ b/Documentation/contents/figures/arch-app-module.svg @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="2000" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="740 640 2000 670" height="670" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 80 L640 80 L640 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 130 L990 130 L990 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 270 L990 270 L990 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 70 L30 70 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 140 L370 140 L370 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 140 L60 140 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 140 L360 140 L360 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(2080,660)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(2080,660)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="274" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="86" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1420,660)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1420,660)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="274" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="92" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(760,660)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(760,660)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="280" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="247" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ControlInterface</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,0,0)" fill-opacity="0.4902" transform="translate(1240,1160)" stroke-opacity="0.4902" stroke="rgb(255,0,0)" + ><rect x="0.5" width="988.5" height="128.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1240,1160)" + ><rect fill="none" x="0.5" width="988.5" height="128.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="427" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Stubs Generated»</text + ><text x="281" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ApplicationModuleNamespace}::{ApplicationModuleName}</text + ><path fill="none" d="M1 40.2188 L989 40.2188" clip-path="url(#clipPath3)" + /><path fill="none" d="M1 61.3281 L989 61.3281" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/{TaskName}_Task()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1240,850)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="988.5" height="268.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1240,850)" + ><rect fill="none" x="0.5" width="988.5" height="268.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="449" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="264" font-size="14px" y="34.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ApplicationModuleNamespace}::{ApplicationModuleName}Base</text + ><path fill="none" d="M1 40.2188 L989 40.2188" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#executor_: vaf::ModuleExecutor&</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#{ConsumerInstanceName}_: std::shared_ptr<{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer></text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#{ProviderInstanceName}_: std::shared_ptr<{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider></text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >... </text + ><path fill="none" d="M1 125.7656 L989 125.7656" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Init(): vaf::Result<void></text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Start()</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Stop()</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/DeInit()</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/OnError(error: const vaf::Error&)</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+{TaskName}_Task()</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g transform="translate(1730,1110)" + ><path fill="none" d="M10.5 10.5 L10.5 50.5" clip-path="url(#clipPath5)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" + /></g + ><g transform="translate(2060,730)" + ><path fill="none" d="M350.5 10.5 L10.5 120.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M337.7875 7.7812 L350.5 10.5 L341.7892 20.1499" clip-path="url(#clipPath6)" + /><text x="164.8989" font-size="14px" y="61" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1720,730)" + ><path fill="none" d="M10.5 10.5 L10.5 120.5" clip-path="url(#clipPath7)" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583" clip-path="url(#clipPath7)" + /><text x="14" font-size="14px" y="65" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1070,730)" + ><path fill="none" d="M10.5 10.5 L340.5 120.5" clip-path="url(#clipPath8)" + /><path fill="white" d="M19.1251 20.2266 L10.5 10.5 L23.2361 7.8938 L19.1251 20.2266" clip-path="url(#clipPath8)" stroke="none" + /><path fill="none" d="M19.1251 20.2266 L10.5 10.5 L23.2361 7.8938 L19.1251 20.2266" clip-path="url(#clipPath8)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-app-module.uxf b/Documentation/contents/figures/arch-app-module.uxf new file mode 100644 index 0000000..069dba3 --- /dev/null +++ b/Documentation/contents/figures/arch-app-module.uxf @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>6</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>744</x> + <y>510</y> + <w>594</w> + <h>162</h> + </coordinates> + <panel_attributes><<Generated>> +{ApplicationModuleNamespace}::{ApplicationModuleName}Base +-- +#executor_: vaf::ModuleExecutor& +#{ConsumerInstanceName}_: std::shared_ptr<{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer> +... +#{ProviderInstanceName}_: std::shared_ptr<{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider> +... +-- ++/Init(): vaf::Result<void> ++/Start() ++/Stop() ++/DeInit() ++/OnError(error: const vaf::Error&) +/+{TaskName}_Task()/ +... + + + + + +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>642</x> + <y>438</y> + <w>216</w> + <h>84</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;340.0;120.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1032</x> + <y>438</y> + <w>36</w> + <h>84</h> + </coordinates> + <panel_attributes>lt=<- +uses +</panel_attributes> + <additional_attributes>10.0;10.0;10.0;120.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1236</x> + <y>438</y> + <w>222</w> + <h>84</h> + </coordinates> + <panel_attributes>lt=<- +uses +</panel_attributes> + <additional_attributes>350.0;10.0;10.0;120.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>744</x> + <y>696</y> + <w>594</w> + <h>78</h> + </coordinates> + <panel_attributes><<Stubs Generated>> +{ApplicationModuleNamespace}::{ApplicationModuleName} +-- + +-- ++/{TaskName}_Task() +... + + + + + +bg=red</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1038</x> + <y>666</y> + <w>18</w> + <h>42</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;50.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>456</x> + <y>396</y> + <w>384</w> + <h>48</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ControlInterface +-- + +bg=yellow</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>852</x> + <y>396</y> + <w>384</w> + <h>48</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1248</x> + <y>396</y> + <w>384</w> + <h>48</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-consumer-module.svg b/Documentation/contents/figures/arch-consumer-module.svg new file mode 100644 index 0000000..9baa1d2 --- /dev/null +++ b/Documentation/contents/figures/arch-consumer-module.svg @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1340" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="450 170 1340 530" height="530" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 80 L640 80 L640 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 230 L1200 230 L1200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 80 L480 80 L480 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 80 L30 80 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 80 L60 80 L60 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1130,190)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1130,190)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="274" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="92" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(470,190)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(470,190)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="280" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="247" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ControlInterface</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(520,320)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="1198.5" height="228.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(520,320)" + ><rect fill="none" x="0.5" width="1198.5" height="228.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="554" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="406" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ProviderModuleNamespace}::{ProviderModuleName}</text + ><path fill="none" d="M1 40.2188 L1199 40.2188" clip-path="url(#clipPath3)" + /><path fill="none" d="M1 61.3281 L1199 61.3281" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Data Elements:</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> ></text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void></text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void></text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Operations:</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f)</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(810,600)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="478.5" height="78.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(810,600)" + ><rect fill="none" x="0.5" width="478.5" height="78.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="102" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Concrete Platform (for example SIL Kit)</text + ></g + ><g transform="translate(780,260)" + ><path fill="none" d="M10.5 10.5 L10.5 60.5" clip-path="url(#clipPath5)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" + /></g + ><g transform="translate(1060,540)" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M17 49.2417 L10.5 60.5 L4 49.2417" clip-path="url(#clipPath6)" + /><text x="14" font-size="14px" y="43.0547" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1440,260)" + ><path fill="none" d="M10.5 10.5 L10.5 60.5" clip-path="url(#clipPath5)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-consumer-module.uxf b/Documentation/contents/figures/arch-consumer-module.uxf new file mode 100644 index 0000000..e443887 --- /dev/null +++ b/Documentation/contents/figures/arch-consumer-module.uxf @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>15</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>1215</x> + <y>900</y> + <w>720</w> + <h>120</h> + </coordinates> + <panel_attributes>Concrete Platform (for example SIL Kit) +bg=gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>780</x> + <y>480</y> + <w>1800</w> + <h>345</h> + </coordinates> + <panel_attributes><<Generated>> +{ProviderModuleNamespace}::{ProviderModuleName} +-- + +-- +Data Elements: ++/Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> > ++/SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void> ++/Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void> +... + +Operations: ++/RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f) +... +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>2160</x> + <y>390</y> + <w>45</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;60.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1590</x> + <y>810</y> + <w>90</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1170</x> + <y>390</y> + <w>45</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;60.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>705</x> + <y>285</y> + <w>960</w> + <h>120</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ControlInterface +-- + +bg=yellow</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1695</x> + <y>285</y> + <w>960</w> + <h>120</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-consumer_get_register_api.svg b/Documentation/contents/figures/arch-consumer_get_register_api.svg new file mode 100644 index 0000000..58ae5f9 --- /dev/null +++ b/Documentation/contents/figures/arch-consumer_get_register_api.svg @@ -0,0 +1,575 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1560" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="350 -20 1560 2510" height="2510" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 330 L20 330 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 360 L360 360 L360 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 540 L20 540 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 580 L20 580 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 140 L20 140 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 210 L20 210 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 80 L30 80 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 140 L30 140 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 510 L30 510 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11" + ><path d="M0 0 L0 80 L20 80 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12" + ><path d="M0 0 L0 60 L280 60 L280 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13" + ><path d="M0 0 L0 200 L460 200 L460 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14" + ><path d="M0 0 L0 170 L30 170 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15" + ><path d="M0 0 L0 160 L30 160 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16" + ><path d="M0 0 L0 130 L30 130 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17" + ><path d="M0 0 L0 50 L380 50 L380 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18" + ><path d="M0 0 L0 110 L200 110 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19" + ><path d="M0 0 L0 90 L210 90 L210 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath20" + ><path d="M-0.5 -0.5 L-0.5 89.5 L209.5 89.5 L209.5 -0.5 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath21" + ><path d="M0 0 L0 120 L30 120 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath22" + ><path d="M0 0 L0 150 L30 150 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath23" + ><path d="M0 0 L0 110 L30 110 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath24" + ><path d="M0 0 L0 30 L220 30 L220 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath25" + ><path d="M0 0 L0 30 L200 30 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath26" + ><path d="M0 0 L0 50 L70 50 L70 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath27" + ><path d="M0 0 L0 40 L120 40 L120 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath28" + ><path d="M0 0 L0 110 L290 110 L290 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath29" + ><path d="M0 0 L0 40 L440 40 L440 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath30" + ><path d="M0 0 L0 50 L540 50 L540 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath31" + ><path d="M0 0 L0 30 L150 30 L150 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath32" + ><path d="M0 0 L0 40 L540 40 L540 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath33" + ><path d="M0 0 L0 110 L540 110 L540 0 Z" + /></clipPath + ></defs + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1450,90)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="328.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1450,90)" + ><rect fill="none" x="0.5" width="18.5" height="328.5" y="0.5" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1250,1850)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="358.5" height="358.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1250,1850)" + ><rect fill="none" x="0.5" width="358.5" height="358.5" y="0.5" clip-path="url(#clipPath3)" + /><path fill="none" d="M323.7123 0.5 L323.7123 14.3656 L314.4686 23.6094 L0.5 23.6094" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >if cached_{DataElementName}_ is available</text + ><path fill="none" d="M1 176.0938 L359 176.0938" clip-path="url(#clipPath3)" + /><text x="180" font-size="14px" y="207.3125" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + > </text + ></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1450,1770)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="538.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1450,1770)" + ><rect fill="none" x="0.5" width="18.5" height="538.5" y="0.5" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(920,1740)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="578.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(920,1740)" + ><rect fill="none" x="0.5" width="18.5" height="578.5" y="0.5" clip-path="url(#clipPath5)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1250,1070)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="358.5" height="358.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1250,1070)" + ><rect fill="none" x="0.5" width="358.5" height="358.5" y="0.5" clip-path="url(#clipPath3)" + /><path fill="none" d="M323.7123 0.5 L323.7123 14.3656 L314.4686 23.6094 L0.5 23.6094" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >if cached_{DataElementName}_ is available</text + ><path fill="none" d="M1 176.0938 L359 176.0938" clip-path="url(#clipPath3)" + /><text x="180" font-size="14px" y="207.3125" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + > </text + ></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1450,990)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="538.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1450,990)" + ><rect fill="none" x="0.5" width="18.5" height="538.5" y="0.5" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(920,960)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="578.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(920,960)" + ><rect fill="none" x="0.5" width="18.5" height="578.5" y="0.5" clip-path="url(#clipPath5)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1450,630)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="138.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(1450,630)" + ><rect fill="none" x="0.5" width="18.5" height="138.5" y="0.5" clip-path="url(#clipPath6)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(920,600)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="208.5" y="0.5" clip-path="url(#clipPath7)" stroke="none" + /></g + ><g transform="translate(920,600)" + ><rect fill="none" x="0.5" width="18.5" height="208.5" y="0.5" clip-path="url(#clipPath7)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,30)" stroke-linecap="butt" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath8)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,410)" stroke-linecap="butt" + ><path fill="none" d="M10.5 120.5 L10.5 10.5" clip-path="url(#clipPath9)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,20)" stroke-linecap="butt" + ><path fill="none" d="M10.5 490.5 L10.5 10.5" clip-path="url(#clipPath10)" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,290)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,290)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,300)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath12)" stroke="none" + >handle_container.</text + ><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath12)" stroke="none" + >handler_(</text + ><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath12)" stroke="none" + >this->cached_{DataElementName}_)</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1300,220)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="458.5" height="198.5" y="0.5" clip-path="url(#clipPath13)" stroke="none" + /></g + ><g transform="translate(1300,220)" + ><rect fill="none" x="0.5" width="458.5" height="198.5" y="0.5" clip-path="url(#clipPath13)" + /><path fill="none" d="M325.2576 0.5 L325.2576 22.2313 L310.7701 36.7188 L0.5 36.7188" clip-path="url(#clipPath13)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath13)" font-family="sans-serif" stroke="none" xml:space="preserve" + >loop handle_container in </text + ><text x="5" font-size="14px" y="31.2188" clip-path="url(#clipPath13)" font-family="sans-serif" stroke="none" xml:space="preserve" + >registered_{DataElemen}_event_handlers_</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,2300)" stroke-linecap="butt" + ><path fill="none" d="M10.5 150.5 L10.5 10.5" clip-path="url(#clipPath14)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,2310)" stroke-linecap="butt" + ><path fill="none" d="M10.5 140.5 L10.5 10.5" clip-path="url(#clipPath15)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,1510)" stroke-linecap="butt" + ><path fill="none" d="M10.5 140.5 L10.5 10.5" clip-path="url(#clipPath15)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,1530)" stroke-linecap="butt" + ><path fill="none" d="M10.5 110.5 L10.5 10.5" clip-path="url(#clipPath16)" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,2060)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,2060)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,2080)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath17)" stroke="none" + >set return value to default value</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1370,2050)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" stroke="none" + /></g + ><g transform="translate(1370,2050)" + ><rect fill="none" x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M48.6811 0.5 L48.6811 14.3656 L39.4373 23.6094 L0.5 23.6094" clip-path="url(#clipPath18)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >False</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1370,1890)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" stroke="none" + /></g + ><g transform="translate(1370,1890)" + ><rect fill="none" x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M45.4682 0.5 L45.4682 14.3656 L36.2244 23.6094 L0.5 23.6094" clip-path="url(#clipPath18)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >True</text + ></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(370.5,1740.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath20)" points=" 0 0 196 0 196 0 209 14 209 14 209 89 209 89 0 89 0 89 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath20)" stroke="none" + >Non-Allocate API</text + ><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="196" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="209" y1="14" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="0" y1="89" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="0" y1="89" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="196" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="14" y2="14" stroke="black" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,1900)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,1900)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,1920)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath17)" stroke="none" + >set return value to cached_{DataElementName}_)</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,1630)" stroke-linecap="butt" + ><path fill="none" d="M10.5 150.5 L10.5 10.5" clip-path="url(#clipPath14)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,1640)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath21)" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,1280)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,1280)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,1300)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath17)" stroke="none" + >set return vaf::Result value to ::vaf::Error</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1370,1270)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" stroke="none" + /></g + ><g transform="translate(1370,1270)" + ><rect fill="none" x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M48.6811 0.5 L48.6811 14.3656 L39.4373 23.6094 L0.5 23.6094" clip-path="url(#clipPath18)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >False</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1370,1110)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" stroke="none" + /></g + ><g transform="translate(1370,1110)" + ><rect fill="none" x="0.5" width="198.5" height="108.5" y="0.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M45.4682 0.5 L45.4682 14.3656 L36.2244 23.6094 L0.5 23.6094" clip-path="url(#clipPath18)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >True</text + ></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(370.5,960.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath20)" points=" 0 0 196 0 196 0 209 14 209 14 209 89 209 89 0 89 0 89 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath20)" stroke="none" + >Allocate API</text + ><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="196" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="209" y1="14" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="0" y1="89" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="0" y1="89" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="196" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="14" y2="14" stroke="black" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,1120)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,1120)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,1140)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath17)" stroke="none" + >set return vaf::Result value to</text + ><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath17)" stroke="none" + >cached_{DataElementName}_)</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,860)" stroke-linecap="butt" + ><path fill="none" d="M10.5 130.5 L10.5 10.5" clip-path="url(#clipPath22)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,860)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath21)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,760)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath21)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,800)" stroke-linecap="butt" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath8)" + /></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(370.5,530.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath20)" points=" 0 0 196 0 196 0 209 14 209 14 209 89 209 89 0 89 0 89 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath20)" stroke="none" + >Registration of </text + ><text fill="black" x="7" xml:space="preserve" y="34" clip-path="url(#clipPath20)" stroke="none" + >DataElement callback </text + ><text fill="black" x="7" xml:space="preserve" y="51" clip-path="url(#clipPath20)" stroke="none" + >handler method</text + ><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="196" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="209" y1="14" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="209" x2="0" y1="89" y2="89" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="0" x2="0" y1="89" y2="0" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="196" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath20)" fill="none" x1="196" x2="209" y1="14" y2="14" stroke="black" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1460,670)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(1460,670)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath11)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1480,690)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath17)" stroke="none" + >registered_{DataElementName}_event_handlers_.</text + ><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath17)" stroke="none" + >emplace_back(owner, std::move(f))</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1450,530)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath21)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(920,510)" stroke-linecap="butt" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1360,10)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath24)" stroke="none" + /></g + ><g transform="translate(1360,10)" + ><rect fill="none" x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath24)" + /><text x="4" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath24)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF SIL Kit consumer module</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(840,0)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath25)" stroke="none" + /></g + ><g transform="translate(840,0)" + ><rect fill="none" x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath25)" + /><text x="14" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath25)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF application module</text + ></g + ><g transform="translate(1430,510)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(1430,520)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,490)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,500)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(1460,100)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,110)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath28)" + /><text x="14" font-size="14px" y="50" clip-path="url(#clipPath28)" font-family="sans-serif" stroke="none" xml:space="preserve" + >store DataElement in </text + ><text x="14" font-size="14px" y="66.1094" clip-path="url(#clipPath28)" font-family="sans-serif" stroke="none" xml:space="preserve" + >this->cached_{DataElementName}_</text + ></g + ><g transform="translate(1460,180)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1460,350)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,280)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,270)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1450,70)" + ><path fill="none" d="M10.5 20.5 L420.5 20.5" clip-path="url(#clipPath29)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath29)" + /><text x="170.1592" font-size="14px" y="16" clip-path="url(#clipPath29)" font-family="sans-serif" stroke="none" xml:space="preserve" + >DataElement</text + ></g + ><g transform="translate(930,2250)" + ><path fill="none" d="M520.5 20.5 L10.5 20.5" clip-path="url(#clipPath30)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath30)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath30)" + /><text x="194.98" font-size="14px" y="16" clip-path="url(#clipPath30)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{DataElementType}</text + ></g + ><g transform="translate(930,1460)" + ><path fill="none" d="M520.5 20.5 L10.5 20.5" clip-path="url(#clipPath30)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath30)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath30)" + /><text x="40.9849" font-size="14px" y="16" clip-path="url(#clipPath30)" font-family="sans-serif" stroke="none" xml:space="preserve" + >::vaf::Result<::vaf::ConstDataPtr<const {DataElementType}>></text + ></g + ><g transform="translate(1460,2120)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,2050)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,2040)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(570,1760)" + ><path fill="none" d="M130.5 10.5 L10.5 10.5" clip-path="url(#clipPath31)" + /><path fill="none" d="M119.2417 4 L130.5 10.5 L119.2417 17" clip-path="url(#clipPath31)" + /></g + ><g transform="translate(1460,1960)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,1890)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,1880)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(930,1750)" + ><path fill="none" d="M10.5 20.5 L520.5 20.5" clip-path="url(#clipPath30)" + /><path fill="white" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath30)" stroke="none" + /><path fill="none" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath30)" + /><text x="169.2979" font-size="14px" y="16" clip-path="url(#clipPath30)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Get_{DataElementName}()</text + ></g + ><g transform="translate(1430,1620)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(1430,1630)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,1630)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,1620)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(1460,1340)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,1270)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,1260)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(570,980)" + ><path fill="none" d="M130.5 10.5 L10.5 10.5" clip-path="url(#clipPath31)" + /><path fill="none" d="M119.2417 4 L130.5 10.5 L119.2417 17" clip-path="url(#clipPath31)" + /></g + ><g transform="translate(1460,1180)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,1110)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,1100)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(930,970)" + ><path fill="none" d="M10.5 20.5 L520.5 20.5" clip-path="url(#clipPath30)" + /><path fill="white" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath30)" stroke="none" + /><path fill="none" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath30)" + /><text x="136.7041" font-size="14px" y="16" clip-path="url(#clipPath30)" font-family="sans-serif" stroke="none" xml:space="preserve" + >GetAllocated_{DataElementName}()</text + ></g + ><g transform="translate(1430,850)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(1430,840)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,840)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(900,850)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(570,550)" + ><path fill="none" d="M130.5 10.5 L10.5 10.5" clip-path="url(#clipPath31)" + /><path fill="none" d="M119.2417 4 L130.5 10.5 L119.2417 17" clip-path="url(#clipPath31)" + /></g + ><g transform="translate(930,750)" + ><path fill="none" d="M520.5 20.5 L10.5 20.5" clip-path="url(#clipPath32)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath32)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath32)" + /></g + ><g transform="translate(1460,730)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath27)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(1550,660)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(1460,650)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath27)" + /></g + ><g transform="translate(930,610)" + ><path fill="none" d="M10.5 20.5 L520.5 20.5" clip-path="url(#clipPath33)" + /><path fill="white" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath33)" stroke="none" + /><path fill="none" d="M509.2417 27 L520.5 20.5 L509.2417 14 L509.2417 27" clip-path="url(#clipPath33)" + /><text x="82.3701" font-size="14px" y="16" clip-path="url(#clipPath33)" font-family="sans-serif" stroke="none" xml:space="preserve" + >RegisterDataElementHandler_{DataElementName}(</text + ><text x="204.3438" font-size="14px" y="32.1094" clip-path="url(#clipPath33)" font-family="sans-serif" stroke="none" xml:space="preserve" + >std::string owner, </text + ><text x="216.1113" font-size="14px" y="48.2188" clip-path="url(#clipPath33)" font-family="sans-serif" stroke="none" xml:space="preserve" + >std::function<</text + ><text x="57.4941" font-size="14px" y="64.3281" clip-path="url(#clipPath33)" font-family="sans-serif" stroke="none" xml:space="preserve" + >void(const vaf::ConstDataPtr<const {DataElementType}>)</text + ><text x="242.1377" font-size="14px" y="80.4375" clip-path="url(#clipPath33)" font-family="sans-serif" stroke="none" xml:space="preserve" + >>&& f)</text + ></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-consumer_get_register_api.uxf b/Documentation/contents/figures/arch-consumer_get_register_api.uxf new file mode 100644 index 0000000..f057d7f --- /dev/null +++ b/Documentation/contents/figures/arch-consumer_get_register_api.uxf @@ -0,0 +1,1111 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>10</zoom_level> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>840</x> + <y>0</y> + <w>200</w> + <h>30</h> + </coordinates> + <panel_attributes>_:VAF application module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1360</x> + <y>10</y> + <w>220</w> + <h>30</h> + </coordinates> + <panel_attributes>_:VAF SIL Kit consumer module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>510</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>920</x> + <y>600</y> + <w>20</w> + <h>210</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>530</y> + <w>30</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>610</y> + <w>540</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=->> +RegisterDataElementHandler_{DataElementName}( +std::string owner, +std::function< +void(const vaf::ConstDataPtr<const {DataElementType}>) +>&& f) +</panel_attributes> + <additional_attributes>10.0;20.0;520.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1450</x> + <y>630</y> + <w>20</w> + <h>140</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>650</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>660</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>730</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>690</y> + <w>380</w> + <h>50</h> + </coordinates> + <panel_attributes>registered_{DataElementName}_event_handlers_. +emplace_back(owner, std::move(f)) +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>670</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>750</y> + <w>540</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>520.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>370</x> + <y>530</y> + <w>210</w> + <h>90</h> + </coordinates> + <panel_attributes>Registration of +DataElement callback +handler method + +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>570</x> + <y>550</y> + <w>150</w> + <h>30</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;10.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>800</y> + <w>30</w> + <h>80</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>760</y> + <w>30</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>850</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=16</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>840</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=16</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>840</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=18</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>850</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=18</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>860</y> + <w>30</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>920</x> + <y>960</y> + <w>20</w> + <h>580</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>860</y> + <w>30</w> + <h>150</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;130.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>970</y> + <w>540</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=->> +GetAllocated_{DataElementName}() +</panel_attributes> + <additional_attributes>10.0;20.0;520.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1450</x> + <y>990</y> + <w>20</w> + <h>540</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1100</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>1110</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1180</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>1140</y> + <w>380</w> + <h>50</h> + </coordinates> + <panel_attributes>set return vaf::Result value to cached_{DataElementName}_) +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>1120</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>370</x> + <y>960</y> + <w>210</w> + <h>90</h> + </coordinates> + <panel_attributes>Allocate API +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>570</x> + <y>980</y> + <w>150</w> + <h>30</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;10.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1250</x> + <y>1070</y> + <w>360</w> + <h>360</h> + </coordinates> + <panel_attributes>if cached_{DataElementName}_ is available +-- + + + + + + + + + +-- + + +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1370</x> + <y>1110</y> + <w>200</w> + <h>110</h> + </coordinates> + <panel_attributes>True</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1370</x> + <y>1270</y> + <w>200</w> + <h>110</h> + </coordinates> + <panel_attributes>False</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1260</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>1270</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1340</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>1300</y> + <w>380</w> + <h>50</h> + </coordinates> + <panel_attributes>set return vaf::Result value to ::vaf::Error +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>1280</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>1620</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=19</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>1630</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=19</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>1630</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=21</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>1620</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=21</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>1640</y> + <w>30</w> + <h>120</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>920</x> + <y>1740</y> + <w>20</w> + <h>580</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>1630</y> + <w>30</w> + <h>170</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;150.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>1750</y> + <w>540</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=->> +Get_{DataElementName}() +</panel_attributes> + <additional_attributes>10.0;20.0;520.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1450</x> + <y>1770</y> + <w>20</w> + <h>540</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1880</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>1890</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>1960</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>1920</y> + <w>380</w> + <h>50</h> + </coordinates> + <panel_attributes>set return value to cached_{DataElementName}_) +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>1900</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>370</x> + <y>1740</y> + <w>210</w> + <h>90</h> + </coordinates> + <panel_attributes>Non-Allocate API +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>570</x> + <y>1760</y> + <w>150</w> + <h>30</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;10.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1250</x> + <y>1850</y> + <w>360</w> + <h>360</h> + </coordinates> + <panel_attributes>if cached_{DataElementName}_ is available +-- + + + + + + + + + +-- + + +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1370</x> + <y>1890</y> + <w>200</w> + <h>110</h> + </coordinates> + <panel_attributes>True</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1370</x> + <y>2050</y> + <w>200</w> + <h>110</h> + </coordinates> + <panel_attributes>False</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>2040</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>2050</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>2120</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>2080</y> + <w>380</w> + <h>50</h> + </coordinates> + <panel_attributes>set return value to default value +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>2060</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>1530</y> + <w>30</w> + <h>130</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;110.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>1510</y> + <w>30</w> + <h>160</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;140.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>1460</y> + <w>540</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=->> +::vaf::Result<::vaf::ConstDataPtr<const {DataElementType}\>> +</panel_attributes> + <additional_attributes>520.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>930</x> + <y>2250</y> + <w>540</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=->> +{DataElementType} +</panel_attributes> + <additional_attributes>520.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>2310</y> + <w>30</w> + <h>160</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;140.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>2300</y> + <w>30</w> + <h>170</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;150.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>70</y> + <w>440</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=<- +DataElement</panel_attributes> + <additional_attributes>10.0;20.0;420.0;20.0</additional_attributes> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>1300</x> + <y>220</y> + <w>460</w> + <h>200</h> + </coordinates> + <panel_attributes>loop handle_container in +registered_{DataElemen}_event_handlers_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>270</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>280</y> + <w>30</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>350</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1480</x> + <y>300</y> + <w>280</w> + <h>60</h> + </coordinates> + <panel_attributes>handle_container. +handler_( +this->cached_{DataElementName}_)</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1460</x> + <y>290</y> + <w>20</w> + <h>80</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1450</x> + <y>90</y> + <w>20</w> + <h>330</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>180</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1550</x> + <y>110</y> + <w>290</w> + <h>110</h> + </coordinates> + <panel_attributes>lt=- +store DataElement in +this->cached_{DataElementName}_</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1460</x> + <y>100</y> + <w>120</w> + <h>40</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>500</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=22</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>900</x> + <y>490</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=22</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>520</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=23</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1430</x> + <y>510</y> + <w>70</w> + <h>50</h> + </coordinates> + <panel_attributes>lt=- +group=23</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>920</x> + <y>20</y> + <w>30</w> + <h>510</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;490.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>410</y> + <w>30</w> + <h>140</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;120.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1450</x> + <y>30</y> + <w>30</w> + <h>80</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-consumer_operation_api.svg b/Documentation/contents/figures/arch-consumer_operation_api.svg new file mode 100644 index 0000000..a2a75a1 --- /dev/null +++ b/Documentation/contents/figures/arch-consumer_operation_api.svg @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="840" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="660 150 840 340" height="340" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 80 L20 80 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 110 L20 110 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 90 L30 90 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 100 L30 100 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 30 L220 30 L220 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 110 L30 110 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 30 L200 30 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 40 L590 40 L590 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 120 L30 120 L30 0 Z" + /></clipPath + ></defs + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1350,290)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1350,290)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(770,280)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(770,280)" + ><rect fill="none" x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath3)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(770,380)" stroke-linecap="butt" + ><path fill="none" d="M10.5 70.5 L10.5 10.5" clip-path="url(#clipPath4)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1350,360)" stroke-linecap="butt" + ><path fill="none" d="M10.5 80.5 L10.5 10.5" clip-path="url(#clipPath5)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1260,170)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(1260,170)" + ><rect fill="none" x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" + /><text x="4" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF SIL Kit consumer module</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(770,190)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 90.5" clip-path="url(#clipPath7)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(680,170)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath8)" stroke="none" + /></g + ><g transform="translate(680,170)" + ><rect fill="none" x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath8)" + /><text x="14" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath8)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF application module</text + ></g + ><g transform="translate(780,350)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath9)" + /><path fill="white" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath9)" stroke="none" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath9)" + /><text x="172.7202" font-size="14px" y="16" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::Future<{OperationOutput}></text + ></g + ><g transform="translate(780,270)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath9)" + /><path fill="white" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath9)" stroke="none" + /><path fill="none" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath9)" + /><text x="137.4937" font-size="14px" y="16" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{OperationName}({OperationParameters})</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1350,190)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 100.5" clip-path="url(#clipPath10)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-consumer_operation_api.uxf b/Documentation/contents/figures/arch-consumer_operation_api.uxf new file mode 100644 index 0000000..c3e59d9 --- /dev/null +++ b/Documentation/contents/figures/arch-consumer_operation_api.uxf @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>9</zoom_level> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>612</x> + <y>153</y> + <w>180</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF application module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>693</x> + <y>171</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;10.0;10.0;90.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1134</x> + <y>153</y> + <w>198</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF SIL Kit consumer module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1215</x> + <y>171</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=.</panel_attributes> + <additional_attributes>10.0;10.0;10.0;100.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>702</x> + <y>243</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +{OperationName}({OperationParameters})</panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>693</x> + <y>252</y> + <w>18</w> + <h>99</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1215</x> + <y>324</y> + <w>27</w> + <h>90</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;80.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>693</x> + <y>342</y> + <w>27</w> + <h>81</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;70.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1215</x> + <y>261</y> + <w>18</w> + <h>72</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>702</x> + <y>315</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<<- +vaf::Future<{OperationOutput}></panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-control-module.svg b/Documentation/contents/figures/arch-control-module.svg new file mode 100644 index 0000000..984f477 --- /dev/null +++ b/Documentation/contents/figures/arch-control-module.svg @@ -0,0 +1,540 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="2820" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="670 330 2820 1750" height="1750" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 1710 L2040 1710 L2040 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 200 L530 200 L530 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 200 L520 200 L520 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 300 L470 300 L470 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 380 L360 380 L360 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 310 L580 310 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 90 L170 90 L170 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 140 L460 140 L460 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 490 L580 490 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11" + ><path d="M0 0 L0 150 L410 150 L410 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12" + ><path d="M0 0 L0 90 L200 90 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13" + ><path d="M0 0 L0 160 L520 160 L520 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14" + ><path d="M0 0 L0 340 L640 340 L640 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15" + ><path d="M0 0 L0 100 L30 100 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16" + ><path d="M0 0 L0 310 L60 310 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17" + ><path d="M0 0 L0 40 L1220 40 L1220 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18" + ><path d="M0 0 L0 550 L60 550 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19" + ><path d="M0 0 L0 40 L100 40 L100 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath20" + ><path d="M0 0 L0 490 L60 490 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath21" + ><path d="M0 0 L0 40 L240 40 L240 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath22" + ><path d="M0 0 L0 140 L70 140 L70 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath23" + ><path d="M0 0 L0 40 L110 40 L110 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath24" + ><path d="M0 0 L0 40 L180 40 L180 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath25" + ><path d="M0 0 L0 90 L30 90 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath26" + ><path d="M0 0 L0 90 L90 90 L90 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath27" + ><path d="M0 0 L0 40 L650 40 L650 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,255,255)" fill-opacity="0.4902" transform="translate(690,350)" stroke-opacity="0.4902" stroke="rgb(255,255,255)" + ><path d="M0.5 0.5 L816.5 0.5 L816.5 21.6094 L2039 21.6094 L2039 1709 L0.5 1709 L0.5 0.5" stroke="none" clip-path="url(#clipPath2)" + /></g + ><g transform="translate(690,350)" + ><path fill="none" d="M0.5 0.5 L816.5 0.5 L816.5 21.6094 L2039 21.6094 L2039 1709 L0.5 1709 L0.5 0.5" clip-path="url(#clipPath2)" + /><path fill="none" d="M0.5 21.6094 L816.5 21.6094" clip-path="url(#clipPath2)" + /><text x="5" font-size="14px" y="16.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Control module</text + ></g + ><g fill="rgb(255,0,0)" fill-opacity="0.4902" transform="translate(1660,1810)" stroke-opacity="0.4902" stroke="rgb(255,0,0)" + ><rect x="0.5" width="528.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1660,1810)" + ><rect fill="none" x="0.5" width="528.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="197" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Stubs Generated»</text + ><text x="214" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >UserController</text + ><path fill="none" d="M1 40.2188 L529 40.2188" clip-path="url(#clipPath3)" + /><path fill="none" d="M1 61.3281 L529 61.3281" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostInitialize()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreStart()</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostStart()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreShutdown()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostShutdown()</text + ></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(1660,1540)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="518.5" height="198.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1660,1540)" + ><rect fill="none" x="0.5" width="518.5" height="198.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="220" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="162" font-size="14px" y="34.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::UserControllerInterface</text + ><path fill="none" d="M1 40.2188 L519 40.2188" clip-path="url(#clipPath4)" + /><path fill="none" d="M1 61.3281 L519 61.3281" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostInitialize()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreStart()</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostStart()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreShutdown()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostShutdown()</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+OnError(vaf::Error error, std::string name, bool critical)</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1170,430)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="468.5" height="298.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(1170,430)" + ><rect fill="none" x="0.5" width="468.5" height="298.5" y="0.5" clip-path="url(#clipPath5)" + /><text x="162" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ModuleExecutor</text + ><path fill="none" d="M1 24.1094 L469 24.1094" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-executor_: Executor&</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-handles_: std::vector<std::shared_ptr<RunnableHandle»</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-started_: bool</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-name_: std::string</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-dependencies_ std::vector<std::string></text + ><path fill="none" d="M1 109.6562 L469 109.6562" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Start()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Stop()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunPeriodic(name: const std::string&, </text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > period: std::chrono::milliseconds , </text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable: T&& , </text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > owner: const std::string&, </text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable_dependencies: std::vector<std::string>,</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > offset: uint64_t,</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(740,410)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="358.5" height="378.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(740,410)" + ><rect fill="none" x="0.5" width="358.5" height="378.5" y="0.5" clip-path="url(#clipPath6)" + /><text x="106" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::RunnableHandle</text + ><path fill="none" d="M1 24.1094 L359 24.1094" clip-path="url(#clipPath6)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-name_: std::string;</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-is_active_: bool</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-period_: uint64_t</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runnable_: std::function<void(void)></text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-owner_: std::string</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-run_after_: std::vector<std::string></text + ><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-offset_: uint64_t</text + ><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >- budget_: std::chrono::nanoseconds</text + ><path fill="none" d="M1 157.9844 L359 157.9844" clip-path="url(#clipPath6)" + /><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Name(): const std::string&</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+IsActive(): bool</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Execute()</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Period(): uint64_t</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Start()</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Stop()</text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Owner(): const std::string&</text + ><text x="5" font-size="14px" y="285.8594" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunAfter(): const std::vector<std::string>&</text + ><text x="5" font-size="14px" y="301.9688" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Offset(): uint64_t</text + ><text x="5" font-size="14px" y="318.0781" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Budget(): std::chrono::nanoseconds</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(860,1250)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="578.5" height="308.5" y="0.5" clip-path="url(#clipPath7)" stroke="none" + /></g + ><g transform="translate(860,1250)" + ><rect fill="none" x="0.5" width="578.5" height="308.5" y="0.5" clip-path="url(#clipPath7)" + /><text x="243" font-size="14px" y="18.1094" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::Executor</text + ><path fill="none" d="M1 24.1094 L579 24.1094" clip-path="url(#clipPath7)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-running_period_: std::chrono::milliseconds </text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runnables_: std::vector<std::shared_ptr<RunnableHandle»</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-exit_requested_: std::atomic<bool></text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-thread_: std::thread</text + ><path fill="none" d="M1 93.5469 L579 93.5469" clip-path="url(#clipPath7)" + /><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunPeriodic(name: const std::string&, </text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > period: std::chrono::milliseconds , </text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable: T&& , </text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > owner: const std::string&, </text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > run_after: const std::vector<std::string>& ,</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > run_after_runnables: const std::vector<std::string>&,</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > offset: uint64_t,</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ExecutorThread</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ExecuteRunnable(runnable: RunnableHandle& )</text + ></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1460,1520)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><path d="M0.5 0.5 L158.5 0.5 L169 12.5 L169 89 L0.5 89 L0.5 0.5" stroke="none" clip-path="url(#clipPath8)" + /></g + ><g transform="translate(1460,1520)" + ><path fill="none" d="M0.5 0.5 L158.5 0.5 L169 12.5 L169 89 L0.5 89 L0.5 0.5" clip-path="url(#clipPath8)" + /><path fill="none" d="M158.5 0.5 L158.5 12.5 L169 12.5" clip-path="url(#clipPath8)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath8)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Class instantiated by</text + ><text x="5" font-size="14px" y="34.2188" clip-path="url(#clipPath8)" font-family="sans-serif" stroke="none" xml:space="preserve" + >main (entry point)</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1650,1330)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="458.5" height="138.5" y="0.5" clip-path="url(#clipPath9)" stroke="none" + /></g + ><g transform="translate(1650,1330)" + ><rect fill="none" x="0.5" width="458.5" height="138.5" y="0.5" clip-path="url(#clipPath9)" + /><text x="184" font-size="14px" y="18.1094" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="75" font-size="14px" y="34.2188" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >executable_controller::ExecutableController</text + ><path fill="none" d="M1 40.2188 L459 40.2188" clip-path="url(#clipPath9)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-executor_: std::unique_ptr<vaf::Executor> </text + ><path fill="none" d="M1 61.3281 L459 61.3281" clip-path="url(#clipPath9)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoStart()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoShutdown()</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1610,770)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="578.5" height="488.5" y="0.5" clip-path="url(#clipPath10)" stroke="none" + /></g + ><g transform="translate(1610,770)" + ><rect fill="none" x="0.5" width="578.5" height="488.5" y="0.5" clip-path="url(#clipPath10)" + /><text x="183" font-size="14px" y="18.1094" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerBase</text + ><path fill="none" d="M1 24.1094 L579 24.1094" clip-path="url(#clipPath10)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-signal_handling_init_: int</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runtime_: vaf::Runtime</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-shutdown_requested_: std::atomic_bool</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-use_execution_mgr_: bool</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-logger_: vaf::Logger&</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-modules_: std::vector<ModuleContainer></text + ><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-user_controller_: std::unique_ptr<UserControllerInterface></text + ><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-signal_handler_thread_: std::thread</text + ><path fill="none" d="M1 157.9844 L579 157.9844" clip-path="url(#clipPath10)" + /><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Run(use_exec_mgr: bool) noexcept;</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Run(argc: int, argv char**,use_exec_mgr bool)</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+InitiateShutdown()</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RegisterModule(module: std::shared_ptr<vaf::ControlInterface>)</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportOperationalOfModule(name: std::string)</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportErrorOfModule(error: vaf::Error, name std::string , critical bool)</text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoInitialize()</text + ><text x="5" font-size="14px" y="285.8594" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoStart()</text + ><text x="5" font-size="14px" y="301.9688" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoShutdown()</text + ><text x="5" font-size="14px" y="318.0781" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#WaitForShutdown()</text + ><text x="5" font-size="14px" y="334.1875" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#IsShutdownRequested(): bool</text + ><text x="5" font-size="14px" y="350.2969" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ChangeStateOfModule(name: std::string , state: ModuleStates )</text + ><text x="5" font-size="14px" y="366.4062" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StartModules()</text + ><text x="5" font-size="14px" y="382.5156" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StartEventHandlersForModule(module_name: const std::string& , dependencies: const std::vector<std::string>&)</text + ><text x="5" font-size="14px" y="398.625" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StopEventHandlersForModule(module_name: const std::string& , dependencies const std::vector<std::string>&)</text + ><text x="5" font-size="14px" y="414.7344" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-CheckStartingModules();</text + ><text x="5" font-size="14px" y="430.8438" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-SetupExecutionManager();</text + ><text x="5" font-size="14px" y="446.9531" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ReportStateToExecutionManager(is_running: bool)</text + ><text x="5" font-size="14px" y="463.0625" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-InitializeSignalHandling()</text + ><text x="5" font-size="14px" y="479.1719" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-SignalHandlerThread()</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(2270,760)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="408.5" height="148.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(2270,760)" + ><rect fill="none" x="0.5" width="408.5" height="148.5" y="0.5" clip-path="url(#clipPath11)" + /><text x="54" font-size="14px" y="18.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«private to vaf::ExecutableControllerBase»</text + ><text x="34" font-size="14px" y="34.2188" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerBase::ModuleContainer</text + ><path fill="none" d="M1 40.2188 L409 40.2188" clip-path="url(#clipPath11)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+name_: std::string</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+module_: std::shared_ptr<vaf::ControlInterface></text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+dependencies_: std::vector<std::string></text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+state_: ModuleStates</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+starting_counter_: uint64_t</text + ><path fill="none" d="M1 125.7656 L409 125.7656" clip-path="url(#clipPath11)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(2260,550)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><path d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" stroke="none" clip-path="url(#clipPath12)" + /></g + ><g transform="translate(2260,550)" + ><path fill="none" d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" clip-path="url(#clipPath12)" + /><path fill="none" d="M188.5 0.5 L188.5 12.5 L199 12.5" clip-path="url(#clipPath12)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath12)" font-family="sans-serif" stroke="none" xml:space="preserve" + >For ReportOperational()</text + ><text x="5" font-size="14px" y="34.2188" clip-path="url(#clipPath12)" font-family="sans-serif" stroke="none" xml:space="preserve" + >and ReportError()</text + ></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(1690,550)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="518.5" height="158.5" y="0.5" clip-path="url(#clipPath13)" stroke="none" + /></g + ><g transform="translate(1690,550)" + ><rect fill="none" x="0.5" width="518.5" height="158.5" y="0.5" clip-path="url(#clipPath13)" + /><text x="220" font-size="14px" y="18.1094" clip-path="url(#clipPath13)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="139" font-size="14px" y="34.2188" clip-path="url(#clipPath13)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerInterface</text + ><path fill="none" d="M1 40.2188 L519 40.2188" clip-path="url(#clipPath13)" + /><path fill="none" d="M1 61.3281 L519 61.3281" clip-path="url(#clipPath13)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath13)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+ReportOperationalOfModule(std::string name)</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath13)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+ReportErrorOfModule(vaf::Error error, std::string name, bool critical)</text + ></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(2830,490)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="638.5" height="338.5" y="0.5" clip-path="url(#clipPath14)" stroke="none" + /></g + ><g transform="translate(2830,490)" + ><rect fill="none" x="0.5" width="638.5" height="338.5" y="0.5" clip-path="url(#clipPath14)" + /><text x="280" font-size="14px" y="18.1094" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="247" font-size="14px" y="34.2188" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ControlInterface</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath14)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#name_: std::string</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#dependencies_: std::vector<std::string> </text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#executable_controller_interface_: ExecutableControllerInterface&</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#executor_: vaf::ModuleExecutor</text + ><path fill="none" d="M1 109.6562 L639 109.6562" clip-path="url(#clipPath14)" + /><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Init(): vaf::Result<void> </text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Start() noexcept</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Stop() noexcept</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+DeInit() noexcept</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportOperational()</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportError(error_code: ErrorCode , msg: std::string , critical: bool = false)</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+OnError(error: const vaf::Error&)</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+GetName(): std::string</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+GetDependencies(): std::vector<std::string> </text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+StartExecutor()</text + ><text x="5" font-size="14px" y="285.8594" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+StopExecutor()</text + ><text x="5" font-size="14px" y="301.9688" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+StartEventHandlerForModule(module_name: const std::string&)</text + ><text x="5" font-size="14px" y="318.0781" clip-path="url(#clipPath14)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+StopEventHandlerForModule(module_name: const std::string& )</text + ></g + ><g transform="translate(1830,1730)" + ><path fill="none" d="M10.5 10.5 L10.5 80.5" clip-path="url(#clipPath15)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath15)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath15)" + /></g + ><g transform="translate(2150,1250)" + ><path fill="none" d="M10.5 290.5 L10.5 10.5" clip-path="url(#clipPath16)" + /><path fill="none" d="M17 279.2417 L10.5 290.5 L4 279.2417" clip-path="url(#clipPath16)" + /><text x="14" font-size="14px" y="158.0547" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1630,490)" + ><path fill="none" d="M10.5 20.5 L1200.5 20.5" clip-path="url(#clipPath17)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath17)" + /><text x="589.8989" font-size="14px" y="16" clip-path="url(#clipPath17)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1250,720)" + ><path fill="none" d="M10.5 530.5 L10.5 10.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M17 519.2417 L10.5 530.5 L4 519.2417" clip-path="url(#clipPath18)" + /><text x="14" font-size="14px" y="278.0547" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1090,600)" + ><path fill="none" d="M10.5 20.5 L80.5 20.5" clip-path="url(#clipPath19)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath19)" + /><text x="29.8989" font-size="14px" y="16" clip-path="url(#clipPath19)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(930,780)" + ><path fill="none" d="M10.5 10.5 L10.5 470.5" clip-path="url(#clipPath20)" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583" clip-path="url(#clipPath20)" + /><text x="14" font-size="14px" y="248.0547" clip-path="url(#clipPath20)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1430,1330)" + ><path fill="none" d="M10.5 20.5 L220.5 20.5" clip-path="url(#clipPath21)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath21)" + /><text x="99.8989" font-size="14px" y="16" clip-path="url(#clipPath21)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1600,1400)" + ><path fill="none" d="M50.5 10.5 L10.5 120.5" clip-path="url(#clipPath22)" + /></g + ><g transform="translate(1890,1250)" + ><path fill="none" d="M10.5 10.5 L10.5 80.5" clip-path="url(#clipPath15)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath15)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath15)" + /></g + ><g transform="translate(2180,810)" + ><path fill="none" d="M90.5 20.5 L10.5 20.5" clip-path="url(#clipPath23)" + /><path fill="none" d="M79.2417 14 L90.5 20.5 L79.2417 27" clip-path="url(#clipPath23)" + /><text x="34.8989" font-size="14px" y="16" clip-path="url(#clipPath23)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(2670,760)" + ><path fill="none" d="M160.5 20.5 L10.5 20.5" clip-path="url(#clipPath24)" + /><path fill="none" d="M149.2417 14 L160.5 20.5 L149.2417 27" clip-path="url(#clipPath24)" + /><text x="69.8989" font-size="14px" y="16" clip-path="url(#clipPath24)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1940,700)" + ><path fill="none" d="M10.5 10.5 L10.5 70.5" clip-path="url(#clipPath25)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath25)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath25)" + /></g + ><g transform="translate(2450,590)" + ><path fill="none" d="M70.5 70.5 L10.5 10.5" clip-path="url(#clipPath26)" + /></g + ><g transform="translate(2200,640)" + ><path fill="none" d="M10.5 20.5 L630.5 20.5" clip-path="url(#clipPath27)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath27)" + /><text x="304.8989" font-size="14px" y="16" clip-path="url(#clipPath27)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-control-module.uxf b/Documentation/contents/figures/arch-control-module.uxf new file mode 100644 index 0000000..20a72ee --- /dev/null +++ b/Documentation/contents/figures/arch-control-module.uxf @@ -0,0 +1,478 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>3</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>849</x> + <y>147</y> + <w>192</w> + <h>102</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ControlInterface +-- +#name_: std::string +#dependencies_: std::vector<std::string> +#executable_controller_interface_: ExecutableControllerInterface& +#executor_: vaf::ModuleExecutor +-- +/+Init(): vaf::Result<void> / +/+Start() noexcept/ +/+Stop() noexcept/ +/+DeInit() noexcept/ ++ReportOperational() ++ReportError(error_code: ErrorCode , msg: std::string , critical: bool = false) +/+OnError(error: const vaf::Error&)/ ++GetName(): std::string ++GetDependencies(): std::vector<std::string> ++StartExecutor() ++StopExecutor() +/+StartEventHandlerForModule(module_name: const std::string&)/ +/+StopEventHandlerForModule(module_name: const std::string& )/ +bg=yellow</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>507</x> + <y>165</y> + <w>156</w> + <h>48</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ExecutableControllerInterface +-- + +-- +/+ReportOperationalOfModule(std::string name)/ +/+ReportErrorOfModule(vaf::Error error, std::string name, bool critical)/ +bg=yellow +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>660</x> + <y>192</y> + <w>195</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;630.0;20.0</additional_attributes> + </element> + <element> + <id>UMLNote</id> + <coordinates> + <x>678</x> + <y>165</y> + <w>60</w> + <h>27</h> + </coordinates> + <panel_attributes>For ReportOperational() and ReportError() +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>735</x> + <y>177</y> + <w>27</w> + <h>27</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>70.0;70.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>582</x> + <y>210</y> + <w>9</w> + <h>27</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>681</x> + <y>228</y> + <w>123</w> + <h>45</h> + </coordinates> + <panel_attributes><<private to vaf::ExecutableControllerBase>> +vaf::ExecutableControllerBase::ModuleContainer +-- ++name_: std::string ++module_: std::shared_ptr<vaf::ControlInterface> ++dependencies_: std::vector<std::string> ++state_: ModuleStates ++starting_counter_: uint64_t +-- + + + +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>801</x> + <y>228</y> + <w>54</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>160.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>654</x> + <y>243</y> + <w>33</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>90.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>483</x> + <y>231</y> + <w>174</w> + <h>147</h> + </coordinates> + <panel_attributes>vaf::ExecutableControllerBase +-- +-signal_handling_init_: int +-runtime_: vaf::Runtime +-shutdown_requested_: std::atomic_bool +-use_execution_mgr_: bool +-logger_: vaf::Logger& +-modules_: std::vector<ModuleContainer> +-user_controller_: std::unique_ptr<UserControllerInterface> +-signal_handler_thread_: std::thread +-- ++Run(use_exec_mgr: bool) noexcept; ++Run(argc: int, argv char**,use_exec_mgr bool) ++InitiateShutdown() ++RegisterModule(module: std::shared_ptr<vaf::ControlInterface>) ++ReportOperationalOfModule(name: std::string) ++ReportErrorOfModule(error: vaf::Error, name std::string , critical bool) +/#DoInitialize()/ +/#DoStart()/ +/#DoShutdown()/ +#WaitForShutdown() +#IsShutdownRequested(): bool +-ChangeStateOfModule(name: std::string , state: ModuleStates ) +-StartModules() +-StartEventHandlersForModule(module_name: const std::string& , dependencies: const std::vector<std::string>&) +-StopEventHandlersForModule(module_name: const std::string& , dependencies const std::vector<std::string>&) +-CheckStartingModules(); +-SetupExecutionManager(); +-ReportStateToExecutionManager(is_running: bool) +-InitializeSignalHandling() +-SignalHandlerThread()</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>495</x> + <y>399</y> + <w>138</w> + <h>42</h> + </coordinates> + <panel_attributes><<Generated>> +executable_controller::ExecutableController +-- +-executor_: std::unique_ptr<vaf::Executor> +-- +#/DoInitialize() +#/DoStart() +#/DoShutdown() +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>567</x> + <y>375</y> + <w>9</w> + <h>30</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes> + </element> + <element> + <id>UMLNote</id> + <coordinates> + <x>438</x> + <y>456</y> + <w>51</w> + <h>27</h> + </coordinates> + <panel_attributes>Class instantiated by main (entry point) +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>480</x> + <y>420</y> + <w>21</w> + <h>42</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>50.0;10.0;10.0;120.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>258</x> + <y>375</y> + <w>174</w> + <h>93</h> + </coordinates> + <panel_attributes>vaf::Executor +-- +-running_period_: std::chrono::milliseconds +-runnables_: std::vector<std::shared_ptr<RunnableHandle>> +-exit_requested_: std::atomic<bool> +-thread_: std::thread +-- ++RunPeriodic(name: const std::string&, + period: std::chrono::milliseconds , + runnable: T&& , + owner: const std::string&, + run_after: const std::vector<std::string>& , + run_after_runnables: const std::vector<std::string>&, + offset: uint64_t, + budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle> +-ExecutorThread +-ExecuteRunnable(runnable: RunnableHandle& )</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>429</x> + <y>399</y> + <w>72</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;220.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>222</x> + <y>123</y> + <w>108</w> + <h>114</h> + </coordinates> + <panel_attributes>vaf::RunnableHandle +-- +-name_: std::string; +-is_active_: bool +-period_: uint64_t +-runnable_: std::function<void(void)> +-owner_: std::string +-run_after_: std::vector<std::string> +-offset_: uint64_t +- budget_: std::chrono::nanoseconds +-- ++Name(): const std::string& ++IsActive(): bool ++Execute() ++Period(): uint64_t ++Start() ++Stop() ++Owner(): const std::string& ++RunAfter(): const std::vector<std::string>& ++Offset(): uint64_t ++Budget(): std::chrono::nanoseconds +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>279</x> + <y>234</y> + <w>18</w> + <h>147</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;10.0;10.0;470.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>351</x> + <y>129</y> + <w>141</w> + <h>90</h> + </coordinates> + <panel_attributes>vaf::ModuleExecutor +-- +-executor_: Executor& +-handles_: std::vector<std::shared_ptr<RunnableHandle>> +-started_: bool +-name_: std::string +-dependencies_ std::vector<std::string> +-- ++Start() ++Stop() ++RunPeriodic(name: const std::string&, + period: std::chrono::milliseconds , + runnable: T&& , + owner: const std::string&, + runnable_dependencies: std::vector<std::string>, + offset: uint64_t, + budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>327</x> + <y>180</y> + <w>30</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;80.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>375</x> + <y>216</y> + <w>18</w> + <h>165</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;530.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>489</x> + <y>147</y> + <w>366</w> + <h>12</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;1200.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>498</x> + <y>462</y> + <w>156</w> + <h>60</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::UserControllerInterface +-- + +-- +/+PreInitialize()/ +/+PostInitialize()/ +/+PreStart()/ +/+PostStart()/ +/+PreShutdown()/ +/+PostShutdown()/ +/+OnError(vaf::Error error, std::string name, bool critical)/ +bg=yellow +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>645</x> + <y>375</y> + <w>18</w> + <h>93</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;290.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>498</x> + <y>543</y> + <w>159</w> + <h>60</h> + </coordinates> + <panel_attributes><<Stubs Generated>> +UserController +-- + +-- ++/PreInitialize() ++/PostInitialize() ++/PreStart() ++/PostStart() ++/PreShutdown() ++/PostShutdown() + + + + + +bg=red</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLPackage</id> + <coordinates> + <x>207</x> + <y>105</y> + <w>612</w> + <h>513</h> + </coordinates> + <panel_attributes>Control module +-- +layer=-4 +bg=white</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>549</x> + <y>519</y> + <w>9</w> + <h>30</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-executor-module.svg b/Documentation/contents/figures/arch-executor-module.svg new file mode 100644 index 0000000..7a3dcc6 --- /dev/null +++ b/Documentation/contents/figures/arch-executor-module.svg @@ -0,0 +1,441 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="2110" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="690 220 2110 1880" height="1880" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 1840 L2070 1840 L2070 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 200 L530 200 L530 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 200 L520 200 L520 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 300 L470 300 L470 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 380 L360 380 L360 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 310 L580 310 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 90 L200 90 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 140 L460 140 L460 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 490 L580 490 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11" + ><path d="M0 0 L0 150 L410 150 L410 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12" + ><path d="M0 0 L0 160 L520 160 L520 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13" + ><path d="M0 0 L0 110 L30 110 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14" + ><path d="M0 0 L0 350 L60 350 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15" + ><path d="M0 0 L0 530 L60 530 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16" + ><path d="M0 0 L0 40 L120 40 L120 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17" + ><path d="M0 0 L0 470 L60 470 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18" + ><path d="M0 0 L0 40 L240 40 L240 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19" + ><path d="M0 0 L0 140 L70 140 L70 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath20" + ><path d="M0 0 L0 90 L30 90 L30 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(710,240)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><path d="M0.5 0.5 L828.5 0.5 L828.5 21.6094 L2069 21.6094 L2069 1839 L0.5 1839 L0.5 0.5" stroke="none" clip-path="url(#clipPath2)" + /></g + ><g transform="translate(710,240)" + ><path fill="none" d="M0.5 0.5 L828.5 0.5 L828.5 21.6094 L2069 21.6094 L2069 1839 L0.5 1839 L0.5 0.5" clip-path="url(#clipPath2)" + /><path fill="none" d="M0.5 21.6094 L828.5 21.6094" clip-path="url(#clipPath2)" + /><text x="5" font-size="14px" y="16.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Controller</text + ></g + ><g fill="rgb(255,0,0)" fill-opacity="0.4902" transform="translate(1710,1750)" stroke-opacity="0.4902" stroke="rgb(255,0,0)" + ><rect x="0.5" width="528.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1710,1750)" + ><rect fill="none" x="0.5" width="528.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="197" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Stubs Generated»</text + ><text x="214" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >UserController</text + ><path fill="none" d="M1 40.2188 L529 40.2188" clip-path="url(#clipPath3)" + /><path fill="none" d="M1 61.3281 L529 61.3281" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostInitialize()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreStart()</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostStart()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PreShutdown()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/PostShutdown()</text + ></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(1720,1470)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="518.5" height="198.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1720,1470)" + ><rect fill="none" x="0.5" width="518.5" height="198.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="220" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="162" font-size="14px" y="34.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::UserControllerInterface</text + ><path fill="none" d="M1 40.2188 L519 40.2188" clip-path="url(#clipPath4)" + /><path fill="none" d="M1 61.3281 L519 61.3281" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostInitialize()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreStart()</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostStart()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PreShutdown()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+PostShutdown()</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath4)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+OnError(vaf::Error error, std::string name, bool critical)</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1210,330)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="468.5" height="298.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(1210,330)" + ><rect fill="none" x="0.5" width="468.5" height="298.5" y="0.5" clip-path="url(#clipPath5)" + /><text x="162" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ModuleExecutor</text + ><path fill="none" d="M1 24.1094 L469 24.1094" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-executor_: Executor&</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-handles_: std::vector<std::shared_ptr<RunnableHandle»</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-started_: bool</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-name_: std::string</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-dependencies_ std::vector<std::string></text + ><path fill="none" d="M1 109.6562 L469 109.6562" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Start()</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Stop()</text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunPeriodic(name: const std::string&, </text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > period: std::chrono::milliseconds , </text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable: T&& , </text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > owner: const std::string&, </text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable_dependencies: std::vector<std::string>,</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > offset: uint64_t,</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + > budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(760,310)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="358.5" height="378.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(760,310)" + ><rect fill="none" x="0.5" width="358.5" height="378.5" y="0.5" clip-path="url(#clipPath6)" + /><text x="106" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::RunnableHandle</text + ><path fill="none" d="M1 24.1094 L359 24.1094" clip-path="url(#clipPath6)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-name_: std::string;</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-is_active_: bool</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-period_: uint64_t</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runnable_: std::function<void(void)></text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-owner_: std::string</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-run_after_: std::vector<std::string></text + ><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-offset_: uint64_t</text + ><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >- budget_: std::chrono::nanoseconds</text + ><path fill="none" d="M1 157.9844 L359 157.9844" clip-path="url(#clipPath6)" + /><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Name(): const std::string&</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+IsActive(): bool</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Execute()</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Period(): uint64_t</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Start()</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Stop()</text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Owner(): const std::string&</text + ><text x="5" font-size="14px" y="285.8594" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunAfter(): const std::vector<std::string>&</text + ><text x="5" font-size="14px" y="301.9688" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Offset(): uint64_t</text + ><text x="5" font-size="14px" y="318.0781" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Budget(): std::chrono::nanoseconds</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(880,1130)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="578.5" height="308.5" y="0.5" clip-path="url(#clipPath7)" stroke="none" + /></g + ><g transform="translate(880,1130)" + ><rect fill="none" x="0.5" width="578.5" height="308.5" y="0.5" clip-path="url(#clipPath7)" + /><text x="243" font-size="14px" y="18.1094" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::Executor</text + ><path fill="none" d="M1 24.1094 L579 24.1094" clip-path="url(#clipPath7)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-running_period_: std::chrono::milliseconds </text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runnables_: std::vector<std::shared_ptr<RunnableHandle»</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-exit_requested_: std::atomic<bool></text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-thread_: std::thread</text + ><path fill="none" d="M1 93.5469 L579 93.5469" clip-path="url(#clipPath7)" + /><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RunPeriodic(name: const std::string&, </text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > period: std::chrono::milliseconds , </text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > runnable: T&& , </text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > owner: const std::string&, </text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > run_after: const std::vector<std::string>& ,</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > run_after_runnables: const std::vector<std::string>&,</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > offset: uint64_t,</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + > budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ExecutorThread</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath7)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ExecuteRunnable(runnable: RunnableHandle& )</text + ></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1480,1420)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><path d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" stroke="none" clip-path="url(#clipPath8)" + /></g + ><g transform="translate(1480,1420)" + ><path fill="none" d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" clip-path="url(#clipPath8)" + /><path fill="none" d="M188.5 0.5 L188.5 12.5 L199 12.5" clip-path="url(#clipPath8)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath8)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Class instantiated by</text + ><text x="5" font-size="14px" y="34.2188" clip-path="url(#clipPath8)" font-family="sans-serif" stroke="none" xml:space="preserve" + >main (entry point)</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1670,1230)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="458.5" height="138.5" y="0.5" clip-path="url(#clipPath9)" stroke="none" + /></g + ><g transform="translate(1670,1230)" + ><rect fill="none" x="0.5" width="458.5" height="138.5" y="0.5" clip-path="url(#clipPath9)" + /><text x="184" font-size="14px" y="18.1094" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="75" font-size="14px" y="34.2188" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >executable_controller::ExecutableController</text + ><path fill="none" d="M1 40.2188 L459 40.2188" clip-path="url(#clipPath9)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-executor_: std::unique_ptr<vaf::Executor> </text + ><path fill="none" d="M1 61.3281 L459 61.3281" clip-path="url(#clipPath9)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoInitialize()</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoStart()</text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#/DoShutdown()</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1610,660)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="578.5" height="488.5" y="0.5" clip-path="url(#clipPath10)" stroke="none" + /></g + ><g transform="translate(1610,660)" + ><rect fill="none" x="0.5" width="578.5" height="488.5" y="0.5" clip-path="url(#clipPath10)" + /><text x="183" font-size="14px" y="18.1094" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerBase</text + ><path fill="none" d="M1 24.1094 L579 24.1094" clip-path="url(#clipPath10)" + /><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-signal_handling_init_: int</text + ><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-runtime_: vaf::Runtime</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-shutdown_requested_: std::atomic_bool</text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-use_execution_mgr_: bool</text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-logger_: vaf::Logger&</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-modules_: std::vector<ModuleContainer></text + ><text x="5" font-size="14px" y="135.875" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-user_controller_: std::unique_ptr<UserControllerInterface></text + ><text x="5" font-size="14px" y="151.9844" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-signal_handler_thread_: std::thread</text + ><path fill="none" d="M1 157.9844 L579 157.9844" clip-path="url(#clipPath10)" + /><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Run(use_exec_mgr: bool) noexcept;</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+Run(argc: int, argv char**,use_exec_mgr bool)</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+InitiateShutdown()</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+RegisterModule(module: std::shared_ptr<vaf::ControlInterface>)</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportOperationalOfModule(name: std::string)</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+ReportErrorOfModule(error: vaf::Error, name std::string , critical bool)</text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoInitialize()</text + ><text x="5" font-size="14px" y="285.8594" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoStart()</text + ><text x="5" font-size="14px" y="301.9688" clip-path="url(#clipPath10)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >#DoShutdown()</text + ><text x="5" font-size="14px" y="318.0781" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#WaitForShutdown()</text + ><text x="5" font-size="14px" y="334.1875" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >#IsShutdownRequested(): bool</text + ><text x="5" font-size="14px" y="350.2969" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ChangeStateOfModule(name: std::string , state: ModuleStates )</text + ><text x="5" font-size="14px" y="366.4062" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StartModules()</text + ><text x="5" font-size="14px" y="382.5156" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StartEventHandlersForModule(module_name: const std::string& , dependencies: const std::vector<std::string>&)</text + ><text x="5" font-size="14px" y="398.625" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-StopEventHandlersForModule(module_name: const std::string& , dependencies const std::vector<std::string>&)</text + ><text x="5" font-size="14px" y="414.7344" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-CheckStartingModules();</text + ><text x="5" font-size="14px" y="430.8438" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-SetupExecutionManager();</text + ><text x="5" font-size="14px" y="446.9531" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-ReportStateToExecutionManager(is_running: bool)</text + ><text x="5" font-size="14px" y="463.0625" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-InitializeSignalHandling()</text + ><text x="5" font-size="14px" y="479.1719" clip-path="url(#clipPath10)" font-family="sans-serif" stroke="none" xml:space="preserve" + >-SignalHandlerThread()</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(2280,650)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="408.5" height="148.5" y="0.5" clip-path="url(#clipPath11)" stroke="none" + /></g + ><g transform="translate(2280,650)" + ><rect fill="none" x="0.5" width="408.5" height="148.5" y="0.5" clip-path="url(#clipPath11)" + /><text x="54" font-size="14px" y="18.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«private to vaf::ExecutableControllerBase»</text + ><text x="34" font-size="14px" y="34.2188" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerBase::ModuleContainer</text + ><path fill="none" d="M1 40.2188 L409 40.2188" clip-path="url(#clipPath11)" + /><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+name_: std::string</text + ><text x="5" font-size="14px" y="71.4375" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+module_: std::shared_ptr<vaf::ControlInterface></text + ><text x="5" font-size="14px" y="87.5469" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+dependencies_: std::vector<std::string></text + ><text x="5" font-size="14px" y="103.6562" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+state_: ModuleStates</text + ><text x="5" font-size="14px" y="119.7656" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+starting_counter_: uint64_t</text + ><path fill="none" d="M1 125.7656 L409 125.7656" clip-path="url(#clipPath11)" + /></g + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(1740,440)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="518.5" height="158.5" y="0.5" clip-path="url(#clipPath12)" stroke="none" + /></g + ><g transform="translate(1740,440)" + ><rect fill="none" x="0.5" width="518.5" height="158.5" y="0.5" clip-path="url(#clipPath12)" + /><text x="220" font-size="14px" y="18.1094" clip-path="url(#clipPath12)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="139" font-size="14px" y="34.2188" clip-path="url(#clipPath12)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ExecutableControllerInterface</text + ><path fill="none" d="M1 40.2188 L519 40.2188" clip-path="url(#clipPath12)" + /><path fill="none" d="M1 61.3281 L519 61.3281" clip-path="url(#clipPath12)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath12)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+ReportOperationalOfModule(std::string name)</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath12)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+ReportErrorOfModule(vaf::Error error, std::string name, bool critical)</text + ></g + ><g transform="translate(1880,1660)" + ><path fill="none" d="M10.5 10.5 L10.5 90.5" clip-path="url(#clipPath13)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath13)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath13)" + /></g + ><g transform="translate(2150,1140)" + ><path fill="none" d="M10.5 330.5 L10.5 10.5" clip-path="url(#clipPath14)" + /><path fill="none" d="M17 319.2417 L10.5 330.5 L4 319.2417" clip-path="url(#clipPath14)" + /><text x="14" font-size="14px" y="178.0547" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1280,620)" + ><path fill="none" d="M10.5 510.5 L10.5 10.5" clip-path="url(#clipPath15)" + /><path fill="none" d="M17 499.2417 L10.5 510.5 L4 499.2417" clip-path="url(#clipPath15)" + /><text x="14" font-size="14px" y="268.0547" clip-path="url(#clipPath15)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1110,500)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath16)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath16)" + /><text x="39.8989" font-size="14px" y="16" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(950,680)" + ><path fill="none" d="M10.5 10.5 L10.5 450.5" clip-path="url(#clipPath17)" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583" clip-path="url(#clipPath17)" + /><text x="14" font-size="14px" y="238.0547" clip-path="url(#clipPath17)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1450,1230)" + ><path fill="none" d="M10.5 20.5 L220.5 20.5" clip-path="url(#clipPath18)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath18)" + /><text x="99.8989" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1620,1300)" + ><path fill="none" d="M50.5 10.5 L10.5 120.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(1860,1140)" + ><path fill="none" d="M10.5 10.5 L10.5 90.5" clip-path="url(#clipPath13)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath13)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath13)" + /></g + ><g transform="translate(2180,730)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath16)" + /><path fill="none" d="M89.2417 14 L100.5 20.5 L89.2417 27" clip-path="url(#clipPath16)" + /><text x="39.8989" font-size="14px" y="16" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1940,590)" + ><path fill="none" d="M10.5 10.5 L10.5 70.5" clip-path="url(#clipPath20)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath20)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath20)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-executor-module.uxf b/Documentation/contents/figures/arch-executor-module.uxf new file mode 100644 index 0000000..1f0966d --- /dev/null +++ b/Documentation/contents/figures/arch-executor-module.uxf @@ -0,0 +1,409 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <help_text>// Uncomment the following line to change the fontsize and font: +// fontsize=14 +// fontfamily=SansSerif //possible: SansSerif,Serif,Monospaced + + +////////////////////////////////////////////////////////////////////////////////////////////// +// Welcome to UMLet! +// +// Double-click on elements to add them to the diagram, or to copy them +// Edit elements by modifying the text in this panel +// Hold Ctrl to select multiple elements +// Use Ctrl+mouse to select via lasso +// +// Use +/- or Ctrl+mouse wheel to zoom +// Drag a whole relation at its central square icon +// +// Press Ctrl+C to copy the whole diagram to the system clipboard (then just paste it to, eg, Word) +// Edit the files in the "palettes" directory to create your own element palettes +// +// Select "Custom Elements > New..." to create new element types +////////////////////////////////////////////////////////////////////////////////////////////// + + +// This text will be stored with each diagram; use it for notes.file:///home/visdks/Projects/014_FC_ApplicationFramework/FTAF-409/pes-ft-applicationframework/Concepts/dominik-uml-diagramm-for-vaf-FTAF-336/ClassDiagram.uxf +</help_text> + <zoom_level>7</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>1218</x> + <y>308</y> + <w>364</w> + <h>112</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ExecutableControllerInterface +-- + +-- +/+ReportOperationalOfModule(std::string name)/ +/+ReportErrorOfModule(vaf::Error error, std::string name, bool critical)/ +bg=yellow +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1358</x> + <y>413</y> + <w>21</w> + <h>63</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1596</x> + <y>455</y> + <w>287</w> + <h>105</h> + </coordinates> + <panel_attributes><<private to vaf::ExecutableControllerBase>> +vaf::ExecutableControllerBase::ModuleContainer +-- ++name_: std::string ++module_: std::shared_ptr<vaf::ControlInterface> ++dependencies_: std::vector<std::string> ++state_: ModuleStates ++starting_counter_: uint64_t +-- + + + +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1526</x> + <y>511</y> + <w>84</w> + <h>28</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1127</x> + <y>462</y> + <w>406</w> + <h>343</h> + </coordinates> + <panel_attributes>vaf::ExecutableControllerBase +-- +-signal_handling_init_: int +-runtime_: vaf::Runtime +-shutdown_requested_: std::atomic_bool +-use_execution_mgr_: bool +-logger_: vaf::Logger& +-modules_: std::vector<ModuleContainer> +-user_controller_: std::unique_ptr<UserControllerInterface> +-signal_handler_thread_: std::thread +-- ++Run(use_exec_mgr: bool) noexcept; ++Run(argc: int, argv char**,use_exec_mgr bool) ++InitiateShutdown() ++RegisterModule(module: std::shared_ptr<vaf::ControlInterface>) ++ReportOperationalOfModule(name: std::string) ++ReportErrorOfModule(error: vaf::Error, name std::string , critical bool) +/#DoInitialize()/ +/#DoStart()/ +/#DoShutdown()/ +#WaitForShutdown() +#IsShutdownRequested(): bool +-ChangeStateOfModule(name: std::string , state: ModuleStates ) +-StartModules() +-StartEventHandlersForModule(module_name: const std::string& , dependencies: const std::vector<std::string>&) +-StopEventHandlersForModule(module_name: const std::string& , dependencies const std::vector<std::string>&) +-CheckStartingModules(); +-SetupExecutionManager(); +-ReportStateToExecutionManager(is_running: bool) +-InitializeSignalHandling() +-SignalHandlerThread()</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1169</x> + <y>861</y> + <w>322</w> + <h>98</h> + </coordinates> + <panel_attributes><<Generated>> +executable_controller::ExecutableController +-- +-executor_: std::unique_ptr<vaf::Executor> +-- +#/DoInitialize() +#/DoStart() +#/DoShutdown() +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1302</x> + <y>798</y> + <w>21</w> + <h>77</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;90.0</additional_attributes> + </element> + <element> + <id>UMLNote</id> + <coordinates> + <x>1036</x> + <y>994</y> + <w>140</w> + <h>63</h> + </coordinates> + <panel_attributes>Class instantiated by main (entry point) +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1134</x> + <y>910</y> + <w>49</w> + <h>98</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>50.0;10.0;10.0;120.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>616</x> + <y>791</y> + <w>406</w> + <h>217</h> + </coordinates> + <panel_attributes>vaf::Executor +-- +-running_period_: std::chrono::milliseconds +-runnables_: std::vector<std::shared_ptr<RunnableHandle>> +-exit_requested_: std::atomic<bool> +-thread_: std::thread +-- ++RunPeriodic(name: const std::string&, + period: std::chrono::milliseconds , + runnable: T&& , + owner: const std::string&, + run_after: const std::vector<std::string>& , + run_after_runnables: const std::vector<std::string>&, + offset: uint64_t, + budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle> +-ExecutorThread +-ExecuteRunnable(runnable: RunnableHandle& )</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1015</x> + <y>861</y> + <w>168</w> + <h>28</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;220.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>532</x> + <y>217</y> + <w>252</w> + <h>266</h> + </coordinates> + <panel_attributes>vaf::RunnableHandle +-- +-name_: std::string; +-is_active_: bool +-period_: uint64_t +-runnable_: std::function<void(void)> +-owner_: std::string +-run_after_: std::vector<std::string> +-offset_: uint64_t +- budget_: std::chrono::nanoseconds +-- ++Name(): const std::string& ++IsActive(): bool ++Execute() ++Period(): uint64_t ++Start() ++Stop() ++Owner(): const std::string& ++RunAfter(): const std::vector<std::string>& ++Offset(): uint64_t ++Budget(): std::chrono::nanoseconds</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>665</x> + <y>476</y> + <w>42</w> + <h>329</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;10.0;10.0;450.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>847</x> + <y>231</y> + <w>329</w> + <h>210</h> + </coordinates> + <panel_attributes>vaf::ModuleExecutor +-- +-executor_: Executor& +-handles_: std::vector<std::shared_ptr<RunnableHandle>> +-started_: bool +-name_: std::string +-dependencies_ std::vector<std::string> +-- ++Start() ++Stop() ++RunPeriodic(name: const std::string&, + period: std::chrono::milliseconds , + runnable: T&& , + owner: const std::string&, + runnable_dependencies: std::vector<std::string>, + offset: uint64_t, + budget: std::chrono::nanoseconds): std::shared_ptr<RunnableHandle></panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>777</x> + <y>350</y> + <w>84</w> + <h>28</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>896</x> + <y>434</y> + <w>42</w> + <h>371</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;510.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1204</x> + <y>1029</y> + <w>364</w> + <h>140</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::UserControllerInterface +-- + +-- +/+PreInitialize()/ +/+PostInitialize()/ +/+PreStart()/ +/+PostStart()/ +/+PreShutdown()/ +/+PostShutdown()/ +/+OnError(vaf::Error error, std::string name, bool critical)/ +bg=yellow +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1505</x> + <y>798</y> + <w>42</w> + <h>245</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;330.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1197</x> + <y>1225</y> + <w>371</w> + <h>140</h> + </coordinates> + <panel_attributes><<Stubs Generated>> +UserController +-- + +-- ++/PreInitialize() ++/PostInitialize() ++/PreStart() ++/PostStart() ++/PreShutdown() ++/PostShutdown() + + + + + +bg=red</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLPackage</id> + <coordinates> + <x>497</x> + <y>168</y> + <w>1449</w> + <h>1288</h> + </coordinates> + <panel_attributes>Controller +-- +layer=-4</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1316</x> + <y>1162</y> + <w>21</w> + <h>77</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;90.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-internal-com-module.svg b/Documentation/contents/figures/arch-internal-com-module.svg new file mode 100644 index 0000000..fc2d48d --- /dev/null +++ b/Documentation/contents/figures/arch-internal-com-module.svg @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1340" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="630 100 1340 720" height="720" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 80 L580 80 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 80 L640 80 L640 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 80 L620 80 L620 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 90 L200 90 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 300 L1300 300 L1300 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 190 L30 190 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 80 L60 80 L60 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 90 L30 90 L30 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(1010,120)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="578.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1010,120)" + ><rect fill="none" x="0.5" width="578.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="250" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="217" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ControlInterface</text + ><path fill="none" d="M1 40.2188 L579 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1310,220)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1310,220)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="274" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="86" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath3)" + /></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(650,220)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="618.5" height="78.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(650,220)" + ><rect fill="none" x="0.5" width="618.5" height="78.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="264" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="82" font-size="14px" y="34.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider</text + ><path fill="none" d="M1 40.2188 L619 40.2188" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1750,710)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><path d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" stroke="none" clip-path="url(#clipPath5)" + /></g + ><g transform="translate(1750,710)" + ><path fill="none" d="M0.5 0.5 L188.5 0.5 L199 12.5 L199 89 L0.5 89 L0.5 0.5" clip-path="url(#clipPath5)" + /><path fill="none" d="M188.5 0.5 L188.5 12.5 L199 12.5" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Stands for</text + ><text x="5" font-size="14px" y="34.2188" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >executable-internal</text + ><text x="5" font-size="14px" y="50.3281" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >communication</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(650,360)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="1298.5" height="298.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(650,360)" + ><rect fill="none" x="0.5" width="1298.5" height="298.5" y="0.5" clip-path="url(#clipPath6)" + /><text x="604" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="350" font-size="14px" y="34.2188" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{InternalCommunicationModuleNamespace}::{InternalCommunicationModuleName}</text + ><path fill="none" d="M1 40.2188 L1299 40.2188" clip-path="url(#clipPath6)" + /><path fill="none" d="M1 61.3281 L1299 61.3281" clip-path="url(#clipPath6)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Data Elements:</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> ></text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void></text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void></text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> ></text + ><text x="5" font-size="14px" y="156.9844" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Get_{DataElementName}(): {DataElementType}</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&)</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="221.4219" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Operations:</text + ><text x="5" font-size="14px" y="237.5312" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f)</text + ><text x="5" font-size="14px" y="253.6406" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output></text + ><text x="5" font-size="14px" y="269.75" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g transform="translate(1280,190)" + ><path fill="none" d="M10.5 10.5 L10.5 170.5" clip-path="url(#clipPath7)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath7)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath7)" + /></g + ><g transform="translate(1810,650)" + ><path fill="none" d="M10.5 10.5 L40.5 60.5" clip-path="url(#clipPath8)" + /></g + ><g transform="translate(1610,290)" + ><path fill="none" d="M10.5 10.5 L10.5 70.5" clip-path="url(#clipPath9)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath9)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath9)" + /></g + ><g transform="translate(960,290)" + ><path fill="none" d="M10.5 10.5 L10.5 70.5" clip-path="url(#clipPath9)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath9)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath9)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-internal-com-module.uxf b/Documentation/contents/figures/arch-internal-com-module.uxf new file mode 100644 index 0000000..41490f6 --- /dev/null +++ b/Documentation/contents/figures/arch-internal-com-module.uxf @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>11</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>715</x> + <y>396</y> + <w>1430</w> + <h>330</h> + </coordinates> + <panel_attributes><<Generated>> +{InternalCommunicationModuleNamespace}::{InternalCommunicationModuleName} +-- + +-- +Data Elements: ++/Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> > ++/SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void> ++/Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void> ++/GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> > ++/Get_{DataElementName}(): {DataElementType} ++/RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&) +... + +Operations: ++/RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f) ++/{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output> +... +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1056</x> + <y>319</y> + <w>33</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1771</x> + <y>319</y> + <w>33</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>UMLNote</id> + <coordinates> + <x>1925</x> + <y>781</y> + <w>220</w> + <h>99</h> + </coordinates> + <panel_attributes>Stands for executable-internal communication +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1991</x> + <y>715</y> + <w>66</w> + <h>88</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;10.0;40.0;60.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>715</x> + <y>242</y> + <w>682</w> + <h>88</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1441</x> + <y>242</y> + <w>704</w> + <h>88</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1408</x> + <y>209</y> + <w>33</w> + <h>209</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;170.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1111</x> + <y>132</y> + <w>638</w> + <h>88</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ControlInterface +-- + +bg=yellow</panel_attributes> + <additional_attributes/> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-module-if.svg b/Documentation/contents/figures/arch-module-if.svg new file mode 100644 index 0000000..20e00ba --- /dev/null +++ b/Documentation/contents/figures/arch-module-if.svg @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="2940" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="120 220 2940 370" height="370" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 220 L1200 220 L1200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 220 L1100 220 L1100 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 140 L260 140 L260 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 170 L260 170 L260 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 40 L200 40 L200 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(140,270)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="1198.5" height="218.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(140,270)" + ><rect fill="none" x="0.5" width="1198.5" height="218.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="554" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="372" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider</text + ><path fill="none" d="M1 40.2188 L1199 40.2188" clip-path="url(#clipPath2)" + /><path fill="none" d="M1 61.3281 L1199 61.3281" clip-path="url(#clipPath2)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Data Elements:</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath2)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> ></text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath2)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void></text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath2)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void></text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Operations:</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath2)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f)</text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1940,270)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="1098.5" height="218.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1940,270)" + ><rect fill="none" x="0.5" width="1098.5" height="218.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="504" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="316" font-size="14px" y="34.2188" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer</text + ><path fill="none" d="M1 40.2188 L1099 40.2188" clip-path="url(#clipPath3)" + /><path fill="none" d="M1 61.3281 L1099 61.3281" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Data Elements:</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath3)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> ></text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath3)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+Get_{DataElementName}(): {DataElementType}</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath3)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&)</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Operations:</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath3)" font-family="sans-serif" font-style="italic" stroke="none" xml:space="preserve" + >+{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output></text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1510,240)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><path d="M0.5 0.5 L117.5898 0.5 L117.5898 21.6094 L259 21.6094 L259 139 L0.5 139 L0.5 0.5" stroke="none" clip-path="url(#clipPath4)" + /></g + ><g transform="translate(1510,240)" + ><path fill="none" d="M0.5 0.5 L117.5898 0.5 L117.5898 21.6094 L259 21.6094 L259 139 L0.5 139 L0.5 0.5" clip-path="url(#clipPath4)" + /><path fill="none" d="M0.5 21.6094 L117.5898 21.6094" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="16.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >BaseDataTypes</text + ><text x="115" font-size="14px" y="53.3906" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >bool</text + ><text x="106" font-size="14px" y="69.5" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >double</text + ><text x="114" font-size="14px" y="85.6094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >float</text + ><text x="120" font-size="14px" y="101.7188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >int</text + ><text x="116" font-size="14px" y="117.8281" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uint</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1510,400)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><path d="M0.5 0.5 L175.1992 0.5 L175.1992 21.6094 L259 21.6094 L259 169 L0.5 169 L0.5 0.5" stroke="none" clip-path="url(#clipPath5)" + /></g + ><g transform="translate(1510,400)" + ><path fill="none" d="M0.5 0.5 L175.1992 0.5 L175.1992 21.6094 L259 21.6094 L259 169 L0.5 169 L0.5 0.5" clip-path="url(#clipPath5)" + /><path fill="none" d="M0.5 21.6094 L175.1992 21.6094" clip-path="url(#clipPath5)" + /><text x="5" font-size="14px" y="16.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»DataTypes</text + ><text x="107" font-size="14px" y="52.2812" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Arrays</text + ><text x="106" font-size="14px" y="68.3906" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Enums</text + ><text x="111" font-size="14px" y="84.5" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Maps</text + ><text x="105" font-size="14px" y="100.6094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Strings</text + ><text x="105" font-size="14px" y="116.7188" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Structs</text + ><text x="99" font-size="14px" y="132.8281" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Typerefs</text + ><text x="103" font-size="14px" y="148.9375" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Vectors</text + ></g + ><g transform="translate(1330,300)" + ><path fill="none" d="M180.5 20.5 L10.5 20.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M169.2417 14 L180.5 20.5 L169.2417 27" clip-path="url(#clipPath6)" + /><text x="79.8989" font-size="14px" y="16" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1330,440)" + ><path fill="none" d="M180.5 20.5 L10.5 20.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M169.2417 14 L180.5 20.5 L169.2417 27" clip-path="url(#clipPath6)" + /><text x="79.8989" font-size="14px" y="16" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1760,300)" + ><path fill="none" d="M10.5 20.5 L180.5 20.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath6)" + /><text x="79.8989" font-size="14px" y="16" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1760,440)" + ><path fill="none" d="M10.5 20.5 L180.5 20.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath6)" + /><text x="79.8989" font-size="14px" y="16" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-module-if.uxf b/Documentation/contents/figures/arch-module-if.uxf new file mode 100644 index 0000000..60140fb --- /dev/null +++ b/Documentation/contents/figures/arch-module-if.uxf @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>9</zoom_level> + <element> + <id>UMLPackage</id> + <coordinates> + <x>1359</x> + <y>360</y> + <w>234</w> + <h>153</h> + </coordinates> + <panel_attributes><<Generated>>DataTypes +-- +Arrays +Enums +Maps +Strings +Structs +Typerefs +Vectors +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1584</x> + <y>396</y> + <w>180</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;180.0;20.0</additional_attributes> + </element> + <element> + <id>UMLPackage</id> + <coordinates> + <x>1359</x> + <y>216</y> + <w>234</w> + <h>126</h> + </coordinates> + <panel_attributes>BaseDataTypes +-- +bool +double +float +int +uint</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1584</x> + <y>270</y> + <w>180</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;20.0;180.0;20.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1746</x> + <y>243</y> + <w>990</w> + <h>198</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer +-- + +-- +Data Elements: +/+GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> >/ +/+Get_{DataElementName}(): {DataElementType}/ +/+RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&)/ +... + +Operations: +/+{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output>/ +... +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>126</x> + <y>243</y> + <w>1080</w> + <h>198</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Provider +-- + +-- +Data Elements: +/+Allocate_{DataElementName}(): vaf::Result<vaf::DataPtr<{DataElementType}> >/ +/+SetAllocated_{DataElementName}(data: vaf::DataPtr<{DataElementType}>&&): vaf::Result<void>/ +/+Set_{DataElementName}(const {data: DataElementType}&): vaf::Result<void>/ +... + +Operations: +/+RegisterOperationHandler_{OperationName}(std::function<namespace::{OperationName}::Output({ParameterName}: const {ParameterDataType}&, ...)>&& f)/ +... +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1197</x> + <y>396</y> + <w>180</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>180.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1197</x> + <y>270</y> + <w>180</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>180.0;20.0;10.0;20.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-provider-module.svg b/Documentation/contents/figures/arch-provider-module.svg new file mode 100644 index 0000000..f1350f1 --- /dev/null +++ b/Documentation/contents/figures/arch-provider-module.svg @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1340" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="450 200 1340 530" height="530" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 80 L640 80 L640 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 80 L480 80 L480 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 230 L1110 230 L1110 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 80 L30 80 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 80 L60 80 L60 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,255,0)" fill-opacity="0.4902" transform="translate(470,220)" stroke-opacity="0.4902" stroke="rgb(255,255,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(470,220)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="280" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Interface»</text + ><text x="247" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::ControlInterface</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(1130,220)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1130,220)" + ><rect fill="none" x="0.5" width="638.5" height="78.5" y="0.5" clip-path="url(#clipPath2)" + /><text x="274" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="86" font-size="14px" y="34.2188" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer</text + ><path fill="none" d="M1 40.2188 L639 40.2188" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(860,630)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="478.5" height="78.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(860,630)" + ><rect fill="none" x="0.5" width="478.5" height="78.5" y="0.5" clip-path="url(#clipPath3)" + /><text x="102" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Concrete Platform (for example SIL Kit)</text + ></g + ><g fill="rgb(255,165,0)" fill-opacity="0.4902" transform="translate(570,350)" stroke-opacity="0.4902" stroke="rgb(255,165,0)" + ><rect x="0.5" width="1108.5" height="228.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(570,350)" + ><rect fill="none" x="0.5" width="1108.5" height="228.5" y="0.5" clip-path="url(#clipPath4)" + /><text x="509" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >«Generated»</text + ><text x="348" font-size="14px" y="34.2188" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >{ConsumerModuleNamespace}::{ConsumerModuleName}</text + ><path fill="none" d="M1 40.2188 L1109 40.2188" clip-path="url(#clipPath4)" + /><path fill="none" d="M1 61.3281 L1109 61.3281" clip-path="url(#clipPath4)" + /><text x="5" font-size="14px" y="76.4375" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >DataElements:</text + ><text x="5" font-size="14px" y="92.5469" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> ></text + ><text x="5" font-size="14px" y="108.6562" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/Get_{DataElementName}(): {DataElementType}</text + ><text x="5" font-size="14px" y="124.7656" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&)</text + ><text x="5" font-size="14px" y="140.875" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ><text x="5" font-size="14px" y="173.0938" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Operations:</text + ><text x="5" font-size="14px" y="189.2031" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >+/{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output></text + ><text x="5" font-size="14px" y="205.3125" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve" + >...</text + ></g + ><g transform="translate(790,290)" + ><path fill="none" d="M10.5 10.5 L10.5 60.5" clip-path="url(#clipPath5)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" + /></g + ><g transform="translate(1070,570)" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath6)" + /><path fill="none" d="M17 49.2417 L10.5 60.5 L4 49.2417" clip-path="url(#clipPath6)" + /><text x="14" font-size="14px" y="43.0547" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve" + >uses</text + ></g + ><g transform="translate(1450,290)" + ><path fill="none" d="M10.5 10.5 L10.5 60.5" clip-path="url(#clipPath5)" + /><path fill="white" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" stroke="none" + /><path fill="none" d="M4 21.7583 L10.5 10.5 L17 21.7583 L4 21.7583" clip-path="url(#clipPath5)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-provider-module.uxf b/Documentation/contents/figures/arch-provider-module.uxf new file mode 100644 index 0000000..bcaf30b --- /dev/null +++ b/Documentation/contents/figures/arch-provider-module.uxf @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>13</zoom_level> + <element> + <id>UMLClass</id> + <coordinates> + <x>741</x> + <y>455</y> + <w>1443</w> + <h>299</h> + </coordinates> + <panel_attributes><<Generated>> +{ConsumerModuleNamespace}::{ConsumerModuleName} +-- + +-- +DataElements: ++/GetAllocated_{DataElementName}(): vaf::Result<vaf::ConstDataPtr<const {DataElementType}> > ++/Get_{DataElementName}(): {DataElementType} ++/RegisterDataElementHandler_{DataElementName}(owner: std::string, f: std::function<void(const vaf::ConstDataPtr<const {DataElementType}>)>&&) +... + +Operations: ++/{OperationName}({ParameterName}: const {ParameterDataType}&, ...): ::vaf::Future<namespace::{OperationName}::Output> +... +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1885</x> + <y>377</y> + <w>39</w> + <h>104</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;60.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1118</x> + <y>819</y> + <w>624</w> + <h>104</h> + </coordinates> + <panel_attributes>Concrete Platform (for example SIL Kit) +bg=gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1391</x> + <y>741</y> + <w>78</w> + <h>104</h> + </coordinates> + <panel_attributes>lt=<- +uses</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1027</x> + <y>377</y> + <w>39</w> + <h>104</h> + </coordinates> + <panel_attributes>lt=<<-</panel_attributes> + <additional_attributes>10.0;10.0;10.0;60.0</additional_attributes> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>1469</x> + <y>286</y> + <w>832</w> + <h>104</h> + </coordinates> + <panel_attributes><<Generated>> +{ModuleInterfaceNamespace}::{ModuleInterfaceName}Consumer +-- + +bg=orange</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLClass</id> + <coordinates> + <x>611</x> + <y>286</y> + <w>832</w> + <h>104</h> + </coordinates> + <panel_attributes><<Interface>> +vaf::ControlInterface +-- + +bg=yellow</panel_attributes> + <additional_attributes/> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-provider_allocate_set_api.svg b/Documentation/contents/figures/arch-provider_allocate_set_api.svg new file mode 100644 index 0000000..617129f --- /dev/null +++ b/Documentation/contents/figures/arch-provider_allocate_set_api.svg @@ -0,0 +1,258 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1090" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="300 160 1090 920" height="920" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 100 L20 100 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 150 L20 150 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 110 L20 110 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 80 L20 80 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 70 L150 70 L150 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M-0.5 -0.5 L-0.5 69.5 L149.5 69.5 L149.5 -0.5 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M0 0 L0 120 L30 120 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 110 L30 110 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 100 L30 100 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11" + ><path d="M0 0 L0 80 L30 80 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12" + ><path d="M0 0 L0 90 L30 90 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13" + ><path d="M0 0 L0 30 L220 30 L220 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14" + ><path d="M0 0 L0 30 L200 30 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15" + ><path d="M0 0 L0 30 L140 30 L140 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16" + ><path d="M0 0 L0 160 L150 160 L150 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17" + ><path d="M0 0 L0 90 L160 90 L160 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18" + ><path d="M0 0 L0 40 L590 40 L590 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19" + ><path d="M0 0 L0 50 L70 50 L70 0 Z" + /></clipPath + ></defs + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1240,830)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="98.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1240,830)" + ><rect fill="none" x="0.5" width="18.5" height="98.5" y="0.5" clip-path="url(#clipPath2)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(660,810)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="148.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(660,810)" + ><rect fill="none" x="0.5" width="18.5" height="148.5" y="0.5" clip-path="url(#clipPath3)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1240,550)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1240,550)" + ><rect fill="none" x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(660,530)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="148.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(660,530)" + ><rect fill="none" x="0.5" width="18.5" height="148.5" y="0.5" clip-path="url(#clipPath3)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1240,300)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(1240,300)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath5)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(660,290)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(660,290)" + ><rect fill="none" x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(330.5,760.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath7)" points=" 0 0 136 0 136 0 149 14 149 14 149 69 149 69 0 69 0 69 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath7)" stroke="none" + >Non-Allocate API</text + ><line clip-path="url(#clipPath7)" fill="none" x1="0" x2="136" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="149" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="149" x2="149" y1="14" y2="69" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="149" x2="0" y1="69" y2="69" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="0" x2="0" y1="69" y2="0" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="136" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="149" y1="14" y2="14" stroke="black" + /></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(320.5,310.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath7)" points=" 0 0 136 0 136 0 149 14 149 14 149 69 149 69 0 69 0 69 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath7)" stroke="none" + >Allocate API</text + ><line clip-path="url(#clipPath7)" fill="none" x1="0" x2="136" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="149" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="149" x2="149" y1="14" y2="69" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="149" x2="0" y1="69" y2="69" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="0" x2="0" y1="69" y2="0" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="136" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath7)" fill="none" x1="136" x2="149" y1="14" y2="14" stroke="black" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,920)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath8)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,950)" stroke-linecap="butt" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath9)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,730)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath8)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,650)" stroke-linecap="butt" + ><path fill="none" d="M10.5 80.5 L10.5 10.5" clip-path="url(#clipPath10)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,730)" stroke-linecap="butt" + ><path fill="none" d="M10.5 80.5 L10.5 10.5" clip-path="url(#clipPath10)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,670)" stroke-linecap="butt" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath11)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,470)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 80.5" clip-path="url(#clipPath10)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,460)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 70.5" clip-path="url(#clipPath12)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,390)" stroke-linecap="butt" + ><path fill="none" d="M10.5 70.5 L10.5 10.5" clip-path="url(#clipPath12)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,370)" stroke-linecap="butt" + ><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath8)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1150,180)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath13)" stroke="none" + /></g + ><g transform="translate(1150,180)" + ><rect fill="none" x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath13)" + /><text x="9" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath13)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF SIL Kit provider module</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(660,200)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 90.5" clip-path="url(#clipPath9)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(570,180)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath14)" stroke="none" + /></g + ><g transform="translate(570,180)" + ><rect fill="none" x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath14)" + /><text x="14" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath14)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF application module</text + ></g + ><g transform="translate(470,790)" + ><path fill="none" d="M120.5 10.5 L10.5 10.5" clip-path="url(#clipPath15)" + /><path fill="none" d="M109.2417 4 L120.5 10.5 L109.2417 17" clip-path="url(#clipPath15)" + /></g + ><g transform="translate(460,350)" + ><path fill="none" d="M130.5 140.5 L10.5 10.5" clip-path="url(#clipPath16)" + /><path fill="none" d="M127.6399 127.8185 L130.5 140.5 L118.0875 136.6362" clip-path="url(#clipPath16)" + /></g + ><g transform="translate(460,270)" + ><path fill="none" d="M140.5 10.5 L10.5 70.5" clip-path="url(#clipPath17)" + /><path fill="none" d="M127.554 9.3162 L140.5 10.5 L133.0018 21.1196" clip-path="url(#clipPath17)" + /></g + ><g transform="translate(670,910)" + ><path fill="none" d="M570.5 20.5 L10.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath18)" + /><text x="222.7432" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >::vaf::Result<void> </text + ></g + ><g transform="translate(670,810)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" + /><text x="78.9434" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Set_{DataElementName}(const {DataElementType}& data)</text + ></g + ><g transform="translate(1220,710)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(1220,720)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(640,710)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(640,720)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(670,640)" + ><path fill="none" d="M570.5 20.5 L10.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath18)" + /><text x="222.7432" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >::vaf::Result<void> </text + ></g + ><g transform="translate(670,530)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" + /><text x="8.1743" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >SetAllocated_{DataElementName}(vaf::DataPtr<{DataElementType}>&& data)</text + ></g + ><g transform="translate(1220,460)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(1220,450)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(640,450)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(640,440)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(670,360)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath18)" + /><text x="115.9922" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >vaf::Result<vaf::DataPtr<{DataElementType}>></text + ></g + ><g transform="translate(670,280)" + ><path fill="none" d="M10.5 20.5 L570.5 20.5" clip-path="url(#clipPath18)" + /><path fill="white" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" stroke="none" + /><path fill="none" d="M559.2417 27 L570.5 20.5 L559.2417 14 L559.2417 27" clip-path="url(#clipPath18)" + /><text x="178.2871" font-size="14px" y="16" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >Allocate_{DataElementName}()</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1240,200)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 100.5" clip-path="url(#clipPath8)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-provider_allocate_set_api.uxf b/Documentation/contents/figures/arch-provider_allocate_set_api.uxf new file mode 100644 index 0000000..f38b534 --- /dev/null +++ b/Documentation/contents/figures/arch-provider_allocate_set_api.uxf @@ -0,0 +1,472 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>9</zoom_level> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>513</x> + <y>162</y> + <w>180</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF application module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>180</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;10.0;10.0;90.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1035</x> + <y>162</y> + <w>198</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF SIL Kit provider module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>180</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=.</panel_attributes> + <additional_attributes>10.0;10.0;10.0;100.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>252</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +Allocate_{DataElementName}()</panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>594</x> + <y>261</y> + <w>18</w> + <h>99</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>333</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>351</y> + <w>27</w> + <h>81</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;70.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1116</x> + <y>270</y> + <w>18</w> + <h>72</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>324</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<<- +vaf::Result<vaf::DataPtr<{DataElementType}\>></panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>576</x> + <y>396</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=4</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>576</x> + <y>405</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=4</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>414</y> + <w>27</w> + <h>81</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>594</x> + <y>477</y> + <w>18</w> + <h>135</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1098</x> + <y>405</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=1</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1098</x> + <y>414</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=1</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1116</x> + <y>495</y> + <w>18</w> + <h>99</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>423</y> + <w>27</w> + <h>90</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>477</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +SetAllocated_{DataElementName}(vaf::DataPtr<{DataElementType}>&& data)</panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>603</y> + <w>27</w> + <h>72</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>576</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +::vaf::Result<void> </panel_attributes> + <additional_attributes>570.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>576</x> + <y>648</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=3</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>576</x> + <y>639</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=3</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>657</y> + <w>27</w> + <h>90</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;80.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1098</x> + <y>648</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=5</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1098</x> + <y>639</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=5</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>585</y> + <w>27</w> + <h>90</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;80.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>594</x> + <y>729</y> + <w>18</w> + <h>135</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1116</x> + <y>747</y> + <w>18</w> + <h>90</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>657</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>729</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +Set_{DataElementName}(const {DataElementType}& data)</panel_attributes> + <additional_attributes>10.0;20.0;570.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>603</x> + <y>819</y> + <w>531</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +::vaf::Result<void> </panel_attributes> + <additional_attributes>570.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>594</x> + <y>855</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1116</x> + <y>828</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;100.0;10.0;10.0</additional_attributes> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>288</x> + <y>279</y> + <w>135</w> + <h>63</h> + </coordinates> + <panel_attributes>Allocate API +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>297</x> + <y>684</y> + <w>135</w> + <h>63</h> + </coordinates> + <panel_attributes>Non-Allocate API +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>414</x> + <y>243</y> + <w>144</w> + <h>81</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>140.0;10.0;10.0;70.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>414</x> + <y>315</y> + <w>135</w> + <h>144</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;140.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>423</x> + <y>711</y> + <w>126</w> + <h>27</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>120.0;10.0;10.0;10.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/arch-provider_operation_api.svg b/Documentation/contents/figures/arch-provider_operation_api.svg new file mode 100644 index 0000000..985d59b --- /dev/null +++ b/Documentation/contents/figures/arch-provider_operation_api.svg @@ -0,0 +1,277 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' + 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'> +<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1770" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="120 130 1770 840" height="840" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto" +><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs" + /><g + ><defs id="defs1" + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1" + ><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2" + ><path d="M0 0 L0 140 L390 140 L390 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3" + ><path d="M0 0 L0 190 L450 190 L450 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4" + ><path d="M0 0 L0 280 L20 280 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5" + ><path d="M0 0 L0 110 L20 110 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6" + ><path d="M0 0 L0 130 L20 130 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7" + ><path d="M0 0 L0 90 L210 90 L210 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8" + ><path d="M-0.5 -0.5 L-0.5 89.5 L209.5 89.5 L209.5 -0.5 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9" + ><path d="M0 0 L0 80 L30 80 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10" + ><path d="M0 0 L0 480 L30 480 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11" + ><path d="M0 0 L0 50 L540 50 L540 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12" + ><path d="M0 0 L0 80 L20 80 L20 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13" + ><path d="M0 0 L0 160 L30 160 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14" + ><path d="M0 0 L0 50 L380 50 L380 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15" + ><path d="M0 0 L0 100 L30 100 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16" + ><path d="M0 0 L0 110 L30 110 L30 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17" + ><path d="M0 0 L0 30 L220 30 L220 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18" + ><path d="M0 0 L0 30 L200 30 L200 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19" + ><path d="M0 0 L0 30 L150 30 L150 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath20" + ><path d="M0 0 L0 40 L120 40 L120 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath21" + ><path d="M0 0 L0 40 L580 40 L580 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath22" + ><path d="M0 0 L0 50 L70 50 L70 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath23" + ><path d="M0 0 L0 40 L570 40 L570 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath24" + ><path d="M0 0 L0 60 L570 60 L570 0 Z" + /></clipPath + ><clipPath clipPathUnits="userSpaceOnUse" id="clipPath25" + ><path d="M0 0 L0 120 L30 120 L30 0 Z" + /></clipPath + ></defs + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1090,680)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="388.5" height="138.5" y="0.5" clip-path="url(#clipPath2)" stroke="none" + /></g + ><g transform="translate(1090,680)" + ><rect fill="none" x="0.5" width="388.5" height="138.5" y="0.5" clip-path="url(#clipPath2)" + /><path fill="none" d="M45.4682 0.5 L45.4682 14.3656 L36.2244 23.6094 L0.5 23.6094" clip-path="url(#clipPath2)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve" + >True</text + ></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1070,640)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="448.5" height="188.5" y="0.5" clip-path="url(#clipPath3)" stroke="none" + /></g + ><g transform="translate(1070,640)" + ><rect fill="none" x="0.5" width="448.5" height="188.5" y="0.5" clip-path="url(#clipPath3)" + /><path fill="none" d="M308.8373 0.5 L308.8373 14.3656 L299.5936 23.6094 L0.5 23.6094" clip-path="url(#clipPath3)" + /><text x="5" font-size="14px" y="18.1094" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" xml:space="preserve" + >if {OperationName}_function_ is available</text + ></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1280,600)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="278.5" y="0.5" clip-path="url(#clipPath4)" stroke="none" + /></g + ><g transform="translate(1280,600)" + ><rect fill="none" x="0.5" width="18.5" height="278.5" y="0.5" clip-path="url(#clipPath4)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(1280,270)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath5)" stroke="none" + /></g + ><g transform="translate(1280,270)" + ><rect fill="none" x="0.5" width="18.5" height="108.5" y="0.5" clip-path="url(#clipPath5)" + /></g + ><g fill="rgb(200,200,200)" fill-opacity="0.4902" transform="translate(720,260)" stroke-opacity="0.4902" stroke="rgb(200,200,200)" + ><rect x="0.5" width="18.5" height="128.5" y="0.5" clip-path="url(#clipPath6)" stroke="none" + /></g + ><g transform="translate(720,260)" + ><rect fill="none" x="0.5" width="18.5" height="128.5" y="0.5" clip-path="url(#clipPath6)" + /></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(140.5,510.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath8)" points=" 0 0 196 0 196 0 209 14 209 14 209 89 209 89 0 89 0 89 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath8)" stroke="none" + >Operation response </text + ><text fill="black" x="7" xml:space="preserve" y="34" clip-path="url(#clipPath8)" stroke="none" + >on request</text + ><line clip-path="url(#clipPath8)" fill="none" x1="0" x2="196" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="209" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="209" x2="209" y1="14" y2="89" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="209" x2="0" y1="89" y2="89" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="0" x2="0" y1="89" y2="0" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="196" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="209" y1="14" y2="14" stroke="black" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1280,870)" stroke-linecap="butt" + ><path fill="none" d="M10.5 60.5 L10.5 10.5" clip-path="url(#clipPath9)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(720,460)" stroke-linecap="butt" + ><path fill="none" d="M10.5 460.5 L10.5 10.5" clip-path="url(#clipPath10)" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1310,730)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath11)" stroke="none" + >{OperationName}_function_({OperationParameters})</text + ></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1290,710)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath12)" stroke="none" + /></g + ><g transform="translate(1290,710)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath12)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1280,460)" stroke-linecap="butt" + ><path fill="none" d="M10.5 140.5 L10.5 10.5" clip-path="url(#clipPath13)" + /></g + ><g fill="rgb(200,200,200)" font-size="14px" font-family="sans-serif" transform="translate(140.5,220.5)" stroke="rgb(200,200,200)" + ><polygon clip-path="url(#clipPath8)" points=" 0 0 196 0 196 0 209 14 209 14 209 89 209 89 0 89 0 89 0 0" opacity="0.5" stroke="none" + /><text fill="black" x="7" xml:space="preserve" y="17" clip-path="url(#clipPath8)" stroke="none" + >Registration of </text + ><text fill="black" x="7" xml:space="preserve" y="34" clip-path="url(#clipPath8)" stroke="none" + >Operation handler </text + ><text fill="black" x="7" xml:space="preserve" y="51" clip-path="url(#clipPath8)" stroke="none" + >method </text + ><line clip-path="url(#clipPath8)" fill="none" x1="0" x2="196" y1="0" y2="0" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="209" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="209" x2="209" y1="14" y2="89" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="209" x2="0" y1="89" y2="89" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="0" x2="0" y1="89" y2="0" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="196" y1="0" y2="14" stroke="black" + /><line clip-path="url(#clipPath8)" fill="none" x1="196" x2="209" y1="14" y2="14" stroke="black" + /></g + ><g font-family="sans-serif" font-size="14px" transform="translate(1310,300)" + ><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath14)" stroke="none" + >{OperationName}_function_ = std::move(f);</text + ></g + ><g fill="rgb(120,120,120)" fill-opacity="0.4902" transform="translate(1290,280)" stroke-opacity="0.4902" stroke="rgb(120,120,120)" + ><rect x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath12)" stroke="none" + /></g + ><g transform="translate(1290,280)" + ><rect fill="none" x="0.5" width="18.5" height="78.5" y="0.5" clip-path="url(#clipPath12)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(720,380)" stroke-linecap="butt" + ><path fill="none" d="M10.5 80.5 L10.5 10.5" clip-path="url(#clipPath15)" + /></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1280,370)" stroke-linecap="butt" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath16)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1190,150)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath17)" stroke="none" + /></g + ><g transform="translate(1190,150)" + ><rect fill="none" x="0.5" width="218.5" height="28.5" y="0.5" clip-path="url(#clipPath17)" + /><text x="9" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath17)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF SIL Kit provider module</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(720,170)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 90.5" clip-path="url(#clipPath16)" + /></g + ><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(630,150)" stroke-opacity="0" stroke="rgb(255,255,255)" + ><rect x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath18)" stroke="none" + /></g + ><g transform="translate(630,150)" + ><rect fill="none" x="0.5" width="198.5" height="28.5" y="0.5" clip-path="url(#clipPath18)" + /><text x="14" font-size="14px" y="18.1094" text-decoration="underline" clip-path="url(#clipPath18)" font-family="sans-serif" stroke="none" xml:space="preserve" + >:VAF application module</text + ></g + ><g transform="translate(340,530)" + ><path fill="none" d="M130.5 10.5 L10.5 10.5" clip-path="url(#clipPath19)" + /><path fill="none" d="M119.2417 4 L130.5 10.5 L119.2417 17" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(1290,770)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath20)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath20)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath20)" + /></g + ><g transform="translate(1380,700)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath16)" + /></g + ><g transform="translate(1290,690)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath20)" + /></g + ><g transform="translate(1290,860)" + ><path fill="none" d="M560.5 20.5 L10.5 20.5" clip-path="url(#clipPath21)" + /><path fill="none" d="M549.2417 14 L560.5 20.5 L549.2417 27" clip-path="url(#clipPath21)" + /><text x="225.8696" font-size="14px" y="16" clip-path="url(#clipPath21)" font-family="sans-serif" stroke="none" xml:space="preserve" + >MethodResponse</text + ></g + ><g transform="translate(1290,580)" + ><path fill="none" d="M10.5 20.5 L560.5 20.5" clip-path="url(#clipPath21)" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14" clip-path="url(#clipPath21)" + /><text x="230.8521" font-size="14px" y="16" clip-path="url(#clipPath21)" font-family="sans-serif" stroke="none" xml:space="preserve" + >MethodRequest</text + ></g + ><g transform="translate(700,450)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath22)" + /></g + ><g transform="translate(700,440)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath22)" + /></g + ><g transform="translate(340,240)" + ><path fill="none" d="M130.5 10.5 L10.5 10.5" clip-path="url(#clipPath19)" + /><path fill="none" d="M119.2417 4 L130.5 10.5 L119.2417 17" clip-path="url(#clipPath19)" + /></g + ><g transform="translate(1260,440)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath22)" + /></g + ><g transform="translate(1260,450)" + ><path fill="none" d="M50.5 30.5 L10.5 10.5" clip-path="url(#clipPath22)" + /></g + ><g transform="translate(1290,340)" + ><path fill="none" d="M100.5 20.5 L10.5 20.5" clip-path="url(#clipPath20)" + /><path fill="white" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath20)" stroke="none" + /><path fill="none" d="M21.7583 14 L10.5 20.5 L21.7583 27 L21.7583 14" clip-path="url(#clipPath20)" + /></g + ><g transform="translate(1380,270)" + ><path fill="none" d="M10.5 90.5 L10.5 10.5" clip-path="url(#clipPath16)" + /></g + ><g transform="translate(1290,260)" + ><path fill="none" d="M10.5 20.5 L100.5 20.5" clip-path="url(#clipPath20)" + /></g + ><g transform="translate(730,360)" + ><path fill="none" d="M10.5 20.5 L550.5 20.5" clip-path="url(#clipPath23)" + /><path fill="white" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath23)" stroke="none" + /><path fill="none" d="M21.7583 27 L10.5 20.5 L21.7583 14 L21.7583 27" clip-path="url(#clipPath23)" + /></g + ><g transform="translate(730,250)" + ><path fill="none" d="M10.5 20.5 L550.5 20.5" clip-path="url(#clipPath24)" + /><path fill="white" d="M539.2417 27 L550.5 20.5 L539.2417 14 L539.2417 27" clip-path="url(#clipPath24)" stroke="none" + /><path fill="none" d="M539.2417 27 L550.5 20.5 L539.2417 14 L539.2417 27" clip-path="url(#clipPath24)" + /><text x="119.0879" font-size="14px" y="16" clip-path="url(#clipPath24)" font-family="sans-serif" stroke="none" xml:space="preserve" + >RegisterOperationHandler_{OperationName}(</text + ><text x="49.123" font-size="14px" y="32.1094" clip-path="url(#clipPath24)" font-family="sans-serif" stroke="none" xml:space="preserve" + >std::function<{OperationOutput}({OperationParameters})>&& f)</text + ></g + ><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(1280,170)" stroke-linecap="butt" + ><path fill="none" d="M10.5 10.5 L10.5 100.5" clip-path="url(#clipPath25)" + /></g + ></g +></svg +> diff --git a/Documentation/contents/figures/arch-provider_operation_api.uxf b/Documentation/contents/figures/arch-provider_operation_api.uxf new file mode 100644 index 0000000..524ff96 --- /dev/null +++ b/Documentation/contents/figures/arch-provider_operation_api.uxf @@ -0,0 +1,441 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<diagram program="umlet" version="13.3"> + <zoom_level>9</zoom_level> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>567</x> + <y>135</y> + <w>180</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF application module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>648</x> + <y>153</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;10.0;10.0;90.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1071</x> + <y>135</y> + <w>198</w> + <h>27</h> + </coordinates> + <panel_attributes>_:VAF SIL Kit provider module_</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1152</x> + <y>153</y> + <w>27</w> + <h>108</h> + </coordinates> + <panel_attributes>lt=.</panel_attributes> + <additional_attributes>10.0;10.0;10.0;100.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>657</x> + <y>225</y> + <w>513</w> + <h>54</h> + </coordinates> + <panel_attributes>lt=->> +RegisterOperationHandler_{OperationName}( +std::function<{OperationOutput}({OperationParameters})>&& f) +</panel_attributes> + <additional_attributes>10.0;20.0;550.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>648</x> + <y>234</y> + <w>18</w> + <h>117</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1152</x> + <y>333</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>648</x> + <y>342</y> + <w>27</w> + <h>90</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;80.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1152</x> + <y>243</y> + <w>18</w> + <h>99</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>657</x> + <y>324</y> + <w>513</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<<- +</panel_attributes> + <additional_attributes>10.0;20.0;550.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1161</x> + <y>252</y> + <w>18</w> + <h>72</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>234</y> + <w>108</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1242</x> + <y>243</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1179</x> + <y>270</y> + <w>342</w> + <h>45</h> + </coordinates> + <panel_attributes>{OperationName}_function_ = std::move(f); +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>306</y> + <w>108</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1134</x> + <y>405</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=1</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1134</x> + <y>396</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=1</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>126</x> + <y>198</y> + <w>189</w> + <h>81</h> + </coordinates> + <panel_attributes>Registration of +Operation handler +method + +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>306</x> + <y>216</y> + <w>135</w> + <h>27</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;10.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>630</x> + <y>396</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=2</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>630</x> + <y>405</y> + <w>63</w> + <h>45</h> + </coordinates> + <panel_attributes>lt=- +group=2</panel_attributes> + <additional_attributes>50.0;30.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>522</y> + <w>522</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +MethodRequest</panel_attributes> + <additional_attributes>10.0;20.0;560.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1152</x> + <y>540</y> + <w>18</w> + <h>252</h> + </coordinates> + <panel_attributes> +bg=light_gray +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1152</x> + <y>414</y> + <w>27</w> + <h>144</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;140.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>963</x> + <y>576</y> + <w>405</w> + <h>171</h> + </coordinates> + <panel_attributes>if {OperationName}_function_ is available +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>UMLFrame</id> + <coordinates> + <x>981</x> + <y>612</y> + <w>351</w> + <h>126</h> + </coordinates> + <panel_attributes>True +layer=-1</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>774</y> + <w>522</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=<- +MethodResponse</panel_attributes> + <additional_attributes>560.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>UMLGeneric</id> + <coordinates> + <x>1161</x> + <y>639</y> + <w>18</w> + <h>72</h> + </coordinates> + <panel_attributes> +bg=gray +layer=0</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>621</y> + <w>108</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=- +</panel_attributes> + <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1242</x> + <y>630</y> + <w>27</w> + <h>99</h> + </coordinates> + <panel_attributes>lt=-</panel_attributes> + <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Text</id> + <coordinates> + <x>1179</x> + <y>657</y> + <w>486</w> + <h>45</h> + </coordinates> + <panel_attributes>{OperationName}_function_({OperationParameters}) +</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1161</x> + <y>693</y> + <w>108</w> + <h>36</h> + </coordinates> + <panel_attributes>lt=->> +</panel_attributes> + <additional_attributes>100.0;20.0;10.0;20.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>648</x> + <y>414</y> + <w>27</w> + <h>432</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;460.0;10.0;10.0</additional_attributes> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>1152</x> + <y>783</y> + <w>27</w> + <h>72</h> + </coordinates> + <panel_attributes>lt=. +layer=0</panel_attributes> + <additional_attributes>10.0;60.0;10.0;10.0</additional_attributes> + </element> + <element> + <type>com.baselet.element.old.element.Note</type> + <coordinates> + <x>126</x> + <y>459</y> + <w>189</w> + <h>81</h> + </coordinates> + <panel_attributes>Operation response +on request + +bg=light_gray</panel_attributes> + <additional_attributes/> + </element> + <element> + <id>Relation</id> + <coordinates> + <x>306</x> + <y>477</y> + <w>135</w> + <h>27</h> + </coordinates> + <panel_attributes>lt=<-</panel_attributes> + <additional_attributes>130.0;10.0;10.0;10.0</additional_attributes> + </element> +</diagram> diff --git a/Documentation/contents/figures/cac-cd_app_module.puml b/Documentation/contents/figures/cac-cd_app_module.puml new file mode 100644 index 0000000..3725c11 --- /dev/null +++ b/Documentation/contents/figures/cac-cd_app_module.puml @@ -0,0 +1,14 @@ +@startuml cac-cd_app_module +skinparam class { + BackgroundColor #FFFFFF +} + +class ApplicationModule { + + app_module: vafmodel.ApplicationModule + + ApplicationModule(name: str, namespace: str) + + add_consumed_interface(instance_name: str, interface: ModuleInterface, is_optional: bool) + + add_provided_interface(instance_name: str, interface: ModuleInterface) + + add_task(task: Task) + + add_task_chain(tasks: list[Task], run_after: list[Task], increment_preferred_offset: bool) +} +@enduml diff --git a/Documentation/contents/figures/cac-cd_app_module.svg b/Documentation/contents/figures/cac-cd_app_module.svg new file mode 100644 index 0000000..bd39e4f --- /dev/null +++ b/Documentation/contents/figures/cac-cd_app_module.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="142px" preserveAspectRatio="none" style="width:561px;height:142px;" version="1.1" viewBox="0 0 561 142" width="561px" zoomAndPan="magnify"><defs><filter height="300%" id="f1fl6fd102rlbu" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[26e2a85c06611372298526764170fca9] +class ApplicationModule--><rect fill="#FFFFFF" filter="url(#f1fl6fd102rlbu)" height="124.8281" id="ApplicationModule" style="stroke: #A80036; stroke-width: 1.5;" width="543" x="7" y="7"/><ellipse cx="217.25" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M220.2188,28.6406 Q219.6406,28.9375 219,29.0781 Q218.3594,29.2344 217.6563,29.2344 Q215.1563,29.2344 213.8281,27.5938 Q212.5156,25.9375 212.5156,22.8125 Q212.5156,19.6875 213.8281,18.0313 Q215.1563,16.375 217.6563,16.375 Q218.3594,16.375 219,16.5313 Q219.6563,16.6875 220.2188,16.9844 L220.2188,19.7031 Q219.5938,19.125 219,18.8594 Q218.4063,18.5781 217.7813,18.5781 Q216.4375,18.5781 215.75,19.6563 Q215.0625,20.7188 215.0625,22.8125 Q215.0625,24.9063 215.75,25.9844 Q216.4375,27.0469 217.7813,27.0469 Q218.4063,27.0469 219,26.7813 Q219.5938,26.5 220.2188,25.9219 L220.2188,28.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="114" x="237.75" y="27.1543">ApplicationModule</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="549" y1="39" y2="39"/><ellipse cx="18" cy="50" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="234" x="27" y="53.2104">app_module: vafmodel.ApplicationModule</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="549" y1="59.8047" y2="59.8047"/><ellipse cx="18" cy="70.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="263" x="27" y="74.0151">ApplicationModule(name: str, namespace: str)</text><ellipse cx="18" cy="83.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="517" x="27" y="86.8198">add_consumed_interface(instance_name: str, interface: ModuleInterface, is_optional: bool)</text><ellipse cx="18" cy="96.4141" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="406" x="27" y="99.6245">add_provided_interface(instance_name: str, interface: ModuleInterface)</text><ellipse cx="18" cy="109.2188" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="118" x="27" y="112.4292">add_task(task: Task)</text><ellipse cx="18" cy="122.0234" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="502" x="27" y="125.2339">add_task_chain(tasks: list[Task], run_after: list[Task], increment_preferred_offset: bool)</text><!--MD5=[1fa8aaa55da906cb5ff357c85d69ad90] +@startuml cac-cd_app_module +skinparam class { + BackgroundColor #FFFFFF +} + +class ApplicationModule { + + app_module: vafmodel.ApplicationModule + + ApplicationModule(name: str, namespace: str) + + add_consumed_interface(instance_name: str, interface: ModuleInterface, is_optional: bool) + + add_provided_interface(instance_name: str, interface: ModuleInterface) + + add_task(task: Task) + + add_task_chain(tasks: list[Task], run_after: list[Task], increment_preferred_offset: bool) +} +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/cac-cd_datatypes.puml b/Documentation/contents/figures/cac-cd_datatypes.puml new file mode 100644 index 0000000..700aaee --- /dev/null +++ b/Documentation/contents/figures/cac-cd_datatypes.puml @@ -0,0 +1,63 @@ +@startuml cac-cd_datatypes +skinparam Linetype ortho +skinparam WrapWidth 500 +skinparam class { + BackgroundColor #FFFFFF +} + +abstract class AbstractVafType { + + data_type: vafmodel.DataType +} + +class Struct { + + Struct(name: str, namespace: str, sub_elements: list[vafmodel.SubElement]) + + add_subelement(name: str, datatype: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.Struct +} + +class Vector { + + Vector(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int, name: str) + + internal_model: vafmodel.Vector +} + +class String { + + String(name: str, namespace: str) + + internal_model: vafmodel.String +} + +class TypeRef { + + TypeRef(name: str, namespace: str, datatype: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.TypeRef +} + +class Map { + + Map(name: str, namespace: str, key_type: BaseTypesWrapper | AbstractVafType, value_type: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.Map +} + +class Array { + + Array(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int, name: str) + + internal_model: vafmodel.Array +} + +class Enum { + + Enum(name: str, namespace: str, literals: list[vafmodel.EnumLiteral]) + + add_entry(label: str, value: int) + + internal_model: vafmodel.VafEnum +} + +AbstractVafType <|-- Struct +AbstractVafType <|-- Vector +AbstractVafType <|-- String +AbstractVafType <|-- TypeRef +AbstractVafType <|-- Map +AbstractVafType <|-- Array +AbstractVafType <|-- Enum + +Struct -[hidden]d- Vector +Vector -[hidden]d- Array + +String -[hidden]d- TypeRef +TypeRef -[hidden]d- Map +Map -[hidden]d- Enum +@enduml diff --git a/Documentation/contents/figures/cac-cd_datatypes.svg b/Documentation/contents/figures/cac-cd_datatypes.svg new file mode 100644 index 0000000..a4ac57e --- /dev/null +++ b/Documentation/contents/figures/cac-cd_datatypes.svg @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="664px" preserveAspectRatio="none" style="width:1262px;height:664px;" version="1.1" viewBox="0 0 1262 664" width="1262px" zoomAndPan="magnify"><defs><filter height="300%" id="f1lk85ser7v77" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[a2fc906216f66dae14bef71e22e0af64] +class AbstractVafType--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="60.8047" id="AbstractVafType" style="stroke: #A80036; stroke-width: 1.5;" width="198" x="300.5" y="8"/><ellipse cx="344.3" cy="24" fill="#A9DCDF" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M344.4094,19.3438 L343.2531,24.4219 L345.5813,24.4219 L344.4094,19.3438 Z M342.925,17.1094 L345.9094,17.1094 L349.2688,29.5 L346.8156,29.5 L346.05,26.4375 L342.7688,26.4375 L342.0188,29.5 L339.5813,29.5 L342.925,17.1094 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="102" x="364.7" y="28.1543">AbstractVafType</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="301.5" x2="497.5" y1="40" y2="40"/><ellipse cx="311.5" cy="51" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="172" x="320.5" y="54.2104">data_type: vafmodel.DataType</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="301.5" x2="497.5" y1="60.8047" y2="60.8047"/><!--MD5=[eb0f4986160aea42d9ece72995cb24c7] +class Struct--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="86.4141" id="Struct" style="stroke: #A80036; stroke-width: 1.5;" width="467" x="166" y="129"/><ellipse cx="376.25" cy="145" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M379.2188,150.6406 Q378.6406,150.9375 378,151.0781 Q377.3594,151.2344 376.6563,151.2344 Q374.1563,151.2344 372.8281,149.5938 Q371.5156,147.9375 371.5156,144.8125 Q371.5156,141.6875 372.8281,140.0313 Q374.1563,138.375 376.6563,138.375 Q377.3594,138.375 378,138.5313 Q378.6563,138.6875 379.2188,138.9844 L379.2188,141.7031 Q378.5938,141.125 378,140.8594 Q377.4063,140.5781 376.7813,140.5781 Q375.4375,140.5781 374.75,141.6563 Q374.0625,142.7188 374.0625,144.8125 Q374.0625,146.9063 374.75,147.9844 Q375.4375,149.0469 376.7813,149.0469 Q377.4063,149.0469 378,148.7813 Q378.5938,148.5 379.2188,147.9219 L379.2188,150.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="38" x="396.75" y="149.1543">Struct</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="167" x2="632" y1="161" y2="161"/><ellipse cx="177" cy="172" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="182" x="186" y="175.2104">internal_model: vafmodel.Struct</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="167" x2="632" y1="181.8047" y2="181.8047"/><ellipse cx="177" cy="192.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="441" x="186" y="196.0151">Struct(name: str, namespace: str, sub_elements: list[vafmodel.SubElement])</text><ellipse cx="177" cy="205.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="437" x="186" y="208.8198">add_subelement(name: str, datatype: BaseTypesWrapper | AbstractVafType)</text><!--MD5=[ea775af43a0da7cb543d6bee4ab62c40] +class Vector--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="86.4141" id="Vector" style="stroke: #A80036; stroke-width: 1.5;" width="495" x="95" y="275"/><ellipse cx="317.75" cy="291" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M320.7188,296.6406 Q320.1406,296.9375 319.5,297.0781 Q318.8594,297.2344 318.1563,297.2344 Q315.6563,297.2344 314.3281,295.5938 Q313.0156,293.9375 313.0156,290.8125 Q313.0156,287.6875 314.3281,286.0313 Q315.6563,284.375 318.1563,284.375 Q318.8594,284.375 319.5,284.5313 Q320.1563,284.6875 320.7188,284.9844 L320.7188,287.7031 Q320.0938,287.125 319.5,286.8594 Q318.9063,286.5781 318.2813,286.5781 Q316.9375,286.5781 316.25,287.6563 Q315.5625,288.7188 315.5625,290.8125 Q315.5625,292.9063 316.25,293.9844 Q316.9375,295.0469 318.2813,295.0469 Q318.9063,295.0469 319.5,294.7813 Q320.0938,294.5 320.7188,293.9219 L320.7188,296.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="41" x="338.25" y="295.1543">Vector</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="96" x2="589" y1="307" y2="307"/><ellipse cx="106" cy="318" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="184" x="115" y="321.2104">internal_model: vafmodel.Vector</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="96" x2="589" y1="327.8047" y2="327.8047"/><ellipse cx="106" cy="338.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="465" x="115" y="342.0151">Vector(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int,</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="60" x="115" y="354.8198">name: str)</text><!--MD5=[9df70cf33be424c1b8543b3f439cae89] +class String--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="73.6094" id="String" style="stroke: #A80036; stroke-width: 1.5;" width="222" x="865.5" y="135"/><ellipse cx="953.75" cy="151" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M956.7188,156.6406 Q956.1406,156.9375 955.5,157.0781 Q954.8594,157.2344 954.1563,157.2344 Q951.6563,157.2344 950.3281,155.5938 Q949.0156,153.9375 949.0156,150.8125 Q949.0156,147.6875 950.3281,146.0313 Q951.6563,144.375 954.1563,144.375 Q954.8594,144.375 955.5,144.5313 Q956.1563,144.6875 956.7188,144.9844 L956.7188,147.7031 Q956.0938,147.125 955.5,146.8594 Q954.9063,146.5781 954.2813,146.5781 Q952.9375,146.5781 952.25,147.6563 Q951.5625,148.7188 951.5625,150.8125 Q951.5625,152.9063 952.25,153.9844 Q952.9375,155.0469 954.2813,155.0469 Q954.9063,155.0469 955.5,154.7813 Q956.0938,154.5 956.7188,153.9219 L956.7188,156.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="37" x="974.25" y="155.1543">String</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="866.5" x2="1086.5" y1="167" y2="167"/><ellipse cx="876.5" cy="178" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="182" x="885.5" y="181.2104">internal_model: vafmodel.String</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="866.5" x2="1086.5" y1="187.8047" y2="187.8047"/><ellipse cx="876.5" cy="198.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="196" x="885.5" y="202.0151">String(name: str, namespace: str)</text><!--MD5=[bb5d160990469bd4f965063233933f15] +class TypeRef--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="73.6094" id="TypeRef" style="stroke: #A80036; stroke-width: 1.5;" width="512" x="739.5" y="281"/><ellipse cx="966.75" cy="297" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M969.7188,302.6406 Q969.1406,302.9375 968.5,303.0781 Q967.8594,303.2344 967.1563,303.2344 Q964.6563,303.2344 963.3281,301.5938 Q962.0156,299.9375 962.0156,296.8125 Q962.0156,293.6875 963.3281,292.0313 Q964.6563,290.375 967.1563,290.375 Q967.8594,290.375 968.5,290.5313 Q969.1563,290.6875 969.7188,290.9844 L969.7188,293.7031 Q969.0938,293.125 968.5,292.8594 Q967.9063,292.5781 967.2813,292.5781 Q965.9375,292.5781 965.25,293.6563 Q964.5625,294.7188 964.5625,296.8125 Q964.5625,298.9063 965.25,299.9844 Q965.9375,301.0469 967.2813,301.0469 Q967.9063,301.0469 968.5,300.7813 Q969.0938,300.5 969.7188,299.9219 L969.7188,302.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="49" x="987.25" y="301.1543">TypeRef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="740.5" x2="1250.5" y1="313" y2="313"/><ellipse cx="750.5" cy="324" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="193" x="759.5" y="327.2104">internal_model: vafmodel.TypeRef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="740.5" x2="1250.5" y1="333.8047" y2="333.8047"/><ellipse cx="750.5" cy="344.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="486" x="759.5" y="348.0151">TypeRef(name: str, namespace: str, datatype: BaseTypesWrapper | AbstractVafType)</text><!--MD5=[4dfc6a72b8dd60daa1b635d583ff79da] +class Map--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="86.4141" id="Map" style="stroke: #A80036; stroke-width: 1.5;" width="524" x="584.5" y="421"/><ellipse cx="829.25" cy="437" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M832.2188,442.6406 Q831.6406,442.9375 831,443.0781 Q830.3594,443.2344 829.6563,443.2344 Q827.1563,443.2344 825.8281,441.5938 Q824.5156,439.9375 824.5156,436.8125 Q824.5156,433.6875 825.8281,432.0313 Q827.1563,430.375 829.6563,430.375 Q830.3594,430.375 831,430.5313 Q831.6563,430.6875 832.2188,430.9844 L832.2188,433.7031 Q831.5938,433.125 831,432.8594 Q830.4063,432.5781 829.7813,432.5781 Q828.4375,432.5781 827.75,433.6563 Q827.0625,434.7188 827.0625,436.8125 Q827.0625,438.9063 827.75,439.9844 Q828.4375,441.0469 829.7813,441.0469 Q830.4063,441.0469 831,440.7813 Q831.5938,440.5 832.2188,439.9219 L832.2188,442.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="26" x="849.75" y="441.1543">Map</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="585.5" x2="1107.5" y1="453" y2="453"/><ellipse cx="595.5" cy="464" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="171" x="604.5" y="467.2104">internal_model: vafmodel.Map</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="585.5" x2="1107.5" y1="473.8047" y2="473.8047"/><ellipse cx="595.5" cy="484.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="498" x="604.5" y="488.0151">Map(name: str, namespace: str, key_type: BaseTypesWrapper | AbstractVafType, value</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="256" x="604.5" y="500.8198">_type: BaseTypesWrapper | AbstractVafType)</text><!--MD5=[99f32fa4e73f6681c1a0ac5117bd3ce1] +class Array--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="86.4141" id="Array" style="stroke: #A80036; stroke-width: 1.5;" width="525" x="24" y="421"/><ellipse cx="266.25" cy="437" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M269.2188,442.6406 Q268.6406,442.9375 268,443.0781 Q267.3594,443.2344 266.6563,443.2344 Q264.1563,443.2344 262.8281,441.5938 Q261.5156,439.9375 261.5156,436.8125 Q261.5156,433.6875 262.8281,432.0313 Q264.1563,430.375 266.6563,430.375 Q267.3594,430.375 268,430.5313 Q268.6563,430.6875 269.2188,430.9844 L269.2188,433.7031 Q268.5938,433.125 268,432.8594 Q267.4063,432.5781 266.7813,432.5781 Q265.4375,432.5781 264.75,433.6563 Q264.0625,434.7188 264.0625,436.8125 Q264.0625,438.9063 264.75,439.9844 Q265.4375,441.0469 266.7813,441.0469 Q267.4063,441.0469 268,440.7813 Q268.5938,440.5 269.2188,439.9219 L269.2188,442.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="32" x="286.75" y="441.1543">Array</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="25" x2="548" y1="453" y2="453"/><ellipse cx="35" cy="464" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="178" x="44" y="467.2104">internal_model: vafmodel.Array</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="25" x2="548" y1="473.8047" y2="473.8047"/><ellipse cx="35" cy="484.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="499" x="44" y="488.0151">Array(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int, name:</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="44" y="500.8198">str)</text><!--MD5=[4298d0dcfa55ecd56071adba7add2166] +class Enum--><rect fill="#FFFFFF" filter="url(#f1lk85ser7v77)" height="86.4141" id="Enum" style="stroke: #A80036; stroke-width: 1.5;" width="423" x="197" y="567"/><ellipse cx="386.75" cy="583" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M389.7188,588.6406 Q389.1406,588.9375 388.5,589.0781 Q387.8594,589.2344 387.1563,589.2344 Q384.6563,589.2344 383.3281,587.5938 Q382.0156,585.9375 382.0156,582.8125 Q382.0156,579.6875 383.3281,578.0313 Q384.6563,576.375 387.1563,576.375 Q387.8594,576.375 388.5,576.5313 Q389.1563,576.6875 389.7188,576.9844 L389.7188,579.7031 Q389.0938,579.125 388.5,578.8594 Q387.9063,578.5781 387.2813,578.5781 Q385.9375,578.5781 385.25,579.6563 Q384.5625,580.7188 384.5625,582.8125 Q384.5625,584.9063 385.25,585.9844 Q385.9375,587.0469 387.2813,587.0469 Q387.9063,587.0469 388.5,586.7813 Q389.0938,586.5 389.7188,585.9219 L389.7188,588.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="35" x="407.25" y="587.1543">Enum</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="198" x2="619" y1="599" y2="599"/><ellipse cx="208" cy="610" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="198" x="217" y="613.2104">internal_model: vafmodel.VafEnum</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="198" x2="619" y1="619.8047" y2="619.8047"/><ellipse cx="208" cy="630.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="397" x="217" y="634.0151">Enum(name: str, namespace: str, literals: list[vafmodel.EnumLiteral])</text><ellipse cx="208" cy="643.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="175" x="217" y="646.8198">add_entry(label: str, value: int)</text><!--MD5=[013009c2a0b74d8ad34a6a3e0336ac9c] +reverse link AbstractVafType to Struct--><path d="M399.5,89.13 C399.5,89.13 399.5,128.87 399.5,128.87 " fill="none" id="AbstractVafType<-Struct" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="392.5,89.13,399.5,69.13,406.5,89.13,392.5,89.13" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[b4d875b56df262c55e5e40382f2c52a5] +reverse link AbstractVafType to Vector--><path d="M280.48,54 C280.48,54 130.5,54 130.5,54 C130.5,54 130.5,200.19 130.5,275 " fill="none" id="AbstractVafType<-Vector" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="280.48,47,300.48,54,280.48,61,280.48,47" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[9d6aa8fb296884c38b92b596158ee77c] +reverse link AbstractVafType to String--><path d="M518.69,24 C518.69,24 976.5,24 976.5,24 C976.5,24 976.5,90.81 976.5,134.65 " fill="none" id="AbstractVafType<-String" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="518.69,31,498.69,24,518.69,17,518.69,31" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[4b5ece495ff9d603d2756682afd75e38] +reverse link AbstractVafType to TypeRef--><path d="M518.6,39 C518.6,39 802.5,39 802.5,39 C802.5,39 802.5,205.06 802.5,280.95 " fill="none" id="AbstractVafType<-TypeRef" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="518.6,46,498.6,39,518.6,32,518.6,46" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[ca30d59a893031839bf2451b77866a72] +reverse link AbstractVafType to Map--><path d="M518.58,54 C518.58,54 686.25,54 686.25,54 C686.25,54 686.25,315.63 686.25,420.9 " fill="none" id="AbstractVafType<-Map" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="518.58,61,498.58,54,518.58,47,518.58,61" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[d2cf894cce83c7ccc30622c7973cfa27] +reverse link AbstractVafType to Array--><path d="M280.24,39 C280.24,39 59.5,39 59.5,39 C59.5,39 59.5,312.86 59.5,420.91 " fill="none" id="AbstractVafType<-Array" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="280.24,32,300.24,39,280.24,46,280.24,32" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[5f9a1d526647954d297912eb8d922fbd] +reverse link AbstractVafType to Enum--><path d="M280.46,24 C280.46,24 6,24 6,24 C6,24 6,610 6,610 C6,610 99.86,610 196.94,610 " fill="none" id="AbstractVafType<-Enum" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="280.46,17,300.46,24,280.46,31,280.46,17" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[5346a22ebda49c29b9a77fafe003be0a] +link Struct to Vector--><!--MD5=[6ed712873cb0fae9851b7bbbf7690df5] +link Vector to Array--><!--MD5=[c7448a721a48e1eb227c5011c6b680dc] +link String to TypeRef--><!--MD5=[1ba4871fe6a587028a64e6493466ddb7] +link TypeRef to Map--><!--MD5=[239a5810e09c404e1e38b7b8f2c41397] +link Map to Enum--><!--MD5=[6a229823fd0116bb683e6cbb07730a23] +@startuml cac-cd_datatypes +skinparam Linetype ortho +skinparam WrapWidth 500 +skinparam class { + BackgroundColor #FFFFFF +} + +abstract class AbstractVafType { + + data_type: vafmodel.DataType +} + +class Struct { + + Struct(name: str, namespace: str, sub_elements: list[vafmodel.SubElement]) + + add_subelement(name: str, datatype: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.Struct +} + +class Vector { + + Vector(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int, name: str) + + internal_model: vafmodel.Vector +} + +class String { + + String(name: str, namespace: str) + + internal_model: vafmodel.String +} + +class TypeRef { + + TypeRef(name: str, namespace: str, datatype: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.TypeRef +} + +class Map { + + Map(name: str, namespace: str, key_type: BaseTypesWrapper | AbstractVafType, value_type: BaseTypesWrapper | AbstractVafType) + + internal_model: vafmodel.Map +} + +class Array { + + Array(namespace: str, datatype: BaseTypesWrapper | AbstractVafType, size: int, name: str) + + internal_model: vafmodel.Array +} + +class Enum { + + Enum(name: str, namespace: str, literals: list[vafmodel.EnumLiteral]) + + add_entry(label: str, value: int) + + internal_model: vafmodel.VafEnum +} + +AbstractVafType <|- - Struct +AbstractVafType <|- - Vector +AbstractVafType <|- - String +AbstractVafType <|- - TypeRef +AbstractVafType <|- - Map +AbstractVafType <|- - Array +AbstractVafType <|- - Enum + +Struct -[hidden]d- Vector +Vector -[hidden]d- Array + +String -[hidden]d- TypeRef +TypeRef -[hidden]d- Map +Map -[hidden]d- Enum +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/cac-cd_executable.puml b/Documentation/contents/figures/cac-cd_executable.puml new file mode 100644 index 0000000..b327561 --- /dev/null +++ b/Documentation/contents/figures/cac-cd_executable.puml @@ -0,0 +1,17 @@ +@startuml cac-cd_executable +skinparam class { + BackgroundColor #FFFFFF +} + +class Executable { + + executable: vafmodel.Executable + -- generic methods -- + + Executable(name: str, executor_period: datetime.timedelta) + + set_executor_period(executor_period: timedelta) + + add_application_module(module: AbstractApplicationModule, task_mapping_info: list[tuple[str, timedelta, int]]) + + connect_interfaces(module_a: AbstractApplicationModule, instance_name_a: str, module_b: AbstractApplicationModule, instance_name_b: str) + .. SilKit related methods .. + + connect_consumed_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str) + + connect_provided_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str) +} +@enduml diff --git a/Documentation/contents/figures/cac-cd_executable.svg b/Documentation/contents/figures/cac-cd_executable.svg new file mode 100644 index 0000000..fecd742 --- /dev/null +++ b/Documentation/contents/figures/cac-cd_executable.svg @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="181px" preserveAspectRatio="none" style="width:851px;height:181px;" version="1.1" viewBox="0 0 851 181" width="851px" zoomAndPan="magnify"><defs><filter height="300%" id="f1qxsm43bu8m9e" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[07b9c9bb2dc14bf7e6468cd90df08689] +class Executable--><rect fill="#FFFFFF" filter="url(#f1qxsm43bu8m9e)" height="163.2422" id="Executable" style="stroke: #A80036; stroke-width: 1.5;" width="833" x="7" y="7"/><ellipse cx="384.75" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M387.7188,28.6406 Q387.1406,28.9375 386.5,29.0781 Q385.8594,29.2344 385.1563,29.2344 Q382.6563,29.2344 381.3281,27.5938 Q380.0156,25.9375 380.0156,22.8125 Q380.0156,19.6875 381.3281,18.0313 Q382.6563,16.375 385.1563,16.375 Q385.8594,16.375 386.5,16.5313 Q387.1563,16.6875 387.7188,16.9844 L387.7188,19.7031 Q387.0938,19.125 386.5,18.8594 Q385.9063,18.5781 385.2813,18.5781 Q383.9375,18.5781 383.25,19.6563 Q382.5625,20.7188 382.5625,22.8125 Q382.5625,24.9063 383.25,25.9844 Q383.9375,27.0469 385.2813,27.0469 Q385.9063,27.0469 386.5,26.7813 Q387.0938,26.5 387.7188,25.9219 L387.7188,28.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="69" x="405.25" y="27.1543">Executable</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="839" y1="39" y2="39"/><ellipse cx="18" cy="50" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="186" x="27" y="53.2104">executable: vafmodel.Executable</text><ellipse cx="18" cy="79.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="339" x="27" y="82.8198">Executable(name: str, executor_period: datetime.timedelta)</text><ellipse cx="18" cy="92.4141" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="275" x="27" y="95.6245">set_executor_period(executor_period: timedelta)</text><ellipse cx="18" cy="105.2188" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="624" x="27" y="108.4292">add_application_module(module: AbstractApplicationModule, task_mapping_info: list[tuple[str, timedelta, int]])</text><ellipse cx="18" cy="118.0234" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="807" x="27" y="121.2339">connect_interfaces(module_a: AbstractApplicationModule, instance_name_a: str, module_b: AbstractApplicationModule, instance_name_b: str)</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="8" x2="375.5" y1="66.207" y2="66.207"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="96" x="375.5" y="69.5151">generic methods</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="471.5" x2="839" y1="66.207" y2="66.207"/><ellipse cx="18" cy="147.6328" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="768" x="27" y="150.8433">connect_consumed_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str)</text><ellipse cx="18" cy="160.4375" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="758" x="27" y="163.6479">connect_provided_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str)</text><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,2.0;" x1="8" x2="360.5" y1="134.2305" y2="134.2305"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="126" x="360.5" y="137.5386">SilKit related methods</text><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,2.0;" x1="486.5" x2="839" y1="134.2305" y2="134.2305"/><!--MD5=[b85bc827191214a4258277651091a7f1] +@startuml cac-cd_executable +skinparam class { + BackgroundColor #FFFFFF +} + +class Executable { + + executable: vafmodel.Executable + - - generic methods - - + + Executable(name: str, executor_period: datetime.timedelta) + + set_executor_period(executor_period: timedelta) + + add_application_module(module: AbstractApplicationModule, task_mapping_info: list[tuple[str, timedelta, int]]) + + connect_interfaces(module_a: AbstractApplicationModule, instance_name_a: str, module_b: AbstractApplicationModule, instance_name_b: str) + .. SilKit related methods .. + + connect_consumed_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str) + + connect_provided_interface_to_silkit(app_module: AbstractApplicationModule, instance_name: str, silkit_address_instance_name: str) +} +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/cac-cd_module_interface.puml b/Documentation/contents/figures/cac-cd_module_interface.puml new file mode 100644 index 0000000..afd7c4d --- /dev/null +++ b/Documentation/contents/figures/cac-cd_module_interface.puml @@ -0,0 +1,12 @@ +@startuml cac-cd_module_interface +skinparam class { + BackgroundColor #FFFFFF +} + +class ModuleInterface { + + mi: vafmodel.ModuleInterface + + ModuleInterface(name: str, namespace: str) + + add_data_element(name: str, datatype: BaseTypesWrapper | AbstractVafType) + + add_operation(name: str,\n\tin_parameter: dict[str, BaseTypesWrapper | AbstractVafType],\n\tout_parameter: dict[str, BaseTypesWrapper | AbstractVafType],\n\tinout_parameter: dict[str, BaseTypesWrapper | AbstractVafType]) +} +@enduml diff --git a/Documentation/contents/figures/cac-cd_module_interface.svg b/Documentation/contents/figures/cac-cd_module_interface.svg new file mode 100644 index 0000000..82167a1 --- /dev/null +++ b/Documentation/contents/figures/cac-cd_module_interface.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="155px" preserveAspectRatio="none" style="width:491px;height:155px;" version="1.1" viewBox="0 0 491 155" width="491px" zoomAndPan="magnify"><defs><filter height="300%" id="f2wtjoo6ohbat" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[31ddb61b196718dfb51737f5c67c2c13] +class ModuleInterface--><rect fill="#FFFFFF" filter="url(#f2wtjoo6ohbat)" height="137.6328" id="ModuleInterface" style="stroke: #A80036; stroke-width: 1.5;" width="473" x="7" y="7"/><ellipse cx="188.75" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M191.7188,28.6406 Q191.1406,28.9375 190.5,29.0781 Q189.8594,29.2344 189.1563,29.2344 Q186.6563,29.2344 185.3281,27.5938 Q184.0156,25.9375 184.0156,22.8125 Q184.0156,19.6875 185.3281,18.0313 Q186.6563,16.375 189.1563,16.375 Q189.8594,16.375 190.5,16.5313 Q191.1563,16.6875 191.7188,16.9844 L191.7188,19.7031 Q191.0938,19.125 190.5,18.8594 Q189.9063,18.5781 189.2813,18.5781 Q187.9375,18.5781 187.25,19.6563 Q186.5625,20.7188 186.5625,22.8125 Q186.5625,24.9063 187.25,25.9844 Q187.9375,27.0469 189.2813,27.0469 Q189.9063,27.0469 190.5,26.7813 Q191.0938,26.5 191.7188,25.9219 L191.7188,28.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="101" x="209.25" y="27.1543">ModuleInterface</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="479" y1="39" y2="39"/><ellipse cx="18" cy="50" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="168" x="27" y="53.2104">mi: vafmodel.ModuleInterface</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="479" y1="59.8047" y2="59.8047"/><ellipse cx="18" cy="70.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="252" x="27" y="74.0151">ModuleInterface(name: str, namespace: str)</text><ellipse cx="18" cy="83.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="447" x="27" y="86.8198">add_data_element(name: str, datatype: BaseTypesWrapper | AbstractVafType)</text><ellipse cx="18" cy="96.4141" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="145" x="27" y="99.6245">add_operation(name: str,</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="354" x="59" y="112.4292">in_parameter: dict[str, BaseTypesWrapper | AbstractVafType],</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="362" x="59" y="125.2339">out_parameter: dict[str, BaseTypesWrapper | AbstractVafType],</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="372" x="59" y="138.0386">inout_parameter: dict[str, BaseTypesWrapper | AbstractVafType])</text><!--MD5=[2a9b663bed0eb7b70a3ad5664cea802e] +@startuml cac-cd_module_interface +skinparam class { + BackgroundColor #FFFFFF +} + +class ModuleInterface { + + mi: vafmodel.ModuleInterface + + ModuleInterface(name: str, namespace: str) + + add_data_element(name: str, datatype: BaseTypesWrapper | AbstractVafType) + + add_operation(name: str,\n\tin_parameter: dict[str, BaseTypesWrapper | AbstractVafType],\n\tout_parameter: dict[str, BaseTypesWrapper | AbstractVafType],\n\tinout_parameter: dict[str, BaseTypesWrapper | AbstractVafType]) +} +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/cac-cd_task.puml b/Documentation/contents/figures/cac-cd_task.puml new file mode 100644 index 0000000..06c9e5f --- /dev/null +++ b/Documentation/contents/figures/cac-cd_task.puml @@ -0,0 +1,11 @@ +@startuml cac-cd_task +skinparam class { + BackgroundColor #FFFFFF +} + +class Task { + + model: vafmodel.ApplicationModuleTasks + + Task(name: str, period: datetime.timedelta, preferred_offset: int, run_after: list[Task]) + + add_run_after(task: Task) +} +@enduml diff --git a/Documentation/contents/figures/cac-cd_task.svg b/Documentation/contents/figures/cac-cd_task.svg new file mode 100644 index 0000000..b637651 --- /dev/null +++ b/Documentation/contents/figures/cac-cd_task.svg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="104px" preserveAspectRatio="none" style="width:537px;height:104px;" version="1.1" viewBox="0 0 537 104" width="537px" zoomAndPan="magnify"><defs><filter height="300%" id="f1fqb73ntkn94g" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[b34797a66dc35cbf1d65f7e3ca75530e] +class Task--><rect fill="#FFFFFF" filter="url(#f1fqb73ntkn94g)" height="86.4141" id="Task" style="stroke: #A80036; stroke-width: 1.5;" width="519" x="7" y="7"/><ellipse cx="247.75" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M250.7188,28.6406 Q250.1406,28.9375 249.5,29.0781 Q248.8594,29.2344 248.1563,29.2344 Q245.6563,29.2344 244.3281,27.5938 Q243.0156,25.9375 243.0156,22.8125 Q243.0156,19.6875 244.3281,18.0313 Q245.6563,16.375 248.1563,16.375 Q248.8594,16.375 249.5,16.5313 Q250.1563,16.6875 250.7188,16.9844 L250.7188,19.7031 Q250.0938,19.125 249.5,18.8594 Q248.9063,18.5781 248.2813,18.5781 Q246.9375,18.5781 246.25,19.6563 Q245.5625,20.7188 245.5625,22.8125 Q245.5625,24.9063 246.25,25.9844 Q246.9375,27.0469 248.2813,27.0469 Q248.9063,27.0469 249.5,26.7813 Q250.0938,26.5 250.7188,25.9219 L250.7188,28.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="29" x="268.25" y="27.1543">Task</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="525" y1="39" y2="39"/><ellipse cx="18" cy="50" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="234" x="27" y="53.2104">model: vafmodel.ApplicationModuleTasks</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="8" x2="525" y1="59.8047" y2="59.8047"/><ellipse cx="18" cy="70.8047" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="493" x="27" y="74.0151">Task(name: str, period: datetime.timedelta, preferred_offset: int, run_after: list[Task])</text><ellipse cx="18" cy="83.6094" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="146" x="27" y="86.8198">add_run_after(task: Task)</text><!--MD5=[6691b58daf41f64dd16e6be49835214d] +@startuml cac-cd_task +skinparam class { + BackgroundColor #FFFFFF +} + +class Task { + + model: vafmodel.ApplicationModuleTasks + + Task(name: str, period: datetime.timedelta, preferred_offset: int, run_after: list[Task]) + + add_run_after(task: Task) +} +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/cac-overview.puml b/Documentation/contents/figures/cac-overview.puml new file mode 100644 index 0000000..c756f12 --- /dev/null +++ b/Documentation/contents/figures/cac-overview.puml @@ -0,0 +1,24 @@ +@startuml cac-overview +skinparam MinClassWidth 150 +skinparam class { + BackgroundColor #FFFFFF +} + +class Executable { + +application_modules: list[AbstractApplicationModule] +} + +class ApplicationModule { + +consumed_interfaces: ModuleInterface + +provided_interfaces: ModuleInterface + +tasks: list[Task] +} + +class Task + +class ModuleInterface + +Executable "1..*" o-- "0..*" ApplicationModule +ApplicationModule "1..*" o-- "0..*" Task +ApplicationModule "1..*" o-- "0..*" ModuleInterface +@enduml diff --git a/Documentation/contents/figures/cac-overview.svg b/Documentation/contents/figures/cac-overview.svg new file mode 100644 index 0000000..f04b839 --- /dev/null +++ b/Documentation/contents/figures/cac-overview.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="334px" preserveAspectRatio="none" style="width:352px;height:334px;" version="1.1" viewBox="0 0 352 334" width="352px" zoomAndPan="magnify"><defs><filter height="300%" id="f1lcwbgf4dlvhz" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[07b9c9bb2dc14bf7e6468cd90df08689] +class Executable--><rect fill="#FFFFFF" filter="url(#f1lcwbgf4dlvhz)" height="60.8047" id="Executable" style="stroke: #A80036; stroke-width: 1.5;" width="323" x="11.5" y="8"/><ellipse cx="134.25" cy="24" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M137.2188,29.6406 Q136.6406,29.9375 136,30.0781 Q135.3594,30.2344 134.6563,30.2344 Q132.1563,30.2344 130.8281,28.5938 Q129.5156,26.9375 129.5156,23.8125 Q129.5156,20.6875 130.8281,19.0313 Q132.1563,17.375 134.6563,17.375 Q135.3594,17.375 136,17.5313 Q136.6563,17.6875 137.2188,17.9844 L137.2188,20.7031 Q136.5938,20.125 136,19.8594 Q135.4063,19.5781 134.7813,19.5781 Q133.4375,19.5781 132.75,20.6563 Q132.0625,21.7188 132.0625,23.8125 Q132.0625,25.9063 132.75,26.9844 Q133.4375,28.0469 134.7813,28.0469 Q135.4063,28.0469 136,27.7813 Q136.5938,27.5 137.2188,26.9219 L137.2188,29.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="69" x="154.75" y="28.1543">Executable</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="12.5" x2="333.5" y1="40" y2="40"/><ellipse cx="22.5" cy="51" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="297" x="31.5" y="54.2104">application_modules: list[AbstractApplicationModule]</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="12.5" x2="333.5" y1="60.8047" y2="60.8047"/><!--MD5=[26e2a85c06611372298526764170fca9] +class ApplicationModule--><rect fill="#FFFFFF" filter="url(#f1lcwbgf4dlvhz)" height="86.4141" id="ApplicationModule" style="stroke: #A80036; stroke-width: 1.5;" width="246" x="50" y="129"/><ellipse cx="111.75" cy="145" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M114.7188,150.6406 Q114.1406,150.9375 113.5,151.0781 Q112.8594,151.2344 112.1563,151.2344 Q109.6563,151.2344 108.3281,149.5938 Q107.0156,147.9375 107.0156,144.8125 Q107.0156,141.6875 108.3281,140.0313 Q109.6563,138.375 112.1563,138.375 Q112.8594,138.375 113.5,138.5313 Q114.1563,138.6875 114.7188,138.9844 L114.7188,141.7031 Q114.0938,141.125 113.5,140.8594 Q112.9063,140.5781 112.2813,140.5781 Q110.9375,140.5781 110.25,141.6563 Q109.5625,142.7188 109.5625,144.8125 Q109.5625,146.9063 110.25,147.9844 Q110.9375,149.0469 112.2813,149.0469 Q112.9063,149.0469 113.5,148.7813 Q114.0938,148.5 114.7188,147.9219 L114.7188,150.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="114" x="132.25" y="149.1543">ApplicationModule</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="51" x2="295" y1="161" y2="161"/><ellipse cx="61" cy="172" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="220" x="70" y="175.2104">consumed_interfaces: ModuleInterface</text><ellipse cx="61" cy="184.8047" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="210" x="70" y="188.0151">provided_interfaces: ModuleInterface</text><ellipse cx="61" cy="197.6094" fill="none" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="91" x="70" y="200.8198">tasks: list[Task]</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="51" x2="295" y1="207.4141" y2="207.4141"/><!--MD5=[b34797a66dc35cbf1d65f7e3ca75530e] +class Task--><rect fill="#FFFFFF" filter="url(#f1lcwbgf4dlvhz)" height="48" id="Task" style="stroke: #A80036; stroke-width: 1.5;" width="150" x="6" y="275"/><ellipse cx="62.25" cy="291" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M65.2188,296.6406 Q64.6406,296.9375 64,297.0781 Q63.3594,297.2344 62.6563,297.2344 Q60.1563,297.2344 58.8281,295.5938 Q57.5156,293.9375 57.5156,290.8125 Q57.5156,287.6875 58.8281,286.0313 Q60.1563,284.375 62.6563,284.375 Q63.3594,284.375 64,284.5313 Q64.6563,284.6875 65.2188,284.9844 L65.2188,287.7031 Q64.5938,287.125 64,286.8594 Q63.4063,286.5781 62.7813,286.5781 Q61.4375,286.5781 60.75,287.6563 Q60.0625,288.7188 60.0625,290.8125 Q60.0625,292.9063 60.75,293.9844 Q61.4375,295.0469 62.7813,295.0469 Q63.4063,295.0469 64,294.7813 Q64.5938,294.5 65.2188,293.9219 L65.2188,296.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="29" x="82.75" y="295.1543">Task</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="7" x2="155" y1="307" y2="307"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="7" x2="155" y1="315" y2="315"/><!--MD5=[31ddb61b196718dfb51737f5c67c2c13] +class ModuleInterface--><rect fill="#FFFFFF" filter="url(#f1lcwbgf4dlvhz)" height="48" id="ModuleInterface" style="stroke: #A80036; stroke-width: 1.5;" width="150" x="191" y="275"/><ellipse cx="213.65" cy="291" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M216.6188,296.6406 Q216.0406,296.9375 215.4,297.0781 Q214.7594,297.2344 214.0563,297.2344 Q211.5563,297.2344 210.2281,295.5938 Q208.9156,293.9375 208.9156,290.8125 Q208.9156,287.6875 210.2281,286.0313 Q211.5563,284.375 214.0563,284.375 Q214.7594,284.375 215.4,284.5313 Q216.0563,284.6875 216.6188,284.9844 L216.6188,287.7031 Q215.9938,287.125 215.4,286.8594 Q214.8063,286.5781 214.1813,286.5781 Q212.8375,286.5781 212.15,287.6563 Q211.4625,288.7188 211.4625,290.8125 Q211.4625,292.9063 212.15,293.9844 Q212.8375,295.0469 214.1813,295.0469 Q214.8063,295.0469 215.4,294.7813 Q215.9938,294.5 216.6188,293.9219 L216.6188,296.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="101" x="229.35" y="295.1543">ModuleInterface</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="192" x2="340" y1="307" y2="307"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="192" x2="340" y1="315" y2="315"/><!--MD5=[b0038aa483aa31042202600f889305b0] +reverse link Executable to ApplicationModule--><path d="M173,82.14 C173,97.12 173,113.93 173,128.87 " fill="none" id="Executable<-ApplicationModule" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="173,69.01,169,75.01,173,81.01,177,75.01,173,69.01" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="147.6281" y="88.9503">1..*</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="148.1672" y="117.8453">0..*</text><!--MD5=[58906a0ee986b370fcb572105533e4a9] +reverse link ApplicationModule to Task--><path d="M133.81,226.25 C121.36,243.17 108.22,261.01 98.17,274.67 " fill="none" id="ApplicationModule<-Task" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="141.85,215.32,135.0708,217.7782,134.7325,224.9813,141.5117,222.5232,141.85,215.32" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="112.0527" y="235.4639">1..*</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="76.5521" y="263.9945">0..*</text><!--MD5=[2b2919824ae23810bb4829460669f6f4] +reverse link ApplicationModule to ModuleInterface--><path d="M212.26,225.77 C224.95,242.83 238.38,260.88 248.64,274.67 " fill="none" id="ApplicationModule<-ModuleInterface" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="204.49,215.32,204.8631,222.5214,211.6541,224.9468,211.281,217.7454,204.49,215.32" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="184.6759" y="235.4639">1..*</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="23" x="218.6054" y="263.9945">0..*</text><!--MD5=[d89a30bea44d88ceb6cfe4c379c16381] +@startuml cac-overview +skinparam MinClassWidth 150 +skinparam class { + BackgroundColor #FFFFFF +} + +class Executable { + +application_modules: list[AbstractApplicationModule] +} + +class ApplicationModule { + +consumed_interfaces: ModuleInterface + +provided_interfaces: ModuleInterface + +tasks: list[Task] +} + +class Task + +class ModuleInterface + +Executable "1..*" o- - "0..*" ApplicationModule +ApplicationModule "1..*" o- - "0..*" Task +ApplicationModule "1..*" o- - "0..*" ModuleInterface +@enduml + +PlantUML version 1.2020.02(Sun Mar 01 11:22:07 CET 2020) +(GPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Java Version: 11.0.26+4-post-Ubuntu-1ubuntu122.04 +Operating System: Linux +Default Encoding: UTF-8 +Language: en +Country: null +--></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/stack-new.svg b/Documentation/contents/figures/stack-new.svg new file mode 100644 index 0000000..816baec --- /dev/null +++ b/Documentation/contents/figures/stack-new.svg @@ -0,0 +1 @@ +<svg width="965" height="386" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><g transform="translate(-3272 -453)"><rect x="3763" y="695" width="474" height="131" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3954.89 735)">Other</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3878.42 773)">communication</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3949.73 812)">stacks</text><rect x="3272" y="695" width="474" height="131" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3430.95 735)">AUTOSAR</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3438.97 773)">Adaptive</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3467.05 812)">stack</text><rect x="3935" y="453" width="302" height="120" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 4048.57 507)">C++</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 4055.15 545)">App</text><rect x="3935" y="573" width="302" height="12.0001" fill="#FBB900"/><rect x="3272" y="453" width="302" height="120" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3345.01 507)">AUTOSAR</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3316.37 545)">Adaptive App</text><rect x="3272" y="573" width="302" height="12.0001" fill="#00B0F0"/><rect x="3603" y="453" width="303" height="120" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3709.68 507)">ADAS</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3723.71 545)">App</text><rect x="3603" y="573" width="303" height="12.0001" fill="#EF7C00"/><rect x="3272" y="600" width="965" height="77" fill="#B70032"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 3571.04 652)">Application Framework</text></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/stack-today.svg b/Documentation/contents/figures/stack-today.svg new file mode 100644 index 0000000..81fe030 --- /dev/null +++ b/Documentation/contents/figures/stack-today.svg @@ -0,0 +1 @@ +<svg width="971" height="532" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><defs><clipPath id="clip0"><rect x="616" y="627" width="971" height="532"/></clipPath></defs><g clip-path="url(#clip0)" transform="translate(-616 -627)"><rect x="616" y="1068" width="971" height="91.0001" fill="#565C5E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 963.89 1127)">Microprocessor</text><rect x="616" y="985" width="968" height="74.0003" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 1001.04 1036)">Hypervisor</text><rect x="618" y="905" width="965" height="72.9999" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 1073.23 956)">OS</text><rect x="1109" y="765" width="474" height="132" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1300.39 805)">Other</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1223.92 843)">communication</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1295.23 882)">stacks</text><rect x="618" y="765" width="474" height="132" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 776.454 805)">AUTOSAR</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 784.475 843)">Adaptive</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 812.548 882)">stack</text><rect x="1280" y="627" width="303" height="119" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1394.08 680)">C++</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1400.65 718)">App</text><rect x="1280" y="746" width="303" height="12.0001" fill="#FBB900"/><rect x="618" y="627" width="302" height="119" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 690.516 680)">AUTOSAR</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 661.87 718)">Adaptive App</text><rect x="618" y="746" width="302" height="12.0001" fill="#00B0F0"/><rect x="949" y="627" width="302" height="119" fill="#848B8E"/><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1055.19 680)">ADAS</text><text fill="#FFFFFF" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="32" transform="matrix(1 0 0 1 1069.21 718)">App</text><rect x="949" y="746" width="302" height="12.0001" fill="#EF7C00"/></g></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/vaf-cli.drawio.svg b/Documentation/contents/figures/vaf-cli.drawio.svg new file mode 100644 index 0000000..4d6dbac --- /dev/null +++ b/Documentation/contents/figures/vaf-cli.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="812px" height="852px" viewBox="-0.5 -0.5 812 852" content="<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2"> <diagram name="Page-1" id="UqtQnKIbU7jp4ZLXrd1d"> <mxGraphModel dx="5676" dy="3972" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2339" pageHeight="3300" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="y4bpetFAl4_TD6zRjlkh-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-42" target="y4bpetFAl4_TD6zRjlkh-51" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-42" target="y4bpetFAl4_TD6zRjlkh-59" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-42" target="y4bpetFAl4_TD6zRjlkh-62" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-42" target="y4bpetFAl4_TD6zRjlkh-67" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-42" value="&lt;b&gt;vaf&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="40" y="510" width="100" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-47" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-51" target="y4bpetFAl4_TD6zRjlkh-70" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-51" target="y4bpetFAl4_TD6zRjlkh-71" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-49" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-51" target="y4bpetFAl4_TD6zRjlkh-72" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-50" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-51" target="y4bpetFAl4_TD6zRjlkh-73" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-51" value="&lt;b&gt;make&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="230" y="130" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-57" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-59" target="y4bpetFAl4_TD6zRjlkh-79" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-59" target="y4bpetFAl4_TD6zRjlkh-80" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-59" value="&lt;b&gt;model&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="230" y="370" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" edge="1" parent="1" source="y4bpetFAl4_TD6zRjlkh-62" target="WFmsDuIPbSD5tHYI6WZj-10"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-62" value="&lt;b&gt;workspace&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="230" y="860" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-63" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-67" target="y4bpetFAl4_TD6zRjlkh-83" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-67" target="y4bpetFAl4_TD6zRjlkh-84" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-65" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-67" target="y4bpetFAl4_TD6zRjlkh-85" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-66" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-67" target="y4bpetFAl4_TD6zRjlkh-86" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" edge="1" parent="1" source="y4bpetFAl4_TD6zRjlkh-67" target="WFmsDuIPbSD5tHYI6WZj-5"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-67" value="&lt;b&gt;project&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="230" y="670" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-70" value="&lt;b&gt;build&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="40" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-71" value="&lt;b&gt;clean&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="100" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-72" value="&lt;b&gt;install&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="160" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-73" value="&lt;b&gt;preset&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="220" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="jZATUV3jU1Qrcf8WkRvf-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-79" target="jZATUV3jU1Qrcf8WkRvf-2" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-79" value="&lt;b&gt;import&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="370" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-80" value="&lt;b&gt;update&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="430" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="rUK_GNVIaD1eHqHd8PEg-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-83" target="rUK_GNVIaD1eHqHd8PEg-9" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-83" value="&lt;b&gt;create&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="520" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-84" value="&lt;b&gt;generate&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="580" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-103" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-85" target="y4bpetFAl4_TD6zRjlkh-96" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-104" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-85" target="y4bpetFAl4_TD6zRjlkh-97" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="660" y="715" /> <mxPoint x="660" y="685" /> </Array> </mxGeometry> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-105" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" parent="1" source="y4bpetFAl4_TD6zRjlkh-85" target="y4bpetFAl4_TD6zRjlkh-98" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="630" y="745" as="sourcePoint" /> </mxGeometry> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-85" value="&lt;b&gt;init&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="700" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-86" value="&lt;b&gt;import&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="470" y="640" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-96" value="&lt;b&gt;app-module&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="690" y="630" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-97" value="&lt;b&gt;integration&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="690" y="670" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="y4bpetFAl4_TD6zRjlkh-98" value="&lt;b&gt;interface&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="690" y="710" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="jZATUV3jU1Qrcf8WkRvf-2" value="&lt;b&gt;vss&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1"> <mxGeometry x="690" y="370" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="rUK_GNVIaD1eHqHd8PEg-9" value="&lt;b&gt;app-module&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#FFFFFF;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="690" y="520" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-2" value="&lt;b&gt;generate&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1"> <mxGeometry x="470" y="310" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" edge="1" parent="1" source="y4bpetFAl4_TD6zRjlkh-59" target="WFmsDuIPbSD5tHYI6WZj-2"> <mxGeometry relative="1" as="geometry"> <mxPoint x="400" y="395" as="sourcePoint" /> <mxPoint x="480" y="455" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-5" value="&lt;b&gt;remove&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1"> <mxGeometry x="470" y="760" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;endArrow=classicThin;endFill=1;" edge="1" parent="1" target="WFmsDuIPbSD5tHYI6WZj-7" source="WFmsDuIPbSD5tHYI6WZj-5"> <mxGeometry relative="1" as="geometry"> <mxPoint x="630" y="775" as="sourcePoint" /> </mxGeometry> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-7" value="&lt;b&gt;app-module&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#FFFFFF;strokeColor=#000000;" vertex="1" parent="1"> <mxGeometry x="690" y="760" width="160" height="30" as="geometry" /> </mxCell> <mxCell id="WFmsDuIPbSD5tHYI6WZj-10" value="&lt;b&gt;init&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1"> <mxGeometry x="470" y="860" width="160" height="30" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> "><defs/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="y4bpetFAl4_TD6zRjlkh-38"><g><path d="M 101 486.2 L 146.2 486.2 L 146.2 106.2 L 182.76 106.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 188.76 106.01 L 180.78 108.71 L 182.76 106.04 L 180.75 103.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-39"><g><path d="M 101 486.2 L 146.2 486.2 L 146.2 346.2 L 182.76 346.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 188.76 346.01 L 180.78 348.71 L 182.76 346.04 L 180.75 343.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-40"><g><path d="M 101 486.2 L 146.2 486.2 L 146.2 836.2 L 182.76 836.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 188.76 836.01 L 180.78 838.71 L 182.76 836.04 L 180.75 833.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-41"><g><path d="M 101 486.2 L 146.2 486.2 L 146.2 646.2 L 182.76 646.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 188.76 646.01 L 180.78 648.71 L 182.76 646.04 L 180.75 643.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-42"><g><rect x="1" y="471" width="100" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 486px; margin-left: 2px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>vaf</b></div></div></div></foreignObject><text x="51" y="490" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">vaf</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-47"><g><path d="M 351 106.2 L 391 106.2 L 391 16.2 L 422.76 16.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 16.01 L 420.78 18.72 L 422.76 16.04 L 420.75 13.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-48"><g><path d="M 351 106.2 L 391 106.2 L 391 76.2 L 422.76 76.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 76.01 L 420.78 78.72 L 422.76 76.04 L 420.75 73.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-49"><g><path d="M 351 106.2 L 391 106.2 L 391 136.2 L 422.76 136.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 136.01 L 420.78 138.72 L 422.76 136.04 L 420.75 133.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-50"><g><path d="M 351 106.2 L 391 106.2 L 391 196.2 L 422.76 196.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 196.01 L 420.78 198.72 L 422.76 196.04 L 420.75 193.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-51"><g><rect x="191" y="91" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 106px; margin-left: 192px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>make</b></div></div></div></foreignObject><text x="271" y="110" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">make</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-57"><g><path d="M 351 346 L 422.76 346" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 346 L 420.76 348.67 L 422.76 346 L 420.76 343.33 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-58"><g><path d="M 351 346.2 L 391 346.2 L 391 406.2 L 422.76 406.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 406.01 L 420.78 408.72 L 422.76 406.04 L 420.75 403.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-59"><g><rect x="191" y="331" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 346px; margin-left: 192px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>model</b></div></div></div></foreignObject><text x="271" y="350" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">model</text></switch></g></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-11"><g><path d="M 351 836 L 422.76 836" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 836 L 420.76 838.67 L 422.76 836 L 420.76 833.33 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-62"><g><rect x="191" y="821" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 836px; margin-left: 192px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>workspace</b></div></div></div></foreignObject><text x="271" y="840" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">workspace</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-63"><g><path d="M 351 646.2 L 391 646.2 L 391 496.2 L 422.76 496.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 496.01 L 420.78 498.72 L 422.76 496.04 L 420.75 493.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-64"><g><path d="M 351 646.2 L 391 646.2 L 391 556.2 L 422.76 556.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 556.01 L 420.78 558.72 L 422.76 556.04 L 420.75 553.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-65"><g><path d="M 351 646.2 L 391 646.2 L 391 676.2 L 422.76 676.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 676.01 L 420.78 678.72 L 422.76 676.04 L 420.75 673.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-66"><g><path d="M 351 646.2 L 391 646.2 L 391 616.2 L 422.76 616.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 616.01 L 420.78 618.72 L 422.76 616.04 L 420.75 613.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-12"><g><path d="M 351 646 L 391 646.2 L 391 736.2 L 422.76 736.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 736.01 L 420.78 738.72 L 422.76 736.04 L 420.75 733.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-67"><g><rect x="191" y="631" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 646px; margin-left: 192px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>project</b></div></div></div></foreignObject><text x="271" y="650" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">project</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-70"><g><rect x="431" y="1" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 16px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>build</b></div></div></div></foreignObject><text x="511" y="20" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">build</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-71"><g><rect x="431" y="61" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 76px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>clean</b></div></div></div></foreignObject><text x="511" y="80" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">clean</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-72"><g><rect x="431" y="121" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 136px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>install</b></div></div></div></foreignObject><text x="511" y="140" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">install</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-73"><g><rect x="431" y="181" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 196px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>preset</b></div></div></div></foreignObject><text x="511" y="200" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">preset</text></switch></g></g></g><g data-cell-id="jZATUV3jU1Qrcf8WkRvf-6"><g><path d="M 591 346 L 642.76 346" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 346 L 640.76 348.67 L 642.76 346 L 640.76 343.33 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-79"><g><rect x="431" y="331" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 346px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>import</b></div></div></div></foreignObject><text x="511" y="350" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">import</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-80"><g><rect x="431" y="391" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 406px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>update</b></div></div></div></foreignObject><text x="511" y="410" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">update</text></switch></g></g></g><g data-cell-id="rUK_GNVIaD1eHqHd8PEg-12"><g><path d="M 591 496 L 642.76 496" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 496 L 640.76 498.67 L 642.76 496 L 640.76 493.33 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-83"><g><rect x="431" y="481" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 496px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>create</b></div></div></div></foreignObject><text x="511" y="500" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">create</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-84"><g><rect x="431" y="541" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 556px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>generate</b></div></div></div></foreignObject><text x="511" y="560" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">generate</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-103"><g><path d="M 591 676.2 L 621 676.2 L 621 606.2 L 642.76 606.05" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 606.01 L 640.78 608.73 L 642.76 606.05 L 640.75 603.4 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-104"><g><path d="M 591 676.2 L 621 676.2 L 621 646.2 L 642.76 646.05" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 646.01 L 640.78 648.73 L 642.76 646.05 L 640.75 643.4 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-105"><g><path d="M 591 676 L 621 676.2 L 621 686.2 L 642.76 686.05" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 686.01 L 640.78 688.73 L 642.76 686.05 L 640.75 683.4 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-85"><g><rect x="431" y="661" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 676px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>init</b></div></div></div></foreignObject><text x="511" y="680" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">init</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-86"><g><rect x="431" y="601" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 616px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>import</b></div></div></div></foreignObject><text x="511" y="620" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">import</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-96"><g><rect x="651" y="591" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 606px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>app-module</b></div></div></div></foreignObject><text x="731" y="610" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">app-module</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-97"><g><rect x="651" y="631" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 646px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>integration</b></div></div></div></foreignObject><text x="731" y="650" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">integration</text></switch></g></g></g><g data-cell-id="y4bpetFAl4_TD6zRjlkh-98"><g><rect x="651" y="671" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 686px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>interface</b></div></div></div></foreignObject><text x="731" y="690" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">interface</text></switch></g></g></g><g data-cell-id="jZATUV3jU1Qrcf8WkRvf-2"><g><rect x="651" y="331" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 346px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>vss</b></div></div></div></foreignObject><text x="731" y="350" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">vss</text></switch></g></g></g><g data-cell-id="rUK_GNVIaD1eHqHd8PEg-9"><g><rect x="651" y="481" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 496px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>app-module</b></div></div></div></foreignObject><text x="731" y="500" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">app-module</text></switch></g></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-2"><g><rect x="431" y="271" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 286px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>generate</b></div></div></div></foreignObject><text x="511" y="290" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">generate</text></switch></g></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-4"><g><path d="M 351 346 L 391 346.2 L 391 286.2 L 422.76 286.04" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 428.76 286.01 L 420.78 288.72 L 422.76 286.04 L 420.75 283.38 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-5"><g><rect x="431" y="721" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 736px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>remove</b></div></div></div></foreignObject><text x="511" y="740" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">remove</text></switch></g></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-6"><g><path d="M 591 736 L 642.76 736" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/><path d="M 648.76 736 L 640.76 738.67 L 642.76 736 L 640.76 733.33 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-7"><g><rect x="651" y="721" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 736px; margin-left: 652px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>app-module</b></div></div></div></foreignObject><text x="731" y="740" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">app-module</text></switch></g></g></g><g data-cell-id="WFmsDuIPbSD5tHYI6WZj-10"><g><rect x="431" y="821" width="160" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="all" style="fill: light-dark(#ffffff, var(--ge-dark-color, #121212)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 836px; margin-left: 432px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>init</b></div></div></div></foreignObject><text x="511" y="840" fill="light-dark(#000000, #ffffff)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">init</text></switch></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/Documentation/contents/figures/vaf-map.svg b/Documentation/contents/figures/vaf-map.svg new file mode 100644 index 0000000..a38b2e1 --- /dev/null +++ b/Documentation/contents/figures/vaf-map.svg @@ -0,0 +1 @@ +<svg width="1598" height="2198" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><defs><clipPath id="clip0"><rect x="2563" y="208" width="1598" height="2198"/></clipPath><image width="94" height="92" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAABcCAMAAADQxPJXAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABjUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZodN4AAAAgdFJOUwAIEBggKDA4QEhQWGBocHiAh4+Xn6evt7/Hz9ff5+/3v+H4wgAAAAlwSFlzAAAywAAAMsABKGRa2wAAA/9JREFUaEPtmVm3syoMhuvQ1s52nhz4/7/yW0FJAhLE7p6Ls1afq13Fl20mIM5mU1gUS/fS15ifW6VUey3cG99gdVeG1zZx7/6NdFehOFCXmTvkc/JTY4kD7WXhDvuM5ZVEL/mZZnpu3KHT2b5Qrj6CRbid6sOfbJSVNUq9yZ9r8nJ7mduPxLO8oIq62dHYxWjHfWXdimTzRIHmlLt3LRuxF4sj3bNAvKXu7Q6WCY12SyRuIL7W7ogeHkfXyHJR3MwTLUZNtXVH9XAbRSRzsn2b0fDCS5yqEp9lNhpJ5vyIL1vvO4svMHzMlSHMRoFkZun5YsbILyYIm1KagIfCw5vMLBDvTsnNTjjBSXz7zQOfr9z3TA+Ynt48zNBqrScHehb4mqo9M5H0ZC6rRnJOWqJ9L+IEvIjczKgcr9V7KTz0BDjuJvqP2bjtTJwYr3B/ekn2NIG8Ii6NjRptiH3/xDMi7RLKooc4QVL2Q07wCzNHPcXUYVDe+WsFs38Fv3E4vA/3uMQaa8XQnDmr1ErBFXjdmkrT3ZsVNgXGuF0rWLnSRoRr8MeF1ZqoJY4moGijdbM5Ztr+cFXLu0v2uJsX+J/qWsESs4bfA3lnad1J9QXJsdq1J6qFfVn2yENWsBVo3M00geFhFl6/vFWUI9xM1Q64kU0leVhSqHhWY25e4uu2Vi2S5Xliw1MBN1OFcRfzoDxEAi0QQjazIcOVbETe3ox53Mzy8z1I3hh5e6Nhb1gpPylYLGLkbTd3W1iA7WulpTtO3nazuq7shVNeGaPlZ7OMuflNJq8Prj8ZE+TtbO4Z2bdOk7fdrNTDu5QwpsrzDSJLfonp8uBmeINK9CfjI3k9+OFe9PGTD/CTD/CTD/CTD/CTD/CTD/B/lIc22T1w+BkjKL/oDn8H+Pvr8mtzFi3h13flky3c0TR6z/xdedqC9s0YS/7mDpcQ5DdG/Gq2+0cjDxO3nuOLF0F+p7XbM24PC9iONvCXnkdVoc06IcinlXU27L2sbZL154HgCdMgyM/yPTUJ8GjUGWqF5w3hhMmQ5JGEOpo6QI2hOupjeHc9Ik8NSdUwd7IeqT6eiQTl53TIc3tCc3a2qeRmS0Ce2tnehnm6IxtZXVSOKI8lQWrhOQ0pf6dZkGfnaLcBbcGPsL5uvE+eBYvyNaBtWKdi+MViKJ9Rc9ltugjwbyfO6diVZ32R4CHdhvcdG6okrny/fgAjh/QBvFNxx1jg8isKltFDugfekDIVj+Q3FCxYhaeyolTpKl4vzzrhrAp/AHfzc6t7/Q/2oUD8WhGN1ZACfzTolGo3zZ8CrFYxvvE5uMf6RqkJfN74iBUrSN6vT38lP3YujUz+DyjKsiyik/8/5x+TLQk3TE4ScwAAAABJRU5ErkJggg==" preserveAspectRatio="none" id="img1"></image></defs><g clip-path="url(#clip0)" transform="translate(-2563 -208)"><text fill="#565C5E" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2609.99 274)">Interface line</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2723.09 404)">Initialize project </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2723.09 528)">Import catalogue </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2723.09 589)">(VSS, etc.)</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2719.65 696)">VAF Config</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2995.8 696)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3018.72 696)">as</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3075.43 696)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3098.35 696)">Code</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2719.65 757)">(interface/type design)</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3549.91 1262)">VAF Config</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3826.06 1262)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3848.97 1262)">as</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3905.69 1262)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3928.61 1262)">Code</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3549.91 1323)">(app</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3666.21 1323)">-</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3689.13 1323)">module design)</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3542.3 968)">Initialize project</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3548.54 1101)">Import interface and </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3548.54 1162)">type definitions</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3549.02 1424)">Generate VAF </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3915.11 1424)">model</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 4069.8 1424)">; </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3549.02 1485)">generate code</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3466.45 2304)">Binary </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3466.45 2365)">executables</text><text fill="#B70032" font-family="Mark Pro for Vector,Mark Pro for Vector_MSFontService,sans-serif" font-weight="700" font-size="73" transform="matrix(1 0 0 1 3550.79 2006)">VAF MAP</text><text fill="#028FC3" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3432.41 847)">App</text><text fill="#028FC3" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3529.81 847)">-</text><text fill="#028FC3" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3552.72 847)">module line</text><path d="M3.43759 22.9167 3.43786 94.0605-3.43714 94.0605-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#028FC3" transform="matrix(1 0 0 -1 3465.5 1239.56)"/><path d="M2637.52 487.969 2637.06 415.522 2643.94 415.478 2644.4 487.926ZM2654.68 483.277 2641.1 510.864 2627.18 483.451Z" fill="#565C5E"/><path d="M2637.06 651.797 2637.06 578.5 2643.94 578.5 2643.94 651.797ZM2654.25 647.214 2640.5 674.714 2626.75 647.214Z" fill="#565C5E"/><path d="M3407.34 1113.67 2637.71 1113.67 2637.71 904.5 2641.15 907.937 2637.5 907.937 2637.5 901.062 2644.58 901.062 2644.58 1110.23 2641.15 1106.8 3407.34 1106.8ZM3402.75 1096.48 3430.25 1110.23 3402.75 1123.98Z" fill="#565C5E"/><path d="M3.43759 22.9167 3.43786 95.395-3.43714 95.3951-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#028FC3" transform="matrix(1 0 0 -1 3465.5 1075.89)"/><text fill="#B70032" font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2830.61 1571)">Integration line</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2700.93 1693)">Initialize project</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2688.32 2342)">Compile and link</text><path d="M3.43759 22.9167 3.43786 95.4856-3.43714 95.4856-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#B70032" transform="matrix(1 0 0 -1 3191.5 1800.99)"/><use width="100%" height="100%" xlink:href="#img1" fill="none" transform="translate(3320 2277)"></use><path d="M22.9166-3.4375 247.242-3.4375 247.242 202.921 243.805 199.483 246.983 199.483 246.983 206.358 240.367 206.358 240.367 0 243.805 3.4375 22.9166 3.4375ZM27.5 13.75 0 0 27.5-13.75Z" fill="#028FC3" transform="matrix(1 0 0 -1 3223.5 1835.42)"/><path d="M3591.5 380C3591.5 362.051 3606.05 347.5 3624 347.5 3641.95 347.5 3656.5 362.051 3656.5 380 3656.5 397.949 3641.95 412.5 3624 412.5 3606.05 412.5 3591.5 397.949 3591.5 380Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M3591.5 254 3607.75 221.5 3640.25 221.5 3656.5 254 3640.25 286.499 3607.75 286.499Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3693.18 398)">Mandatory step</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3693.18 274)">Optional step</text><path d="M3407.53 1081.94 3386.9 1081.94 3386.9 1075.06 3407.53 1075.06ZM3380.03 1081.94 3359.4 1081.94 3359.4 1075.06 3380.03 1075.06ZM3352.53 1081.94 3339.5 1081.94 3339.5 1075.06 3352.53 1075.06ZM3402.94 1064.75 3430.44 1078.5 3402.94 1092.25Z" fill="#565C5E"/><path d="M22.9167-3.43741 43.5417-3.43733 43.5417 3.43767 22.9167 3.43759ZM50.4167-3.4373 71.0417-3.43722 71.0417 3.43778 50.4167 3.4377ZM77.9167-3.43719 90.693-3.43714 90.693 3.43786 77.9167 3.43781ZM27.4999 13.7501 0 0 27.5001-13.7499Z" fill="#565C5E" transform="matrix(-1 0 0 1 3430.19 1140.5)"/><path d="M22.9167-3.43741 43.5417-3.43733 43.5417 3.43767 22.9167 3.43759ZM50.4167-3.4373 71.0417-3.43722 71.0417 3.43778 50.4167 3.4377ZM77.9167-3.43719 90.9449-3.43714 90.9449 3.43786 77.9167 3.43781ZM27.4999 13.7501 0 0 27.5001-13.7499Z" fill="#028FC3" transform="matrix(1 0 0 -1 3222.5 1805.5)"/><path d="M22.9167-3.43741 43.5417-3.43733 43.5417 3.43767 22.9167 3.43759ZM50.4167-3.4373 71.0417-3.43722 71.0417 3.43778 50.4167 3.4377ZM77.9167-3.43719 90.9449-3.43714 90.9449 3.43786 77.9167 3.43781ZM27.4999 13.7501 0 0 27.5001-13.7499Z" fill="#028FC3" transform="matrix(1 0 0 -1 3223.5 1864.5)"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 3298.27 1092)">1</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 3297.12 1153)">N</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 3328.33 1819)">1</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="37" transform="matrix(1 0 0 1 3327.54 1878)">M</text><path d="M2638.52 813.727 2638.06 739.521 2644.94 739.479 2645.4 813.684ZM2655.68 809.036 2642.1 836.621 2628.18 809.208Z" fill="#565C5E"/><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2723.09 889)">Generate VAF model</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3548.54 1612)">I</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3569.74 1612)">mplement </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 3843.02 1612)">and test</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2754.09 1819)">Create</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2920.81 1819)">/</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2943.73 1819)">import </text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2605.71 1880)">app</text><text font-family="Verdana,Verdana_MSFontService,sans-serif" font-weight="400" font-size="50" transform="matrix(1 0 0 1 2699.09 1880)">lication modules</text><path d="M2609.5 544 2625.75 511.5 2658.25 511.5 2674.5 544 2658.25 576.5 2625.75 576.5Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#565C5E" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M2608.5 383 2624.75 350.5 2657.25 350.5 2673.5 383 2657.25 415.5 2624.75 415.5Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#565C5E" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M2608.5 708 2624.5 675.5 2656.5 675.5 2672.5 708 2656.5 740.5 2624.5 740.5Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#565C5E" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3.43759 22.9167 3.43786 94.0605-3.43714 94.0605-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#028FC3" transform="matrix(1 0 0 -1 3466.5 1401.56)"/><path d="M3.43759 22.9167 3.43786 94.0605-3.43714 94.0605-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#028FC3" transform="matrix(1 0 0 -1 3466.5 1562.56)"/><path d="M3432.5 946C3432.5 928.051 3447.05 913.5 3465 913.5 3482.95 913.5 3497.5 928.051 3497.5 946 3497.5 963.949 3482.95 978.5 3465 978.5 3447.05 978.5 3432.5 963.949 3432.5 946Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#028FC3" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3433.5 1110 3449.75 1077.5 3482.25 1077.5 3498.5 1110 3482.25 1142.5 3449.75 1142.5Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#028FC3" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3433.5 1273C3433.5 1255.05 3448.05 1240.5 3466 1240.5 3483.95 1240.5 3498.5 1255.05 3498.5 1273 3498.5 1290.95 3483.95 1305.5 3466 1305.5 3448.05 1305.5 3433.5 1290.95 3433.5 1273Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#028FC3" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3433.5 1435C3433.5 1417.05 3448.05 1402.5 3466 1402.5 3483.95 1402.5 3498.5 1417.05 3498.5 1435 3498.5 1452.95 3483.95 1467.5 3466 1467.5 3448.05 1467.5 3433.5 1452.95 3433.5 1435Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#028FC3" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3433.5 1596C3433.5 1578.05 3448.05 1563.5 3466 1563.5 3483.95 1563.5 3498.5 1578.05 3498.5 1596 3498.5 1613.95 3483.95 1628.5 3466 1628.5 3448.05 1628.5 3433.5 1613.95 3433.5 1596Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#028FC3" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3.43759 22.9167 3.43786 95.4856-3.43714 95.4856-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#B70032" transform="matrix(1 0 0 -1 3191.5 1963.99)"/><path d="M3.43759 22.9167 3.43786 95.4856-3.43714 95.4856-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#B70032" transform="matrix(1 0 0 -1 3191.5 2126.99)"/><path d="M3.43759 22.9167 3.43786 95.4856-3.43714 95.4856-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#B70032" transform="matrix(1 0 0 -1 3191.5 2289.99)"/><path d="M3.43759 22.9167 3.43786 95.4856-3.43714 95.4856-3.43741 22.9167ZM-13.7499 27.5001 0 0 13.7501 27.4999Z" fill="#B70032" transform="matrix(-1.83697e-16 -1 -1 1.83697e-16 3320.99 2323.5)"/><path d="M3158.5 1835C3158.5 1817.05 3173.05 1802.5 3191 1802.5 3208.95 1802.5 3223.5 1817.05 3223.5 1835 3223.5 1852.95 3208.95 1867.5 3191 1867.5 3173.05 1867.5 3158.5 1852.95 3158.5 1835Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#B70032" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3158.5 1998C3158.5 1980.05 3173.05 1965.5 3191 1965.5 3208.95 1965.5 3223.5 1980.05 3223.5 1998 3223.5 2015.95 3208.95 2030.5 3191 2030.5 3173.05 2030.5 3158.5 2015.95 3158.5 1998Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#B70032" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3158.5 2162C3158.5 2144.05 3173.05 2129.5 3191 2129.5 3208.95 2129.5 3223.5 2144.05 3223.5 2162 3223.5 2179.95 3208.95 2194.5 3191 2194.5 3173.05 2194.5 3158.5 2179.95 3158.5 2162Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#B70032" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3157.5 1672C3157.5 1654.05 3172.05 1639.5 3190 1639.5 3207.95 1639.5 3222.5 1654.05 3222.5 1672 3222.5 1689.95 3207.95 1704.5 3190 1704.5 3172.05 1704.5 3157.5 1689.95 3157.5 1672Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#B70032" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M3158.5 2323C3158.5 2305.05 3173.05 2290.5 3191 2290.5 3208.95 2290.5 3223.5 2305.05 3223.5 2323 3223.5 2340.95 3208.95 2355.5 3191 2355.5 3173.05 2355.5 3158.5 2340.95 3158.5 2323Z" stroke="#000000" stroke-width="4.58333" stroke-miterlimit="8" fill="#B70032" fill-rule="evenodd" fill-opacity="0.901961"/><path d="M2608.5 870 2624.5 837.5 2656.5 837.5 2672.5 870 2656.5 902.5 2624.5 902.5Z" stroke="#343739" stroke-width="4.58333" stroke-miterlimit="8" fill="#565C5E" fill-rule="evenodd" fill-opacity="0.901961"/></g></svg> \ No newline at end of file diff --git a/README.md b/README.md index d229cd2..f6ee2d2 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,124 @@ -# code - - +# Welcome to the Git repository of the [Eclipse Automotive API Framework](https://projects.eclipse.org/projects/automotive.autoapiframework) + +This space is where the implementation of our Vehicle Application Framework (VAF) is versioned and +maintained. + +## Repository contents + +- 📂 [.devcontainer](./.devcontainer) + VS Code development container configuration file for contributors of this project. +- 📂 [.vscode](./.vscode) + Tasks, scripts, and settings for easier development in VS Code. +- 📂 [Container](./Container) + Dockerfile recipe for the container image that is supposed to be provided to users of the + framework. +- 📂 [Demo](./Demo) + Several demo projects with sample files that demonstrate the usage of the VAF. +- 📂 [Documentation](./Documentation) + The VAF technical documentation. +- 📂 [SwLibraries](./SwLibraries) + Libraries in C++ (the current main target programming language of this project). +- 📂 [Tools](./Tools) + Project-related tools. +- 📂 [VAF](./VAF) + The actual implementation of the framework. Includes model, Configuration as Code, importers, CLI + tooling, and code generators. ## Getting started -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files +Please check, which role applies to you and follow the provided instructions to get started... -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin https://gitlab.eclipse.org/eclipse/autoapiframework/code.git -git branch -M main -git push -uf origin main -``` +### Application Framework user -## Integrate with your tools +1. Make sure Docker is installed on your machine. Otherwise, please follow the instructions in: + [Install Docker using the apt + repository.](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository) +2. Optional step if you are working in a corporate environment with a SSL proxy server. Modify + the [eclipse.Dockerfile](./Container/eclipse.Dockerfile) in lines 35 ff. and insert your SSL + proxy settings. +3. Start the `build.sh` script in the [Container](./Container) folder to create the image. +4. Check out the different example projects that are provided in [Demo](./Demo). Each demo comes + with a detailed step-by-step tutorial. +5. Start own projects based on the VAF. -- [ ] [Set up project integrations](https://gitlab.eclipse.org/eclipse/autoapiframework/code/-/settings/integrations) +In case of feedback do not hesitate to get back to us. Or, even better, become a contributor +yourself and join us on the development of the Vehicle Application Framework! -## Collaborate with your team +### Project contributor -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) +To make development easier, a devcontainer is also provided for project contributors. It contains +all the necessary dependencies and development tools to contribute to this project. It includes also +all runtime dependencies to use VAF itself in this container. The dockerfile and the corresponding +devcontainer configuration are located in the [.devcontainer](./.devcontainer) directory. -## Test and Deploy +At the bottom of the configuration file are some commented templates to mount your ssh config and +root CA certificates from your host into the container. The latter might be necessary if you are +working in a corporate environment with a SSL proxy server. The +[Dockerfile](./.devcontainer/Dockerfile) itself must also be adapted if an SSL proxy server is +available. To do this, adapt lines 42 ff. according to your requirements. -Use the built-in continuous integration in GitLab. +The project uses `Conan` to manage C++ dependencies. Since there are no prebuilt packages available +in the public Conan center for the used compiler settings, the packages are built as the last step +of the dockerfile. This avoids a long wait when (re-)creating a new container. -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) +>**â„¹ï¸ Note** +>On first start of the devcontainer it will take a few minutes, depending on your machine, to +>build all the Conan dependencies. -*** +#### Building vaf-cli -# Editing this README +The VAF CLI program uses `pdm` as build tool. To install VAF in your container, go to the `./VAF` +directory and run: -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README - -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. +``` bash +pdm install +``` -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. +This will install the Python packages as symlinks to the repository so you don't have to re-install +them every time you make a change. This step creates a virtual environment that should be selected +as the Python environment in VS Code to enable IntelliSense. When working in a terminal window, the +virtual environment must be activated. To do this, execute the following command in the `./VAF` +directory: -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. +``` bash +source .venv/bin/activate +``` -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. +The VAF supports bash completion. To enable it, activate the virtual environment as described +above. Then execute the following commands: -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. +``` bash +mkdir -p ~/.local/share/bash-completion/completions +_VAF_COMPLETE=bash_source vaf > ~/.local/share/bash-completion/completions/vaf.sh +source ~/.local/share/bash-completion/completions/vaf.sh +``` -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. +#### Building vafcpp -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. +The C++ library `vafcpp` uses `Conan` as its build tool. To build an updated package, you can use +the included Rakefile. Run `rake prod:install:vafcpp` in the project root directory. By default, the +version number stored in the [version.txt](version.txt) file is used for the Conan package. This can +be overridden with the following syntax: `rake prod:install:vafcpp[0.6.0]`. -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. +Note that each VAF project lists its dependencies in the `conanfile.py`, which also includes a +reference to a specific version of this package. If you want to test changes with a different +version number, you need to update it accordingly. To update the version number in the template for +new projects, use the rake task `rake prod:patch:project_vafcpp_version[version]` in the project +root directory. -## Contributing -State if you are open to contributions and what your requirements are for accepting them. +>**â„¹ï¸ Hint** +>To list all available rake tasks, run `rake --tasks` in the project root directory. -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. +## Related projects -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. +This project makes use of the following open-source projects: -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. +- [expected by TartanLlama](https://github.com/TartanLlama/expected) available under [CC0 1.0 + Universal License](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) +- [Vector SIL Kit](https://github.com/vectorgrp/sil-kit) available under [MIT + License](https://mit-license.org/) -## License -For open source projects, say how it is licensed. +Other dependencies via Conan include: -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +- [protobuf v5.27.0](https://github.com/protocolbuffers/protobuf/tree/v5.27.0) +- [gtest v1.13.0](https://github.com/google/googletest/tree/v1.13.0) diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..a9ef646 --- /dev/null +++ b/Rakefile @@ -0,0 +1,141 @@ +namespace :dev do + + desc "DEV: Initialize Project" + namespace :init do + task_name = ["install-all", "format", "lint"] + descriptions = ["Installing", "Formatting", "Run Linters in"] + + task_name.each_with_index do |dev_task, index| + desc "DEV: #{descriptions[index]} VAF Python Project" + task dev_task.split("-")[0] do + Dir.chdir("VAF") do + sh "make #{dev_task}" + end + end + end + + desc "DEV: #{descriptions[1]} and #{descriptions[2]} VAF Python Project" + task precommit: %i[format lint] + end + + desc "DEV: Run test suites in Project" + namespace :test do + + namespace :unit do + unit_tests = ["cli-core", "vafarxmltojson", "vafgeneration", "vafjsontoarxml", "vafmodel", "vafpy", "vafvssimport"] + unit_tests.each do |ut| + desc "DEV: Run Unit Test for #{ut} in Project" + task ut do + Dir.chdir("VAF") do + sh "make test-unit-#{ut}" + end + end + end + + desc "DEV: Run ALL Unit Test in Project" + task :all do + Dir.chdir("VAF") do + sh "make test-unit" + end + end + end + + namespace :component do + comp_tests = ["cli"] + comp_tests.each do |ct| + desc "DEV: Run Component Test for #{ct} in Project" + task ct do + Dir.chdir("VAF") do + sh "make test-component-#{ct}" + end + end + end + + desc "DEV: Run ALL Component Test in Project" + task :all do + Dir.chdir("VAF") do + sh "make test-component" + end + end + end + + desc "DEV: Run ALL test suites in Project" + task all: %i[unit:all component:all] + end + + desc "DEV: Rake job for Pipeline" + task pipeline: %i[init:precommit test:all] +end + +namespace :prod do + namespace :patch do + desc 'Patches the vafcpp in project conanfile' + task :project_vafcpp_version, [:version] do |t, args| + if args[:version].nil? + # Retrieve the current vafcpp version installed, we need that version later + # to patch the conanfile.py + vafcpp_version_info = `conan list vafcpp -f json` + vafcpp_version = JSON.parse(vafcpp_version_info)['Local Cache'].keys.first + else + vafcpp_version = "vafcpp/#{args[:version]}" + end + puts "#{vafcpp_version}" + + files_to_patch = ["project/default/{{project_name}}/conanfile.py", "application_module/{{module_dir_name}}/conanfile.py"] + files_to_patch.each do |file| + location = "./VAF/src/vaf/cli_core/bootstrap/templates/#{file}" + conanfile = IO.read(location) + conanfile.gsub!(%r{"vafcpp/.+"}, "\"#{vafcpp_version}\"") + File.open(location, 'w') do |fh| + fh.write(conanfile) + end + end + end + + desc 'Patches the container version in project devcontainer.json' + task :project_dev_container_json, [:version] do |t, args| + unless args[:version].nil? + files_to_patch = ["workspace/{{workspace_name}}/.devcontainer/devcontainer.json.jinja"] + + files_to_patch.each do |file| + location = "./VAF/src/vaf/cli_core/bootstrap/templates/#{file}" + devcontainer = IO.read(location) + devcontainer.gsub!(/devcontainer:latest"/, "devcontainer:#{args[:version]}\"") + File.open(location, 'w') do |fh| + fh.write(devcontainer) + end + end + end + end + end + + namespace :install do + desc 'PROD: Install vaf wheel with pip' + task :vafcli do + path_to_vafinstall = "_vafinstall" + FileUtils.rm_rf(path_to_vafinstall) + FileUtils.mkdir_p(path_to_vafinstall) + + Dir.chdir("VAF") do + sh 'make clean build' + end + wheel = Dir.glob('VAF/dist/*.whl')[0] + cp wheel, path_to_vafinstall + sh 'pip3 install _vafinstall/vaf-*.whl --force-reinstall --break-system-packages' + end + + desc 'PROD: Install vafcpp' + task :vafcpp, [:version] do |t, args| + Dir.chdir('SwLibraries/vaf_core_library') do + conan_cmd = [] + conan_cmd << 'conan create .' + conan_cmd << '--profile:host=test_package/gcc12__x86_64-pc-linux-elf' + conan_cmd << '--profile:build=test_package/gcc12__x86_64-pc-linux-elf' + conan_cmd << "--version #{args[:version]}" unless args[:version].nil? + + #sh (conan_cmd + ['-s build_type=Debug']).join(' ') + sh (conan_cmd + ['-s build_type=Release']).join(' ') + end + end + end +end diff --git a/SwLibraries/README.md b/SwLibraries/README.md new file mode 100644 index 0000000..deb16a9 --- /dev/null +++ b/SwLibraries/README.md @@ -0,0 +1,38 @@ +# Software libraries + +## VAF core library + +The VAF core library (C++) covers static code artifacts on executable-level. +It includes implementations for: +- Data pointer handling +- Asynchronous operation support via future/promise +- Executor +- Logging +- Error handling +- and more... + +More details are provided in the following subsection of the project documentation: [SW library](../Documentation/contents/28_sw_library.md) + +### Conan Package + +First check if an update of the version number is required. If so, update the version number of the +package within the `conanfile.py` + +To create a Conan package from the library, execute the following command: + + conan create . --profile:host=test_package/gcc12__x86_64-pc-linux-elf --profile:build=test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug + conan create . --profile:host=test_package/gcc12__x86_64-pc-linux-elf --profile:build=test_package/gcc12__x86_64-pc-linux-elf -s build_type=Release + +It something incompatible changes regarding the build, i.e., some errors occur while creating the +package, execute the following commands in the given order to narrow down where the package +creation fails: + + conan install . --profile:host=test_package/gcc12__x86_64-pc-linux-elf --profile:build=test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug + + conan build . --profile:host=test_package/gcc12__x86_64-pc-linux-elf --profile:build=test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug + + conan export-pkg . --profile:host=test_package/gcc12__x86_64-pc-linux-elf --profile:build=test_package/gcc12__x86_64-pc-linux-elf -s build_type=Debug + +Choose the right package version for the next command, here version 0.1.0 is used: + + conan test test_package vafcpp/0.1.0 --profile:host=gcc12__x86_64-pc-linux-elf --profile:build=gcc12__x86_64-pc-linux-elf -s build_type=Debug diff --git a/SwLibraries/vaf_core_library/.gitignore b/SwLibraries/vaf_core_library/.gitignore new file mode 100644 index 0000000..490edea --- /dev/null +++ b/SwLibraries/vaf_core_library/.gitignore @@ -0,0 +1 @@ +CMakeUserPresets.json diff --git a/SwLibraries/vaf_core_library/CMakeLists.txt b/SwLibraries/vaf_core_library/CMakeLists.txt new file mode 100644 index 0000000..d311b4d --- /dev/null +++ b/SwLibraries/vaf_core_library/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.25) + +project(vafcpp) + +add_subdirectory(lib) +add_subdirectory(test) diff --git a/SwLibraries/vaf_core_library/cmake/vafcppConfig.cmake b/SwLibraries/vaf_core_library/cmake/vafcppConfig.cmake new file mode 100644 index 0000000..b78b0db --- /dev/null +++ b/SwLibraries/vaf_core_library/cmake/vafcppConfig.cmake @@ -0,0 +1,8 @@ +# vafcppConfig.cmake + +# Load the target export set +include("${CMAKE_CURRENT_LIST_DIR}/vafcppTargets.cmake") + +# Optional: Set variables that point to installed directories +set(vafcpp_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../include") +set(vafcpp_LIBRARIES vafcpp::vaf_core) diff --git a/SwLibraries/vaf_core_library/conanfile.py b/SwLibraries/vaf_core_library/conanfile.py new file mode 100644 index 0000000..503efb0 --- /dev/null +++ b/SwLibraries/vaf_core_library/conanfile.py @@ -0,0 +1,64 @@ +import os + +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.files import load, update_conandata, copy + +from pathlib import Path + + +class VafcppRecipe(ConanFile): + name = "vafcpp" + + # Optional metadata + license = "Vector Informatik GmbH" + author = "christian.marchl@vector.com" + url = "https://gitlab.vi.vector.int/pes/teamprojects/pes-ft-applicationframework" + description = "Vehicle Application Framework" + topics = ("API", "Application Development", "Application Framework", "SDV") + + # Binary configuration + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + + def export(self): + update_conandata(self, {"src_path": Path(__file__).resolve().parent.as_posix()}) + + def source(self): + files_to_copy = ["CMakeLists.txt", "lib/*", "include/*", "test/*", "cmake/*"] + for file in files_to_copy: + copy(self, file, self.conan_data["src_path"], self.source_folder) + + def set_version(self): + self.version = self.version or load(self, "../../version.txt") + + def config_options(self): + if self.settings.os == "Windows": + # del self.options.fPIC + raise ConanException("Windows OS is currently not supported") + + def layout(self): + cmake_layout(self) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + # self.cpp_info.libs = ["vafcpp"] + + # Integrate cmake files packaged with the software stack + self.cpp_info.set_property("cmake_find_mode", "none") + self.cpp_info.builddirs.append(os.path.join("lib", "cmake", "vafcpp")) diff --git a/SwLibraries/vaf_core_library/lib/CMakeLists.txt b/SwLibraries/vaf_core_library/lib/CMakeLists.txt new file mode 100644 index 0000000..5b3826f --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/CMakeLists.txt @@ -0,0 +1,46 @@ +find_package(Threads) + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +set(TARGET vaf_core) +add_library(${TARGET} STATIC) +target_sources( + ${TARGET} + PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include/vaf/receiver_handler_container.h" + "${CMAKE_CURRENT_LIST_DIR}/include/vaf/controller_interface.h" + "${CMAKE_CURRENT_LIST_DIR}/include/vaf/executable_controller_base.h" + "${CMAKE_CURRENT_LIST_DIR}/include/vaf/future.h" + "${CMAKE_CURRENT_LIST_DIR}/include/vaf/result.h" + "${CMAKE_CURRENT_LIST_DIR}/include/vaf/data_ptr.h" + "${CMAKE_CURRENT_LIST_DIR}/src/controller_interface.cpp" + "${CMAKE_CURRENT_LIST_DIR}/src/executable_controller_base.cpp" + "${CMAKE_CURRENT_LIST_DIR}/src/executor.cpp" + "${CMAKE_CURRENT_LIST_DIR}/src/logging.cpp" + "${CMAKE_CURRENT_LIST_DIR}/src/runtime.cpp") + +target_include_directories( + ${TARGET} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" + "$<INSTALL_INTERFACE:include>") + +install( + TARGETS ${TARGET} + EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.h*") + +install( + EXPORT ${PROJECT_NAME}Targets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE vafcpp:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + +install(FILES "${CMAKE_CURRENT_LIST_DIR}/../cmake/${PROJECT_NAME}Config.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) diff --git a/SwLibraries/vaf_core_library/lib/include/tl/expected.h b/SwLibraries/vaf_core_library/lib/include/tl/expected.h new file mode 100644 index 0000000..65b0afb --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/tl/expected.h @@ -0,0 +1,2506 @@ +/// +// expected - An implementation of std::expected with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at http://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// <http://creativecommons.org/publicdomain/zero/1.0/>. +// +// Base commit 41d3e1f +// Changes by Vector Informatik GmbH +// +// Rename or_else() --> InspectError() +// Rename or_else_impl( --> inspect_error_impl( +// Rename and_then( --> AndThen( +// Rename error --> Error +// Rename has_value --> HasValue +// Rename value() --> Value() +// Added static expected<U,Y> FromValue(U &input) +// Added static expected<U,Y> FromValue(U&& input) +// Added constexpr explicit expected(E error) +// +/// + + +#ifndef TL_EXPECTED_HPP +#define TL_EXPECTED_HPP + +#define TL_EXPECTED_VERSION_MAJOR 1 +#define TL_EXPECTED_VERSION_MINOR 1 +#define TL_EXPECTED_VERSION_PATCH 0 + +#include <exception> +#include <functional> +#include <type_traits> +#include <utility> + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_EXPECTED_MSVC2015 +#define TL_EXPECTED_MSVC2015_CONSTEXPR +#else +#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC55 +#endif + +#if !defined(TL_ASSERT) +//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug +#if (TL_CPLUSPLUS > 201103L) && !defined(TL_EXPECTED_GCC49) +#include <cassert> +#define TL_ASSERT(x) assert(x) +#else +#define TL_ASSERT(x) +#endif +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions + +#define TL_EXPECTED_NO_CONSTRR +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor<T> +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign<T> + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible<T> + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template <class T> +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible<T> {}; +#ifdef _GLIBCXX_VECTOR +template <class T, class A> +struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {}; +#endif +} // namespace detail +} // namespace tl +#endif + +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible<T> +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable<T> +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible<T> +#else +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible<T> +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable<T> +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible<T> +#endif + +#ifdef _MSVC_LANG +#define TL_CPLUSPLUS _MSVC_LANG +#else +#define TL_CPLUSPLUS __cplusplus +#endif + +#if TL_CPLUSPLUS > 201103L +#define TL_EXPECTED_CXX14 +#endif + +#ifdef TL_EXPECTED_GCC49 +#define TL_EXPECTED_GCC49_CONSTEXPR +#else +#define TL_EXPECTED_GCC49_CONSTEXPR constexpr +#endif + +#if (TL_CPLUSPLUS == 201103L || defined(TL_EXPECTED_MSVC2015) || \ + defined(TL_EXPECTED_GCC49)) +#define TL_EXPECTED_11_CONSTEXPR +#else +#define TL_EXPECTED_11_CONSTEXPR constexpr +#endif + +namespace tl { +template <class T, class E> class expected; + +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +class monostate {}; + +struct in_place_t { + explicit in_place_t() = default; +}; +static constexpr in_place_t in_place{}; +#endif + +template <class E> class unexpected { +public: + static_assert(!std::is_same<E, void>::value, "E must not be void"); + + unexpected() = delete; + constexpr explicit unexpected(const E &e) : m_val(e) {} + + constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} + + template <class... Args, typename std::enable_if<std::is_constructible< + E, Args &&...>::value>::type * = nullptr> + constexpr explicit unexpected(Args &&...args) + : m_val(std::forward<Args>(args)...) {} + template < + class U, class... Args, + typename std::enable_if<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr> + constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args) + : m_val(l, std::forward<Args>(args)...) {} + + constexpr const E &Value() const & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &Value() & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &&Value() && { return std::move(m_val); } + constexpr const E &&Value() const && { return std::move(m_val); } + +private: + E m_val; +}; + +#ifdef __cpp_deduction_guides +template <class E> unexpected(E) -> unexpected<E>; +#endif + +template <class E> +constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() == rhs.Value(); +} +template <class E> +constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() != rhs.Value(); +} +template <class E> +constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() < rhs.Value(); +} +template <class E> +constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() <= rhs.Value(); +} +template <class E> +constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() > rhs.Value(); +} +template <class E> +constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) { + return lhs.Value() >= rhs.Value(); +} + +template <class E> +unexpected<typename std::decay<E>::type> make_unexpected(E &&e) { + return unexpected<typename std::decay<E>::type>(std::forward<E>(e)); +} + +struct unexpect_t { + unexpect_t() = default; +}; +static constexpr unexpect_t unexpect{}; + +namespace detail { +template <typename E> +[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + throw std::forward<E>(e); +#else + (void)e; +#ifdef _MSC_VER + __assume(0); +#else + __builtin_unreachable(); +#endif +#endif +} + +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template <class T> using remove_const_t = typename std::remove_const<T>::type; +template <class T> +using remove_reference_t = typename std::remove_reference<T>::type; +template <class T> using decay_t = typename std::decay<T>::type; +template <bool E, class T = void> +using enable_if_t = typename std::enable_if<E, T>::type; +template <bool B, class T, class F> +using conditional_t = typename std::conditional<B, T, F>::type; + +// std::conjunction from C++17 +template <class...> struct conjunction : std::true_type {}; +template <class B> struct conjunction<B> : B {}; +template <class B, class... Bs> +struct conjunction<B, Bs...> + : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template <class T> +struct is_pointer_to_non_const_member_func : std::false_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> + : std::true_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &> + : std::true_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> + : std::true_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> + : std::true_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &> + : std::true_type {}; +template <class T, class Ret, class... Args> +struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&> + : std::true_type {}; + +template <class T> struct is_const_or_const_ref : std::false_type {}; +template <class T> struct is_const_or_const_ref<T const &> : std::true_type {}; +template <class T> struct is_const_or_const_ref<T const> : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && + is_const_or_const_ref<Args...>::value)>, +#endif + typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) + -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { + return std::mem_fn(f)(std::forward<Args>(args)...); +} + +template <typename Fn, typename... Args, + typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) + -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { + return std::forward<Fn>(f)(std::forward<Args>(args)...); +} + +// std::invoke_result from C++17 +template <class F, class, class... Us> struct invoke_result_impl; + +template <class F, class... Us> +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...)); +}; + +template <class F, class... Us> +using invoke_result = invoke_result_impl<F, void, Us...>; + +template <class F, class... Us> +using invoke_result_t = typename invoke_result<F, Us...>::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template <class T, class U = T> struct is_swappable : std::true_type {}; + +template <class T, class U = T> struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template <class T> tag swap(T &, T &); +template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template <class, class> std::false_type can_swap(...) noexcept(false); +template <class T, class U, + class = decltype(swap(std::declval<T &>(), std::declval<U &>()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(), + std::declval<U &>()))); + +template <class, class> std::false_type uses_std(...); +template <class T, class U> +std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag> +uses_std(int); + +template <class T> +struct is_std_swap_noexcept + : std::integral_constant<bool, + std::is_nothrow_move_constructible<T>::value && + std::is_nothrow_move_assignable<T>::value> {}; + +template <class T, std::size_t N> +struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; + +template <class T, class U> +struct is_adl_swap_noexcept + : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {}; +} // namespace swap_adl_tests + +template <class T, class U = T> +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value && + (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value || + (std::is_move_assignable<T>::value && + std::is_move_constructible<T>::value))> {}; + +template <class T, std::size_t N> +struct is_swappable<T[N], T[N]> + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value && + (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>( + 0))::value || + is_swappable<T, T>::value)> {}; + +template <class T, class U = T> +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable<T, U>::value && + ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value && + detail::swap_adl_tests::is_std_swap_noexcept<T>::value) || + (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {}; +#endif +#endif + +// Trait for checking if a type is a tl::expected +template <class T> struct is_expected_impl : std::false_type {}; +template <class T, class E> +struct is_expected_impl<expected<T, E>> : std::true_type {}; +template <class T> using is_expected = is_expected_impl<decay_t<T>>; + +template <class T, class E, class U> +using expected_enable_forward_value = detail::enable_if_t< + std::is_constructible<T, U &&>::value && + !std::is_same<detail::decay_t<U>, in_place_t>::value && + !std::is_same<expected<T, E>, detail::decay_t<U>>::value && + !std::is_same<unexpected<E>, detail::decay_t<U>>::value>; + +template <class T, class E, class U, class G, class UR, class GR> +using expected_enable_from_other = detail::enable_if_t< + std::is_constructible<T, UR>::value && + std::is_constructible<E, GR>::value && + !std::is_constructible<T, expected<U, G> &>::value && + !std::is_constructible<T, expected<U, G> &&>::value && + !std::is_constructible<T, const expected<U, G> &>::value && + !std::is_constructible<T, const expected<U, G> &&>::value && + !std::is_convertible<expected<U, G> &, T>::value && + !std::is_convertible<expected<U, G> &&, T>::value && + !std::is_convertible<const expected<U, G> &, T>::value && + !std::is_convertible<const expected<U, G> &&, T>::value>; + +template <class T, class U> +using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>; + +template <class T> +using is_copy_constructible_or_void = + is_void_or<T, std::is_copy_constructible<T>>; + +template <class T> +using is_move_constructible_or_void = + is_void_or<T, std::is_move_constructible<T>>; + +template <class T> +using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>; + +template <class T> +using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>; + +} // namespace detail + +namespace detail { +struct no_init_t {}; +static constexpr no_init_t no_init{}; + +// Implements the storage of the values, and ensures that the destructor is +// trivial if it can be. +// +// This specialization is for where neither `T` or `E` is trivially +// destructible, so the destructors must be called on destruction of the +// `expected` +template <class T, class E, bool = std::is_trivially_destructible<T>::value, + bool = std::is_trivially_destructible<E>::value> +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward<Args>(args)...), m_has_val(true) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, + Args &&...args) + : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } else { + m_unexpect.~unexpected<E>(); + } + } + union { + T m_val; + unexpected<E> m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// This specialization is for when both `T` and `E` are trivially-destructible, +// so the destructor of the `expected` can be trivial. +template <class T, class E> struct expected_storage_base<T, E, true, true> { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward<Args>(args)...), m_has_val(true) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, + Args &&...args) + : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() = default; + union { + T m_val; + unexpected<E> m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// T is trivial, E is not. +template <class T, class E> struct expected_storage_base<T, E, true, false> { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) + : m_no_init(), m_has_val(false) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward<Args>(args)...), m_has_val(true) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, + Args &&...args) + : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected<E>(); + } + } + + union { + T m_val; + unexpected<E> m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// E is trivial, T is not. +template <class T, class E> struct expected_storage_base<T, E, false, true> { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward<Args>(args)...), m_has_val(true) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, + Args &&...args) + : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } + } + union { + T m_val; + unexpected<E> m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is trivially-destructible +template <class E> struct expected_storage_base<void, E, false, true> { + #if __GNUC__ <= 5 + //no constexpr for GCC 4/5 bug + #else + TL_EXPECTED_MSVC2015_CONSTEXPR + #endif + expected_storage_base() : m_has_val(true) {} + + constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_has_val(true) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() = default; + struct dummy {}; + union { + unexpected<E> m_unexpect; + dummy m_val; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is not trivially-destructible +template <class E> struct expected_storage_base<void, E, false, false> { + constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list<U> il, + Args &&...args) + : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected<E>(); + } + } + + union { + unexpected<E> m_unexpect; + char m_dummy; + }; + bool m_has_val; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template <class T, class E> +struct expected_operations_base : expected_storage_base<T, E> { + using expected_storage_base<T, E>::expected_storage_base; + + template <class... Args> void construct(Args &&...args) noexcept { + new (std::addressof(this->m_val)) T(std::forward<Args>(args)...); + this->m_has_val = true; + } + + template <class Rhs> void construct_with(Rhs &&rhs) noexcept { + new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get()); + this->m_has_val = true; + } + + template <class... Args> void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected<E>(std::forward<Args>(args)...); + this->m_has_val = false; + } + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + + // These assign overloads ensure that the most efficient assignment + // implementation is used while maintaining the strong exception guarantee. + // The problematic case is where rhs has a value, but *this does not. + // + // This overload handles the case where we can just copy-construct `T` + // directly into place without throwing. + template <class U = T, + detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected<E>(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + // This overload handles the case where we can attempt to create a copy of + // `T`, then no-throw move it into place if the copy was successful. + template <class U = T, + detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value && + std::is_nothrow_move_constructible<U>::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + T tmp = rhs.get(); + geterr().~unexpected<E>(); + construct(std::move(tmp)); + } else { + assign_common(rhs); + } + } + + // This overload is the worst-case, where we have to move-construct the + // unexpected value into temporary storage, then try to copy the T into place. + // If the construction succeeds, then everything is fine, but if it throws, + // then we move the old unexpected value back into place before rethrowing the + // exception. + template <class U = T, + detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value && + !std::is_nothrow_move_constructible<U>::value> + * = nullptr> + void assign(const expected_operations_base &rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected<E>(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(rhs.get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(rhs.get()); +#endif + } else { + assign_common(rhs); + } + } + + // These overloads do the same as above, but for rvalues + template <class U = T, + detail::enable_if_t<std::is_nothrow_move_constructible<U>::value> + * = nullptr> + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected<E>(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + + template <class U = T, + detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value> + * = nullptr> + void assign(expected_operations_base &&rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected<E>(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(std::move(rhs).get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(std::move(rhs).get()); +#endif + } else { + assign_common(std::move(rhs)); + } + } + +#else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected<E>(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected<E>(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + +#endif + + // The common part of move/copy assigning + template <class Rhs> void assign_common(Rhs &&rhs) { + if (this->m_has_val) { + if (rhs.m_has_val) { + get() = std::forward<Rhs>(rhs).get(); + } else { + destroy_val(); + construct_error(std::forward<Rhs>(rhs).geterr()); + } + } else { + if (!rhs.m_has_val) { + geterr() = std::forward<Rhs>(rhs).geterr(); + } + } + } + + bool HasValue() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } + constexpr const T &get() const & { return this->m_val; } + TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_val); } +#endif + + TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected<E> &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template <class E> +struct expected_operations_base<void, E> : expected_storage_base<void, E> { + using expected_storage_base<void, E>::expected_storage_base; + + template <class... Args> void construct() noexcept { this->m_has_val = true; } + + // This function doesn't use its argument, but needs it so that code in + // levels above this can work independently of whether T is void + template <class Rhs> void construct_with(Rhs &&) noexcept { + this->m_has_val = true; + } + + template <class... Args> void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected<E>(std::forward<Args>(args)...); + this->m_has_val = false; + } + + template <class Rhs> void assign(Rhs &&rhs) noexcept { + if (!this->m_has_val) { + if (rhs.m_has_val) { + geterr().~unexpected<E>(); + construct(); + } else { + geterr() = std::forward<Rhs>(rhs).geterr(); + } + } else { + if (!rhs.m_has_val) { + construct_error(std::forward<Rhs>(rhs).geterr()); + } + } + } + + bool HasValue() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected<E> &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { + // no-op + } +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T and E are trivially copy constructible +template <class T, class E, + bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>:: + value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value, + bool = (is_copy_constructible_or_void<T>::value && + std::is_copy_constructible<E>::value)> +struct expected_copy_base : expected_operations_base<T, E> { + using expected_operations_base<T, E>::expected_operations_base; +}; + +// This specialization is for when T or E are non-trivially copy constructible +template <class T, class E> +struct expected_copy_base<T, E, false, true> : expected_operations_base<T, E> { + using expected_operations_base<T, E>::expected_operations_base; + + expected_copy_base() = default; + expected_copy_base(const expected_copy_base &rhs) + : expected_operations_base<T, E>(no_init) { + if (rhs.HasValue()) { + this->construct_with(rhs); + } else { + this->construct_error(rhs.geterr()); + } + } + + expected_copy_base(expected_copy_base &&rhs) = default; + expected_copy_base &operator=(const expected_copy_base &rhs) = default; + expected_copy_base &operator=(expected_copy_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_EXPECTED_GCC49 +template <class T, class E, + bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value + &&std::is_trivially_move_constructible<E>::value> +struct expected_move_base : expected_copy_base<T, E> { + using expected_copy_base<T, E>::expected_copy_base; +}; +#else +template <class T, class E, bool = false> struct expected_move_base; +#endif +template <class T, class E> +struct expected_move_base<T, E, false> : expected_copy_base<T, E> { + using expected_copy_base<T, E>::expected_copy_base; + + expected_move_base() = default; + expected_move_base(const expected_move_base &rhs) = default; + + expected_move_base(expected_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible<T>::value) + : expected_copy_base<T, E>(no_init) { + if (rhs.HasValue()) { + this->construct_with(std::move(rhs)); + } else { + this->construct_error(std::move(rhs.geterr())); + } + } + expected_move_base &operator=(const expected_move_base &rhs) = default; + expected_move_base &operator=(expected_move_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template <class T, class E, + bool = is_void_or< + T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T), + TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T), + TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value, + bool = (is_copy_constructible_or_void<T>::value && + std::is_copy_constructible<E>::value && + is_copy_assignable_or_void<T>::value && + std::is_copy_assignable<E>::value)> +struct expected_copy_assign_base : expected_move_base<T, E> { + using expected_move_base<T, E>::expected_move_base; +}; + +template <class T, class E> +struct expected_copy_assign_base<T, E, false, true> : expected_move_base<T, E> { + using expected_move_base<T, E>::expected_move_base; + + expected_copy_assign_base() = default; + expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; + + expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; + expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + expected_copy_assign_base & + operator=(expected_copy_assign_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_EXPECTED_GCC49 +template <class T, class E, + bool = + is_void_or<T, conjunction<std::is_trivially_destructible<T>, + std::is_trivially_move_constructible<T>, + std::is_trivially_move_assignable<T>>>:: + value &&std::is_trivially_destructible<E>::value + &&std::is_trivially_move_constructible<E>::value + &&std::is_trivially_move_assignable<E>::value> +struct expected_move_assign_base : expected_copy_assign_base<T, E> { + using expected_copy_assign_base<T, E>::expected_copy_assign_base; +}; +#else +template <class T, class E, bool = false> struct expected_move_assign_base; +#endif + +template <class T, class E> +struct expected_move_assign_base<T, E, false> + : expected_copy_assign_base<T, E> { + using expected_copy_assign_base<T, E>::expected_copy_assign_base; + + expected_move_assign_base() = default; + expected_move_assign_base(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base(expected_move_assign_base &&rhs) = default; + + expected_move_assign_base & + operator=(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base & + operator=(expected_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible<T>::value + &&std::is_nothrow_move_assignable<T>::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// expected_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template <class T, class E, + bool EnableCopy = (is_copy_constructible_or_void<T>::value && + std::is_copy_constructible<E>::value), + bool EnableMove = (is_move_constructible_or_void<T>::value && + std::is_move_constructible<E>::value)> +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template <class T, class E> +struct expected_delete_ctor_base<T, E, true, false> { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template <class T, class E> +struct expected_delete_ctor_base<T, E, false, true> { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template <class T, class E> +struct expected_delete_ctor_base<T, E, false, false> { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +// expected_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T and E are copy/move constructible + +// assignable +template <class T, class E, + bool EnableCopy = (is_copy_constructible_or_void<T>::value && + std::is_copy_constructible<E>::value && + is_copy_assignable_or_void<T>::value && + std::is_copy_assignable<E>::value), + bool EnableMove = (is_move_constructible_or_void<T>::value && + std::is_move_constructible<E>::value && + is_move_assignable_or_void<T>::value && + std::is_move_assignable<E>::value)> +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template <class T, class E> +struct expected_delete_assign_base<T, E, true, false> { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +template <class T, class E> +struct expected_delete_assign_base<T, E, false, true> { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template <class T, class E> +struct expected_delete_assign_base<T, E, false, false> { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +// This is needed to be able to construct the expected_default_ctor_base which +// follows, while still conditionally deleting the default constructor. +struct default_constructor_tag { + explicit constexpr default_constructor_tag() = default; +}; + +// expected_default_ctor_base will ensure that expected has a deleted default +// constructor if T is not default constructible. +// This specialization is for when T is default constructible +template <class T, class E, + bool Enable = + std::is_default_constructible<T>::value || std::is_void<T>::value> +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = default; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; + +// This specialization is for when T is not default constructible +template <class T, class E> struct expected_default_ctor_base<T, E, false> { + constexpr expected_default_ctor_base() noexcept = delete; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; +} // namespace detail + +template <class E> class bad_expected_access : public std::exception { +public: + explicit bad_expected_access(E e) : m_val(std::move(e)) {} + + virtual const char *what() const noexcept override { + return "Bad expected access"; + } + + const E &Error() const & { return m_val; } + E &Error() & { return m_val; } + const E &&Error() const && { return std::move(m_val); } + E &&Error() && { return std::move(m_val); } + +private: + E m_val; +}; + +/// An `expected<T, E>` object is an object that contains the storage for +/// another object and manages the lifetime of this contained object `T`. +/// Alternatively it could contain the storage for another unexpected object +/// `E`. The contained object may not be initialized after the expected object +/// has been initialized, and may not be destroyed before the expected object +/// has been destroyed. The initialization state of the contained object is +/// tracked by the expected object. +template <class T, class E> +class expected : private detail::expected_move_assign_base<T, E>, + private detail::expected_delete_ctor_base<T, E>, + private detail::expected_delete_assign_base<T, E>, + private detail::expected_default_ctor_base<T, E> { + static_assert(!std::is_reference<T>::value, "T must not be a reference"); + static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value, + "T must not be in_place_t"); + static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value, + "T must not be unexpect_t"); + static_assert( + !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value, + "T must not be unexpected<E>"); + static_assert(!std::is_reference<E>::value, "E must not be a reference"); + + T *valptr() { return std::addressof(this->m_val); } + const T *valptr() const { return std::addressof(this->m_val); } + unexpected<E> *errptr() { return std::addressof(this->m_unexpect); } + const unexpected<E> *errptr() const { + return std::addressof(this->m_unexpect); + } + + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &val() { + return this->m_val; + } + TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; } + + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + constexpr const U &val() const { + return this->m_val; + } + constexpr const unexpected<E> &err() const { return this->m_unexpect; } + + using impl_base = detail::expected_move_assign_base<T, E>; + using ctor_base = detail::expected_default_ctor_base<T, E>; + +public: + typedef T value_type; + typedef E error_type; + typedef unexpected<E> unexpected_type; + + template <class U = T, class Y = E, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + static expected<U,Y> FromValue(U &input) { + return expected<U,Y>(input); + } + + template <class U = T, class Y = E, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + static expected<U,Y> FromValue(U&& input) { + return expected<U,Y>(std::move(input)); + } + +constexpr explicit expected(E error) : impl_base(unexpect, error), ctor_base(detail::default_constructor_tag{}) {} + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template <class F> TL_EXPECTED_11_CONSTEXPR auto AndThen(F &&f) & { + return and_then_impl(*this, std::forward<F>(f)); + } + template <class F> TL_EXPECTED_11_CONSTEXPR auto AndThen(F &&f) && { + return and_then_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> constexpr auto AndThen(F &&f) const & { + return and_then_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> constexpr auto AndThen(F &&f) const && { + return and_then_impl(std::move(*this), std::forward<F>(f)); + } +#endif + +#else + template <class F> + TL_EXPECTED_11_CONSTEXPR auto + AndThen(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(), + std::forward<F>(f))) { + return and_then_impl(*this, std::forward<F>(f)); + } + template <class F> + TL_EXPECTED_11_CONSTEXPR auto + AndThen(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(), + std::forward<F>(f))) { + return and_then_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> + constexpr auto AndThen(F &&f) const & -> decltype(and_then_impl( + std::declval<expected const &>(), std::forward<F>(f))) { + return and_then_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> + constexpr auto AndThen(F &&f) const && -> decltype(and_then_impl( + std::declval<expected const &&>(), std::forward<F>(f))) { + return and_then_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> constexpr auto map(F &&f) const & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> constexpr auto map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval<expected &>(), std::declval<F &&>())) + map(F &&f) & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(), + std::declval<F &&>())) + map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> + constexpr decltype(expected_map_impl(std::declval<const expected &>(), + std::declval<F &&>())) + map(F &&f) const & { + return expected_map_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> + constexpr decltype(expected_map_impl(std::declval<const expected &&>(), + std::declval<F &&>())) + map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> constexpr auto transform(F &&f) const & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> constexpr auto transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval<expected &>(), std::declval<F &&>())) + transform(F &&f) & { + return expected_map_impl(*this, std::forward<F>(f)); + } + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(), + std::declval<F &&>())) + transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> + constexpr decltype(expected_map_impl(std::declval<const expected &>(), + std::declval<F &&>())) + transform(F &&f) const & { + return expected_map_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> + constexpr decltype(expected_map_impl(std::declval<const expected &&>(), + std::declval<F &&>())) + transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> constexpr auto map_error(F &&f) const & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> constexpr auto map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } +#else + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(), + std::declval<F &&>())) + map_error(F &&f) & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(), + std::declval<F &&>())) + map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> + constexpr decltype(map_error_impl(std::declval<const expected &>(), + std::declval<F &&>())) + map_error(F &&f) const & { + return map_error_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> + constexpr decltype(map_error_impl(std::declval<const expected &&>(), + std::declval<F &&>())) + map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> constexpr auto transform_error(F &&f) const & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> constexpr auto transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } +#else + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(), + std::declval<F &&>())) + transform_error(F &&f) & { + return map_error_impl(*this, std::forward<F>(f)); + } + template <class F> + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(), + std::declval<F &&>())) + transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } + template <class F> + constexpr decltype(map_error_impl(std::declval<const expected &>(), + std::declval<F &&>())) + transform_error(F &&f) const & { + return map_error_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> + constexpr decltype(map_error_impl(std::declval<const expected &&>(), + std::declval<F &&>())) + transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + template <class F> expected TL_EXPECTED_11_CONSTEXPR InspectError(F &&f) & { + return inspect_error_impl(*this, std::forward<F>(f)); + } + + template <class F> expected TL_EXPECTED_11_CONSTEXPR InspectError(F &&f) && { + return inspect_error_impl(std::move(*this), std::forward<F>(f)); + } + + template <class F> expected constexpr InspectError(F &&f) const & { + return inspect_error_impl(*this, std::forward<F>(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template <class F> expected constexpr InspectError(F &&f) const && { + return inspect_error_impl(std::move(*this), std::forward<F>(f)); + } +#endif + constexpr expected() = default; + constexpr expected(const expected &rhs) = default; + constexpr expected(expected &&rhs) = default; + expected &operator=(const expected &rhs) = default; + expected &operator=(expected &&rhs) = default; + + template <class... Args, + detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = + nullptr> + constexpr expected(in_place_t, Args &&...args) + : impl_base(in_place, std::forward<Args>(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args) + : impl_base(in_place, il, std::forward<Args>(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template <class G = E, + detail::enable_if_t<std::is_constructible<E, const G &>::value> * = + nullptr, + detail::enable_if_t<!std::is_convertible<const G &, E>::value> * = + nullptr> + explicit constexpr expected(const unexpected<G> &e) + : impl_base(unexpect, e.Value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t<std::is_constructible<E, const G &>::value> * = + nullptr, + detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr> + constexpr expected(unexpected<G> const &e) + : impl_base(unexpect, e.Value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr, + detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr> + explicit constexpr expected(unexpected<G> &&e) noexcept( + std::is_nothrow_constructible<E, G &&>::value) + : impl_base(unexpect, std::move(e.Value())), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr, + detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr> + constexpr expected(unexpected<G> &&e) noexcept( + std::is_nothrow_constructible<E, G &&>::value) + : impl_base(unexpect, std::move(e.Value())), + ctor_base(detail::default_constructor_tag{}) {} + + template <class... Args, + detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = + nullptr> + constexpr explicit expected(unexpect_t, Args &&...args) + : impl_base(unexpect, std::forward<Args>(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template <class U, class... Args, + detail::enable_if_t<std::is_constructible< + E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + constexpr explicit expected(unexpect_t, std::initializer_list<U> il, + Args &&...args) + : impl_base(unexpect, il, std::forward<Args>(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template <class U, class G, + detail::enable_if_t<!(std::is_convertible<U const &, T>::value && + std::is_convertible<G const &, E>::value)> * = + nullptr, + detail::expected_enable_from_other<T, E, U, G, const U &, const G &> + * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.HasValue()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.Error()); + } + } + + template <class U, class G, + detail::enable_if_t<(std::is_convertible<U const &, T>::value && + std::is_convertible<G const &, E>::value)> * = + nullptr, + detail::expected_enable_from_other<T, E, U, G, const U &, const G &> + * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.HasValue()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.Error()); + } + } + + template < + class U, class G, + detail::enable_if_t<!(std::is_convertible<U &&, T>::value && + std::is_convertible<G &&, E>::value)> * = nullptr, + detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.HasValue()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.Error())); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible<U &&, T>::value && + std::is_convertible<G &&, E>::value)> * = nullptr, + detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.HasValue()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.Error())); + } + } + + template < + class U = T, + detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr, + detail::expected_enable_forward_value<T, E, U> * = nullptr> + explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward<U>(v)) {} + + template < + class U = T, + detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr, + detail::expected_enable_forward_value<T, E, U> * = nullptr> + TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward<U>(v)) {} + + template < + class U = T, class G = T, + detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * = + nullptr, + detail::enable_if_t<!std::is_void<G>::value> * = nullptr, + detail::enable_if_t< + (!std::is_same<expected<T, E>, detail::decay_t<U>>::value && + !detail::conjunction<std::is_scalar<T>, + std::is_same<T, detail::decay_t<U>>>::value && + std::is_constructible<T, U>::value && + std::is_assignable<G &, U>::value && + std::is_nothrow_move_constructible<E>::value)> * = nullptr> + expected &operator=(U &&v) { + if (HasValue()) { + val() = std::forward<U>(v); + } else { + err().~unexpected<E>(); + ::new (valptr()) T(std::forward<U>(v)); + this->m_has_val = true; + } + + return *this; + } + + template < + class U = T, class G = T, + detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * = + nullptr, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr, + detail::enable_if_t< + (!std::is_same<expected<T, E>, detail::decay_t<U>>::value && + !detail::conjunction<std::is_scalar<T>, + std::is_same<T, detail::decay_t<U>>>::value && + std::is_constructible<T, U>::value && + std::is_assignable<G &, U>::value && + std::is_nothrow_move_constructible<E>::value)> * = nullptr> + expected &operator=(U &&v) { + if (HasValue()) { + val() = std::forward<U>(v); + } else { + auto tmp = std::move(err()); + err().~unexpected<E>(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward<U>(v)); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward<U>(v)); + this->m_has_val = true; +#endif + } + + return *this; + } + + template <class G = E, + detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value && + std::is_assignable<G &, G>::value> * = nullptr> + expected &operator=(const unexpected<G> &rhs) { + if (!HasValue()) { + err() = rhs; + } else { + this->destroy_val(); + ::new (errptr()) unexpected<E>(rhs); + this->m_has_val = false; + } + + return *this; + } + + template <class G = E, + detail::enable_if_t<std::is_nothrow_move_constructible<G>::value && + std::is_move_assignable<G>::value> * = nullptr> + expected &operator=(unexpected<G> &&rhs) noexcept { + if (!HasValue()) { + err() = std::move(rhs); + } else { + this->destroy_val(); + ::new (errptr()) unexpected<E>(std::move(rhs)); + this->m_has_val = false; + } + + return *this; + } + + template <class... Args, detail::enable_if_t<std::is_nothrow_constructible< + T, Args &&...>::value> * = nullptr> + void emplace(Args &&...args) { + if (HasValue()) { + val().~T(); + } else { + err().~unexpected<E>(); + this->m_has_val = true; + } + ::new (valptr()) T(std::forward<Args>(args)...); + } + + template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible< + T, Args &&...>::value> * = nullptr> + void emplace(Args &&...args) { + if (HasValue()) { + val().~T(); + ::new (valptr()) T(std::forward<Args>(args)...); + } else { + auto tmp = std::move(err()); + err().~unexpected<E>(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward<Args>(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward<Args>(args)...); + this->m_has_val = true; +#endif + } + } + + template <class U, class... Args, + detail::enable_if_t<std::is_nothrow_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list<U> il, Args &&...args) { + if (HasValue()) { + T t(il, std::forward<Args>(args)...); + val() = std::move(t); + } else { + err().~unexpected<E>(); + ::new (valptr()) T(il, std::forward<Args>(args)...); + this->m_has_val = true; + } + } + + template <class U, class... Args, + detail::enable_if_t<!std::is_nothrow_constructible< + T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list<U> il, Args &&...args) { + if (HasValue()) { + T t(il, std::forward<Args>(args)...); + val() = std::move(t); + } else { + auto tmp = std::move(err()); + err().~unexpected<E>(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(il, std::forward<Args>(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(il, std::forward<Args>(args)...); + this->m_has_val = true; +#endif + } + } + +private: + using t_is_void = std::true_type; + using t_is_not_void = std::false_type; + using t_is_nothrow_move_constructible = std::true_type; + using move_constructing_t_can_throw = std::false_type; + using e_is_nothrow_move_constructible = std::true_type; + using move_constructing_e_can_throw = std::false_type; + + void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept { + // swapping void is a no-op + } + + void swap_where_both_have_value(expected &rhs, t_is_not_void) { + using std::swap; + swap(val(), rhs.val()); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept( + std::is_nothrow_move_constructible<E>::value) { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_not_void) { + swap_where_only_one_has_value_and_t_is_not_void( + rhs, typename std::is_nothrow_move_constructible<T>::type{}, + typename std::is_nothrow_move_constructible<E>::type{}); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + e_is_nothrow_move_constructible) noexcept { + auto temp = std::move(val()); + val().~T(); + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + move_constructing_e_can_throw) { + auto temp = std::move(val()); + val().~T(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + val() = std::move(temp); + throw; + } +#else + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, move_constructing_t_can_throw, + e_is_nothrow_move_constructible) { + auto temp = std::move(rhs.err()); + rhs.err().~unexpected_type(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + rhs.err() = std::move(temp); + throw; + } +#else + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + +public: + template <class OT = T, class OE = E> + detail::enable_if_t<detail::is_swappable<OT>::value && + detail::is_swappable<OE>::value && + (std::is_nothrow_move_constructible<OT>::value || + std::is_nothrow_move_constructible<OE>::value)> + swap(expected &rhs) noexcept( + std::is_nothrow_move_constructible<T>::value + &&detail::is_nothrow_swappable<T>::value + &&std::is_nothrow_move_constructible<E>::value + &&detail::is_nothrow_swappable<E>::value) { + if (HasValue() && rhs.HasValue()) { + swap_where_both_have_value(rhs, typename std::is_void<T>::type{}); + } else if (!HasValue() && rhs.HasValue()) { + rhs.swap(*this); + } else if (HasValue()) { + swap_where_only_one_HasValue(rhs, typename std::is_void<T>::type{}); + } else { + using std::swap; + swap(err(), rhs.err()); + } + } + + constexpr const T *operator->() const { + TL_ASSERT(HasValue()); + return valptr(); + } + TL_EXPECTED_11_CONSTEXPR T *operator->() { + TL_ASSERT(HasValue()); + return valptr(); + } + + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + constexpr const U &operator*() const & { + TL_ASSERT(HasValue()); + return val(); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &operator*() & { + TL_ASSERT(HasValue()); + return val(); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + constexpr const U &&operator*() const && { + TL_ASSERT(HasValue()); + return std::move(val()); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&operator*() && { + TL_ASSERT(HasValue()); + return std::move(val()); + } + + constexpr bool HasValue() const noexcept { return this->m_has_val; } + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &Value() const & { + if (!HasValue()) + detail::throw_exception(bad_expected_access<E>(err().Value())); + return val(); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &Value() & { + if (!HasValue()) + detail::throw_exception(bad_expected_access<E>(err().Value())); + return val(); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &&Value() const && { + if (!HasValue()) + detail::throw_exception(bad_expected_access<E>(std::move(err()).Value())); + return std::move(val()); + } + template <class U = T, + detail::enable_if_t<!std::is_void<U>::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&Value() && { + if (!HasValue()) + detail::throw_exception(bad_expected_access<E>(std::move(err()).Value())); + return std::move(val()); + } + + constexpr const E &Error() const & { + TL_ASSERT(!HasValue()); + return err().Value(); + } + TL_EXPECTED_11_CONSTEXPR E &Error() & { + TL_ASSERT(!HasValue()); + return err().Value(); + } + constexpr const E &&Error() const && { + TL_ASSERT(!HasValue()); + return std::move(err().Value()); + } + TL_EXPECTED_11_CONSTEXPR E &&Error() && { + TL_ASSERT(!HasValue()); + return std::move(err().Value()); + } + + template <class U> constexpr T value_or(U &&v) const & { + static_assert(std::is_copy_constructible<T>::value && + std::is_convertible<U &&, T>::value, + "T must be copy-constructible and convertible to from U&&"); + return bool(*this) ? **this : static_cast<T>(std::forward<U>(v)); + } + template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { + static_assert(std::is_move_constructible<T>::value && + std::is_convertible<U &&, T>::value, + "T must be move-constructible and convertible to from U&&"); + return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v)); + } +}; + +namespace detail { +template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type; +template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type; +template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>; + +#ifdef TL_EXPECTED_CXX14 +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + + return exp.HasValue() + ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)) + : Ret(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + + return exp.HasValue() ? detail::invoke(std::forward<F>(f)) + : Ret(unexpect, std::forward<Exp>(exp).Error()); +} +#else +template <class> struct TC; +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>())), + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr> +auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + + return exp.HasValue() + ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)) + : Ret(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>())), + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr> +constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + + return exp.HasValue() ? detail::invoke(std::forward<F>(f)) + : Ret(unexpect, std::forward<Exp>(exp).Error()); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t<Exp, detail::decay_t<Ret>>; + return exp.HasValue() ? result(detail::invoke(std::forward<F>(f), + *std::forward<Exp>(exp))) + : result(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected<void, err_t<Exp>>; + if (exp.HasValue()) { + detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)); + return result(); + } + + return result(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t<Exp, detail::decay_t<Ret>>; + return exp.HasValue() ? result(detail::invoke(std::forward<F>(f))) + : result(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected<void, err_t<Exp>>; + if (exp.HasValue()) { + detail::invoke(std::forward<F>(f)); + return result(); + } + + return result(unexpect, std::forward<Exp>(exp).Error()); +} +#else +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t<Exp, detail::decay_t<Ret>> { + using result = ret_t<Exp, detail::decay_t<Ret>>; + + return exp.HasValue() ? result(detail::invoke(std::forward<F>(f), + *std::forward<Exp>(exp))) + : result(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + *std::declval<Exp>())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { + if (exp.HasValue()) { + detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)); + return {}; + } + + return unexpected<err_t<Exp>>(std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t<Exp, detail::decay_t<Ret>> { + using result = ret_t<Exp, detail::decay_t<Ret>>; + + return exp.HasValue() ? result(detail::invoke(std::forward<F>(f))) + : result(unexpect, std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { + if (exp.HasValue()) { + detail::invoke(std::forward<F>(f)); + return {}; + } + + return unexpected<err_t<Exp>>(std::forward<Exp>(exp).Error()); +} +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; + return exp.HasValue() + ? result(*std::forward<Exp>(exp)) + : result(unexpect, detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error())); +} +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected<exp_t<Exp>, monostate>; + if (exp.HasValue()) { + return result(*std::forward<Exp>(exp)); + } + + detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).Error()); + return result(unexpect, monostate{}); +} +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; + return exp.HasValue() + ? result() + : result(unexpect, detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error())); +} +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected<exp_t<Exp>, monostate>; + if (exp.HasValue()) { + return result(); + } + + detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).Error()); + return result(unexpect, monostate{}); +} +#else +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected<exp_t<Exp>, detail::decay_t<Ret>> { + using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; + + return exp.HasValue() + ? result(*std::forward<Exp>(exp)) + : result(unexpect, detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error())); +} + +template <class Exp, class F, + detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { + using result = expected<exp_t<Exp>, monostate>; + if (exp.HasValue()) { + return result(*std::forward<Exp>(exp)); + } + + detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).Error()); + return result(unexpect, monostate{}); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected<exp_t<Exp>, detail::decay_t<Ret>> { + using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; + + return exp.HasValue() + ? result() + : result(unexpect, detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error())); +} + +template <class Exp, class F, + detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { + using result = expected<exp_t<Exp>, monostate>; + if (exp.HasValue()) { + return result(); + } + + detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).Error()); + return result(unexpect, monostate{}); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +constexpr auto inspect_error_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + return exp.HasValue() ? std::forward<Exp>(exp) + : detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +detail::decay_t<Exp> inspect_error_impl(Exp &&exp, F &&f) { + return exp.HasValue() ? std::forward<Exp>(exp) + : (detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error()), + std::forward<Exp>(exp)); +} +#else +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> +auto inspect_error_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected<Ret>::value, "F must return an expected"); + return exp.HasValue() ? std::forward<Exp>(exp) + : detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error()); +} + +template <class Exp, class F, + class Ret = decltype(detail::invoke(std::declval<F>(), + std::declval<Exp>().Error())), + detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> +detail::decay_t<Exp> inspect_error_impl(Exp &&exp, F &&f) { + return exp.HasValue() ? std::forward<Exp>(exp) + : (detail::invoke(std::forward<F>(f), + std::forward<Exp>(exp).Error()), + std::forward<Exp>(exp)); +} +#endif +} // namespace detail + +template <class T, class E, class U, class F> +constexpr bool operator==(const expected<T, E> &lhs, + const expected<U, F> &rhs) { + return (lhs.HasValue() != rhs.HasValue()) + ? false + : (!lhs.HasValue() ? lhs.Error() == rhs.Error() : *lhs == *rhs); +} +template <class T, class E, class U, class F> +constexpr bool operator!=(const expected<T, E> &lhs, + const expected<U, F> &rhs) { + return (lhs.HasValue() != rhs.HasValue()) + ? true + : (!lhs.HasValue() ? lhs.Error() != rhs.Error() : *lhs != *rhs); +} +template <class E, class F> +constexpr bool operator==(const expected<void, E> &lhs, + const expected<void, F> &rhs) { + return (lhs.HasValue() != rhs.HasValue()) + ? false + : (!lhs.HasValue() ? lhs.Error() == rhs.Error() : true); +} +template <class E, class F> +constexpr bool operator!=(const expected<void, E> &lhs, + const expected<void, F> &rhs) { + return (lhs.HasValue() != rhs.HasValue()) + ? true + : (!lhs.HasValue() ? lhs.Error() != rhs.Error() : false); +} + +template <class T, class E, class U> +constexpr bool operator==(const expected<T, E> &x, const U &v) { + return x.HasValue() ? *x == v : false; +} +template <class T, class E, class U> +constexpr bool operator==(const U &v, const expected<T, E> &x) { + return x.HasValue() ? *x == v : false; +} +template <class T, class E, class U> +constexpr bool operator!=(const expected<T, E> &x, const U &v) { + return x.HasValue() ? *x != v : true; +} +template <class T, class E, class U> +constexpr bool operator!=(const U &v, const expected<T, E> &x) { + return x.HasValue() ? *x != v : true; +} + +template <class T, class E> +constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) { + return x.HasValue() ? false : x.Error() == e.Value(); +} +template <class T, class E> +constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) { + return x.HasValue() ? false : x.Error() == e.Value(); +} +template <class T, class E> +constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) { + return x.HasValue() ? true : x.Error() != e.Value(); +} +template <class T, class E> +constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) { + return x.HasValue() ? true : x.Error() != e.Value(); +} + +template <class T, class E, + detail::enable_if_t<(std::is_void<T>::value || + std::is_move_constructible<T>::value) && + detail::is_swappable<T>::value && + std::is_move_constructible<E>::value && + detail::is_swappable<E>::value> * = nullptr> +void swap(expected<T, E> &lhs, + expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} +} // namespace tl + +#endif + diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/controller_interface.h b/SwLibraries/vaf_core_library/lib/include/vaf/controller_interface.h new file mode 100644 index 0000000..e64eb31 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/controller_interface.h @@ -0,0 +1,66 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file controller_interface.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_CONTROLLER_INTERFACE_H +#define INCLUDE_VAF_CONTROLLER_INTERFACE_H + +#include "vaf/error_domain.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/executor.h" +#include "vaf/result.h" + +namespace vaf { + +class ControlInterface { + public: + ControlInterface(std::string name, std::vector<std::string> dependencies, ExecutableControllerInterface& executable_controller_interface, vaf::Executor& executor); + ControlInterface(const ControlInterface&) = delete; + ControlInterface(ControlInterface&&) = delete; + ControlInterface& operator=(const ControlInterface&) = delete; + ControlInterface& operator=(ControlInterface&&) = delete; + + virtual ~ControlInterface() = default; + + virtual vaf::Result<void> Init() noexcept = 0; + virtual void Start() noexcept = 0; + virtual void Stop() noexcept = 0; + virtual void DeInit() noexcept = 0; + + void ReportOperational(); + void ReportError(ErrorCode error_code, std::string msg, bool critical = false); + + virtual void OnError(const vaf::Error& error); + + std::string GetName(); + std::vector<std::string> GetDependencies(); + + void StartExecutor(); + void StopExecutor(); + + virtual void StartEventHandlerForModule(const std::string& module_name); + virtual void StopEventHandlerForModule(const std::string& module_name); + +protected: + std::string name_; + std::vector<std::string> dependencies_; + ExecutableControllerInterface& executable_controller_interface_; + vaf::ModuleExecutor executor_; +}; + +} // namespace vaf + +#endif // INCLUDE_VAF_CONTROLLER_INTERFACE_H diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/data_ptr.h b/SwLibraries/vaf_core_library/lib/include/vaf/data_ptr.h new file mode 100644 index 0000000..937c933 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/data_ptr.h @@ -0,0 +1,155 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file controller_interface.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_DATA_PTR_H +#define INCLUDE_VAF_DATA_PTR_H + +#include "vaf/logging.h" + +#include <memory> +#include <type_traits> + +namespace vaf { + + namespace internal { + template<typename T> + class DataPtrHelper; + } // namespace internal + + template<typename T> + class DataPtr { + friend internal::DataPtrHelper<T>; + + private: + enum class Contains { + Empty, RawPtr + }; + + struct Container { + std::unique_ptr<T> raw_ptr_; + }; + + public: + DataPtr() : contains_{Contains::Empty}, container_{std::make_shared<Container>()} {} + + DataPtr (const DataPtr& other) { + this->container_= other.container_; + this->contains_= other.contains_; + } + + DataPtr (DataPtr&& other) { + this->container_= std::move(other.container_); + this->contains_= std::move(other.contains_); + } + + DataPtr(std::unique_ptr<T> &&ptr) : contains_{Contains::RawPtr}, container_{std::make_shared<Container>()} { + container_->raw_ptr_ = std::move(ptr); + } + + T &operator*() noexcept { return *(this->operator->()); } + + T *operator->() const noexcept { + if (contains_ == Contains::RawPtr) { + return container_->raw_ptr_.get(); + } + vaf::LoggerSingleton::getInstance()->default_logger_.LogFatal() << "DataPtr is empty"; + std::abort(); + } + + DataPtr& operator=(const DataPtr& other) { + this->container_= other.container_; + this->contains_= other.contains_; + return *this; + } + + DataPtr& operator=(DataPtr&& other) { + this->container_= std::move(other.container_); + this->contains_= std::move(other.contains_); + return *this; + } + + explicit operator bool() const { return contains_ != Contains::Empty; } + + private: + Contains contains_; + std::shared_ptr<Container> container_; + }; + + template<typename T> + class ConstDataPtr { + private: + enum class Contains { + Empty, SamplePtr, RawPtr + }; + + struct Container { + std::unique_ptr<T> raw_ptr_{}; + }; + + public: + ConstDataPtr() : contains_{Contains::Empty}, container_{std::make_shared<Container>()} {} + + ConstDataPtr (const ConstDataPtr& other) { + this->container_= other.container_; + this->contains_= other.contains_; + } + + ConstDataPtr (ConstDataPtr&& other) { + this->container_= std::move(other.container_); + this->contains_= std::move(other.contains_); + } + + ConstDataPtr(std::unique_ptr<T> &&ptr) : contains_{Contains::RawPtr}, + container_{std::make_shared<Container>()} { + container_->raw_ptr_ = std::move(ptr); + } + + const T &operator*() const noexcept { return *(this->operator->()); } + + const T *operator->() const noexcept { + if (contains_ == Contains::RawPtr) { + return container_->raw_ptr_.get(); + } + vaf::LoggerSingleton::getInstance()->default_logger_.LogFatal() << "DataPtr is empty"; + std::abort(); + } + + ConstDataPtr& operator=(const ConstDataPtr& other) { + this->container_= other.container_; + this->contains_= other.contains_; + return *this; + } + + ConstDataPtr& operator=(ConstDataPtr&& other) { + this->container_= std::move(other.container_); + this->contains_= std::move(other.contains_); + return *this; + } + + explicit operator bool() const { return contains_ != Contains::Empty; } + + std::unique_ptr<T> getRawPtr() { return std::move(container_->raw_ptr_); }; + + private: + Contains contains_; + std::shared_ptr<Container> container_; + }; + +} // namespace vaf + +#endif // INCLUDE_VAF_DATA_PTR_H + diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/error_domain.h b/SwLibraries/vaf_core_library/lib/include/vaf/error_domain.h new file mode 100644 index 0000000..3dcddd0 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/error_domain.h @@ -0,0 +1,62 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file error_domain.h + * brief + * + *********************************************************************************************************************/ +#ifndef VAF_ERROR_DOMAIN_H_ +#define VAF_ERROR_DOMAIN_H_ + +#include <string> + +namespace vaf { + + enum class ErrorCode { + kDefaultErrorCode = 1, + kServiceNotFound, + kServiceModelMissMatch, + kServiceLost, + kNoSampleAvailable, + kServiceNotRunning, + kNoOperationHandlerRegistered + }; + + class Error { + public: + Error(ErrorCode error_code, std::string message) : error_code_{error_code}, message_{message} {} + + const std::string Message() const noexcept { + return std::string{std::to_string(static_cast<int>(error_code_)) + ": " + message_}; + } + + const std::string UserMessage() const noexcept { + return message_; + } + + Error(const Error &) = default; + Error(Error &&) = default; + + Error &operator=(const Error &) = default; + Error &operator=(Error &&) = default; + + private: + ErrorCode error_code_; + std::string message_; + + }; + + +} // namespace vaf + +#endif // VAF_ERROR_DOMAIN_H_ diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h b/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h new file mode 100644 index 0000000..1e37b14 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_base.h @@ -0,0 +1,105 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file executable_controller_base.h + * brief + * + *********************************************************************************************************************/ +#ifndef VAF_EXECUTABLE_CONTROLLER_BASE_H_ +#define VAF_EXECUTABLE_CONTROLLER_BASE_H_ + +/*!******************************************************************************************************************** + * INCLUDES + *********************************************************************************************************************/ +#include <atomic> +#include <thread> +#include <vector> + +#include "vaf/controller_interface.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/logging.h" +#include "vaf/module_states.h" +#include "vaf/runtime.h" +#include "vaf/user_controller_interface.h" + +namespace vaf { + +class ExecutableControllerBase : public vaf::ExecutableControllerInterface { + public: + ExecutableControllerBase(); + virtual ~ExecutableControllerBase() = default; + + ExecutableControllerBase(const ExecutableControllerBase&) = delete; + ExecutableControllerBase(ExecutableControllerBase&&) = delete; + ExecutableControllerBase& operator=(const ExecutableControllerBase&) = delete; + ExecutableControllerBase& operator=(ExecutableControllerBase&&) = delete; + + void Run(bool use_exec_mgr = false) noexcept; + void Run(int argc, char* argv[], bool use_exec_mgr = false) noexcept; + void InitiateShutdown() noexcept; + + void RegisterModule(std::shared_ptr<vaf::ControlInterface> module); + + void ReportOperationalOfModule(std::string name) override; + void ReportErrorOfModule(vaf::Error error, std::string name, bool critical) override; + + protected: + virtual void DoInitialize(); + virtual void DoStart(); + virtual void DoShutdown(); + void WaitForShutdown(); + bool IsShutdownRequested(); + + private: + void ChangeStateOfModule(std::string name, ModuleStates state); + void StartModules(); + void StartEventHandlersForModule(const std::string& module_name, const std::vector<std::string>& dependencies); + void StopEventHandlersForModule(const std::string& module_name, const std::vector<std::string>& dependencies); + void CheckStartingModules(); + + class ModuleContainer { + public: + ModuleContainer(std::string name, std::shared_ptr<vaf::ControlInterface> module, std::vector<std::string> dependencies) + : name_{std::move(name)}, module_{std::move(module)}, dependencies_{std::move(dependencies)} { + } + std::string name_; + std::shared_ptr<vaf::ControlInterface> module_; + std::vector<std::string> dependencies_; + ModuleStates state_{ModuleStates::kNotInitialized}; + uint64_t starting_counter_{0}; + }; + + void SetupExecutionManager(); + void ReportStateToExecutionManager(bool is_running); + + /*! + * \brief Entry point of the thread receiving signals from the execution manager. + */ + void InitializeSignalHandling() noexcept; + void SignalHandlerThread(); + + int signal_handling_init_; + vaf::Runtime runtime_; + std::atomic_bool shutdown_requested_; + bool use_execution_mgr_{false}; + + vaf::Logger& logger_; + std::vector<ModuleContainer> modules_; + std::unique_ptr<UserControllerInterface> user_controller_; + + std::thread signal_handler_thread_; +}; + +} // namespace vaf + +#endif // VAF_EXECUTABLE_CONTROLLER_BASE_H_ diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_interface.h b/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_interface.h new file mode 100644 index 0000000..2fe205b --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/executable_controller_interface.h @@ -0,0 +1,41 @@ + +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file executable_controller_interface.h + * brief + * + *********************************************************************************************************************/ +#ifndef VAF_EXECUTABLE_CONTROLLER_INTERFACE_H_ +#define VAF_EXECUTABLE_CONTROLLER_INTERFACE_H_ + +/*!******************************************************************************************************************** + * INCLUDES + *********************************************************************************************************************/ + +#include <string> +#include "vaf/error_domain.h" +#include "vaf/module_states.h" + +namespace vaf { + +class ExecutableControllerInterface { +public: + virtual ~ExecutableControllerInterface() = default; + virtual void ReportOperationalOfModule(std::string name) = 0; + virtual void ReportErrorOfModule(vaf::Error error, std::string name, bool critical) = 0; +}; + +} // namespace vaf + +#endif // VAF_EXECUTABLE_CONTROLLER_INTERFACE_H_ diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/executor.h b/SwLibraries/vaf_core_library/lib/include/vaf/executor.h new file mode 100644 index 0000000..73bbdf5 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/executor.h @@ -0,0 +1,198 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file controller_interface.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_EXECUTOR_H +#define INCLUDE_VAF_EXECUTOR_H + +#include "vaf/logging.h" + +#include <atomic> +#include <chrono> +#include <functional> +#include <memory> +#include <string> +#include <thread> +#include <utility> +#include <vector> + +namespace vaf { + + class RunnableHandle { + public: + RunnableHandle(std::string name, uint64_t period, std::function<void(void)> runnable, const std::string &owner, + const std::vector<std::string> &run_after, uint64_t offset, std::chrono::nanoseconds budget); + + const std::string &Name() const; + + bool IsActive() const; + + void Execute() const; + + uint64_t Period() const; + + void Start(); + + void Stop(); + + const std::string &Owner(); + + const std::vector<std::string> &RunAfter(); + + uint64_t Offset() const; + + std::chrono::nanoseconds Budget() const; + + private: + std::string name_; + bool is_active_{false}; + uint64_t period_; + std::function<void(void)> runnable_; + std::string owner_; + std::vector<std::string> run_after_; + uint64_t offset_; + std::chrono::nanoseconds budget_; + }; + + class Executor { + public: + explicit Executor(std::chrono::milliseconds running_period); + + ~Executor(); + + Executor(const Executor &) = delete; + + Executor(Executor &&) = delete; + + Executor &operator=(const Executor &) = delete; + + Executor &operator=(Executor &&) = delete; + + template<typename T> + std::shared_ptr<RunnableHandle> RunPeriodic(std::chrono::milliseconds period, + T &&runnable, + const std::string &owner, + const std::vector<std::string> &run_after, + uint64_t offset = 0, + std::chrono::nanoseconds budget = std::chrono::nanoseconds{0}) { + + return RunPeriodic("", period, std::move(runnable), owner, run_after, {}, offset, budget); + } + + template<typename T> + std::shared_ptr<RunnableHandle> RunPeriodic(const std::string &name, + std::chrono::milliseconds period, + T &&runnable, + const std::string &owner, + const std::vector<std::string> &run_after, + const std::vector<std::string> &run_after_runnables = {}, + uint64_t offset = 0, + std::chrono::nanoseconds budget = std::chrono::nanoseconds{0}) { + auto check_can_run = [this, &run_after, &run_after_runnables]( + std::vector<std::shared_ptr<RunnableHandle>>::iterator current_position) { + auto pos{std::next(current_position)}; + bool can_run{true}; + for (; pos != runnables_.end(); ++pos) { + if (std::any_of(run_after.begin(), run_after.end(), [&pos](const std::string &run_after_element) { + return pos->get()->Owner() == run_after_element; + })) { + can_run = false; + break; + } + if (current_position->get()->Owner() == pos->get()->Owner()) { + if (std::any_of(run_after_runnables.begin(), run_after_runnables.end(), + [&pos](const std::string &run_after_element) { + return pos->get()->Name() == run_after_element; + })) { + can_run = false; + break; + } + } + } + + return can_run; + }; + + auto search_pos{runnables_.begin()}; + for (; search_pos != runnables_.end(); ++search_pos) { + if (check_can_run(search_pos)) { + break; + } + } + + // TODO(virmlj) implement run_after_runnables + + auto insert_pos = runnables_.insert(search_pos, + std::make_unique<RunnableHandle>(name, period / running_period_, + std::forward<T>(runnable), owner, + run_after, offset, budget)); + return *insert_pos; + } + + private: + void ExecutorThread(); + + void ExecuteRunnable(RunnableHandle &runnable); + + std::chrono::milliseconds running_period_; + std::vector<std::shared_ptr<RunnableHandle>> runnables_{}; + std::atomic<bool> exit_requested_{false}; + std::thread thread_; + vaf::Logger &logger_; + }; + + class ModuleExecutor { + public: + ModuleExecutor(Executor &executor, std::string name, std::vector<std::string> dependencies); + + template<typename T> + void RunPeriodic(std::chrono::milliseconds period, T &&runnable, uint64_t offset = 0, + std::chrono::nanoseconds budget = std::chrono::nanoseconds{0}) { + handles_.emplace_back( + executor_.RunPeriodic(period, std::move(runnable), name_, dependencies_, offset, budget)); + + if (started_) { + handles_.back()->Start(); + } + } + + template<typename T> + void RunPeriodic(const std::string &name, std::chrono::milliseconds period, T &&runnable, + std::vector<std::string> runnable_dependencies = {}, uint64_t offset = 0, + std::chrono::nanoseconds budget = std::chrono::nanoseconds{0}) { + handles_.emplace_back(executor_.RunPeriodic(name, period, std::move(runnable), name_, dependencies_, + std::move(runnable_dependencies), offset, budget)); + + if (started_) { + handles_.back()->Start(); + } + } + + void Start(); + + void Stop(); + + private: + Executor &executor_; + std::vector<std::shared_ptr<RunnableHandle>> handles_; + bool started_; + std::string name_; + std::vector<std::string> dependencies_; + }; + +} // namespace vaf + +#endif // INCLUDE_VAF_EXECUTOR_H \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/future.h b/SwLibraries/vaf_core_library/lib/include/vaf/future.h new file mode 100644 index 0000000..67bf6dc --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/future.h @@ -0,0 +1,101 @@ +#ifndef VAF_FUTURE_H_ +#define VAF_FUTURE_H_ + +#include "vaf/logging.h" +#include "vaf/result.h" +#include <future> + + +namespace vaf { + + template<typename T, typename E = vaf::Error> + class Future { + public: + Future() : future_{} {} + Future(std::future<vaf::Result<T, E>>&& future) : future_{std::move(future)} {} + + Future(Future&& future) : future_{std::move(future.future_)}{} + Future(const Future& other ) = delete; + + Future& operator=( Future&& other ) noexcept { + if (this != &other) + future_ = std::move(other.future_); + return *this; + } + Future& operator=( const Future& other ) = delete; + + bool valid() const noexcept { + return future_.valid(); + } + + void wait() const { + future_.wait(); + } + + template< class Rep, class Period > + std::future_status wait_for( const std::chrono::duration<Rep,Period>& timeout_duration ) const { + return future_.wait_for(timeout_duration); + } + + template< class Clock, class Duration > + std::future_status wait_until( const std::chrono::time_point<Clock,Duration>& timeout_time ) const { + return wait_until(timeout_time); + } + + vaf::Result<T, E> GetResult() { + return future_.get(); + } + + T get() { + vaf::Result<T, E> res{GetResult()}; + if (!res.HasValue()) { + vaf::LoggerSingleton::getInstance()->default_logger_.LogFatal() << "Future result has no value!"; + std::abort(); + } + return std::move(res).Value(); + } + + bool is_ready() const noexcept { + if (this->valid()) + return future_.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready; + return false; + } + + private: + std::future<vaf::Result<T, E>> future_; + }; + + template<typename T, typename E = vaf::Error> + class Promise : protected std::promise<vaf::Result<T, E>> { + public: + void SetError(E error_code) { + std::promise<vaf::Result<T, E>>::set_value(vaf::Result<T, E>{error_code}); + } + template <class U = T, class Y = E, + std::enable_if_t<!std::is_void<U>::value, int> = 0> + void set_value(U value) { + std::promise<vaf::Result<T, E>>::set_value(vaf::Result<U, Y>{value}); + } + template <class U = T, class Y = E, + std::enable_if_t<std::is_void<U>::value, int> = 0> + void set_value() { + std::promise<vaf::Result<T, E>>::set_value(vaf::Result<U, Y>{}); + } + + vaf::Future<T,E> get_future() { + return std::move(vaf::Future<T,E>(std::promise<vaf::Result<T, E>>::get_future())); + } + }; + + + template<typename T> + bool is_future_ready(vaf::Future<T> const &f, uint32_t timeout_ms = 0) { + if (f.valid()) + return f.wait_for(std::chrono::milliseconds(timeout_ms)) == std::future_status::ready; + return false; + } +} // namespace vaf + +#endif // VAF_FUTURE_H_ + + diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/internal/data_ptr_helper.h b/SwLibraries/vaf_core_library/lib/include/vaf/internal/data_ptr_helper.h new file mode 100644 index 0000000..3638409 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/internal/data_ptr_helper.h @@ -0,0 +1,41 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file data_ptr_helper.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_DATA_PTR_HELPER_H +#define INCLUDE_VAF_DATA_PTR_HELPER_H + +#include "vaf/data_ptr.h" + +namespace vaf { + namespace internal { + + template<typename T> + class DataPtrHelper { + public: + DataPtrHelper() = delete; + + DataPtrHelper(const DataPtrHelper &) = delete; + + DataPtrHelper &operator=(const DataPtrHelper &) = delete; + + static std::unique_ptr<T> getRawPtr(::vaf::DataPtr<T> &ptr) { return std::move(ptr.container_->raw_ptr_); }; + }; + + } // namespace internal +} // namespace vaf + +#endif // INCLUDE_VAF_DATA_PTR_H \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/logging.h b/SwLibraries/vaf_core_library/lib/include/vaf/logging.h new file mode 100644 index 0000000..da87fbc --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/logging.h @@ -0,0 +1,211 @@ +#ifndef VAF_LOGGING_H_ +#define VAF_LOGGING_H_ + +#include <iostream> +#include <mutex> +#include <list> + +namespace vaf { + class LoggerSingleton; + + class Logger { + public: + ~Logger() { + if (previous_line_streamed) { + std::cout << std::endl; + } + std::cout << std::flush; + } + + auto LogFatal() -> Logger & { + current_log_level_ = FATAL; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + + auto LogError() -> Logger & { + current_log_level_ = ERROR; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + auto LogWarn() -> Logger & { + current_log_level_ = WARN; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + auto LogInfo() -> Logger & { + current_log_level_ = INFO; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + auto LogDebug() -> Logger & { + current_log_level_ = DEBUG; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + auto LogVerbose() -> Logger & { + current_log_level_ = VERBOSE; + log_start_message = true; + if (previous_line_streamed) { + std::cout << std::endl; + } + return *this; + } + + auto operator<<(const char *s) noexcept -> Logger & { + if (current_log_level_ <= aimed_log_level_) { + previous_line_streamed = true; + if (log_start_message) { + std::cout << "[" << ctx_id_ << ": " << ctx_description_ << "] "; + log_start_message = false; + } + std::cout << s; + } + return *this; + } + + auto operator<<(int i) noexcept -> Logger & { + if (current_log_level_ <= aimed_log_level_) { + previous_line_streamed = true; + if (log_start_message) { + std::cout << "[" << ctx_id_ << ": " << ctx_description_ << "] "; + log_start_message = false; + } + std::cout << i; + } + return *this; + } + + friend class LoggerSingleton; + + Logger(Logger &&logger_) { + this->log_start_message = logger_.log_start_message; + this->previous_line_streamed = logger_.previous_line_streamed; + this->current_log_level_ = logger_.current_log_level_; + this->ctx_description_ = logger_.ctx_description_; + this->ctx_id_ = logger_.ctx_id_; + this->aimed_log_level_ = logger_.aimed_log_level_; + } + + private: + + enum LogLevel { + OFF = 0, + FATAL = 1, + ERROR = 2, + WARN = 3, + INFO = 4, + DEBUG = 5, + VERBOSE = 6 + }; + + Logger(const char *ctx_id, const char *ctx_description, LogLevel aimed_log_level) : ctx_id_{ctx_id}, + ctx_description_{ + ctx_description}, + aimed_log_level_{ + aimed_log_level} {} + + Logger() = delete; + + Logger(const Logger &) = delete; + + Logger &operator=(const Logger &) = delete; + + const char *ctx_id_; + const char *ctx_description_; + LogLevel aimed_log_level_; + LogLevel current_log_level_ = DEBUG; + bool log_start_message = false; + bool previous_line_streamed = false; + }; + + class LoggerSingleton { + private: + LoggerSingleton() : log_level_{Logger::LogLevel::FATAL}, + default_logger_{CreateLogger("DL", "DefaultLogger")} {} + + LoggerSingleton(const LoggerSingleton &) = delete; + + LoggerSingleton &operator=(const LoggerSingleton &) = delete; + + static std::mutex mtx; // Mutex for thread safety + static LoggerSingleton *instance; + + std::list<Logger> loggers_{}; + + Logger::LogLevel log_level_; + public: + static LoggerSingleton *getInstance() { + // Acquire lock before checking instance + std::lock_guard<std::mutex> lock(mtx); // automatically releases lock + if (instance == nullptr) { + instance = new LoggerSingleton(); // Create the instance only once + } + return instance; + } + + Logger &CreateLogger(const char *ctx_id, const char *ctx_description) { + loggers_.push_back(std::move(Logger{ctx_id, ctx_description, log_level_})); + return loggers_.back(); + } + + void SetLogLevelOff() { + log_level_ = Logger::LogLevel::OFF; + }; + + void SetLogLevelFatal() { + log_level_ = Logger::LogLevel::FATAL; + }; + + void SetLogLevelError() { + log_level_ = Logger::LogLevel::ERROR; + }; + + void SetLogLevelWarn() { + log_level_ = Logger::LogLevel::WARN; + }; + + void SetLogLevelInfo() { + log_level_ = Logger::LogLevel::INFO; + }; + + void SetLogLevelDebug() { + log_level_ = Logger::LogLevel::DEBUG; + }; + + void SetLogLevelVerbose() { + log_level_ = Logger::LogLevel::VERBOSE; + }; + + void CleanLoggers() { + loggers_.clear(); + } + + Logger &default_logger_; + }; + + Logger &CreateLogger(const char *ctx_id, const char *ctx_description); + +} // namespace vaf + +#endif // VAF_LOGGING_H_ \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/module_states.h b/SwLibraries/vaf_core_library/lib/include/vaf/module_states.h new file mode 100644 index 0000000..cdb1a5a --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/module_states.h @@ -0,0 +1,46 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file module_states.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_MODULE_STATES_H +#define INCLUDE_VAF_MODULE_STATES_H + +#include <string> + +namespace vaf { + +enum class ModuleStates { + kNotInitialized, + kNotOperational, + kStarting, + kOperational, + kShutdown +}; + +inline std::string ModuleStateToString(ModuleStates state) { + switch (state) { + case ModuleStates::kNotInitialized: return "kNotInitialized"; + case ModuleStates::kNotOperational: return "kNotOperational"; + case ModuleStates::kStarting: return "kStarting"; + case ModuleStates::kOperational: return "kOperational"; + case ModuleStates::kShutdown: return "kShutdown"; + } + return "Unknow state"; +} + +} // namespace vaf + +#endif // INCLUDE_VAF_MODULE_STATES_H \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/receiver_handler_container.h b/SwLibraries/vaf_core_library/lib/include/vaf/receiver_handler_container.h new file mode 100644 index 0000000..766e6e1 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/receiver_handler_container.h @@ -0,0 +1,39 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file receiver_handler_container.h + * brief + * + *********************************************************************************************************************/ +#ifndef INCLUDE_VAF_RECEIVER_HANDLER_CONTAINER_H +#define INCLUDE_VAF_RECEIVER_HANDLER_CONTAINER_H + +#include <string> + +namespace vaf { +template<typename T> + +class ReceiverHandlerContainer { +public: + ReceiverHandlerContainer(std::string owner, T&& handler) + : owner_{std::move(owner)}, handler_{std::move(handler)}, is_active_{false} { + } + + std::string owner_; + T handler_; + bool is_active_; +}; + +} // namespace vaf + +#endif // INCLUDE_VAF_RECEIVER_HANDLER_CONTAINER_H \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/result.h b/SwLibraries/vaf_core_library/lib/include/vaf/result.h new file mode 100644 index 0000000..3f2744b --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/result.h @@ -0,0 +1,14 @@ +#ifndef VAF_RESULT_H_ +#define VAF_RESULT_H_ + +#include "vaf/error_domain.h" +#include "tl/expected.h" + +namespace vaf { + + template<typename T, typename E = vaf::Error> + using Result = tl::expected<T, E>; + +} // namespace vaf + +#endif // VAF_RESULT_H_ \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/runtime.h b/SwLibraries/vaf_core_library/lib/include/vaf/runtime.h new file mode 100644 index 0000000..a135d40 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/runtime.h @@ -0,0 +1,18 @@ +#ifndef INCLUDE_VAF_RUNTIME_H_ +#define INCLUDE_VAF_RUNTIME_H_ + +namespace vaf { + class Runtime { + public: + Runtime(); + ~Runtime(); + + Runtime(const Runtime&) = delete; + Runtime(Runtime&&) = delete; + Runtime& operator=(const Runtime&) = delete; + Runtime& operator=(Runtime&&) = delete; + }; + +} // namespace vaf + +#endif // INCLUDE_VAF_RUNTIME_H_ \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/include/vaf/user_controller_interface.h b/SwLibraries/vaf_core_library/lib/include/vaf/user_controller_interface.h new file mode 100644 index 0000000..93a1d5f --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/include/vaf/user_controller_interface.h @@ -0,0 +1,27 @@ +#ifndef INCLUDE_VAF_USER_CONTROLLER_H_ +#define INCLUDE_VAF_USER_CONTROLLER_H_ + +#include <memory> +#include "vaf/error_domain.h" + +namespace vaf { + +class UserControllerInterface { +public: + virtual ~UserControllerInterface() = default; + + virtual void PreInitialize() = 0; + virtual void PostInitialize() = 0; + virtual void PreStart() = 0; + virtual void PostStart() = 0; + virtual void PreShutdown() = 0; + virtual void PostShutdown() = 0; + + virtual void OnError(vaf::Error error, std::string name, bool critical) = 0; +}; + +} // namespace vaf + +extern std::unique_ptr<vaf::UserControllerInterface> CreateUserController(); + +#endif // INCLUDE_VAF_USER_CONTROLLER_H_ \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/src/controller_interface.cpp b/SwLibraries/vaf_core_library/lib/src/controller_interface.cpp new file mode 100644 index 0000000..b45de66 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/src/controller_interface.cpp @@ -0,0 +1,53 @@ +#include "vaf/controller_interface.h" +#include <iostream> +#include "vaf/error_domain.h" + +namespace vaf { + +ControlInterface::ControlInterface(std::string name, std::vector<std::string> dependencies, ExecutableControllerInterface& executable_controller_interface, vaf::Executor& executor) + : name_{std::move(name)}, + dependencies_{std::move(dependencies)}, + executable_controller_interface_{executable_controller_interface}, + executor_{vaf::ModuleExecutor{executor, name_, dependencies_}} { +} + +void ControlInterface::ReportOperational() { + executable_controller_interface_.ReportOperationalOfModule(name_); +} + +void ControlInterface::ReportError(ErrorCode error_code, std::string msg, bool critical) { + std::cout << "ReportError of module " << name_ << " (msg: " << msg << ")\n"; + Error error{error_code, msg.c_str()}; + executable_controller_interface_.ReportErrorOfModule(std::move(error), name_, critical); +} + +void ControlInterface::OnError(const vaf::Error& error) { + static_cast<void>(error); + ReportError(ErrorCode::kDefaultErrorCode, "Unhandled error", true); +} + +std::string ControlInterface::GetName() { + return name_; +} + +std::vector<std::string> ControlInterface::GetDependencies() { + return dependencies_; +} + +void ControlInterface::StartExecutor() { + executor_.Start(); +} + +void ControlInterface::StopExecutor() { + executor_.Stop(); +} + +void ControlInterface::StartEventHandlerForModule(const std::string& module_name) { + static_cast<void>(module_name); +}; + +void ControlInterface::StopEventHandlerForModule(const std::string& module_name) { + static_cast<void>(module_name); +}; + +} // namespace vaf diff --git a/SwLibraries/vaf_core_library/lib/src/executable_controller_base.cpp b/SwLibraries/vaf_core_library/lib/src/executable_controller_base.cpp new file mode 100644 index 0000000..bad3635 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/src/executable_controller_base.cpp @@ -0,0 +1,313 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * + * Copyright (c) 2018 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! file executable_controller_base.cpp + * brief + * + *********************************************************************************************************************/ + +#include "vaf/executable_controller_base.h" +#include <algorithm> +#include <csignal> +#include <iostream> +#include <memory> +#include <thread> +#include <utility> +#include "vaf/controller_interface.h" +#include "vaf/module_states.h" +#include "vaf/user_controller_interface.h" + +namespace vaf { + + ExecutableControllerBase::ExecutableControllerBase() + : signal_handling_init_{[this]() { + InitializeSignalHandling(); + return 1; + }()}, // InitializeSignalHandling must be called before the runtime is created + runtime_{}, + shutdown_requested_{false}, + logger_{vaf::CreateLogger("ECB", "ExecutableControllerBase")}, + modules_{}, + user_controller_{CreateUserController()}, + signal_handler_thread_{} { + } + + void ExecutableControllerBase::Run(bool use_exec_mgr) noexcept { Run(0, nullptr, use_exec_mgr); } + + void ExecutableControllerBase::Run(int /*argc*/, char ** /*argv*/, bool use_exec_mgr) noexcept { + + use_execution_mgr_ = use_exec_mgr; + + InitializeSignalHandling(); + + user_controller_->PreInitialize(); + DoInitialize(); + user_controller_->PostInitialize(); + user_controller_->PreStart(); + DoStart(); + user_controller_->PostStart(); + + while (!IsShutdownRequested()) { + std::this_thread::sleep_for(std::chrono::milliseconds{100}); // TODO(virmlj) magic number + StartModules(); + CheckStartingModules(); + } + + user_controller_->PreShutdown(); + DoShutdown(); + user_controller_->PostShutdown(); + } + + void ExecutableControllerBase::InitiateShutdown() noexcept { shutdown_requested_ = true; } + + void ExecutableControllerBase::RegisterModule(std::shared_ptr<vaf::ControlInterface> module) { + modules_.emplace_back(module->GetName(), std::move(module), module->GetDependencies()); + } + + void ExecutableControllerBase::ReportOperationalOfModule(std::string name) { + ChangeStateOfModule(name, ModuleStates::kOperational); + } + + void ExecutableControllerBase::ReportErrorOfModule(vaf::Error error, std::string name, bool critical) { + user_controller_->OnError(error, name, critical); + if (critical) { + ChangeStateOfModule(name, ModuleStates::kNotOperational); + } + + for (ModuleContainer &module: modules_) { + if (std::find(module.dependencies_.begin(), module.dependencies_.end(), name) != + module.dependencies_.end()) { + module.module_->OnError(error); + } + } + } + + void ExecutableControllerBase::ChangeStateOfModule(std::string name, ModuleStates state) { + std::cout << "ExecutableControllerBase::ChangeStateOfModule: name " << name << " state: " + << ModuleStateToString(state) << std::endl; + + auto module_pos = std::find_if(modules_.begin(), modules_.end(), [&name](ModuleContainer &m) { + return m.name_ == name; + }); + + if (module_pos == modules_.end()) { + std::cerr << "ExecutableControllerBase::ChangeStateOfModule: Unknown module: " << name << std::endl; + std::abort(); + } + + ModuleStates current_state{module_pos->state_}; + module_pos->state_ = state; + + switch (state) { + case ModuleStates::kNotInitialized: + std::cerr << "ExecutableControllerBase: Invalid state transition for module " << name << " from " + << ModuleStateToString(current_state) << " to kNotInitialized\n"; + std::abort(); + break; + case ModuleStates::kNotOperational: + if (current_state == ModuleStates::kNotInitialized) { + module_pos->module_->Init(); + } else { + StopEventHandlersForModule(module_pos->name_, module_pos->dependencies_); + module_pos->module_->StopExecutor(); + module_pos->module_->Stop(); + } + break; + case ModuleStates::kStarting: + module_pos->starting_counter_ = 0; + module_pos->module_->Start(); + module_pos->module_->StartExecutor(); + break; + case ModuleStates::kOperational: + StartEventHandlersForModule(module_pos->name_, module_pos->dependencies_); + break; + case ModuleStates::kShutdown: + module_pos->module_->DeInit(); + break; + } + } + + void ExecutableControllerBase::StartModules() { + auto canStart = [this](ModuleContainer &module) { + return std::all_of(module.dependencies_.begin(), module.dependencies_.end(), + [this](const std::string &dependency) { + for (size_t i = 0; i < modules_.size(); ++i) { + if (modules_[i].name_ == dependency) { + if (modules_[i].state_ == ModuleStates::kOperational) { + return true; + } + break; + } + } + return false; + }); + }; + + for (ModuleContainer &module: modules_) { + if (module.state_ == ModuleStates::kNotOperational) { + if (canStart(module)) { + ChangeStateOfModule(module.name_, ModuleStates::kStarting); + } + } + } + } + + void ExecutableControllerBase::StartEventHandlersForModule(const std::string &module_name, + const std::vector<std::string> &dependencies) { + for (const std::string &dependency: dependencies) { + auto dependency_pos{ + std::find_if(modules_.begin(), modules_.end(), [&dependency](ModuleContainer &module) { + return module.name_ == dependency; + })}; + + dependency_pos->module_->StartEventHandlerForModule(module_name); + } + } + + void ExecutableControllerBase::StopEventHandlersForModule(const std::string &module_name, + const std::vector<std::string> &dependencies) { + for (const std::string &dependency: dependencies) { + auto dependency_pos{ + std::find_if(modules_.begin(), modules_.end(), [&dependency](ModuleContainer &module) { + return module.name_ == dependency; + })}; + + dependency_pos->module_->StopEventHandlerForModule(module_name); + } + } + + void ExecutableControllerBase::CheckStartingModules() { + for (ModuleContainer &module: modules_) { + if (module.state_ == ModuleStates::kStarting) { + module.starting_counter_ += 1; + if (module.starting_counter_ > 20) { // TODO(virmlj) magic number + std::cout << "Module " << module.name_ << " violated its startup time limit\n"; + ChangeStateOfModule(module.name_, ModuleStates::kNotOperational); + } + } + } + } + + void ExecutableControllerBase::DoInitialize() { + SetupExecutionManager(); + signal_handler_thread_ = std::thread{&ExecutableControllerBase::SignalHandlerThread, this}; + + for (ModuleContainer &module: modules_) { + ChangeStateOfModule(module.name_, ModuleStates::kNotOperational); + } + } + + void ExecutableControllerBase::DoStart() { + for (ModuleContainer &module: modules_) { + if (module.dependencies_.empty()) { + ChangeStateOfModule(module.name_, ModuleStates::kStarting); + } + } + } + + void ExecutableControllerBase::DoShutdown() { + for (auto iterator = modules_.rbegin(); iterator != modules_.rend(); ++iterator) { + ChangeStateOfModule(iterator->name_, ModuleStates::kNotOperational); + } + for (auto iterator = modules_.rbegin(); iterator != modules_.rend(); ++iterator) { + ChangeStateOfModule(iterator->name_, ModuleStates::kShutdown); + } + ReportStateToExecutionManager(false); + signal_handler_thread_.join(); + } + + void ExecutableControllerBase::InitializeSignalHandling() noexcept { + bool success{true}; + sigset_t signals; + + // Block all signals except the SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV + // signals because blocking them will lead to undefined behavior. Their + // default handling shall not be changed (dependent on underlying POSIX + // environment, usually process is killed and a dump file is written). Signal + // mask will be inherited by subsequent threads. + + success = success && (0 == sigfillset(&signals)); + success = success && (0 == sigdelset(&signals, SIGABRT)); + success = success && (0 == sigdelset(&signals, SIGBUS)); + success = success && (0 == sigdelset(&signals, SIGFPE)); + success = success && (0 == sigdelset(&signals, SIGILL)); + success = success && (0 == sigdelset(&signals, SIGSEGV)); + success = success && (0 == pthread_sigmask(SIG_SETMASK, &signals, nullptr)); + + if (!success) { + logger_.LogFatal() << "InitializeSignalHandling failed."; + std::abort(); + } + } + + void ExecutableControllerBase::SignalHandlerThread() { + sigset_t signal_set; + + if (0 != sigemptyset(&signal_set)) { + logger_.LogFatal() << "Could not empty signal set."; + std::abort(); + } + + if (0 != sigaddset(&signal_set, SIGTERM)) { + logger_.LogFatal() << "Cannot add signal to signalset: SIGTERM"; + std::abort(); + } + + if (0 != sigaddset(&signal_set, SIGINT)) { + logger_.LogFatal() << "Cannot add signal to signalset: SIGINT"; + std::abort(); + } + + // Loop until SIGTERM or SIGINT signal received + int sig{-1}; + + do { + if (0 != sigwait(&signal_set, &sig)) { + logger_.LogFatal() << "Called sigwait() with invalid signalset."; + std::abort(); + } + logger_.LogInfo() << "Received signal: " << sig << "."; + + if ((sig == SIGTERM) || (sig == SIGINT)) { + logger_.LogInfo() << "Received SIGTERM or SIGINT, requesting application shutdown."; + if (!shutdown_requested_) { + // Request application exit. (SignalHandler initiate the shutdown!) + shutdown_requested_ = true; + } + } + } while (!shutdown_requested_); + } + + bool ExecutableControllerBase::IsShutdownRequested() { return shutdown_requested_; } + + void ExecutableControllerBase::SetupExecutionManager() { +#if 0 + if (use_execution_mgr_) { + app_client_ = std::make_unique<ApplicationClient>(); + } +#endif + } + + void ExecutableControllerBase::ReportStateToExecutionManager(bool is_running) { +#if 0 + if (app_client_ != nullptr) { + if (is_running) { + app_client_->ReportApplicationState(ApplicationState::kRunning); + } else { + app_client_->ReportApplicationState(ApplicationState::kTerminating); + } + } +#endif + } + +} // namespace vaf diff --git a/SwLibraries/vaf_core_library/lib/src/executor.cpp b/SwLibraries/vaf_core_library/lib/src/executor.cpp new file mode 100644 index 0000000..8e195a5 --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/src/executor.cpp @@ -0,0 +1,114 @@ +#include "vaf/executor.h" + +#include <iostream> + +namespace vaf { + + RunnableHandle::RunnableHandle(std::string name, uint64_t period, std::function<void(void)> runnable, + const std::string &owner, const std::vector<std::string> &run_after, uint64_t offset, + std::chrono::nanoseconds budget) + : name_{std::move(name)}, + period_{period}, + runnable_{std::move(runnable)}, + owner_{owner}, + run_after_{run_after}, + offset_{offset}, + budget_{budget} { + } + + const std::string &RunnableHandle::Name() const { return name_; } + + bool RunnableHandle::IsActive() const { return is_active_; } + + void RunnableHandle::Execute() const { runnable_(); } + + uint64_t RunnableHandle::Period() const { return period_; } + + void RunnableHandle::Start() { is_active_ = true; } + + void RunnableHandle::Stop() { is_active_ = false; } + + const std::string &RunnableHandle::Owner() { return owner_; } + + const std::vector<std::string> &RunnableHandle::RunAfter() { return run_after_; } + + uint64_t RunnableHandle::Offset() const { return offset_; } + + std::chrono::nanoseconds RunnableHandle::Budget() const { return budget_; } + + Executor::Executor(std::chrono::milliseconds running_period) + : running_period_{running_period}, + thread_{[this]() { ExecutorThread(); }}, + logger_{vaf::CreateLogger("E", "Executor")} { + } + + Executor::~Executor() { + exit_requested_ = true; + thread_.join(); + } + + void Executor::ExecutorThread() { + uint64_t counter{0}; + std::chrono::steady_clock::time_point next_run{std::chrono::steady_clock::now()}; + while (!exit_requested_) { + next_run += running_period_; + + for (std::shared_ptr<RunnableHandle> &runnable: runnables_) { + if (runnable->IsActive()) { + if (counter >= runnable->Offset()) { + if (((counter - runnable->Offset()) % runnable->Period()) == 0) { + ExecuteRunnable(*runnable); + } + } + } + } + + if (std::chrono::steady_clock::now() > next_run) { + logger_.LogWarn() << "Executor could no execute all runnables in time."; + } + + ++counter; + + std::this_thread::sleep_until(next_run); + } + } + + void Executor::ExecuteRunnable(RunnableHandle &runnable) { + std::chrono::nanoseconds budget = runnable.Budget(); + if (budget.count() == 0) { + runnable.Execute(); + } else { + auto start{std::chrono::high_resolution_clock::now()}; + runnable.Execute(); + auto end{std::chrono::high_resolution_clock::now()}; + if ((end - start) > budget) { + logger_.LogWarn() << "Budget violation of runnable from " << runnable.Owner().c_str(); + } + } + } + + ModuleExecutor::ModuleExecutor(Executor &executor, std::string name, std::vector<std::string> dependencies) + : executor_{executor}, + handles_{}, + started_{false}, + name_{std::move(name)}, + dependencies_{std::move(dependencies)} { + } + + void ModuleExecutor::Start() { + for (std::shared_ptr<RunnableHandle> &handle: handles_) { + handle->Start(); + } + + started_ = true; + } + + void ModuleExecutor::Stop() { + for (std::shared_ptr<RunnableHandle> &handle: handles_) { + handle->Stop(); + } + + started_ = false; + } + +} // namespace vaf diff --git a/SwLibraries/vaf_core_library/lib/src/logging.cpp b/SwLibraries/vaf_core_library/lib/src/logging.cpp new file mode 100644 index 0000000..7b8b64c --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/src/logging.cpp @@ -0,0 +1,13 @@ +#include "vaf/logging.h" + +namespace vaf { + +// Initialize static members outside the class definition + std::mutex LoggerSingleton::mtx; + LoggerSingleton *LoggerSingleton::instance = nullptr; + + Logger &CreateLogger(const char *ctx_id, const char *ctx_description) { + return LoggerSingleton::getInstance()->CreateLogger(ctx_id, ctx_description); + } + +} // namespace vaf \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/lib/src/runtime.cpp b/SwLibraries/vaf_core_library/lib/src/runtime.cpp new file mode 100644 index 0000000..a90c1fb --- /dev/null +++ b/SwLibraries/vaf_core_library/lib/src/runtime.cpp @@ -0,0 +1,14 @@ +#include "vaf/runtime.h" +#include "vaf/logging.h" + +namespace vaf { + + Runtime::Runtime() { + vaf::LoggerSingleton::getInstance()->SetLogLevelVerbose(); + } + + Runtime::~Runtime() { + vaf::LoggerSingleton::getInstance()->CleanLoggers(); + } + +} // namespace vaf diff --git a/SwLibraries/vaf_core_library/test/CMakeLists.txt b/SwLibraries/vaf_core_library/test/CMakeLists.txt new file mode 100644 index 0000000..0b6feae --- /dev/null +++ b/SwLibraries/vaf_core_library/test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(test) +target_sources(test PRIVATE "${CMAKE_CURRENT_LIST_DIR}/src/test.cpp") +target_link_libraries(test PRIVATE vaf_core) \ No newline at end of file diff --git a/SwLibraries/vaf_core_library/test/src/test.cpp b/SwLibraries/vaf_core_library/test/src/test.cpp new file mode 100644 index 0000000..62e39a9 --- /dev/null +++ b/SwLibraries/vaf_core_library/test/src/test.cpp @@ -0,0 +1,41 @@ +#include <iostream> +#include "vaf/future.h" +#include "vaf/internal/data_ptr_helper.h" +#include "vaf/result.h" +#include "vaf/logging.h" + +int main() { + vaf::Result<void> r1; + vaf::Result<int> r2{1}; + + vaf::Promise<int> p; + vaf::Future<int> f{p.get_future()}; + p.set_value(1); + + std::unique_ptr<double> test_unique_ptr{new double(21.21)}; + vaf::DataPtr<double> myDataPtr{std::move(test_unique_ptr)}; + + if (test_unique_ptr) std::cout << "1 - The result of test_unique_ptr is: " << *test_unique_ptr << std::endl; + + test_unique_ptr.release(); + + if (test_unique_ptr) std::cout << "2 - The result of test_unique_ptr is: " << *test_unique_ptr << std::endl; + + test_unique_ptr = vaf::internal::DataPtrHelper<double>::getRawPtr(myDataPtr); + + if (test_unique_ptr) std::cout << "3 - The result of test_unique_ptr is: " << *test_unique_ptr << std::endl; + + vaf::LoggerSingleton::getInstance()->SetLogLevelVerbose(); + + vaf::Logger &logger_ = vaf::CreateLogger("MyID", "MyLogger"); + + logger_.LogFatal() << "This is my Test Logging1"; + + logger_.LogDebug() << "This is my Test Logging2 " << 13 << " That is a number"; + + std::cout << std::flush; + + vaf::LoggerSingleton::getInstance()->CleanLoggers(); + + return 0; +} diff --git a/SwLibraries/vaf_core_library/test_package/CMakeLists.txt b/SwLibraries/vaf_core_library/test_package/CMakeLists.txt new file mode 100644 index 0000000..996bdb1 --- /dev/null +++ b/SwLibraries/vaf_core_library/test_package/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.15) +project(PackageTest CXX) + +find_package(vafcpp CONFIG REQUIRED) +find_package(Threads) + +add_executable(example src/example.cpp) +target_link_libraries(example vafcpp::vaf_core) diff --git a/SwLibraries/vaf_core_library/test_package/conanfile.py b/SwLibraries/vaf_core_library/test_package/conanfile.py new file mode 100644 index 0000000..7aac168 --- /dev/null +++ b/SwLibraries/vaf_core_library/test_package/conanfile.py @@ -0,0 +1,26 @@ +import os + +from conan import ConanFile +from conan.tools.cmake import CMake, cmake_layout +from conan.tools.build import can_run + + +class vafcppTestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps", "CMakeToolchain" + + def requirements(self): + self.requires(self.tested_reference_str) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def layout(self): + cmake_layout(self) + + def test(self): + if can_run(self): + cmd = os.path.join(self.cpp.build.bindir, "example") + self.run(cmd, env="conanrun") diff --git a/SwLibraries/vaf_core_library/test_package/gcc12__x86_64-pc-linux-elf b/SwLibraries/vaf_core_library/test_package/gcc12__x86_64-pc-linux-elf new file mode 100644 index 0000000..fe1b560 --- /dev/null +++ b/SwLibraries/vaf_core_library/test_package/gcc12__x86_64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=x86_64 +compiler=gcc +compiler.version=12 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-12 +CXX=g++-12 diff --git a/SwLibraries/vaf_core_library/test_package/gcc7__aarch64-pc-linux-elf b/SwLibraries/vaf_core_library/test_package/gcc7__aarch64-pc-linux-elf new file mode 100644 index 0000000..9ea5a2c --- /dev/null +++ b/SwLibraries/vaf_core_library/test_package/gcc7__aarch64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=armv8 +compiler=gcc +compiler.version=7 +compiler.cppstd=14 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=aarch64-linux-gnu-gcc-7 +CXX=aarch64-linux-gnu-g++-7 diff --git a/SwLibraries/vaf_core_library/test_package/src/example.cpp b/SwLibraries/vaf_core_library/test_package/src/example.cpp new file mode 100644 index 0000000..fecf41d --- /dev/null +++ b/SwLibraries/vaf_core_library/test_package/src/example.cpp @@ -0,0 +1,19 @@ + +#include <vaf/controller_interface.h> + +#include <string> +#include <vector> + +class MyController final : public vaf::ControlInterface { +public: + vaf::Result<void> Init() noexcept { return vaf::Result<void>{}; } + void Start() noexcept {} + void Stop() noexcept {} + void DeInit() noexcept {} +}; + +int main() { + + std::vector<std::string> vec; + vec.push_back("test_package"); +} diff --git a/Tools/.gitkeep b/Tools/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/VAF/.gitignore b/VAF/.gitignore new file mode 100644 index 0000000..1e05db3 --- /dev/null +++ b/VAF/.gitignore @@ -0,0 +1,86 @@ +# IDE's +## Jetbrains IDE's +.DS_Store +.idea + +## Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Ansible +## Retry Files +*.retry + +# Python +## Local History for Visual Studio Code +.history/ + +## Byte-compiled / optimized / DLL files +**/__pycache__/ +*.py[cod] + +## C extensions +*.so + +## Distribution / packaging +build/ +dist/ +*.egg-info/ +pip-wheel-metadata/ + +## Installer logs +pip-log.txt +pip-delete-this-directory.txt + +## Unit test / coverage reports +.pytest_cache/ +.tox/ +.coverage* +.cache +nosetests.xml +coverage.xml +htmlcov/ +report.xml +tests/_temp/ +tests/*/results/*.xml + +## Translations +*.mo + +## Mr Developer +.mr.developer.cfg +.project +.pydevproject + +## Rope +.ropeproject + +## Django stuff: +*.log +*.pot + +## Sphinx Spec documentation +spec/_build/ +spec/_temp/ + +# Sphinx API documentation +doc/api/ + +## General documentation +**/_build/ +**/_release/ + +## PDM +.venv/ +venv/ +env/ +__pypackages__ +.pdm-python +.pdm.toml + +## MYPY +.mypy_cache diff --git a/VAF/LICENSE b/VAF/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/VAF/Makefile b/VAF/Makefile new file mode 100644 index 0000000..304ff27 --- /dev/null +++ b/VAF/Makefile @@ -0,0 +1,8 @@ +# To change the coverage (or any other set variable in the central Makefile) the include statement must occur after the overwritten variable, like this: +# fail verify:coverage job if branch coverage is below a specific value. +# default value: 100 +# COV_FAIL_UNDER=99 + +include python3-makefile/Makefile + +include tests/Makefile diff --git a/VAF/README.md b/VAF/README.md new file mode 100644 index 0000000..8d250d7 --- /dev/null +++ b/VAF/README.md @@ -0,0 +1,3 @@ +# VAF implementation + +For more details please check the provided section in [Documentation](../Documentation/README.md). diff --git a/VAF/bootstrap/LICENSE b/VAF/bootstrap/LICENSE new file mode 100644 index 0000000..07350f4 --- /dev/null +++ b/VAF/bootstrap/LICENSE @@ -0,0 +1 @@ +# Dummy file for the vector license diff --git a/VAF/bootstrap/README.md b/VAF/bootstrap/README.md new file mode 100644 index 0000000..e69de29 diff --git a/VAF/bootstrap/pdm.lock b/VAF/bootstrap/pdm.lock new file mode 100644 index 0000000..5370717 --- /dev/null +++ b/VAF/bootstrap/pdm.lock @@ -0,0 +1,504 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default"] +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:0792fccedef3488fff25d6a6b2e24afcae1dadffe2dd77815da7e4252ecdba9e" + +[[metadata.targets]] +requires_python = ">=3.10" + +[[package]] +name = "annotated-types" +version = "0.7.0" +requires_python = ">=3.8" +summary = "Reusable constraint types to use with typing.Annotated" +groups = ["default"] +dependencies = [ + "typing-extensions>=4.0.0; python_version < \"3.9\"", +] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "click" +version = "8.1.8" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", +] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[[package]] +name = "click-prompt" +version = "0.6.1" +requires_python = "<4.0,>=3.6.9" +summary = "click-prompt provides more beautiful interactive options for the Python click library" +groups = ["default"] +dependencies = [ + "click>=8.0.4", + "questionary<2.0.0,>=1.10.0", +] +files = [ + {file = "click_prompt-0.6.1-py3-none-any.whl", hash = "sha256:22c5d137b6febe8dbbb11705e63a79222d3432de7a4cdf0d247f712139fc1b8a"}, + {file = "click_prompt-0.6.1.tar.gz", hash = "sha256:c158c6227a30a803970d08cfcb2b83bcdbc1729bf0189c03981a2db28ac1ef04"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "copier" +version = "9.6.0" +requires_python = ">=3.9" +summary = "A library for rendering project templates." +groups = ["default"] +dependencies = [ + "colorama>=0.4.6", + "dunamai>=1.7.0", + "eval-type-backport<0.3.0,>=0.1.3; python_version < \"3.10\"", + "funcy>=1.17", + "jinja2-ansible-filters>=1.3.1", + "jinja2>=3.1.5", + "packaging>=23.0", + "pathspec>=0.9.0", + "platformdirs>=4.3.6", + "plumbum>=1.6.9", + "pydantic>=2.4.2", + "pygments>=2.7.1", + "pyyaml>=5.3.1", + "questionary>=1.8.1", +] +files = [ + {file = "copier-9.6.0-py3-none-any.whl", hash = "sha256:aaf992600a373fa2dda9f61725916a230c210ede14a968c60dab855d524c6cf3"}, + {file = "copier-9.6.0.tar.gz", hash = "sha256:e05a18b387b96e8d1fbd5271d37f59c9a02be5ad717f7878d0505562fd62b786"}, +] + +[[package]] +name = "dunamai" +version = "1.23.1" +requires_python = ">=3.5" +summary = "Dynamic version generation" +groups = ["default"] +dependencies = [ + "importlib-metadata>=1.6.0; python_version < \"3.8\"", + "packaging>=20.9", +] +files = [ + {file = "dunamai-1.23.1-py3-none-any.whl", hash = "sha256:2611b0b9105a5797149ef82f4968a01dd912bdac857d49fc06856a4cfa58cf78"}, + {file = "dunamai-1.23.1.tar.gz", hash = "sha256:0b5712fc63bfb235263d912bfc5eb84590ba2201bb737268d25a5dbad7085489"}, +] + +[[package]] +name = "funcy" +version = "2.0" +summary = "A fancy and practical functional tools" +groups = ["default"] +files = [ + {file = "funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0"}, + {file = "funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["default"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[[package]] +name = "jinja2-ansible-filters" +version = "1.3.2" +summary = "A port of Ansible's jinja2 filters without requiring ansible core." +groups = ["default"] +dependencies = [ + "Jinja2", + "PyYAML", +] +files = [ + {file = "jinja2-ansible-filters-1.3.2.tar.gz", hash = "sha256:07c10cf44d7073f4f01102ca12d9a2dc31b41d47e4c61ed92ef6a6d2669b356b"}, + {file = "jinja2_ansible_filters-1.3.2-py3-none-any.whl", hash = "sha256:e1082f5564917649c76fed239117820610516ec10f87735d0338688800a55b34"}, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +requires_python = ">=3.9" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["default"] +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "packaging" +version = "24.2" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["default"] +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["default"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.7" +requires_python = ">=3.9" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["default"] +files = [ + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, +] + +[[package]] +name = "plumbum" +version = "1.9.0" +requires_python = ">=3.8" +summary = "Plumbum: shell combinators library" +groups = ["default"] +dependencies = [ + "importlib-resources; python_version < \"3.9\"", + "pywin32; platform_system == \"Windows\" and platform_python_implementation != \"PyPy\"", +] +files = [ + {file = "plumbum-1.9.0-py3-none-any.whl", hash = "sha256:9fd0d3b0e8d86e4b581af36edf3f3bbe9d1ae15b45b8caab28de1bcb27aaa7f5"}, + {file = "plumbum-1.9.0.tar.gz", hash = "sha256:e640062b72642c3873bd5bdc3effed75ba4d3c70ef6b6a7b907357a84d909219"}, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.50" +requires_python = ">=3.8.0" +summary = "Library for building powerful interactive command lines in Python" +groups = ["default"] +dependencies = [ + "wcwidth", +] +files = [ + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, +] + +[[package]] +name = "pydantic" +version = "2.11.1" +requires_python = ">=3.9" +summary = "Data validation using Python type hints" +groups = ["default"] +dependencies = [ + "annotated-types>=0.6.0", + "pydantic-core==2.33.0", + "typing-extensions>=4.12.2", + "typing-inspection>=0.4.0", +] +files = [ + {file = "pydantic-2.11.1-py3-none-any.whl", hash = "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8"}, + {file = "pydantic-2.11.1.tar.gz", hash = "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968"}, +] + +[[package]] +name = "pydantic-core" +version = "2.33.0" +requires_python = ">=3.9" +summary = "Core functionality for Pydantic validation and serialization" +groups = ["default"] +dependencies = [ + "typing-extensions!=4.7.0,>=4.6.0", +] +files = [ + {file = "pydantic_core-2.33.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e"}, + {file = "pydantic_core-2.33.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5"}, + {file = "pydantic_core-2.33.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276"}, + {file = "pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760"}, + {file = "pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa"}, + {file = "pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c"}, + {file = "pydantic_core-2.33.0-cp310-cp310-win32.whl", hash = "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025"}, + {file = "pydantic_core-2.33.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc"}, + {file = "pydantic_core-2.33.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef"}, + {file = "pydantic_core-2.33.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd"}, + {file = "pydantic_core-2.33.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453"}, + {file = "pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b"}, + {file = "pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915"}, + {file = "pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2"}, + {file = "pydantic_core-2.33.0-cp311-cp311-win32.whl", hash = "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86"}, + {file = "pydantic_core-2.33.0-cp311-cp311-win_amd64.whl", hash = "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b"}, + {file = "pydantic_core-2.33.0-cp311-cp311-win_arm64.whl", hash = "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a"}, + {file = "pydantic_core-2.33.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43"}, + {file = "pydantic_core-2.33.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862"}, + {file = "pydantic_core-2.33.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a"}, + {file = "pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099"}, + {file = "pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6"}, + {file = "pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3"}, + {file = "pydantic_core-2.33.0-cp312-cp312-win32.whl", hash = "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2"}, + {file = "pydantic_core-2.33.0-cp312-cp312-win_amd64.whl", hash = "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48"}, + {file = "pydantic_core-2.33.0-cp312-cp312-win_arm64.whl", hash = "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6"}, + {file = "pydantic_core-2.33.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555"}, + {file = "pydantic_core-2.33.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9"}, + {file = "pydantic_core-2.33.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181"}, + {file = "pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d"}, + {file = "pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3"}, + {file = "pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b"}, + {file = "pydantic_core-2.33.0-cp313-cp313-win32.whl", hash = "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585"}, + {file = "pydantic_core-2.33.0-cp313-cp313-win_amd64.whl", hash = "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606"}, + {file = "pydantic_core-2.33.0-cp313-cp313-win_arm64.whl", hash = "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225"}, + {file = "pydantic_core-2.33.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87"}, + {file = "pydantic_core-2.33.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b"}, + {file = "pydantic_core-2.33.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330"}, + {file = "pydantic_core-2.33.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936"}, + {file = "pydantic_core-2.33.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8"}, + {file = "pydantic_core-2.33.0.tar.gz", hash = "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3"}, +] + +[[package]] +name = "pygments" +version = "2.19.1" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["default"] +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[[package]] +name = "pywin32" +version = "310" +summary = "Python for Window Extensions" +groups = ["default"] +marker = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +requires_python = ">=3.8" +summary = "YAML parser and emitter for Python" +groups = ["default"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "questionary" +version = "1.10.0" +requires_python = ">=3.6,<4.0" +summary = "Python library to build pretty command line user prompts âï¸" +groups = ["default"] +dependencies = [ + "prompt-toolkit<4.0,>=2.0", +] +files = [ + {file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"}, + {file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"}, +] + +[[package]] +name = "typing-extensions" +version = "4.13.0" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default"] +files = [ + {file = "typing_extensions-4.13.0-py3-none-any.whl", hash = "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5"}, + {file = "typing_extensions-4.13.0.tar.gz", hash = "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.0" +requires_python = ">=3.9" +summary = "Runtime typing introspection tools" +groups = ["default"] +dependencies = [ + "typing-extensions>=4.12.0", +] +files = [ + {file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"}, + {file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +summary = "Measures the displayed width of unicode strings in a terminal" +groups = ["default"] +dependencies = [ + "backports-functools-lru-cache>=1.2.1; python_version < \"3.2\"", +] +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] diff --git a/VAF/bootstrap/pyproject.toml b/VAF/bootstrap/pyproject.toml new file mode 100644 index 0000000..e6435b9 --- /dev/null +++ b/VAF/bootstrap/pyproject.toml @@ -0,0 +1,60 @@ +[project] +name = "vaf-bootstrap" +dynamic = ["version"] +description = "Commandline tool for bootstrapping projects in the Vehicle Application Framework (VAF)" +readme = "README.md" +keywords = ["python", "module"] +classifiers = [ + "Topic :: Software Development :: Libraries :: Python Modules", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +authors = [{ name = "Christian Marchl", email = "christian.marchl@vector.com" }] +license = { file = "LICENSE" } + +dependencies = [ + "click>=8.1.7", + "copier>=9.3.1", + "jinja2>=3.1.4", + "click-prompt==0.6.1", +] +requires-python = ">=3.10" + +[project.urls] +Homepage = "https://vgroup.sharepoint.com/sites/pes_ft_application_framework/SitePages/Home.aspx" +Repository = "https://gitlab.vi.vector.int/pes/teamprojects/pes-ft-applicationframework" +Documentation = "<spo url>" +Changelog = "<source url>" + +[project.scripts] +vaf = "vaf.__main_bootstrap__:cli" + +[build-system] +requires = ["pdm-backend==2.3.3", "pdm-build-locked==0.3.2"] +build-backend = "pdm.backend" + + +######### +# TOOLS # +######### + +[tool.pdm.version] +source = "scm" +fallback_version = "0.1.0" + +[tool.pdm] +plugins = ["pdm-build-locked"] + +[tool.pdm.build] +package-dir = "src" +includes = [ + "src/vaf/cli_core/bootstrap/", + "src/vaf/cli_core/common/", + "src/vaf/__main_bootstrap__.py", + "src/vaf/py.typed", + "src/vaf/constants.py", +] diff --git a/VAF/bootstrap/src b/VAF/bootstrap/src new file mode 100644 index 0000000..e69de29 diff --git a/VAF/pdm.lock b/VAF/pdm.lock new file mode 100644 index 0000000..0f6a648 --- /dev/null +++ b/VAF/pdm.lock @@ -0,0 +1,1199 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "dev"] +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:7eda94ee2d30a827a9859f76bbb6b4f13fd1f066a3bf950656886438a23ca3d0" + +[[metadata.targets]] +requires_python = ">=3.10" + +[[package]] +name = "annotated-types" +version = "0.7.0" +requires_python = ">=3.8" +summary = "Reusable constraint types to use with typing.Annotated" +groups = ["default"] +dependencies = [ + "typing-extensions>=4.0.0; python_version < \"3.9\"", +] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "astroid" +version = "3.3.8" +requires_python = ">=3.9.0" +summary = "An abstract syntax tree for Python with inference support." +groups = ["dev"] +dependencies = [ + "typing-extensions>=4.0.0; python_version < \"3.11\"", +] +files = [ + {file = "astroid-3.3.8-py3-none-any.whl", hash = "sha256:187ccc0c248bfbba564826c26f070494f7bc964fd286b6d9fff4420e55de828c"}, + {file = "astroid-3.3.8.tar.gz", hash = "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b"}, +] + +[[package]] +name = "certifi" +version = "2025.1.31" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] +files = [ + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +requires_python = ">=3.7" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["default"] +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, +] + +[[package]] +name = "click" +version = "8.1.8" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", +] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[[package]] +name = "click-prompt" +version = "0.6.1" +requires_python = "<4.0,>=3.6.9" +summary = "click-prompt provides more beautiful interactive options for the Python click library" +groups = ["default"] +dependencies = [ + "click>=8.0.4", + "questionary<2.0.0,>=1.10.0", +] +files = [ + {file = "click_prompt-0.6.1-py3-none-any.whl", hash = "sha256:22c5d137b6febe8dbbb11705e63a79222d3432de7a4cdf0d247f712139fc1b8a"}, + {file = "click_prompt-0.6.1.tar.gz", hash = "sha256:c158c6227a30a803970d08cfcb2b83bcdbc1729bf0189c03981a2db28ac1ef04"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default", "dev"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "conan" +version = "2.13.0" +requires_python = ">=3.6" +summary = "Conan C/C++ package manager" +groups = ["default"] +dependencies = [ + "Jinja2<4.0.0,>=3.0", + "PyYAML<7.0,>=6.0", + "colorama<0.5.0,>=0.4.3", + "distro<=1.8.0,>=1.4.0; platform_system == \"Linux\" or platform_system == \"FreeBSD\"", + "fasteners>=0.15", + "patch-ng<1.19,>=1.18.0", + "python-dateutil<3,>=2.8.0", + "requests<3.0.0,>=2.25", + "urllib3<2.1,>=1.26.6", +] +files = [ + {file = "conan-2.13.0.tar.gz", hash = "sha256:0ad929984e5842fe6bb686361ae1a6240e28b24a6df09aab2c87aaa46ff71f33"}, +] + +[[package]] +name = "copier" +version = "9.5.0" +requires_python = ">=3.9" +summary = "A library for rendering project templates." +groups = ["default"] +dependencies = [ + "colorama>=0.4.6", + "dunamai>=1.7.0", + "eval-type-backport<0.3.0,>=0.1.3; python_version < \"3.10\"", + "funcy>=1.17", + "jinja2-ansible-filters>=1.3.1", + "jinja2>=3.1.5", + "packaging>=23.0", + "pathspec>=0.9.0", + "platformdirs>=4.3.6", + "plumbum>=1.6.9", + "pydantic>=2.4.2", + "pygments>=2.7.1", + "pyyaml>=5.3.1", + "questionary>=1.8.1", +] +files = [ + {file = "copier-9.5.0-py3-none-any.whl", hash = "sha256:d7d9851649ad71518f8e868ab761362af0ee9008025a3f85647e9724983cf540"}, + {file = "copier-9.5.0.tar.gz", hash = "sha256:db7311075176376ee746fe610ffb5b27db7ac755585d6149894f677ffbce127d"}, +] + +[[package]] +name = "coverage" +version = "7.6.12" +requires_python = ">=3.9" +summary = "Code coverage measurement for Python" +groups = ["dev"] +files = [ + {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, +] + +[[package]] +name = "coverage" +version = "7.6.12" +extras = ["toml"] +requires_python = ">=3.9" +summary = "Code coverage measurement for Python" +groups = ["dev"] +dependencies = [ + "coverage==7.6.12", + "tomli; python_full_version <= \"3.11.0a6\"", +] +files = [ + {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, +] + +[[package]] +name = "dill" +version = "0.3.9" +requires_python = ">=3.8" +summary = "serialize all of Python" +groups = ["dev"] +files = [ + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, +] + +[[package]] +name = "distro" +version = "1.8.0" +requires_python = ">=3.6" +summary = "Distro - an OS platform information API" +groups = ["default"] +marker = "platform_system == \"Linux\" or platform_system == \"FreeBSD\"" +files = [ + {file = "distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff"}, + {file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"}, +] + +[[package]] +name = "dunamai" +version = "1.23.0" +requires_python = ">=3.5" +summary = "Dynamic version generation" +groups = ["default"] +dependencies = [ + "importlib-metadata>=1.6.0; python_version < \"3.8\"", + "packaging>=20.9", +] +files = [ + {file = "dunamai-1.23.0-py3-none-any.whl", hash = "sha256:a0906d876e92441793c6a423e16a4802752e723e9c9a5aabdc5535df02dbe041"}, + {file = "dunamai-1.23.0.tar.gz", hash = "sha256:a163746de7ea5acb6dacdab3a6ad621ebc612ed1e528aaa8beedb8887fccd2c4"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["dev"] +marker = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[[package]] +name = "fasteners" +version = "0.19" +requires_python = ">=3.6" +summary = "A python package that provides useful locks" +groups = ["default"] +files = [ + {file = "fasteners-0.19-py3-none-any.whl", hash = "sha256:758819cb5d94cdedf4e836988b74de396ceacb8e2794d21f82d131fd9ee77237"}, + {file = "fasteners-0.19.tar.gz", hash = "sha256:b4f37c3ac52d8a445af3a66bce57b33b5e90b97c696b7b984f530cf8f0ded09c"}, +] + +[[package]] +name = "funcy" +version = "2.0" +summary = "A fancy and practical functional tools" +groups = ["default"] +files = [ + {file = "funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0"}, + {file = "funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb"}, +] + +[[package]] +name = "idna" +version = "3.10" +requires_python = ">=3.6" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["dev"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "6.0.1" +requires_python = ">=3.9.0" +summary = "A Python utility / library to sort Python imports." +groups = ["dev"] +files = [ + {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, + {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, +] + +[[package]] +name = "jinja2" +version = "3.1.5" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["default"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, +] + +[[package]] +name = "jinja2-ansible-filters" +version = "1.3.2" +summary = "A port of Ansible's jinja2 filters without requiring ansible core." +groups = ["default"] +dependencies = [ + "Jinja2", + "PyYAML", +] +files = [ + {file = "jinja2-ansible-filters-1.3.2.tar.gz", hash = "sha256:07c10cf44d7073f4f01102ca12d9a2dc31b41d47e4c61ed92ef6a6d2669b356b"}, + {file = "jinja2_ansible_filters-1.3.2-py3-none-any.whl", hash = "sha256:e1082f5564917649c76fed239117820610516ec10f87735d0338688800a55b34"}, +] + +[[package]] +name = "lxml" +version = "5.3.1" +requires_python = ">=3.6" +summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +groups = ["default"] +files = [ + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, + {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, + {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, + {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, + {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, + {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, + {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, + {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, + {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, + {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +requires_python = ">=3.9" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["default"] +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +requires_python = ">=3.6" +summary = "McCabe checker, plugin for flake8" +groups = ["dev"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.15.0" +requires_python = ">=3.9" +summary = "Optional static typing for Python" +groups = ["dev"] +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.6.0", +] +files = [ + {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"}, + {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"}, + {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, + {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, + {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, + {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, + {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, + {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, + {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, + {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, + {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "networkx" +version = "3.4.2" +requires_python = ">=3.10" +summary = "Python package for creating and manipulating graphs and networks" +groups = ["default"] +files = [ + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, +] + +[[package]] +name = "packaging" +version = "24.2" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["default", "dev"] +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "patch-ng" +version = "1.18.1" +requires_python = ">=3.6" +summary = "Library to parse and apply unified diffs." +groups = ["default"] +files = [ + {file = "patch-ng-1.18.1.tar.gz", hash = "sha256:52fd46ee46f6c8667692682c1fd7134edc65a2d2d084ebec1d295a6087fc0291"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["default"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pip" +version = "25.0.1" +requires_python = ">=3.8" +summary = "The PyPA recommended tool for installing Python packages." +groups = ["dev"] +files = [ + {file = "pip-25.0.1-py3-none-any.whl", hash = "sha256:c46efd13b6aa8279f33f2864459c8ce587ea6a1a59ee20de055868d8f7688f7f"}, + {file = "pip-25.0.1.tar.gz", hash = "sha256:88f96547ea48b940a3a385494e181e29fb8637898f88d88737c5049780f196ea"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["default", "dev"] +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +groups = ["dev"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[[package]] +name = "plumbum" +version = "1.9.0" +requires_python = ">=3.8" +summary = "Plumbum: shell combinators library" +groups = ["default"] +dependencies = [ + "importlib-resources; python_version < \"3.9\"", + "pywin32; platform_system == \"Windows\" and platform_python_implementation != \"PyPy\"", +] +files = [ + {file = "plumbum-1.9.0-py3-none-any.whl", hash = "sha256:9fd0d3b0e8d86e4b581af36edf3f3bbe9d1ae15b45b8caab28de1bcb27aaa7f5"}, + {file = "plumbum-1.9.0.tar.gz", hash = "sha256:e640062b72642c3873bd5bdc3effed75ba4d3c70ef6b6a7b907357a84d909219"}, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.50" +requires_python = ">=3.8.0" +summary = "Library for building powerful interactive command lines in Python" +groups = ["default"] +dependencies = [ + "wcwidth", +] +files = [ + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +requires_python = ">=3.8" +summary = "Data validation using Python type hints" +groups = ["default"] +dependencies = [ + "annotated-types>=0.6.0", + "pydantic-core==2.27.2", + "typing-extensions>=4.12.2", +] +files = [ + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, +] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +requires_python = ">=3.8" +summary = "Core functionality for Pydantic validation and serialization" +groups = ["default"] +dependencies = [ + "typing-extensions!=4.7.0,>=4.6.0", +] +files = [ + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, +] + +[[package]] +name = "pygments" +version = "2.19.1" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["default"] +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[[package]] +name = "pylint" +version = "3.3.4" +requires_python = ">=3.9.0" +summary = "python code static checker" +groups = ["dev"] +dependencies = [ + "astroid<=3.4.0-dev0,>=3.3.8", + "colorama>=0.4.5; sys_platform == \"win32\"", + "dill>=0.2; python_version < \"3.11\"", + "dill>=0.3.6; python_version >= \"3.11\"", + "dill>=0.3.7; python_version >= \"3.12\"", + "isort!=5.13.0,<7,>=4.2.5", + "mccabe<0.8,>=0.6", + "platformdirs>=2.2.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "tomlkit>=0.10.1", + "typing-extensions>=3.10.0; python_version < \"3.10\"", +] +files = [ + {file = "pylint-3.3.4-py3-none-any.whl", hash = "sha256:289e6a1eb27b453b08436478391a48cd53bb0efb824873f949e709350f3de018"}, + {file = "pylint-3.3.4.tar.gz", hash = "sha256:74ae7a38b177e69a9b525d0794bd8183820bfa7eb68cc1bee6e8ed22a42be4ce"}, +] + +[[package]] +name = "pytest" +version = "8.3.5" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +groups = ["dev"] +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2,>=1.5", + "tomli>=1; python_version < \"3.11\"", +] +files = [ + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, +] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +requires_python = ">=3.9" +summary = "Pytest plugin for measuring coverage." +groups = ["dev"] +dependencies = [ + "coverage[toml]>=7.5", + "pytest>=4.6", +] +files = [ + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, +] + +[[package]] +name = "pytest-dependency" +version = "0.6.0" +requires_python = ">=3.4" +summary = "Manage dependencies of tests" +groups = ["dev"] +dependencies = [ + "pytest>=3.7.0", + "setuptools", +] +files = [ + {file = "pytest-dependency-0.6.0.tar.gz", hash = "sha256:934b0e6a39d95995062c193f7eaeed8a8ffa06ff1bcef4b62b0dc74a708bacc1"}, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["default"] +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[[package]] +name = "pywin32" +version = "308" +summary = "Python for Window Extensions" +groups = ["default"] +marker = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +requires_python = ">=3.8" +summary = "YAML parser and emitter for Python" +groups = ["default"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "questionary" +version = "1.10.0" +requires_python = ">=3.6,<4.0" +summary = "Python library to build pretty command line user prompts âï¸" +groups = ["default"] +dependencies = [ + "prompt-toolkit<4.0,>=2.0", +] +files = [ + {file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"}, + {file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["default"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[[package]] +name = "ruff" +version = "0.9.9" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["dev"] +files = [ + {file = "ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367"}, + {file = "ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7"}, + {file = "ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e"}, + {file = "ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1"}, + {file = "ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1"}, + {file = "ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf"}, + {file = "ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933"}, +] + +[[package]] +name = "setuptools" +version = "75.8.2" +requires_python = ">=3.9" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" +groups = ["dev"] +files = [ + {file = "setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f"}, + {file = "setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2"}, +] + +[[package]] +name = "six" +version = "1.17.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "tomli" +version = "2.2.1" +requires_python = ">=3.8" +summary = "A lil' TOML parser" +groups = ["dev"] +marker = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +requires_python = ">=3.8" +summary = "Style preserving TOML library" +groups = ["dev"] +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default", "dev"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "urllib3" +version = "2.0.7" +requires_python = ">=3.7" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["default"] +files = [ + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +summary = "Measures the displayed width of unicode strings in a terminal" +groups = ["default"] +dependencies = [ + "backports-functools-lru-cache>=1.2.1; python_version < \"3.2\"", +] +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] diff --git a/VAF/pyproject.toml b/VAF/pyproject.toml new file mode 100644 index 0000000..87ab82f --- /dev/null +++ b/VAF/pyproject.toml @@ -0,0 +1,154 @@ +[project] +name = "vaf" +dynamic = ["version"] +description = "Commandline tool for the Vehicle Application Framework (VAF)" +readme = "README.md" +keywords = ["python", "module"] +classifiers = [ + "Topic :: Software Development :: Libraries :: Python Modules", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +authors = [{ name = "author", email = "" }] +license = { file = "LICENSE" } + +dependencies = [ + "click>=8.1.7", + "conan>=2.9.0", + "copier>=9.3.1", + "jinja2>=3.1.4", + "pydantic>=2.9.2", + "lxml", + "networkx", + "click-prompt==0.6.1", +] +requires-python = ">=3.10" + +[project.urls] +Homepage = "https://projects.eclipse.org/projects/automotive.autoapiframework" +Repository = "https://gitlab.eclipse.org/eclipse/autoapiframework" +Documentation = "<spo url>" +Changelog = "<source url>" + +[project.scripts] +vaf = "vaf.__main__:cli" + +[build-system] +requires = ["pdm-backend==2.3.3", "pdm-build-locked==0.3.2"] +build-backend = "pdm.backend" + + +######### +# TOOLS # +######### + +[tool.pdm.version] +source = "scm" +fallback_version = "0.1.0" + +[tool.pdm] +plugins = ["pdm-build-locked"] + +[tool.pdm.build] +package-dir = "src" +excludes = ["tests/_temp"] + +[tool.pdm.dev-dependencies] +dev = [ + # lint + "ruff>=0.5.4", + "mypy>=1.11.0", + "pip>=24.1.2", + "pylint>=3.2.6", + # test + "pytest>=8.3.1", + "pytest-cov>=5.0.0", + "pytest-dependency", + # "pes-pytest-utils>=0.1.0", + # doc and spec + "packaging>=24.1", +] + + +[tool.ruff] +extend = "python3-makefile/ruff.toml" +exclude = ["src/vaf/cli_core/templates", "tests/unit/vafpy/test_data", "tests/unit/cli_core/test_data"] + +[tool.pylint] +## pylint linter settings +## see `pylint --generate-toml-config` +## justify single line via: # pylint: disable=<rule> +extension-pkg-allow-list = "lxml" +disable = [ + "C0103", #Buggy line disabling mechanism +] + +[tool.pylint.main] +ignore-paths = [ + ".git", + "__pypackages__", + "tests/_temp", + "src/vaf/cli_core/main/templates", + "src/vaf/cli_core/bootstrap/templates", + # "tests" # enable/disable linting within tests directory +] +load-plugins = ["pylint.extensions.docparams"] +accept-no-param-doc = "no" +accept-no-raise-doc = "no" +accept-no-yields-doc = "no" +default-docstring-type = "google" + +[tool.pylint.format] +max-line-length = 120 + +[tool.black] +## black code formatter settings +line-length = 120 + +[tool.mypy] +## mypy static typechecker settings +## see https://mypy.readthedocs.io/en/stable/config_file.html +## justify single line via: +## # type: ignore[<error-code>] +## # type: ignore +files = [ + "src/", + "tests/", # enable/disable linting within tests directory +] +mypy_path = "src" +exclude = [ + "tests/_temp", # Exclude tests/_temp from mypy. Some tests will install venvs there. + "src/vaf/cli_core/main/templates", + "src/vaf/cli_core/bootstrap/templates", + "tests/unit/cli_core/test_data", + "tests/unit/vafpy/test_data", +] +show_error_codes = true +strict = true # https://mypy.readthedocs.io/en/stable/config_file.html#confval-strict +ignore_missing_imports = true + +#[[tool.mypy.overrides]] + +[tool.pytest.ini_options] +testpaths = ["tests"] +norecursedirs = ["_temp/*"] +addopts = "--verbose --cov-report=term" +# markers for testing vafpy +markers = [ + "vafpy_xy_data_el: test XyDataElement", + "vafpy_xy_operations: test XyOperations", + "slow: mark test as slow" +] + + +[tool.coverage.run] +branch = true +source = ["src"] +relative_files = true + +[tool.coverage.report] +show_missing = true diff --git a/VAF/python3-makefile/Makefile b/VAF/python3-makefile/Makefile new file mode 100644 index 0000000..de64bce --- /dev/null +++ b/VAF/python3-makefile/Makefile @@ -0,0 +1,118 @@ +# utility functions (OS dependent if necessary) +OS ?= $(shell uname) +PYTHON_VERSION ?= 3.12 +ifeq ($(OS),Windows_NT) + rm_if_exist = if exist $(1) rm -rf $(1) +endif +ifeq ($(OS),Linux) + rm_if_exist = if [ -e $(1) ] ; then rm -rf $(1) ; fi ; +endif +rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) + + +# fail test job if branch coverage is below a specific value +# should be set via CI-variables +ifeq ($(COV_FAIL_UNDER),) + COV_FAIL_UNDER=100 +endif + +.PHONY: staging-version release-version install install-extras-test check-format format lint test traceability remove build release clean + + +.venv: +ifdef CI +# In CI we want to make use of the specified interpreter + pdm venv create ${PYTHON_VERSION} +else +# Locally we want to use the Python interpreter at hand + pdm venv create +endif + +.pdm.toml: .venv + pdm use --ignore-remembered --first ./.venv + +staging-version: + @echo "This function is deprecated. Just used as placeholder for the pipeline-template" + +release-version: + @echo "This function is deprecated. Just used as placeholder for the pipeline-template" + +install: +# SHELL=sh.exe only inside Makefile on Windows cmd/powershell +ifeq ($(SHELL), sh.exe) + @powershell Write-Host "Testing package installation in venv install-deploy. To create a development venv, please use " -ForegroundColor Red; Write-Host "make install-all" -ForegroundColor Green; + @powershell 'if (pdm venv list | Select-String -Pattern "install-deploy") { pdm venv remove install-deploy -y }' +# Git Bash/Linux Shell +else + @echo -e "\e[31mTesting package installation in venv install-deploy\e[m. To create a development venv, please use \e[32mmake install-all\e[m" + @if pdm venv list | grep -q "install-deploy"; then \ + pdm venv remove install-deploy -y; \ + fi +endif + pdm venv create --with-pip --name install-deploy ${PYTHON_VERSION} + pdm run --venv install-deploy pip install . + +install-all: .pdm.toml + pdm install + +install-coverage: .pdm.toml + pdm export --format requirements --without-hashes --output requirements.tmp + cat requirements.tmp | grep coverage | xargs pdm run pip --python $(shell pdm run python -c 'import sys;print(sys.executable)') install + rm requirements.tmp + +install-extras-test: + @echo "Call to deprecated target install-extras-test" + +check-format: install-all + pdm run ruff format --check --diff + +format: install-all + pdm run ruff format + pdm run ruff check --fix + +lint: install-all + @EXIT_CODE=0; \ + pdm run ruff check || EXIT_CODE=$$?; \ + pdm run pylint src/ || EXIT_CODE=$$?; \ + pdm run pylint tests/ || EXIT_CODE=$$?; \ + pdm run mypy --install-types --non-interactive || EXIT_CODE=$$?; \ + if [ $$EXIT_CODE -ne 0 ]; then exit 1; fi + +remove: + @echo "This function is deprecated. Just used as placeholder for the pipeline-template" + +build: + pdm install --plugins + pdm build + +coverage-verify: install-coverage + @echo "This target verifies the latest coverage result against COV_FAIL_UNDER. However, only on CI the merged coverage from all Python versions and platforms is considered." + pdm run coverage report --precision 2 --fail-under ${COV_FAIL_UNDER} + +coverage-report: install-coverage + pdm run coverage combine $(wildcard .coverage.*) + pdm run coverage xml + # the following sed hack ensures that coverage.xml is parsed correctly by GitLab + # [tool.coverage.run] relative_files=true breaks GitLab's automatic path correction otherwise + # see here: https://docs.gitlab.com/ee/ci/testing/test_coverage_visualization.html#automatic-class-path-correction + sed -iE "s%<source>\(.*\)</source>%<source>${CI_PROJECT_DIR}/\1</source>%" coverage.xml + pdm run coverage html --precision 2 + pdm run coverage report --precision 2 + +release: + pdm publish --username ${ARTIFACTORY_USER} --password ${ARTIFACTORY_PASSWORD} --repository ${PYPI_REPOSITORY} --no-build + +clean: + @$(foreach path, $(call rwildcard, *, *.py[co]), $(call rm_if_exist, ${path})) + @$(foreach path, $(call rwildcard, *, *__pycache__), $(call rm_if_exist, ${path})) + @$(call rm_if_exist, __pypackages__) + @$(call rm_if_exist, dist) + @$(call rm_if_exist, report.xml) + @$(call rm_if_exist, htmlcov) + @$(call rm_if_exist, .pdm.toml) + @$(call rm_if_exist, .pypy_cache) + @$(call rm_if_exist, .pytest_cache) + @$(call rm_if_exist, .mypy_cache) + @$(call rm_if_exist, .coverage) + @$(call rm_if_exist, .venv) + @$(call rm_if_exist, .tox) diff --git a/VAF/python3-makefile/ruff.toml b/VAF/python3-makefile/ruff.toml new file mode 100644 index 0000000..1d0ec25 --- /dev/null +++ b/VAF/python3-makefile/ruff.toml @@ -0,0 +1,19 @@ +src = ["../src", "../tests"] +line-length = 120 +include = ["../src/**/*.py", "../tests/**/*.py"] + + +[lint] +ignore = [ + "PTH123", # replacing open with Path.open is not really idiomatic +] +extend-select = [ + "I", # isort + "PTH", # path +] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] + +[lint.pydocstyle] +convention = "google" diff --git a/VAF/src/vaf/__init__.py b/VAF/src/vaf/__init__.py new file mode 100644 index 0000000..d35fa1b --- /dev/null +++ b/VAF/src/vaf/__init__.py @@ -0,0 +1,11 @@ +# ruff: noqa: F401 +"""Initialize the module. + +Could be used to define the public interface of the module. +""" + +# TODO: Import modules and objects that belong to the public interface # pylint: disable=W0511 +from vaf.cli_core.common.exceptions import VafProjectTemplateError + +# VAFPY is accessable through VAFCLI +from vaf.vafpy import * # noqa: F403 diff --git a/VAF/src/vaf/__main__.py b/VAF/src/vaf/__main__.py new file mode 100644 index 0000000..c4dbd46 --- /dev/null +++ b/VAF/src/vaf/__main__.py @@ -0,0 +1,113 @@ +"""Initialize the module. +Could be used to define the public interface of the module. +CLI Function with the click module: e.g. "vaf version --help" +""" + +# Python Standard Library imports +import warnings +from importlib import metadata + +# External imports +import click + +# Internal imports +from vaf.cli_core.bootstrap.cli_subcommands.project_subcmd import project_init +from vaf.cli_core.bootstrap.cli_subcommands.workspace_subcmd import workspace_init +from vaf.cli_core.common.click_help import CLICK_CONTEXT_SETTINGS, CustomHelpGroup, simple_user_warning +from vaf.cli_core.main.cli_subcommands.make_subcmd import make_build, make_clean, make_install, make_preset +from vaf.cli_core.main.cli_subcommands.model_subcmd import model_generate, model_import, model_update +from vaf.cli_core.main.cli_subcommands.project_subcmd import ( + project_create, + project_generate, + project_import, + project_remove, +) + +# Define pip package name +PACKAGE_NAME = "vaf" + + +# Static function to identify the pip package version. +def get_version() -> str: + """Get the installed version of this pip package. + + Returns: + str: Version of this pip package. + """ + return metadata.version(PACKAGE_NAME) + + +# Switch to simple user warning message without stack trace or file info. +warnings.formatwarning = simple_user_warning + + +@click.group( + context_settings=CLICK_CONTEXT_SETTINGS, + help=f"This is the Vehicle Application Framework command-line interface (vaf-cli) version {get_version()}.", + cls=CustomHelpGroup, +) +@click.version_option(get_version(), "-v", "--version", message="%(prog)s version %(version)s") +def cli() -> None: + """This function is the entrypoint for the click arguments cli.""" + + +# Command 'project' +@cli.group() +def project() -> None: + """Project-related commands.""" + + +# vaf project init # +project.add_command(name="init", cmd=project_init) +# vaf project create # +project.add_command(name="create", cmd=project_create) +# vaf project generate # +project.command(name="generate")(project_generate) +# vaf project import # +project.command(name="import")(project_import) +# vaf project remove # +project.add_command(name="remove", cmd=project_remove) + + +# Command 'model' +@cli.group() +def model() -> None: + """Model-related commands.""" + + +# vaf model import # +model.add_command(name="import", cmd=model_import) +# vaf model update # +model.command(name="update")(model_update) +# vaf model generate # +model.command(name="generate")(model_generate) + + +# Command 'make' +@cli.group() +def make() -> None: + """Make-related commands.""" + + +# vaf make preset # +make.command(name="preset")(make_preset) +# vaf make build # +make.command(name="build")(make_build) +# vaf make install # +make.command(name="install")(make_install) +# vaf make clean # +make.command(name="clean")(make_clean) + + +# Command 'workspace' +@cli.group() +def workspace() -> None: + """Workspace-related commands.""" + + +# vaf project init # +workspace.command(name="init")(workspace_init) + + +if __name__ == "__main__": # pragma: no cover + cli() # pylint: disable=no-value-for-parameter diff --git a/VAF/src/vaf/__main_bootstrap__.py b/VAF/src/vaf/__main_bootstrap__.py new file mode 100644 index 0000000..997d212 --- /dev/null +++ b/VAF/src/vaf/__main_bootstrap__.py @@ -0,0 +1,67 @@ +"""Initialize the module. +Could be used to define the public interface of the module. +CLI Function with the click module: e.g. "vaf version --help" +""" + +# Python Standard Library imports +import warnings +from importlib import metadata + +# External imports +import click + +# Internal imports +from vaf.cli_core.bootstrap.cli_subcommands.project_subcmd import project_init +from vaf.cli_core.bootstrap.cli_subcommands.workspace_subcmd import workspace_init +from vaf.cli_core.common.click_help import CLICK_CONTEXT_SETTINGS, CustomHelpGroup, simple_user_warning + +# Define pip package name +PACKAGE_NAME = "vaf-bootstrap" + + +# Static function to identify the pip package version. +def get_version() -> str: + """Get the installed version of this pip package. + + Returns: + str: Version of this pip package. + """ + return metadata.version(PACKAGE_NAME) + + +# Switch to simple user warning message without stack trace or file info. +warnings.formatwarning = simple_user_warning + + +@click.group( + context_settings=CLICK_CONTEXT_SETTINGS, + help=f"This is the Vehicle Application Framework command-line interface (vaf-cli) version {get_version()}.", + cls=CustomHelpGroup, +) +@click.version_option(get_version(), "-v", "--version", message="%(prog)s version %(version)s") +def cli() -> None: + """This function is the entrypoint for the click arguments cli.""" + + +# Command 'project' +@cli.group() +def project() -> None: + """Project-related commands.""" + + +# vaf project init # +project.add_command(name="init", cmd=project_init) + + +# Command 'workspace' +@cli.group() +def workspace() -> None: + """Workspace-related commands.""" + + +# vaf workspace init # +workspace.command(name="init")(workspace_init) + + +if __name__ == "__main__": # pragma: no cover + cli() # pylint: disable=no-value-for-parameter diff --git a/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/project_subcmd.py b/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/project_subcmd.py new file mode 100644 index 0000000..7edddb0 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/project_subcmd.py @@ -0,0 +1,102 @@ +"""Source code for vaf project init subcommand""" + +import click + +from vaf.cli_core.bootstrap.project_init_cmd import ProjectInitCmd +from vaf.cli_core.common.click_extension import filepath_option, sanatized_str_option + + +# vaf project init group # +@click.group() +def project_init() -> None: + """Initiate a project of chosen VAF project type and template.""" + + +# vaf project init integration # +@project_init.command(name="integration") +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="Name of the project.", prompt="Enter your project name" +) +@filepath_option( + "-p", + "--project-dir", + type=click.Path(exists=False, writable=True, file_okay=False), + default=".", + required=True, + help="Path to output directory.", + prompt="Enter the directory to store your project in", +) +@click.option( + "-t", + "--template", + type=click.Path(file_okay=False), + default="", + help="Path to template directory.", +) +@click.option( + "--skip-git-init", + is_flag=True, + help="Skip initialization of an empty git repository and introduction of a .gitignore file", +) +def integration_project_init(name: str, project_dir: str, template: str, skip_git_init: bool) -> None: # pylint: disable=missing-param-doc + """Creates a VAF integration project from the given template.""" + cmd = ProjectInitCmd() + cmd.integration_project_init(name, project_dir, template, not skip_git_init) + + +# vaf interface project init # +@project_init.command(name="interface") +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="Name of the project.", prompt="Enter your project name" +) +@filepath_option( + "-p", + "--project-dir", + type=click.Path(exists=False, writable=True, file_okay=False), + required=True, + help="Path to output directory.", + default=".", + prompt="Enter the directory to store your project in", +) +@click.option( + "--skip-git-init", + is_flag=True, + help="Skip initialization of an empty git repository and introduction of a .gitignore file", +) +def interface_project_init(name: str, project_dir: str, skip_git_init: bool) -> None: # pylint: disable=missing-param-doc + """Creates a VAF interface project from the given template.""" + cmd = ProjectInitCmd() + cmd.interface_project_init(name, project_dir, not skip_git_init) + + +# vaf app module project init # +@project_init.command(name="app-module") +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="App-module name", prompt="Enter the name of the app-module" +) +@click.option( + "--namespace", + type=str, + required=True, + help="App-module namespace.", + prompt="Enter the namespace of the app-module", +) +@filepath_option( + "-p", + "--project-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + required=True, + help="Path to the output directory.", + default=".", + prompt="Enter the path to the output root directory", +) +@click.option( + "--skip-git-init", + is_flag=True, + help="Skip initialization of an empty git repository and introduction of a .gitignore file", +) +def app_module_project_init(namespace: str, name: str, project_dir: str, skip_git_init: bool) -> None: # pylint: disable=missing-param-doc + """Creates a VAF app-module project from the given template.""" + click.echo(f"Init app-module {namespace}::{name} project.") + cmd = ProjectInitCmd() + cmd.app_module_project_init(namespace, name, project_dir, not skip_git_init) diff --git a/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/workspace_subcmd.py b/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/workspace_subcmd.py new file mode 100644 index 0000000..797f5e1 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/cli_subcommands/workspace_subcmd.py @@ -0,0 +1,32 @@ +"""Source code for vaf workspace subcommands""" + +import click + +from vaf.cli_core.bootstrap.workspace_cmd import WorkspaceCmd +from vaf.cli_core.common.click_extension import filepath_option, sanatized_str_option + + +# vaf workspace init # +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="Name of the workspace.", prompt="Enter your workspace name" +) +@filepath_option( + "-w", + "--workspace-dir", + type=click.Path(exists=False, writable=True, file_okay=False), + default=".", + required=True, + help="Path to directory where the workspace is to be created.", + prompt="Enter the directory to store your workspace in", +) +@click.option( + "-m", + "--mount", + type=click.Path(exists=True, file_okay=False, readable=True), + multiple=True, + help="Mount a directory into the DevContainer. Can be specified multiple times.", +) +def workspace_init(name: str, workspace_dir: str, mount: tuple[str, ...]) -> None: # pylint: disable=missing-param-doc + """Initiate a VAF workspace with devcontainer and VS Code settings.""" + cmd = WorkspaceCmd() + cmd.init(name, workspace_dir, mount) diff --git a/VAF/src/vaf/cli_core/bootstrap/project_init_cmd.py b/VAF/src/vaf/cli_core/bootstrap/project_init_cmd.py new file mode 100644 index 0000000..a1c0e24 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/project_init_cmd.py @@ -0,0 +1,196 @@ +""" +Implements the functionality of project init related commands +""" + +import json +import subprocess +from pathlib import Path + +from copier import run_copy + +from vaf.cli_core.common.utils import ( + ProjectType, + get_project_type, + get_projects_in_path, + to_snake_case, +) +from vaf.constants import VAF_CFG_FILE + +from ..common.exceptions import VafProjectGenerationError, VafProjectTemplateError + + +class ProjectInitCmd: + """Class implementing related project init commands""" + + def __init__(self, verbose_mode: bool = False) -> None: + """ + Ctor for CmdProject class + Args: + verbose_mode (bool): Flag to enable verbose mode. + """ + self.verbose_mode = verbose_mode + + def _init_git_repository(self, output_dir: str) -> None: + git_init_path = Path(output_dir).resolve() + print(f"Initializing git repository in {git_init_path}") + try: + subprocess.run(["git", "init", "--initial-branch=main", git_init_path], check=True) + subprocess.run(["git", "-C", git_init_path, "add", "."], check=True) + print("Git repository initialized with 'main' branch.") + except subprocess.CalledProcessError as e: + print(f"Error initializing git repository: {e}") + + def _update_project_paths_in_ws(self, ws_path: Path) -> None: + file_path = ws_path / ".vscode" / "settings.json" + + with open(file_path, "r", encoding="utf-8") as file: + data = json.load(file) + + source_dirs = set() + for pr_path, pr_type in get_projects_in_path(ws_path): + if pr_type == ProjectType.INTEGRATION: + # add nested app-modules + for nested_path, _ in get_projects_in_path(pr_path): + source_dirs.add(f"${{workspaceFolder}}/{nested_path.resolve().relative_to(ws_path).as_posix()}") + source_dirs.add(f"${{workspaceFolder}}/{pr_path.relative_to(ws_path).as_posix()}") + + data["cmake.sourceDirectory"] = sorted(source_dirs) + + with open(file_path, "w", encoding="utf-8") as file: + json.dump(data, file, indent=4) + + def integration_project_init( # pylint: disable=too-many-arguments, too-many-positional-arguments + self, name: str, project_dir: str, template: str = "", git: bool = False + ) -> None: + """ + Args: + name (str): The name of the project to create. + project_dir (str): Path to the output directory. + template (str): Project template to be used. + git (bool): Flag to indicate if a git repository must be initialized. + + Raises: + VafProjectTemplateError: In cases of project template errors. + """ + + if template is None or template == "": + pwd = Path(__file__).resolve().parent + template = str(pwd / "templates" / "project" / "default") + else: + if not Path(template).is_dir(): + raise VafProjectTemplateError("Project template not found.") + + # Validate the minimal requirements on templates + self._validate_vaf_config(template) + + print(f"Create Integration Project {name} in {Path(project_dir).absolute()} using template {template}") + run_copy( + template, + project_dir, + data={ + "project_name": name, + "project_name_snk": to_snake_case(name), + }, + ) + + project_dir = str(Path(project_dir) / name) + if git: + self._init_git_repository(project_dir) + + # Check if project is generated inside of a workspace + if get_project_type() == ProjectType.WORKSPACE and Path(project_dir).absolute().is_relative_to(Path.cwd()): + self._update_project_paths_in_ws(Path.cwd()) + + def interface_project_init(self, name: str, project_dir: str, git: bool = False) -> None: + """ + Args: + name (str): The name of the project to create. + project_dir (str): Path to the output directory. + git (bool): Flag to indicate if a git repository must be initialized. + + Raises: + VafProjectTemplateError: In cases of project template errors. + """ + pwd = Path(__file__).resolve().parent + template = str(pwd / "templates" / "interface_project") + + print(f"Create Interface Project {name} in {Path(project_dir).absolute()}") + run_copy( + template, + project_dir, + data={ + "project_name": name, + "project_name_snk": to_snake_case(name), + "export_path": "export", + "export_name": name, + "base_file_name": name, + "output_path": "export", + }, + ) + + if git: + project_dir = str(Path(project_dir) / name) + self._init_git_repository(project_dir) + + def app_module_project_init( # pylint: disable=too-many-arguments, too-many-locals, too-many-statements, too-many-positional-arguments + self, namespace: str, name: str, project_dir: str, git: bool = False + ) -> None: + """ + Args: + namespace: Namespace of the newly created app-module. + name: Name of the newly created app-module. + project_dir: Root path of the integration project. + git (bool): Flag to indicate if a git repository must be initialized. + + Raises: + VafProjectGenerationError: If there is a system-related error during init. + ValueError: If the name of the app module to be created contains "-". + """ + if "-" in name: + raise ValueError(f'The name {name} of the application module must not contain "-".') + + # check if application module already exists + full_app_module_dir: Path = Path(project_dir + to_snake_case(name)) + if full_app_module_dir.exists(): + raise VafProjectGenerationError("Application module already exists on specified location!") + app_module_dir: Path = Path(project_dir) + + app_module_dir.mkdir(parents=True, exist_ok=True) + pwd = Path(__file__).resolve().parent + template = str(pwd / "templates" / "application_module") + + run_copy( + template, + app_module_dir, + data={ + "module_namespace": namespace, + "module_name": name, + "module_name_snk": to_snake_case(name), + "module_dir_name": name, + }, + ) + + project_dir = str(Path(project_dir) / name) + if git: + self._init_git_repository(project_dir) + + # Check if project is generated inside of a workspace + if get_project_type() == ProjectType.WORKSPACE and Path(project_dir).absolute().is_relative_to(Path.cwd()): + self._update_project_paths_in_ws(Path.cwd()) + + def _validate_vaf_config(self, template: str) -> None: + """ + Validates the VAF_CFG_FILE within the template directory if any. + + Args: + template (str): Project template to be validated. + """ + expected_vafconfig = Path(template) / VAF_CFG_FILE + + if not expected_vafconfig.is_file(): + raise VafProjectTemplateError( + f""" + Template does not have a {VAF_CFG_FILE}. + Please refer to the documentation on how to create a valid {VAF_CFG_FILE} + """ + ) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-format b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-format new file mode 100644 index 0000000..eb8b70a --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-format @@ -0,0 +1,89 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ (IWYU pragma:|VECTOR (SL|NL|NC|Same Line|Next Line|Next Construct)|COV_|VCA_)|\\(trace|copydoc)[ ]+[^ ]' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-tidy b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-tidy new file mode 100644 index 0000000..a6d7c58 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clang-tidy @@ -0,0 +1,97 @@ +--- +Checks: > + -*, + clang-diagnostic-*, + clang-analyzer-*, + vector-*, + readability-*, + bugprone-*, + modernize-*, + performance-*, + cert-*, + cppcoreguidelines-*, + hicpp-*, + portability-*, + -readability-uppercase-literal-suffix, + -cert-dcl16-c, + -hicpp-uppercase-literal-suffix, + -readability-named-parameter, + -hicpp-named-parameter, + -readability-redundant-member-init, + -readability-make-member-function-const, + -modernize-concat-nested-namespaces, + -modernize-use-trailing-return-type, + +FormatStyle: file + +# warnings are NOT treated as errors +WarningsAsErrors: "" + +# analyze all included headers (not system-headers) +HeaderFilterRegex: ".*" + +CheckOptions: + ########## readability-identifier-naming ######### + # Class, structs, enums and unions + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } # redundant with ClassCase + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + + # Functions and methods (all are treated equally, only FunctionCase needed) + - { key: readability-identifier-naming.FunctionCase, value: CamelCase } + + # Non-static and static non-const variables and pointers + - { key: readability-identifier-naming.VariableCase, value: lower_case } + + # static, global or constexpr constant variables + - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } + - { key: readability-identifier-naming.StaticConstantPrefix, value: k } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantPrefix, value: k } + - { + key: readability-identifier-naming.ConstexprVariableCase, + value: CamelCase, + } + - { key: readability-identifier-naming.ConstexprVariablePrefix, value: k } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantPrefix, value: k } + + # Class / Struct data members (including static members) + - { key: readability-identifier-naming.MemberCase, value: lower_case } + - { key: readability-identifier-naming.MemberSuffix, value: _ } + - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } + - { key: readability-identifier-naming.PublicMemberCase, value: lower_case } # public members dont require trailing _ + + # Parameters + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + + # Templates + - { + key: readability-identifier-naming.TemplateParameterCase, + value: CamelCase, + } + - { + key: readability-identifier-naming.ValueTemplateParameterCase, + value: aNy_CasE, + } # not clearly specified + + # Miscellaneous + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { + key: readability-identifier-naming.MacroDefinitionCase, + value: UPPER_CASE, + } + - { + key: readability-identifier-naming.MacroDefinitionIgnoredRegexp, + value: .*_H_, + } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + + ########## End of readability-identifier-naming ########## + + - { key: vector-noexcept-special-functions.FunctionsToInclude, value: "Swap" } + - { key: hicpp-move-const-arg.CheckTriviallyCopyableMove, value: false } + - { key: performance-move-const-arg.CheckTriviallyCopyableMove, value: false } diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clangd b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clangd new file mode 100644 index 0000000..21e5abb --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.clangd @@ -0,0 +1,10 @@ +CompileFlags: + CompilationDatabase: ./build + Add: + - -I/usr/include/c++/12 + - -I/usr/include/x86_64-linux-gnu/c++/12 + - -I/usr/include/c++/12/backward + - -I/usr/lib/gcc/x86_64-linux-gnu/12/include + - -I/usr/local/include + - -I/usr/include/x86_64-linux-gnu + - -I/usr/include diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc11__x86_64-pc-linux-elf b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc11__x86_64-pc-linux-elf new file mode 100644 index 0000000..ea4945b --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc11__x86_64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=x86_64 +compiler=gcc +compiler.version=11 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-11 +CXX=g++-11 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc12__x86_64-pc-linux-elf b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc12__x86_64-pc-linux-elf new file mode 100644 index 0000000..fe1b560 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.conan/gcc12__x86_64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=x86_64 +compiler=gcc +compiler.version=12 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-12 +CXX=g++-12 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.gitignore b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.gitignore new file mode 100644 index 0000000..380b76a --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.gitignore @@ -0,0 +1,15 @@ +.cache +build +CMakeUserPresets.json +compile_commands.json +.idea +.rake_tasks~ +external/vaf-generator/common +implementation/**/*.h~ +implementation/**/*.cpp~ +src-gen +__pycache__/ +*.pyc +.env +.vscode/ +.DS_Store diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.vafconfig.json b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.vafconfig.json new file mode 100644 index 0000000..cb57304 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/.vafconfig.json @@ -0,0 +1,8 @@ +{ + "version": "0.1.0", + "vaf-artifacts": { + "vaf-output": ".", + "vaf-init-model": "model" + }, + "project-type": "application-module-project" +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/CMakeLists.txt.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/CMakeLists.txt.jinja new file mode 100644 index 0000000..fa40746 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/CMakeLists.txt.jinja @@ -0,0 +1,47 @@ +option(VAF_STAND_ALONE_BUILD "Do you want to build the application module stand alone?" TRUE) +option(VAF_BUILD_TESTS "Enable unit and integration tests for this VAF project" ON) + +if(VAF_STAND_ALONE_BUILD) + + cmake_minimum_required(VERSION 3.25) + + project({{module_name}}) + + find_package(Threads) + find_package(vafcpp REQUIRED) + + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") + endif() + + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + + set(CMAKE_INSTALL_PREFIX + "${CMAKE_BINARY_DIR}/install" + CACHE PATH "install prefix" FORCE) + + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + + if(VAF_BUILD_TESTS) + # This include needs to be run before any add_subdirectories that include tests + include(CTest) + add_subdirectory(test-gen) + endif() + + add_subdirectory(implementation) + add_subdirectory(src-gen) + + execute_process( + COMMAND + ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_BINARY_DIR}/compile_commands.json + ${CMAKE_BINARY_DIR}/../compile_commands.json) + +else() + + add_subdirectory(implementation) + +endif() diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/README.md.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/README.md.jinja new file mode 100644 index 0000000..b81f975 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/README.md.jinja @@ -0,0 +1,44 @@ +# {{module_name}} + +This is a VAF application module project: {{module_name}} +An application module project can do the following: + +Import model artifacts from a catalogue according to the COVESA VSS: +``` bash +vaf model import vss +``` + +Update the existing model artifacts (from related interface projects): +``` bash +vaf model update +``` + +Import from an existing interface project: +``` bash +vaf project import +``` + +Generate code based on the configuration and preset the build dependencies: +``` bash +vaf project generate +``` + +Optionally, preset the build dependencies manually: +``` bash +vaf make preset +``` + +Build the project: +``` bash +vaf make build +``` + +Install the built files to a target location: +``` bash +vaf make install +``` + +Clean up the build folder: +``` bash +vaf make clean +``` diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/conanfile.py b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/conanfile.py new file mode 100644 index 0000000..d2fe863 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/conanfile.py @@ -0,0 +1,20 @@ +from pathlib import Path + +from conan import ConanFile +from conan.tools.cmake import cmake_layout +from conan.tools.files import load + + +class VafRecipe(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps", "CMakeToolchain" + + def requirements(self): + self.requires("vafcpp/0.6.0") + self.requires("gtest/1.13.0") + + for dependency in load(self, Path(__file__).resolve().parent / "src-gen" / "conan_deps.list").splitlines(): + self.requires(dependency) + + def layout(self): + cmake_layout(self) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/implementation/CMakeLists.txt b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/implementation/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.json.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.json.jinja new file mode 100644 index 0000000..2b3a6a2 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.json.jinja @@ -0,0 +1,19 @@ +{ + "ApplicationModules": [ + { + "Name": "{{module_name}}", + "Namespace": "{{module_namespace}}", + "ConsumedInterfaces": [], + "ProvidedInterfaces": [], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.py.jinja new file mode 100644 index 0000000..5d31783 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/model.py.jinja @@ -0,0 +1,19 @@ +from pathlib import Path + +from vaf.cli_core.common.utils import ProjectType +from vaf import save_part_of_main_model + +# Import the application module model +from . import {{module_name_snk}} + +def export_model(): + script_path = Path(__file__).resolve().parent + save_part_of_main_model( + script_path / "model.json", + ["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], + project_type=ProjectType.APP_MODULE, + cleanup=True, + ) + +if __name__ == "__main__": + export_model() diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/{{module_name_snk}}.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/{{module_name_snk}}.py.jinja new file mode 100644 index 0000000..a15517d --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/model/{{module_name_snk}}.py.jinja @@ -0,0 +1,12 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +# TODO: Import the CaC support from platform derive or interface import +# from .imported_models import * + +{{ module_name_snk }} = vafpy.ApplicationModule(name="{{ module_name }}", namespace="{{ module_namespace }}") +# TODO: Add consumed and provided interfaces using the ApplicationModule API +# e.g. {{ module_name_snk }}.add_consumed_interface(instance_name="AccelerationProvider", interface=Acceleration) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +{{ module_name_snk }}.add_task(task=periodic_task) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/test-gen/CMakeLists.txt b/VAF/src/vaf/cli_core/bootstrap/templates/application_module/{{module_dir_name}}/test-gen/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.gitignore b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.gitignore new file mode 100644 index 0000000..380b76a --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.gitignore @@ -0,0 +1,15 @@ +.cache +build +CMakeUserPresets.json +compile_commands.json +.idea +.rake_tasks~ +external/vaf-generator/common +implementation/**/*.h~ +implementation/**/*.cpp~ +src-gen +__pycache__/ +*.pyc +.env +.vscode/ +.DS_Store diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.vafconfig.json b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.vafconfig.json new file mode 100644 index 0000000..f207fef --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/.vafconfig.json @@ -0,0 +1,8 @@ +{ + "version": "0.1.0", + "vaf-artifacts": { + "vaf-output": ".", + "vaf-init-model": "." + }, + "project-type": "interface-project" +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/README.md.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/README.md.jinja new file mode 100644 index 0000000..5a44dc1 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/README.md.jinja @@ -0,0 +1,15 @@ +# {{project_name}} + +This is a VAF interface project: {{project_name}} +An interface project can do the following: + +Import model artifacts from a catalogue according to the COVESA VSS: +``` bash +vaf model import vss +``` + +Configure the project in the {{project_name_snk}}.py file and generate the database in JSON format +using VAF CaC (Configuration as Code) support: +``` bash +vaf model generate +``` diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/model.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/model.py.jinja new file mode 100644 index 0000000..9265a12 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/model.py.jinja @@ -0,0 +1,22 @@ +from pathlib import Path + +from vaf import save_part_of_main_model +from vaf.vafgeneration import generate_cac_support +from vaf.cli_core.common.utils import ProjectType + +# Import the interface project model +from . import {{ project_name_snk }} + +def export_model(): + script_path = Path(__file__).resolve().parent + export_path = script_path / "{{export_path}}" + export_path.mkdir(parents=True, exist_ok=True) + save_part_of_main_model( + export_path / "{{export_name}}.json", + ["DataTypeDefinitions", "ModuleInterfaces"], + project_type=ProjectType.INTERFACE, + ) + generate_cac_support(export_path, "{{export_name}}.json", "{{base_file_name}}", script_path / "{{output_path}}", ProjectType.INTERFACE) + +if __name__ == "__main__": + export_model() diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/{{project_name_snk}}.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/{{project_name_snk}}.py.jinja new file mode 100644 index 0000000..8c83048 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/interface_project/{{project_name}}/{{project_name_snk}}.py.jinja @@ -0,0 +1,15 @@ +from vaf import BaseTypes, vafpy + +# TODO: Import the CaC support from platform derive or catalogue import +# from .vss import * + +# TODO: Extend with own datatype and interface definitions +# object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="demo") +# object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +# object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +# object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +# od_list = vafpy.datatypes.Vector(name="ObjectDetectionList", namespace="demo", datatype=object_detection) + +# od_list_interface = vafpy.ModuleInterface(name="ObjectDetectionListInterface", namespace="demo") +# od_list_interface.add_data_element(name="object_detection_list", datatype=od_list) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-format b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-format new file mode 100644 index 0000000..eb8b70a --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-format @@ -0,0 +1,89 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ (IWYU pragma:|VECTOR (SL|NL|NC|Same Line|Next Line|Next Construct)|COV_|VCA_)|\\(trace|copydoc)[ ]+[^ ]' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-tidy b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-tidy new file mode 100644 index 0000000..a6d7c58 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clang-tidy @@ -0,0 +1,97 @@ +--- +Checks: > + -*, + clang-diagnostic-*, + clang-analyzer-*, + vector-*, + readability-*, + bugprone-*, + modernize-*, + performance-*, + cert-*, + cppcoreguidelines-*, + hicpp-*, + portability-*, + -readability-uppercase-literal-suffix, + -cert-dcl16-c, + -hicpp-uppercase-literal-suffix, + -readability-named-parameter, + -hicpp-named-parameter, + -readability-redundant-member-init, + -readability-make-member-function-const, + -modernize-concat-nested-namespaces, + -modernize-use-trailing-return-type, + +FormatStyle: file + +# warnings are NOT treated as errors +WarningsAsErrors: "" + +# analyze all included headers (not system-headers) +HeaderFilterRegex: ".*" + +CheckOptions: + ########## readability-identifier-naming ######### + # Class, structs, enums and unions + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } # redundant with ClassCase + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + + # Functions and methods (all are treated equally, only FunctionCase needed) + - { key: readability-identifier-naming.FunctionCase, value: CamelCase } + + # Non-static and static non-const variables and pointers + - { key: readability-identifier-naming.VariableCase, value: lower_case } + + # static, global or constexpr constant variables + - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } + - { key: readability-identifier-naming.StaticConstantPrefix, value: k } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantPrefix, value: k } + - { + key: readability-identifier-naming.ConstexprVariableCase, + value: CamelCase, + } + - { key: readability-identifier-naming.ConstexprVariablePrefix, value: k } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantPrefix, value: k } + + # Class / Struct data members (including static members) + - { key: readability-identifier-naming.MemberCase, value: lower_case } + - { key: readability-identifier-naming.MemberSuffix, value: _ } + - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } + - { key: readability-identifier-naming.PublicMemberCase, value: lower_case } # public members dont require trailing _ + + # Parameters + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + + # Templates + - { + key: readability-identifier-naming.TemplateParameterCase, + value: CamelCase, + } + - { + key: readability-identifier-naming.ValueTemplateParameterCase, + value: aNy_CasE, + } # not clearly specified + + # Miscellaneous + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { + key: readability-identifier-naming.MacroDefinitionCase, + value: UPPER_CASE, + } + - { + key: readability-identifier-naming.MacroDefinitionIgnoredRegexp, + value: .*_H_, + } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + + ########## End of readability-identifier-naming ########## + + - { key: vector-noexcept-special-functions.FunctionsToInclude, value: "Swap" } + - { key: hicpp-move-const-arg.CheckTriviallyCopyableMove, value: false } + - { key: performance-move-const-arg.CheckTriviallyCopyableMove, value: false } diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clangd b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clangd new file mode 100644 index 0000000..21e5abb --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.clangd @@ -0,0 +1,10 @@ +CompileFlags: + CompilationDatabase: ./build + Add: + - -I/usr/include/c++/12 + - -I/usr/include/x86_64-linux-gnu/c++/12 + - -I/usr/include/c++/12/backward + - -I/usr/lib/gcc/x86_64-linux-gnu/12/include + - -I/usr/local/include + - -I/usr/include/x86_64-linux-gnu + - -I/usr/include diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc11__x86_64-pc-linux-elf b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc11__x86_64-pc-linux-elf new file mode 100644 index 0000000..ea4945b --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc11__x86_64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=x86_64 +compiler=gcc +compiler.version=11 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-11 +CXX=g++-11 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc12__x86_64-pc-linux-elf b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc12__x86_64-pc-linux-elf new file mode 100644 index 0000000..fe1b560 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.conan/gcc12__x86_64-pc-linux-elf @@ -0,0 +1,13 @@ +[settings] +arch=x86_64 +compiler=gcc +compiler.version=12 +compiler.cppstd=17 +compiler.libcxx=libstdc++11 +os=Linux + +[options] + +[buildenv] +CC=gcc-12 +CXX=g++-12 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.gitignore b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.gitignore new file mode 100644 index 0000000..380b76a --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.gitignore @@ -0,0 +1,15 @@ +.cache +build +CMakeUserPresets.json +compile_commands.json +.idea +.rake_tasks~ +external/vaf-generator/common +implementation/**/*.h~ +implementation/**/*.cpp~ +src-gen +__pycache__/ +*.pyc +.env +.vscode/ +.DS_Store diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.vafconfig.json b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.vafconfig.json new file mode 100644 index 0000000..ad8ab96 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/.vafconfig.json @@ -0,0 +1,8 @@ +{ + "version": "0.1.0", + "vaf-artifacts": { + "vaf-output": ".", + "vaf-init-model": "model/vaf" + }, + "project-type": "integration-project" +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/CMakeLists.txt.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/CMakeLists.txt.jinja new file mode 100644 index 0000000..cb60396 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/CMakeLists.txt.jinja @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.25) + +project({{project_name}}) + +option(VAF_BUILD_TESTS "Enable unit and integration tests for this VAF project" ON) + +find_package(Threads) +find_package(vafcpp REQUIRED) + +find_program(CCACHE_PROGRAM ccache) +if(CCACHE_PROGRAM) + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") +endif() + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +set(CMAKE_INSTALL_PREFIX + "${CMAKE_BINARY_DIR}/install" + CACHE PATH "install prefix" FORCE) + + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +option(VAF_STAND_ALONE_BUILD "Do you want to build the application module stand alone?" FALSE) + +# Workaround for statically linked SilKit +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") + +if(VAF_BUILD_TESTS) + # This include needs to be run before any add_subdirectories that include tests + include(CTest) + add_subdirectory(test-gen) +endif() + +add_subdirectory(src) +add_subdirectory(src-gen) + +execute_process( +COMMAND + ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_BINARY_DIR}/compile_commands.json + ${CMAKE_BINARY_DIR}/../compile_commands.json) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/README.md.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/README.md.jinja new file mode 100644 index 0000000..c220360 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/README.md.jinja @@ -0,0 +1,52 @@ +# {{project_name}} + +This is a VAF integration project: {{project_name}} +An integration project can do the following: + +Import model artifacts from a catalogue according to the COVESA VSS: +``` bash +vaf model import vss +``` + +Update the existing model artifacts (from related app-module projects): +``` bash +vaf model update +``` + +Create a new or import an existing application module: +``` bash +vaf project create app-module +``` +``` bash +vaf project import +``` + +Remove an existing application module from the project: +``` bash +vaf project remove app-module +``` + +Generate code based on the configuration and preset the build dependencies: +``` bash +vaf project generate +``` + +Optionally, preset the build dependencies manually: +``` bash +vaf make preset +``` + +Build the code: +``` bash +vaf make build +``` + +Install the built files to a target location: +``` bash +vaf make install +``` + +Clean the build folder: +``` bash +vaf make clean +``` diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/cmake/FindSilKit.cmake b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/cmake/FindSilKit.cmake new file mode 100644 index 0000000..69cc1e6 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/cmake/FindSilKit.cmake @@ -0,0 +1,51 @@ +# Workaround for statically linked SilKit + +# Locate the spdlog library +find_library(SPDLOG_LIBRARY + NAMES spdlog + PATHS /usr/local/lib + NO_DEFAULT_PATH +) + +# Locate the yaml-cpp library +find_library(YAML_CPP_LIBRARY + NAMES yaml-cpp + PATHS /usr/local/lib + NO_DEFAULT_PATH +) + +# Locate the SilKit library +find_library(SILKIT_LIBRARY + NAMES SilKit + PATHS /usr/local/lib + NO_DEFAULT_PATH +) + +# Set the imported targets +if(SPDLOG_LIBRARY AND YAML_CPP_LIBRARY AND SILKIT_LIBRARY) + add_library(spdlog STATIC IMPORTED) + set_property(TARGET spdlog PROPERTY IMPORTED_LOCATION ${SPDLOG_LIBRARY}) + + add_library(yaml_cpp STATIC IMPORTED) + set_property(TARGET yaml_cpp PROPERTY IMPORTED_LOCATION ${YAML_CPP_LIBRARY}) + + add_library(SilKit::SilKit STATIC IMPORTED) + set_property(TARGET SilKit::SilKit PROPERTY IMPORTED_LOCATION ${SILKIT_LIBRARY}) + + target_link_libraries(SilKit::SilKit INTERFACE yaml_cpp spdlog) +else() + if(NOT SilKit_FIND_QUIETLY) + if(NOT SPDLOG_LIBRARY) + message(WARNING "SilKit dependency spdlog library not found") + endif() + if(NOT YAML_CPP_LIBRARY) + message(WARNING "SilKit dependency yaml-cpp library not found") + endif() + if(NOT SILKIT_LIBRARY) + message(WARNING "SilKit library not found") + endif() + endif() + if(SilKit_FIND_REQUIRED) + message(FATAL_ERROR "SilKit or dependencies not found") + endif() +endif() diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/conanfile.py b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/conanfile.py new file mode 100644 index 0000000..d2fe863 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/conanfile.py @@ -0,0 +1,20 @@ +from pathlib import Path + +from conan import ConanFile +from conan.tools.cmake import cmake_layout +from conan.tools.files import load + + +class VafRecipe(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps", "CMakeToolchain" + + def requirements(self): + self.requires("vafcpp/0.6.0") + self.requires("gtest/1.13.0") + + for dependency in load(self, Path(__file__).resolve().parent / "src-gen" / "conan_deps.list").splitlines(): + self.requires(dependency) + + def layout(self): + cmake_layout(self) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/application_modules/__init__.py b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/application_modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/model.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/model.py.jinja new file mode 100644 index 0000000..3dcb808 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/model.py.jinja @@ -0,0 +1,17 @@ +import os +from pathlib import Path + +from vaf import save_main_model +from vaf.cli_core.common.utils import ProjectType + +os.environ["IMPORT_APPLICATION_MODULES"] = "import" + +# Import the integration project model +from . import {{ project_name_snk }} + +def export_model(): + script_path = Path(__file__).resolve().parent + save_main_model(script_path / "model.json", project_type=ProjectType.INTEGRATION) + +if __name__ == "__main__": + export_model() diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/{{project_name_snk}}.py.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/{{project_name_snk}}.py.jinja new file mode 100644 index 0000000..73ab0db --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/model/vaf/{{project_name_snk}}.py.jinja @@ -0,0 +1,23 @@ +from datetime import timedelta + +from .application_modules import * +from vaf import * + +# TODO: Import the CaC support depending on your middleware to have access to platform interfaces, modules, and executables + +# TODO: Create executable instances (or configure existing ones from the platform configuration) +# executable = Executable("ExecutableName", timedelta(milliseconds=10)) + +# TODO: Add application modules to executable instances +# executable.add_application_module(AppModule1, [(Instances.AppModule1.Tasks.PeriodicTask, timedelta(milliseconds=1), 0)]) +# executable.add_application_module(AppModule2, [(Instances.AppModule2.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)]) + +# TODO: Wire the internal application module instances +# executable.connect_interfaces(AppModule1, Instances.AppModule1.ProvidedInterfaces.MyInternalProvider, +# AppModule2, Instances.AppModule2.ConsumedInterfaces.MyInternalConsumer) + +# TODO: Connect application modules with platform or platform modules (lower layer abstraction modules) +# executable.connect_consumed_interface_to_platform(AppModule1, Instances.AppModule1.ConsumedInterfaces.MyExternalConsumer, +# SomeExecutable.ConsumerModules.ExternalConsumer) +# executable.connect_provided_interface_to_platform(AppModule2, Instances.AppModule2.ProvidedInterfaces.MyExternalProvider, +# SomeExecutable.ProviderModules.ExternalProvider) diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/src/CMakeLists.txt b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/src/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/test-gen/CMakeLists.txt b/VAF/src/vaf/cli_core/bootstrap/templates/project/default/{{project_name}}/test-gen/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.devcontainer/devcontainer.json.jinja b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.devcontainer/devcontainer.json.jinja new file mode 100644 index 0000000..8ee047f --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.devcontainer/devcontainer.json.jinja @@ -0,0 +1,48 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/cpp +{ + "name": "{{workspace_name}}", + "image": "vaf:latest", + "runArgs": [ + "--sysctl=net.ipv6.conf.all.disable_ipv6=0" + ], + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff" + }, + "editor.formatOnSave": true, + "json.format.keepLines": true, + "cmake.configureOnEdit": true, + "cmake.configureOnOpen": false, + "C_Cpp.intelliSenseEngine": "disabled", + "ruff.exclude": [ + ".pdm-build" + ], + "ruff.nativeServer": true + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "charliermarsh.ruff", + "llvm-vs-code-extensions.vscode-clangd", + "ms-python.python", + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "SanaAjani.taskrunnercode", + "yzhang.markdown-all-in-one" + ] + } + }, + "mounts": [ + {% for mount in mount_paths -%} + "{{ mount }}", + {% endfor -%} + "source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt,type=bind,consistency=cached", + "source=vaf_bashhistory,target=/commandhistory,type=volume" + ] +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vafconfig.json b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vafconfig.json new file mode 100644 index 0000000..cc1f986 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vafconfig.json @@ -0,0 +1,4 @@ +{ + "version": "0.1.0", + "project-type": "workspace" +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/launch.json b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/launch.json new file mode 100644 index 0000000..ce014c4 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(ctest) Launch", + "type": "cppdbg", + "cwd": "${workspaceFolder}", + "request": "launch", + // Resolved by CMake Tools: + "program": "${cmake.testProgram}", + "args": [ "${cmake.testArgs}" ], + } + ] +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/scripts/set_cwd.sh b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/scripts/set_cwd.sh new file mode 100644 index 0000000..d117fa3 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/scripts/set_cwd.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Locates the parent VAF project in the folder hierarchy and runs the command in its root directory. +# + +DEPTH="$(pwd | tr -c -d / | wc -c)" +MOD=. + +while [[ $DEPTH -gt 0 ]]; do + if [[ -f $MOD/.vafconfig.json ]]; then + echo "Run $@ in $(realpath $MOD)" + if [[ $MOD == "." ]]; then + "$@" + else + cd $MOD && "$@" + fi + exit $? + fi + MOD=$MOD/.. + (( DEPTH-- )) || true +done + +echo "No VAF project found in the directory hirachry. Make sure to open a file in a VAF project." >&2 +exit 1 diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/settings.json b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/settings.json new file mode 100644 index 0000000..d873a28 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cmake.configureOnEdit": false, + "cmake.configureOnOpen": false, + "cmake.sourceDirectory": [ ], + "cmake.buildDirectory": "${sourceDirectory}/build" +} diff --git a/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/tasks.json b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/tasks.json new file mode 100644 index 0000000..4f7ea95 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/templates/workspace/{{workspace_name}}/.vscode/tasks.json @@ -0,0 +1,295 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Model: â¬‡ï¸ Import VSS catalogue", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf model import vss", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule", + "integration", + "interface" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Model: 🔄 Update interfaces", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf model update", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Model: 🔄 Update application modules", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf model update", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Model: âš¡ Generate all", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf model generate", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: â¬‡ï¸ Import interfaces", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project import", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: âš¡ Generate application module project", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project generate", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: âž• Create application module", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project create app-module", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: â¬‡ï¸ Import application module", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project import", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: âš¡ Generate integration project", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project generate", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Project: âš¡ Generate all", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf project generate --mode ALL", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Make: 📌 Preset", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf make preset", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule", + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Make: âš™ï¸ Build", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf make build", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule", + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Make: 🚀 Install", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf make install", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "Make: 🧹 Clean", + "type": "shell", + "command": "${workspaceFolder}/.vscode/scripts/set_cwd.sh vaf make clean", + "options": { + "cwd": "${fileDirname}", + "projectTypes": [ + "applicationModule", + "integration" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: ðŸ·ï¸ New workspace", + "type": "shell", + "command": "vaf workspace init", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "default" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: ðŸ·ï¸ New interface project", + "type": "shell", + "command": "vaf project init interface", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "workspace", + "default" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: ðŸ·ï¸ New app-module project", + "type": "shell", + "command": "vaf project init app-module", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "workspace", + "default" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: ðŸ·ï¸ New integration project", + "type": "shell", + "command": "vaf project init integration", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "workspace", + "default" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: ðŸ·ï¸ Version", + "type": "shell", + "command": "vaf --version", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "workspace", + "default" + ] + }, + "presentation": { + "clear": true + } + }, + { + "label": "VAF: 🙋 Help", + "type": "shell", + "command": "vaf --help", + "options": { + "cwd": "${workspaceFolder}", + "projectTypes": [ + "workspace", + "default" + ] + }, + "presentation": { + "clear": true + } + } + ] +} \ No newline at end of file diff --git a/VAF/src/vaf/cli_core/bootstrap/workspace_cmd.py b/VAF/src/vaf/cli_core/bootstrap/workspace_cmd.py new file mode 100644 index 0000000..6560653 --- /dev/null +++ b/VAF/src/vaf/cli_core/bootstrap/workspace_cmd.py @@ -0,0 +1,64 @@ +""" +Implements the functionality of project related commands +""" + +import os +from pathlib import Path + +from copier import run_copy + + +class WorkspaceCmd: # pylint: disable=too-few-public-methods + """Class implementing related workspace commands""" + + def __init__(self) -> None: + """ + Ctor for WorkspaceCmd class + """ + + def _get_devcontainer_mounts(self, paths: tuple[str, ...], project_dir: str) -> list[str]: + """Converts a tuple of paths into mount point statements for a DevContainer. + Relative paths are converted to be relative to the corresponding project. + + Args: + paths (tuple[str]): Relative or absolute paths to mount in the DevContainer. + project_dir (str): Path to the project directory. + + Returns: + A list of strings that match the syntax of devcontainer's mount points. + """ + mounts = [] + for path_str in paths: + if not Path(path_str).is_absolute(): + path_str = f"${{localWorkspaceFolder}}/../{os.path.relpath(path_str, project_dir)}" + mounts.append( + f"source={path_str},target=/opt/vaf/mounts/{Path(path_str).name},type=bind,consistency=cached" + ) + return mounts + + def init( # pylint: disable=too-many-arguments, too-many-positional-arguments + self, name: str, workspace_dir: str, mount_paths: tuple[str, ...] = () + ) -> None: + """Initializes a new VAF workspace with required directories and configuration files. + + Args: + name (str): The name of the project to create. + workspace_dir (str): Path to the output directory. + mount_paths (tuple[str]): List of paths to include in the DevContainer mounts. + + Raises: + VafProjectTemplateError: In cases of project template errors. + """ + + pwd = Path(__file__).resolve().parent + template = str(pwd / "templates" / "workspace") + + print(f"Creating Workspace {name} in {Path(workspace_dir).absolute()}") + run_copy( + template, + workspace_dir, + data={ + "workspace_name": name, + "mount_paths": self._get_devcontainer_mounts(mount_paths, workspace_dir), + }, + ) diff --git a/VAF/src/vaf/cli_core/common/click_extension.py b/VAF/src/vaf/cli_core/common/click_extension.py new file mode 100644 index 0000000..ae51293 --- /dev/null +++ b/VAF/src/vaf/cli_core/common/click_extension.py @@ -0,0 +1,308 @@ +"""Implements custom extensions to the click library""" + +import re +from pathlib import Path +from typing import Any, Callable, Mapping, Optional, Type + +import click +from click_prompt.core.option import ChoiceOption, FilePathOption + +from vaf.cli_core.common.utils import ProjectType, _get_default_model_path, get_project_type, get_subprojects_in_path + + +# pylint: disable-next=missing-param-doc +def choice_option(*args: str, **kwargs: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: + """Typed decorator to replace the untyped one from click_prompt""" + + def decorator(f: Callable[[Any], Any]) -> Callable[[Any], Any]: + if "cls" not in kwargs: + kwargs["cls"] = ChoiceOption + return click.option(*args, **kwargs)(f) + + return decorator + + +# pylint: disable-next=missing-param-doc +def filepath_option(*args: str, **kwargs: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: + """Typed decorator to replace the untyped one from click_prompt""" + + def decorator(f: Callable[[Any], Any]) -> Callable[[Any], Any]: + if "cls" not in kwargs: + kwargs["cls"] = FilePathOption + return click.option(*args, **kwargs)(f) + + return decorator + + +# pylint: disable-next=missing-param-doc +def sanatized_str_option(*args: str, **kwargs: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: + """Click decorator that sanitizes the input string to ensure compatibility with POSIX 'Fully portable filenames'.""" + + # pylint:disable-next=unused-argument + def callback_handler(ctx: click.Context, option: click.Option, value: str) -> Any: + """Sanatizes the input string to ensure compatibility with POSIX 'Fully portable filenames'. + + Args: + ctx (click.Context): Click context object. + option (click.Option): The option instance being handled. + value (str): The value of the option. + Returns: + The value of the option. + Raises: + BadParameter: If the value contains invalid characters. + """ + value = value.strip() + if not re.match(r"^[a-zA-Z0-9._-]+$", value): + raise click.BadParameter("Only A-Z, a-z, 0-9, underscores, hyphens and dots are allowed.") + return value + + def decorator(func: Callable[[Any], Any]) -> Callable[[Any], Any]: + kwargs["callback"] = callback_handler + return click.option(*args, **kwargs)(func) + + return decorator + + +def cli_verbose_option(function: Callable[..., Any]) -> Callable[..., Any]: + """Function to create verbose CLI option that can be reusable in multiple cmds + Args: + function: Function to be decorated + Returns: + function decorated with click.option + """ + function = click.option( + "-v", + "--verbose", + "verbose", + help="Flag to enable verbose mode for debugging.", + is_flag=True, + )(function) + return function + + +def get_project_type_for_project_dir(project_dir: Optional[str] = None) -> ProjectType: + """Safely get project type based on project directory. + Args: + project_dir: project directory + Returns: + ProjectType: Type of the VAF project + """ + + if project_dir is not None: + return get_project_type(Path(project_dir)) # Use explicitly passed project_dir + + ctx = click.get_current_context(silent=True) + if ctx and ctx.params.get("project_dir"): + return get_project_type(Path(ctx.params["project_dir"])) # Use Click context + + return get_project_type(Path()) # Fallback if no Click context + + +def preserve_params(function: Callable[..., Any]) -> Callable[..., Any]: + """Decorator to preserve the click command parameters in __vaf_click_params__ + Args: + function: Function to be decorated + Returns: + function decorated with with the click params in __vaf_click_params__ + Raises: + AttributeError: If the function does not have __click_params__ + """ + try: + params = getattr(function, "__click_params__") + except AttributeError as e: + raise AttributeError( + f"The @preserve_params decorator must be the outermost decorator of the click command {function.__name__}" + ) from e + + setattr(function, "__vaf_click_params__", params) + return function + + +def project_generate_common_click_decorators(function: Callable[..., Any]) -> Callable[..., Any]: + """Function to create common options for vaf project generate + Args: + function: Function to be decorated + Returns: + function decorated with click.option + """ + # verbose + function = cli_verbose_option(function) + # -p + function = click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=False), + required=False, + help="Path to the project directory.", + default=".", + )(function) + # -i + function = click.option( + "-i", + "--input-file", + type=click.Path(exists=False, dir_okay=False, writable=True), + required=False, + help="Path to the project model JSON file.", + default=lambda: str( + Path(click.get_current_context().params.get("project_dir", ".")) + / _get_default_model_path(get_project_type_for_project_dir()) + / "model.json" + ), + )(function) + # -b + function = click.option( + "-b", + "--build-dir", + type=click.Path(exists=False, file_okay=False, writable=False), + default="build", + help="Build directory", + show_default=True, + )(function) + # -m + function = click.option( + "--manual-merge", + "manual_merge", + help="Flag to disable the automatic 3-way merge mechanism on re-generation of user-editable source files.", + is_flag=True, + )(function) + # --skip-model-update + function = click.option( + "--skip-model-update", + "skip_model_update", + help="Flag to not update model.json before generating the project.", + is_flag=True, + )(function) + # --skip-make-preset + function = click.option( + "--skip-make-preset", + "skip_make_preset", + help="Flag to skip the make preset call after generating the project.", + is_flag=True, + )(function) + # pass context + function = click.pass_context(function) + return function + + +class DisableForProjectOption(click.Option): + """This class disables click options for certain project types.""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.parse_opts: Mapping[str, Any] | None = None + self.disable_for_type = kwargs.pop("disable_param_for_project_type", {}) + self.original_callback = kwargs.get("callback", None) + kwargs["callback"] = self.callback_handler + super().__init__(*args, **kwargs) + + def handle_parse_result(self, ctx: click.Context, opts: Mapping[str, Any], args: list[str]) -> Any: + """ + Saves the parsed options for later use. + + Args: + ctx (click.Context): The Click context object. + opts (Mapping[str, Any]): A dictionary of parsed options. + args (list[str]): A list of remaining command-line arguments. + """ + self.parse_opts = opts + return super().handle_parse_result(ctx, opts, args) + + def callback_handler(self, ctx: click.Context, option: click.Option, value: str) -> Any: + """Disables specific options for certain project types. + Calls the original callback function, if one exists. + + Args: + ctx (click.Context): Click context object. + option (click.Option): The option instance being handled. + value (str): The value of the option. + Returns: + The value of the option. + """ + if value and self.parse_opts is not None and not self.parse_opts.get("help"): + project_type = get_project_type(Path(value)) + + for param in ctx.command.params: + # Click replaces dashes with underscores in parameter names, so we need to convert them back + actual_name = getattr(param, "name", "").replace("_", "-") + + # Check if the parameter should be disabled for the current project type, + # or disable all parameters for unsupported types + if actual_name in self.disable_for_type.get(project_type, []) or ( + project_type not in self.disable_for_type.keys() + and any(actual_name in sublist for sublist in self.disable_for_type.values()) + ): + setattr(param, "prompt_required", False) + param.required = False + + if self.original_callback: + return self.original_callback(ctx, option, value) + return value + + +def modifying_choice_fp_option(*args: str, choice_to_modify: str = "app-modules") -> Type[FilePathOption]: + """Function to get the custom click option ModifyingChoiceFpOption. + This class modifies the specified click choice option and adds application modules paths as choices. + + Args: + *args (str): Names of the click option + choice_to_modify (str): Name of the click option to modify + Returns: + ModifyingChoiceFpOption class + """ + choice_to_modify = choice_to_modify.replace("-", "_") + + class ModifyingChoiceFpOption(FilePathOption): # type: ignore + """This class adds application module paths found in the model path as choices to a specified click choice.""" + + def __init__(self, _: str, **kwargs: Any) -> None: + assert args, "Pass option names into modifying_choice_fp_option()" + + self.parse_opts: Mapping[str, Any] | None = None + self.original_callback = kwargs.get("callback", None) + kwargs["callback"] = self.callback_handler + super().__init__(args, **kwargs) + + def handle_parse_result(self, ctx: click.Context, opts: Mapping[str, Any], args: list[str]) -> Any: + """ + Saves the parsed options for later use. + + Args: + ctx (click.Context): The Click context object. + opts (Mapping[str, Any]): A dictionary of parsed options. + args (list[str]): A list of remaining command-line arguments. + """ + self.parse_opts = opts + return super().handle_parse_result(ctx, opts, args) + + def callback_handler(self, ctx: click.Context, option: click.Option, value: str) -> Any: + """Searches for application modules and add their paths as click choices to the specified click option. + Calls the original callback function, if one exists. + + Args: + ctx (click.Context): Click context object. + option (click.Option): The option instance being handled. + value (str): The value of the option. + Returns: + The value of the option. + """ + if value and self.parse_opts is not None and not self.parse_opts.get("help"): + project_type = get_project_type_for_project_dir() + if project_type == ProjectType.INTEGRATION: + project_dir = Path(ctx.params.get("project_dir", ".")) + app_modules = get_subprojects_in_path(ProjectType.APP_MODULE, project_dir / value) + if len(app_modules) < 1: + click.echo(f"No application modules found in {project_dir / value}") + ctx.exit(1) + for parameter in ctx.command.params: + if choice_to_modify == parameter.name and isinstance(parameter.type, click.Choice): + parameter.type.choices = [module.as_posix() for module in app_modules] + if len(app_modules) == 1 and not self.parse_opts.get(choice_to_modify): + # This is required for the interactive prompt to work with only one choice. + # If the parameter is specified on the CLI `multiple` has always be True, + # regardless of the number of choices. + parameter.multiple = False + + if self.original_callback: + return self.original_callback(ctx, option, value) + return value + + return ModifyingChoiceFpOption diff --git a/VAF/src/vaf/cli_core/common/click_help.py b/VAF/src/vaf/cli_core/common/click_help.py new file mode 100644 index 0000000..b6bdb44 --- /dev/null +++ b/VAF/src/vaf/cli_core/common/click_help.py @@ -0,0 +1,49 @@ +"""Setup click options to configure the help output of the CLI commands.""" + +import click + +# Per default, click only displays help for --help option +# In our tools, we usually display help for both -h and --help +CLICK_CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]} + + +# Custom warning format to display warnings without stack trace or file info +def simple_user_warning( + message: str | Warning, category: type[Warning], filename: str, lineno: int, line: str | None = None +) -> str: + # pylint: disable=unused-argument + """Generates a simple user warning message without stack trace or file info. + Args: + message (str | Warning): The warning message to display. + category (type[Warning]): The type of warning. + filename (str): The filename related to the warning. + lineno (int): The line number related to the warning. + line (str | None): The line of code related to the warning. + Returns: + str: A formatted warning message. + """ + return f"{category.__name__}: {message}\n" + + +class CustomHelpGroup(click.Group): + """Custom click group to modify the CLI help output.""" + + def _format_subcommands(self, cmd: click.Group, ctx: click.Context, formatter: click.HelpFormatter) -> None: + with formatter.indentation(): + sub_commands = cmd.list_commands(ctx) + for index, sub_cmd_name in enumerate(sub_commands): + sub_cmd = cmd.get_command(ctx, sub_cmd_name) + if sub_cmd is not None: + formatter.write_text(f"{sub_cmd_name}: {sub_cmd.get_short_help_str(100)}") + if index == len(sub_commands) - 1: + # Add newline after last subcommand + formatter.write_paragraph() + + def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: + with formatter.section("Commands"): + for cmd_name in self.list_commands(ctx): + cmd = self.get_command(ctx, cmd_name) + if cmd is not None: + formatter.write_text(f"{cmd_name}: {cmd.get_short_help_str(100)}") + if isinstance(cmd, click.Group): + self._format_subcommands(cmd, ctx, formatter) diff --git a/VAF/src/vaf/cli_core/common/exceptions.py b/VAF/src/vaf/cli_core/common/exceptions.py new file mode 100644 index 0000000..5a562f5 --- /dev/null +++ b/VAF/src/vaf/cli_core/common/exceptions.py @@ -0,0 +1,34 @@ +""" +vaf.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of vaf' exceptions. +""" + + +class VafProjectTemplateError(Exception): + """Exception class for specific error handling regarding project template errors""" + + def __init__(self, message: str, error_code: int = 0) -> None: + """ + Initialize VafProjectTemplateError with a message and optional error code. + + :param message: The error message. + :param error_code: An optional error code. + """ + super().__init__(message) + self.error_code = error_code + + +class VafProjectGenerationError(Exception): + """Exception class for specific error handling regarding project generation errors""" + + def __init__(self, message: str, error_code: int = 0) -> None: + """ + Initialize VafProjectGenerationError with a message and optional error code. + + :param message: The error message. + :param error_code: An optional error code. + """ + super().__init__(message) + self.error_code = error_code diff --git a/VAF/src/vaf/cli_core/common/utils.py b/VAF/src/vaf/cli_core/common/utils.py new file mode 100644 index 0000000..9dac4af --- /dev/null +++ b/VAF/src/vaf/cli_core/common/utils.py @@ -0,0 +1,257 @@ +"""Utilities function that are used across components""" + +import importlib.util +import json +import re +from enum import Enum +from pathlib import Path +from typing import Any, Callable, Dict, Tuple + +from vaf.constants import VAF_CFG_FILE + + +class ProjectType(Enum): + """Enum class representing a VAF project type""" + + UNKNOWN = "unknown" + INTERFACE = "interface-project" + APP_MODULE = "application-module-project" + INTEGRATION = "integration-project" + WORKSPACE = "workspace" + + +def create_name_namespace_full_name(name: str, namespace: str) -> str: + """Function to create full name based on name & namespace + Args: + name: name string + namespace: namespace string + Returns: + Full Name + """ + return "::".join([namespace, name]) + + +def concat_str_to_path(path: Path, concat_str: str) -> Path: + """Function to concatenate a string to a path + Args: + path: Path to dir/file to be concatenated + concat_str: string to be concatenated at the end of the path + """ + return path.parent / (path.name + concat_str) + + +def check_str_has_conflict(in_str: str) -> bool: + """Function to check if a string has conflict + Args: + in_str: string to be checked + Returns: + boolean if string has any conflicts + """ + return all(conflict_sign in in_str for conflict_sign in ["<<<<<<<", "=======", ">>>>>>>"]) + + +def check_file_has_conflict(file_path: Path) -> bool: + """Function to check if file has conflict(s) + Args: + file_path: Path to file to be checked + Returns: + boolean if file has any conflicts + """ + with open(file_path, "r", encoding="utf-8") as file: + file_content = file.read() + + return check_str_has_conflict(file_content) + + +def remove_file_if_exist(file_path: str | Path) -> None: + """Function to remove file if it exists + Args: + file_path: Path/str of the file to be removed + """ + if isinstance(file_path, str): + file_path = Path(file_path) + + if file_path.is_file(): + file_path.unlink() + + +def resolve_dotdot(path: Path) -> Path: + """Resolve the dotdot notation in a path. + Args: + path (Path): The path to resolve. + Returns: + The resolved, absolute path. + """ + parts = path.absolute().parts + new_parts: list[str] = [] + for part in parts: + if part == "..": + if new_parts and new_parts[-1] != "..": + new_parts.pop() + else: + new_parts.append(part) + else: + new_parts.append(part) + return Path("/").joinpath(*new_parts) + + +def _get_default_model_path(project_type: ProjectType) -> str: + if project_type == ProjectType.INTEGRATION: + return "model/vaf/" + if project_type == ProjectType.APP_MODULE: + return "model/" + if project_type == ProjectType.INTERFACE: + return "." + return "" + + +def get_project_type(path: Path | None = None) -> ProjectType: + """Function to read the current project type from VAF_CFG_FILE + Args: + path (Path, optional): Project path to search for the VAF_CFG_FILE + Returns: + ProjectType enum representation of the project in the specified path or cwd + """ + project_type_str = "" + config_path = Path(VAF_CFG_FILE) + if path is not None: + config_path = path / VAF_CFG_FILE + if Path.is_file(config_path): + with open(config_path, encoding="utf-8") as fh: + project_type_str = json.load(fh).get("project-type", "unknown") + return ProjectType(project_type_str) + return ProjectType.UNKNOWN + + +def get_subprojects_in_path(project_type: ProjectType, search_path: Path) -> list[Path]: + """Function that recursively returns the path of imported vaf subprojects. + + Interface projects are only returned, if they are imported be copy. + + Note: + This function is only implemented for APP_MODULE project type. + + Args: + project_type (ProjectType): Project type to search for + search_path (Path): Directory to search in + Returns: + List of paths to VAF projects + """ + assert project_type == ProjectType.APP_MODULE, ( + "This function is currently only implemented for APP_MODULE project type." + ) + + project_paths = [] + for file_path in search_path.rglob("import_*.py"): + spec = importlib.util.spec_from_file_location(file_path.stem, file_path) + if spec is not None and spec.loader is not None: + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + # Check if 'model_path' variable exists in the module + if hasattr(module, "model_path"): + project_paths.append(resolve_dotdot((file_path.parent / module.model_path)).parent) + return project_paths + + +def get_projects_in_path(search_path: Path) -> list[tuple[Path, ProjectType]]: + """Function that returns the paths and types of all VAF projects in the search path. + + Args: + search_path (Path): Directory to search in + Returns: + List of tuples containing the paths and project types + """ + projects = set() + + def search_directory(directory: Path) -> None: + for path in directory.iterdir(): + if path.is_dir(): + project_type = get_project_type(path) + if project_type != ProjectType.UNKNOWN: + projects.add((path, project_type)) + else: + search_directory(path) + + search_directory(search_path) + return list(projects) + + +def get_parent_ws(search_path: Path) -> Path | None: + """Function that searches for a parent workspace in the specified path. + + Args: + search_path (Path): Directory to start the search from + Returns: + Path to workspace or None if no workspace is found + """ + current_path = search_path.resolve() + + while current_path != current_path.parent: + if get_project_type(current_path) == ProjectType.WORKSPACE: + return current_path + current_path = current_path.parent + return None + + +def convert_args_to_kwargs(args: Tuple[Any], target_function: Callable[[Any], Any]) -> Dict[str, Any]: + """Function to convert args into kwargs for a given target function + Example: args = ("Devil Jin", 35, 95676) + target_function's arguments (name, age, power) + -> kwargs = {"name": "Devil Jin", "age": 35, "power": 95676} + if args = (2234, "Kazuya", 44) + -> kwargs = {"name": 2234, "age": "Kazuya", "power": 44} + Args: + args: Tuple of positional arguments that are going to be passed into target_function as kwargs + target_function: function to which kwargs will be passed + Returns: + Dictionary that contains can be passed as kwargs to target_function + """ + function_varnames = target_function.__code__.co_varnames + return {function_varnames[idx]: arg for idx, arg in enumerate(args)} + + +def get_kwargs_from_local_variables( + local_vars: Dict[str, Any], target_function: Callable[[Any], Any] +) -> Dict[str, Any]: + """Function to build kwargs for a given target function based on current locals variables + Args: + local_vars: Dictionary that contains local variables + target_function: function to which kwargs will be passed + Returns: + Dictionary that contains can be passed as kwargs to target_function + """ + # also consider variables index + function_varnames = target_function.__code__.co_varnames[: target_function.__code__.co_argcount] + return {key: value for key, value in local_vars.items() if key in function_varnames} + + +def to_snake_case(s: str) -> str: + """Converts a string to snake case + + Args: + s (str): The input string + + Returns: + str: The string converted to snake case + """ + return ( + "_".join(re.sub("([A-Z][a-z]+)", r" \1", re.sub("([A-Z]+)", r" \1", s.replace("-", " "))).split()) + .lower() + .replace(" ", "") + .replace("__", "_") + ) + + +def to_camel_case(s: str) -> str: + """Converts a string to camel case + + Args: + s (str): The input string + + Returns: + str: The string converted to camel case + """ + pattern = re.compile(r"(?<!^)(?=[A-Z])") + tmp = pattern.sub(" ", s) + return re.sub(r"(_|-)+", " ", tmp).title().replace(" ", "") diff --git a/VAF/src/vaf/cli_core/main/cli_subcommands/make_subcmd.py b/VAF/src/vaf/cli_core/main/cli_subcommands/make_subcmd.py new file mode 100644 index 0000000..41b64b3 --- /dev/null +++ b/VAF/src/vaf/cli_core/main/cli_subcommands/make_subcmd.py @@ -0,0 +1,187 @@ +"""Source code for vaf project subcommands""" + +from pathlib import Path + +import click + +from vaf.cli_core.common.click_extension import cli_verbose_option, preserve_params +from vaf.cli_core.common.utils import ProjectType, get_project_type +from vaf.cli_core.main.make_cmd import MakeCmd + + +# vaf make preset # +@preserve_params +@cli_verbose_option +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "-b", + "--build-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=lambda: str(Path(click.get_current_context().params.get("project_dir", ".")) / "build"), + help="Build directory", + show_default=True, +) +@click.option( + "-t", + "--build-type", + help="Type variant of build, either 'Debug' or 'Release'", + required=True, + type=click.Choice(["Debug", "Release"], case_sensitive=True), + default="Release", + show_default=True, +) +@click.option( + "-c", + "--compiler", + help="Compiler version, either 'gcc11__x86_64-pc-linux-elf' or 'gcc12__x86_64-pc-linux-elf'", + required=False, + type=click.Choice(["gcc11__x86_64-pc-linux-elf", "gcc12__x86_64-pc-linux-elf"], case_sensitive=True), + default="gcc12__x86_64-pc-linux-elf", + show_default=True, +) +@click.option( + "-d", + "--defines", + type=str, + default="", + help="Additional defines, -d -DVAF_BUILD_TESTS=OFF", + show_default=True, +) +def make_preset( # pylint: disable=too-many-arguments, too-many-positional-arguments + project_dir: str, build_dir: str, compiler: str, build_type: str, defines: str, verbose: bool = False +) -> None: + """ + Preset build. + :param project_dir: Project directory. + :param build_dir: Build directory. + :param compiler: Compiler version. + :param build_type: Debug or release build. + :param defines: Set defines. + :param verbose: enable verbose mode (show full CMake output) + """ + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type in {ProjectType.INTEGRATION, ProjectType.APP_MODULE}: + cmd = MakeCmd(verbose) + cmd.preset(build_dir, compiler, build_type, defines, Path(project_dir).as_posix()) + else: + click.echo("\nInvalid VAF project type for make preset command.") + + +# vaf make build # +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "--preset", + required=True, + type=click.Choice(["conan-debug", "conan-release"], case_sensitive=True), + default="conan-release", + show_default=True, +) +def make_build(project_dir: str, preset: str) -> None: + """ + Build the project artifacts. + :param project_dir: Project directory. + :param preset: CMake preset. + + """ + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type in {ProjectType.INTEGRATION, ProjectType.APP_MODULE}: + cmd = MakeCmd() + cmd.build(preset) + else: + click.echo("\nInvalid VAF project type for make build command.") + + +# vaf make clean # +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "--preset", + required=True, + type=click.Choice(["conan-debug", "conan-release"], case_sensitive=True), + default="conan-release", + show_default=True, +) +def make_clean(project_dir: str, preset: str) -> None: + """ + Clean up the project build directory. + :param project_dir: Project directory. + :param preset: CMake preset. + + """ + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type in {ProjectType.INTEGRATION, ProjectType.APP_MODULE}: + cmd = MakeCmd() + cmd.clean(preset) + else: + click.echo("\nInvalid VAF project type for make clean command.") + + +# vaf make install # +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "--preset", + required=True, + type=click.Choice(["conan-debug", "conan-release"], case_sensitive=True), + default="conan-release", + show_default=True, +) +def make_install(project_dir: str, preset: str) -> None: + """ + Install the built artifacts to build/<build-type>/install directory. + :param project_dir: Project directory. + :param preset: CMake preset. + + """ + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type in {ProjectType.INTEGRATION, ProjectType.APP_MODULE}: + cmd = MakeCmd() + cmd.install(preset) + else: + click.echo("\nInvalid VAF project type for make install command.") diff --git a/VAF/src/vaf/cli_core/main/cli_subcommands/model_subcmd.py b/VAF/src/vaf/cli_core/main/cli_subcommands/model_subcmd.py new file mode 100644 index 0000000..47dda3a --- /dev/null +++ b/VAF/src/vaf/cli_core/main/cli_subcommands/model_subcmd.py @@ -0,0 +1,165 @@ +"""Source code for vaf model subcommands""" + +from pathlib import Path + +import click + +from vaf.cli_core.common.click_extension import ( + DisableForProjectOption, + choice_option, + filepath_option, + get_project_type_for_project_dir, + modifying_choice_fp_option, +) +from vaf.cli_core.common.utils import ProjectType, _get_default_model_path, get_project_type +from vaf.cli_core.main.model_cmd import ModelCmd + + +# vaf model import group # +@click.group() +def model_import() -> None: + """Import the VAF model from a specified model input file.""" + + +# vaf model import vss # +@model_import.command(name="vss") +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@filepath_option( + "-i", + "--input-file", + help="JSON file to import.", + required=True, + type=click.Path(exists=True, dir_okay=False), + prompt="Enter the path to the VSS catalogue file in JSON format", +) +def model_import_vss(project_dir: str, input_file: str) -> None: # pylint: disable=missing-param-doc + """Import the VAF model from a VSS input file.""" + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + model_dir = project_dir # Applies for interface project + if project_type == ProjectType.APP_MODULE: + model_dir = project_dir + "/model" + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + else: + click.echo(f"Derive for model VSS from {input_file}.") + cmd = ModelCmd() + cmd.import_vss(input_file, model_dir) + + +# vaf model update # +# This option has to come before all options mentioned in the disable_param_for_project_type dictionary. +@click.option( + "-p", + "--project-dir", + cls=DisableForProjectOption, + disable_param_for_project_type={ + ProjectType.INTEGRATION: ["model-dir"], + ProjectType.APP_MODULE: ["app-model-dir", "app-modules"], + }, + type=click.Path(exists=True, file_okay=False, writable=True), + required=True, + help="Path to the project root directory.", + default=".", +) +# This option has to come before the --app-modules option, because the app-modules are populated by it's callback +@filepath_option( + "-m", + "--model-dir", + cls=modifying_choice_fp_option("--model-dir", choice_to_modify="app-modules"), + type=click.Path(exists=True, file_okay=False, writable=True), + help="Path to the model directory.", + default=lambda: str( + Path(click.get_current_context().params.get("project_dir", ".")) + / _get_default_model_path(get_project_type_for_project_dir()) + / "" + ), + prompt_required=False, +) +@choice_option( + "--app-modules", + prompt="Choose one ore more application modules", + type=click.Choice([]), + help="Absolute path to the application module directory to update. Specify multiple times for multiple modules.", + multiple=True, +) +def model_update(project_dir: str, model_dir: str, app_modules: list[str]) -> None: # pylint: disable=missing-param-doc + "Update previously imported model or application module artifacts based on the project type." + + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type == ProjectType.APP_MODULE: + click.echo(f"Updating imported model artifacts in {model_dir} directory for an app-module project.") + cmd = ModelCmd() + cmd.update_imported_models(model_dir) + elif project_type == ProjectType.INTEGRATION: + # This workaround is necessary, because of the hacky solution to support only one choice in + # ModifyingChoiceFpOption.callback_handler() + if isinstance(app_modules, str): + app_modules = [app_modules] + + paths = set() + for app_module in app_modules: + click.echo(f"Updating app-module model artifacts in {model_dir} directory for an integration project.") + paths.add(Path(app_module)) + cmd = ModelCmd() + cmd.update_app_modules(model_dir=Path(model_dir), app_modules=list(paths)) + else: + click.echo("\nInvalid VAF project type for model update command.") + + +# vaf model generate # +@click.option( + "-p", + "--project-dir", + type=click.Path(exists=False, file_okay=False, writable=True), + default=".", + help="Path to the project root directory", + show_default=True, +) +@click.option( + "-t", + "--project-type", + help="Project type.", + required=False, + type=ProjectType, + default=get_project_type_for_project_dir(), + show_default=True, +) +@filepath_option( + "-m", + "--model-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + help="Path to the VAF model configuration directory.", + default=lambda: str( + Path(click.get_current_context().params.get("project_dir", ".")) + / _get_default_model_path(get_project_type_for_project_dir()) + / "" + ), + prompt_required=False, +) +@click.option( + "--mode", + help="Generation mode, either 'PRJ' or 'ALL'.", + required=False, + envvar="TYPE_VARIANT", + type=click.Choice(["PRJ", "ALL"], case_sensitive=False), + default="ALL", + show_default=True, +) +def model_generate(project_dir: str, project_type: ProjectType, model_dir: str, mode: str) -> None: # pylint: disable=missing-param-doc + """Process the VAF configuration to JSON model exchange format.""" + if project_type == ProjectType.UNKNOWN: + click.echo(f"\nNo valid VAF project found in {project_dir}!") + else: + cmd = ModelCmd() + cmd.generate(project_type, model_dir, mode) diff --git a/VAF/src/vaf/cli_core/main/cli_subcommands/project_subcmd.py b/VAF/src/vaf/cli_core/main/cli_subcommands/project_subcmd.py new file mode 100644 index 0000000..2ddf67f --- /dev/null +++ b/VAF/src/vaf/cli_core/main/cli_subcommands/project_subcmd.py @@ -0,0 +1,322 @@ +"""Source code for vaf project subcommands""" + +from pathlib import Path +from typing import Any + +import click +from click.core import ParameterSource + +from vaf.cli_core.common.click_extension import ( + DisableForProjectOption, + choice_option, + filepath_option, + get_project_type_for_project_dir, + modifying_choice_fp_option, + project_generate_common_click_decorators, + sanatized_str_option, +) +from vaf.cli_core.common.utils import ( + ProjectType, + _get_default_model_path, + get_project_type, + get_projects_in_path, +) + +from ..cli_subcommands.make_subcmd import make_preset +from ..cli_subcommands.model_subcmd import model_generate +from ..model_cmd import ModelCmd +from ..project_cmd import ProjectCmd + + +# vaf project create group # +@click.group() +def project_create() -> None: + """Create the specified project artifacts inside the given project.""" + + +# vaf project create app-module # +@project_create.command(name="app-module") +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="App-module name.", prompt="Enter the name of the app-module" +) +@click.option( + "--namespace", + type=str, + required=True, + help="App-module namespace.", + prompt="Enter the namespace of the app-module", + callback=lambda ctx, param, value: value.strip() if value else "", +) +@filepath_option( + "-p", + "--project-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + required=True, + help="Path to the project root directory.", + default=".", + prompt="Enter the path to the project root directory", +) +@click.option( + "--pre-path", + type=click.Path(exists=False, file_okay=False, writable=True), + help="Relative pre-path to the app module directory: <project_root_dir>/src/application_modules/<pre_path>/<app_module_dir>", # pylint: disable=line-too-long + default=".", + required=False, +) +@click.option( + "-m", + "--model-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + required=False, + help="Relative path to VAF model directory from project dir.", + default=_get_default_model_path(get_project_type_for_project_dir()), +) +def project_create_app_module(namespace: str, name: str, project_dir: str, pre_path: str, model_dir: str) -> None: # pylint: disable=missing-param-doc + """Create an application module project and add it to the given integration project.""" + click.echo(f"Creating app-module {namespace}::{name} to {project_dir}/src/application_modules/{pre_path}/{name}.") + cmd = ProjectCmd() + cmd.create_appmodule(namespace, name, project_dir, pre_path, model_dir) + + +# pylint:disable=unused-argument # mode used via kwargs +def __update_vaf_model( + ctx: click.Context, project_type: ProjectType, project_dir: str, input_file: str, mode: str +) -> None: + """Function to also update vaf model by calling vaf model generate + Args: + input_file: Path to the model.json as string + mode: type of generation mode used + """ + model_dir = str(Path(input_file).parent) + click.echo(f"\nTriggering vaf model generate in {model_dir}...") + ctx.invoke(model_generate, project_type=project_type, project_dir=project_dir, model_dir=model_dir, mode=mode) + click.echo(f"\nSUCCESS: VAF model generated and stored in {model_dir}") + + +# vaf project generate # +@project_generate_common_click_decorators +@click.option( + "--mode", + help="Generation mode for integration project, either 'PRJ' or 'ALL'", + required=False, + envvar="TYPE_VARIANT", + type=click.Choice(["PRJ", "ALL"], case_sensitive=False), + default="PRJ", + show_default=True, +) +# pylint: disable=missing-param-doc, missing-raises-doc, line-too-long, too-many-arguments, too-many-positional-arguments, too-many-locals +def project_generate( + ctx: click.Context, + project_dir: str, + input_file: str, + build_dir: str, + mode: str, + manual_merge: bool = False, + verbose: bool = False, + skip_model_update: bool = False, + skip_make_preset: bool = False, +) -> None: + """Generate the source code of the VAF project based on the configuration and generation mode.""" + + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + else: + # Check if the user provided `--input-file` or if it's using the default value + ctx = click.get_current_context() + input_file_source = ctx.get_parameter_source("input_file") + if input_file_source != ParameterSource.DEFAULT and not skip_model_update: + click.echo("Disabling the model update for a user provided model JSON file.") + skip_model_update = True + + # Check if required parameters for cmake execution are available + make_preset_params = getattr(make_preset, "__vaf_click_params__", None) + assert make_preset_params is not None, ( + "Make sure you have added the @preserve_params decorator to the click command make_preset." + ) + make_preset_cmd = click.Command(name="", callback=make_preset, params=make_preset_params) + + def __run_make_preset(project_dir: str = project_dir, **kwargs: Any) -> None: + ctx.invoke(make_preset_cmd, project_dir=project_dir, verbose=verbose, **kwargs) + + def __run_make_preset_debug(**kwargs: Any) -> None: + __run_make_preset(build_type="Debug", **kwargs) + + def __run_make_preset_release(**kwargs: Any) -> None: + __run_make_preset(build_type="Release", **kwargs) + + cmd = ProjectCmd(verbose) + if project_type == ProjectType.INTEGRATION: + if not skip_model_update: + click.echo("Updating integration project model before generation.") + __update_vaf_model(ctx, project_type, project_dir, input_file, mode) + click.echo(f"Generating integration project for {mode} based on model in {input_file}") + cmd.generate_integration( + input_file, + project_dir, + mode, + manual_merge, + ) + if not skip_make_preset: + if mode == "ALL": + # Execute cmake preset for all included app-module projects + for pr_path, _ in get_projects_in_path(Path(project_dir)): + __run_make_preset_debug(project_dir=pr_path) + __run_make_preset_release(project_dir=pr_path) + __run_make_preset_debug() + __run_make_preset_release() + + elif project_type == ProjectType.APP_MODULE: + click.echo("\nSkipping generation mode selection as the project is not an integration project.") + + if not skip_model_update: + click.echo("Updating integration project model before generation.") + __update_vaf_model(ctx, project_type, project_dir, input_file, "PRJ") + click.echo(f"\nGenerating application module based on model in {input_file}") + cmd.generate_app_module( + input_file, + project_dir, + manual_merge, + ) + if not skip_make_preset: + __run_make_preset_debug() + __run_make_preset_release() + else: + click.echo("\nInvalid VAF project for project generate command.") + + +# vaf project import # +# This option has to come before all options mentioned in the disable_param_for_project_type dictionary. +@click.option( + "-p", + "--project-dir", + cls=DisableForProjectOption, + disable_param_for_project_type={ + ProjectType.INTEGRATION: ["input-file"], + ProjectType.APP_MODULE: ["input-dir"], + }, + type=click.Path(exists=True, file_okay=False, writable=True), + required=False, + help="Path to the project root directory.", + default=".", +) +@filepath_option( + "--input-dir", + type=click.Path(exists=True, file_okay=False, writable=False), + required=True, + help="Path to the application module project to be imported. " + "Applicable only for the app-module import into an integration project.", + prompt="Enter the path to the application module project to be imported:", +) +@click.option( + "--pre-path", + type=click.Path(exists=False, file_okay=False, writable=False), + help="Relative pre-path to the app-module directory: <project_root_dir>/src/application_modules/<pre_path>/<app_module_dir>", # pylint: disable=line-too-long + default=".", + required=False, +) +@click.option( + "-m", + "--model-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + required=False, + help="Path to the VAF model directory.", + default=lambda: str( + Path(click.get_current_context().params.get("project_dir", ".")) + / _get_default_model_path(get_project_type_for_project_dir()) + / "" + ), +) +@filepath_option( + "--input-file", + type=click.Path(exists=True, dir_okay=False), + help="Path to the exported VAF model JSON file(from the interface project). " + "Applicable only for the interface import into an application module project.", + required=True, + prompt="Please provide the path to the exported VAF model JSON file", +) +@click.option("--force-import", is_flag=True, help="Carry out import in any case. Will overwrite existing files.") +@click.option("--skip-import", is_flag=True, help="Cancel operation directly in case of a re-import.") +@click.argument("import-mode", default="copy", type=click.Choice(["copy", "reference"], case_sensitive=False)) +def project_import( # pylint: disable=missing-param-doc, too-many-positional-arguments, too-many-arguments + project_dir: str, + input_dir: str, + pre_path: str, + model_dir: str, + input_file: str, + force_import: bool, + skip_import: bool, + import_mode: str, +) -> None: + """Import an interface/app-module project to the given project based on the project type.""" + + # Look for project type in VAF_CFG_FILE in the project directory + project_type = get_project_type(Path(project_dir)) + if project_type == ProjectType.UNKNOWN: + click.echo("\nNo valid VAF project found!") + elif project_type == ProjectType.INTEGRATION: + click.echo(f"Importing an app-module from {input_dir} to the integration project {model_dir}.") + project_cmd = ProjectCmd() + project_cmd.import_appmodule(input_dir, project_dir, pre_path, model_dir) + elif project_type == ProjectType.APP_MODULE: + click.echo(f"Importing an interface from {input_file} to the app-module project {model_dir}.") + model_cmd = ModelCmd() + model_cmd.import_model(input_file, model_dir, import_mode, force_import, skip_import) + else: + click.echo("\nInvalid VAF project type for project import command.") + + +# vaf project remove group # +@click.group() +def project_remove() -> None: + """Remove the specified project artifacts from the given project.""" + + +def __validate_integration_project_dir(ctx: click.Context, option: click.Option, value: str) -> str: + """Validates that the given project directory is an integration project.""" + if get_project_type(Path(value)) != ProjectType.INTEGRATION: + raise click.BadParameter("This command is only supported for integration projects.") + return value + + +# vaf project remove app_module # +@project_remove.command(name="app-module") +@sanatized_str_option( + "-n", "--name", type=str, required=True, help="App-module name.", prompt="Enter the name of the app-module" +) +@filepath_option( + "-p", + "--project-dir", + type=click.Path(exists=True, file_okay=False, writable=True), + required=True, + help="Path to the project root directory.", + default=".", + prompt="Enter the path to the project root directory", + callback=__validate_integration_project_dir, +) +# This option has to come before the --app-modules option, because the app-modules are populated by it's callback +@filepath_option( + cls=modifying_choice_fp_option("-m", "--model-dir", choice_to_modify="app-modules"), + type=click.Path(exists=True, file_okay=False, writable=True), + help="Path to the model directory.", + default=_get_default_model_path(get_project_type_for_project_dir()), + prompt="Enter the path to the model directory", +) +@choice_option( + "--app-modules", + prompt="Choose one ore more application modules", + type=click.Choice([]), + help="Absolute path to the application module project to remove. Specify multiple times for multiple modules.", + multiple=True, +) +# pylint: disable=missing-param-doc +def project_remove_app_module(project_dir: Path, model_dir: Path, app_modules: list[str]) -> None: + """Remove an app-module from an integration project.""" + # This workaround is necessary, because of the hacky solution to support only one choice in + # ModifyingChoiceFpOption.callback_handler() + if isinstance(app_modules, str): + app_modules = [app_modules] + + cmd = ProjectCmd() + cmd.remove_appmodule(project_dir, model_dir, app_modules) diff --git a/VAF/src/vaf/cli_core/main/make_cmd.py b/VAF/src/vaf/cli_core/main/make_cmd.py new file mode 100644 index 0000000..f2d8bfe --- /dev/null +++ b/VAF/src/vaf/cli_core/main/make_cmd.py @@ -0,0 +1,107 @@ +""" +This module contains the implementation of the make commands + +""" + +import os +import subprocess +import sys +from pathlib import Path + + +class MakeCmd: + """Class implementing the make related commands""" + + def __init__(self, verbose_mode: bool = False) -> None: + """ + Ctor for CmdProject class + Args: + verbose_mode (bool): Flag to enable verbose mode + """ + self.verbose_mode = verbose_mode + + def preset(self, build_dir: str, compiler: str, build_type: str, defines: str, cwd: str) -> None: # pylint: disable=too-many-arguments, too-many-positional-arguments + """ + Preset. + + Args: + build_dir: Build directory + compiler: Compiler version + build_type: Debug or release build + defines: Additional defines + cwd: Current working directory + + """ + opt_build_dir = "tools.cmake.cmake_layout:build_folder=" + build_dir + opt_compiler = "-pr:a=" + cwd + "/.conan/" + compiler + opt_type = "build_type=" + build_type + subprocess.run( + ["conan", "install", cwd, opt_compiler, "-s", opt_type, "-c", opt_build_dir, "--build=missing"], + check=False, + stderr=None if self.verbose_mode else subprocess.DEVNULL, + stdout=None if self.verbose_mode else subprocess.DEVNULL, + ) + current_dir = Path.cwd() + os.chdir(cwd) # cmake --preset must run in project root directory + if build_type == "Release": + subprocess.run( + ["cmake", "--preset", "conan-release", defines], + check=False, + stderr=None if self.verbose_mode else subprocess.DEVNULL, + stdout=None if self.verbose_mode else subprocess.DEVNULL, + ) + else: + subprocess.run( + ["cmake", "--preset", "conan-debug", defines], + check=False, + stderr=None if self.verbose_mode else subprocess.DEVNULL, + stdout=None if self.verbose_mode else subprocess.DEVNULL, + ) + os.chdir(current_dir) + + def build(self, preset: str) -> None: + """ + Build. + + Args: + preset: CMake preset + + """ + cpu_count = os.cpu_count() or 1 + subprocess.run( + ["cmake", "--build", "--preset", preset, "--parallel", str(cpu_count)], + check=False, + stderr=sys.stderr, + stdout=sys.stdout, + ) + + def clean(self, preset: str) -> None: + """ + Clean. + + Args: + preset: CMake preset + + """ + subprocess.run( + ["cmake", "--build", "--target", "clean", "--preset", preset], + check=False, + stderr=sys.stderr, + stdout=sys.stdout, + ) + + def install(self, preset: str) -> None: + """ + Install. + + Args: + preset: CMake preset + + """ + cpu_count = os.cpu_count() or 1 + subprocess.run( + ["cmake", "--build", "--target", "install", "--preset", preset, "--parallel", str(cpu_count)], + check=False, + stderr=sys.stderr, + stdout=sys.stdout, + ) diff --git a/VAF/src/vaf/cli_core/main/model_cmd.py b/VAF/src/vaf/cli_core/main/model_cmd.py new file mode 100644 index 0000000..3977569 --- /dev/null +++ b/VAF/src/vaf/cli_core/main/model_cmd.py @@ -0,0 +1,327 @@ +"""Implements the functionality of model related commands""" + +import gc +import importlib.util +import inspect +import json +import os +import pkgutil +import re +import sys +from pathlib import Path +from typing import Any + +from copier import run_copy + +from vaf.cli_core.common.exceptions import VafProjectGenerationError +from vaf.cli_core.common.utils import ( + ProjectType, + get_subprojects_in_path, + to_snake_case, +) +from vaf.cli_core.main.project_cmd import ProjectCmd +from vaf.constants import VAF_CFG_FILE +from vaf.vafgeneration import generate_cac_support +from vaf.vafpy.model_runtime import model_runtime +from vaf.vafvssimport import vss_import + +# pylint: disable=duplicate-code + + +class ModelCmd: # pylint: disable=too-few-public-methods + """Class implementing the platform-related commands""" + + def __init__(self) -> None: + """ + Initializes the class. If the VAF_CFG_FILE is found within + the current working directory the file is used to read information + mostly default values from that file. + """ + if Path.is_file(Path(VAF_CFG_FILE)): + with open(VAF_CFG_FILE, encoding="utf-8") as fh: + self._vaf_config = json.load(fh) + + @staticmethod + def __get_modules_to_import(input_dir: Path) -> list[str]: + """Method to get modules that have the `import_module()` function + Args: + input_dir (Path): directory to search in + Returns: + List of modules to add to the __init__.py + """ + modules: set[str] = set() + sys.path.insert(0, input_dir.as_posix()) + + # Iterate over all elements in folder + for _, element_name, is_package in pkgutil.iter_modules([str(input_dir)]): + if is_package: + continue + module = importlib.import_module(element_name) + + # check if import_model function is there -> found module to import + if any(func_name == "import_model" for func_name, _ in inspect.getmembers(module, inspect.isfunction)): + modules.add(element_name) + + sys.path.pop(0) + return list(modules) + + def import_vss(self, input_file: str, model_dir: str) -> None: + """ + :param input_file: JSON file of the input model. + :param model_dir: Output directory to generate the resulting artifacts. + """ + if model_dir is None or model_dir == "": + # check if it's there is any vaf_config + if hasattr(self, "_vaf_config") and self._vaf_config is not None: + model_dir = Path(self._vaf_config["vaf-artifacts"]["vaf-init-model"]).as_posix() + + if model_dir is not None: + vss_import.run_import(model_dir, input_file) + # Generate the initial model Python helper + generate_cac_support(Path(model_dir), "vss-derived-model.json", "vss", Path(model_dir)) + else: + print("Importing VSS fail! Define -m or --model-dir!") + + def import_model( # pylint: disable = too-many-arguments, too-many-positional-arguments, too-many-locals, too-many-branches, too-many-statements + self, + source_json_file: str, + model_dir: str, + import_mode: str, + force_import: bool = False, + skip_import: bool = False, + ) -> None: # pylint: disable=too-many-locals. too-many-branches, too-many-statements + """ + Args: + source_json_file: Path to the source json file. + model_dir: Path to the directory of the VAF model. + import_mode: Mode of import, either import by copy or reference. + force_import: If true force import. + skip_import: If true force skip import. + + Raises: + FileNotFoundError: If needed artifact does not exist + ValueError: If force import and force skip both are True + """ + source_json_path: Path = Path(source_json_file) + if not source_json_path.exists(): + raise FileNotFoundError(f"Given source {source_json_file} does not exist!") + if not source_json_path.is_file(): + raise FileNotFoundError(f"Given source {source_json_file} is not a file!") + if source_json_path.suffix != ".json": + raise FileNotFoundError(f"Given source {source_json_file} has no suffix '.json'!") + if len(source_json_path.suffixes) > 1: + raise FileNotFoundError(f"Given source {source_json_file} has more than one suffix!") + if force_import and skip_import: + raise ValueError("The CLI parameters 'force-import' and 'skip-import' cannot be set at the same time!") + source_dir: Path = source_json_path.parent + name: str = source_json_path.stem + target_base_path: Path = Path(model_dir) + if not target_base_path.exists(): + raise FileNotFoundError(f"Directory {model_dir} does not exist!") + target_import_path: Path = target_base_path / "imported_models" + if not target_import_path.exists(): + target_import_path.mkdir(exist_ok=True) + imported_models_json_path: Path = target_import_path / "_imported_models.json" + imported_models: dict[str, Any] = {"ImportedModels": []} + if imported_models_json_path.exists(): + with open(imported_models_json_path, "r", encoding="utf-8") as file: + imported_models = json.loads(file.read()) + # Check that source files exists + source_base_path: Path = source_dir + py_file_name = to_snake_case(name.replace("derived-model", "")) + if not source_base_path.exists(): + raise FileNotFoundError(f"Directory {str(source_dir)} does not exist!") + source_py_path: Path = source_base_path / (py_file_name + ".py") + if not source_py_path.exists(): + raise FileNotFoundError(f"Source Py file {source_py_path} does not exist!") + target_json_path: Path = target_import_path / (name + ".json") + target_py_path: Path = target_import_path / (py_file_name + ".py") + # Check if it is a reimport or new import + found_in_registry: bool = False + for imported_element in imported_models["ImportedModels"]: + if imported_element["Name"] == name: + if not force_import: + if skip_import: + print("Import canceled!") + return + user_response: str = input( + "Model with same name already imported. Do you want to overwrite? (yes/no) [no]: " + ) # pylint: disable=line-too-long + if user_response != "yes": + print("Import canceled!") + return + imported_element["SourceDir"] = os.path.relpath(source_dir, target_import_path) + imported_element["ImportMode"] = import_mode + found_in_registry = True + break + if not found_in_registry: + add_element: dict[str, str] = { + "Name": name, + "SourceDir": os.path.relpath(source_dir, target_import_path), + "ImportMode": import_mode, + } + imported_models["ImportedModels"].append(add_element) + + with open(imported_models_json_path, "w", encoding="utf-8") as file: + json.dump(imported_models, file, indent=2) + + if import_mode == "copy": + print("Importing model by copy!") + target_json_path.unlink(missing_ok=True) + target_py_path.unlink(missing_ok=True) + # Copy source to target + target_json_path.write_text(source_json_path.read_text(encoding="utf-8")) + target_py_path.write_text(source_py_path.read_text(encoding="utf-8")) + else: + print("Importing model by reference!") + target_json_path.unlink(missing_ok=True) + target_py_path.unlink(missing_ok=True) + target_json_path.symlink_to(os.path.relpath(source_json_path, target_json_path.parent)) + target_py_path.symlink_to(os.path.relpath(source_py_path, target_py_path.parent)) + + # Clear __init__.py to prevent conflicts while searching for modules + imported_models_init_path: Path = target_import_path / "__init__.py" + with open(imported_models_init_path, "w", encoding="utf-8"): + pass + + # create __init__.py for current directory + template = str(Path(__file__).resolve().parent / "templates" / "interface_model_subfolder") + modules = self.__get_modules_to_import(target_import_path) + run_copy( + template, + target_import_path, + data={"modules": modules}, + overwrite=True, + quiet=True, + ) + + def update_imported_models(self, model_dir: str) -> None: # pylint: disable=too-many-locals + """ + Args: + model_dir: Path to the directory of the VAF model. + + Raises: + FileNotFoundError: If needed artifact does not exist + """ + target_base_path: Path = Path(model_dir) + if not target_base_path.exists(): + raise FileNotFoundError(f"Directory {model_dir} does not exist!") + target_import_path: Path = target_base_path / "imported_models" + if not target_import_path.exists(): + print("No imported modules to update. Skipping!") + return + imported_models_json_path: Path = target_import_path / "_imported_models.json" + imported_models: dict[str, Any] = {"ImportedModels": []} + if imported_models_json_path.exists(): + with open(imported_models_json_path, "r", encoding="utf-8") as file: + imported_models = json.loads(file.read()) + else: + print("No imported modules to update. Skipping!") + return + for imported_element in imported_models["ImportedModels"]: + if imported_element["ImportMode"] == "copy": + print(f"Update imported module {imported_element['Name']}.") + source_base_path: Path = target_import_path / Path(imported_element["SourceDir"]) + if not source_base_path.exists(): + raise FileNotFoundError(f"Directory {source_base_path} does not exist!") + source_json_path: Path = source_base_path / (imported_element["Name"] + ".json") + if not source_json_path.exists(): + raise FileNotFoundError(f"Source Json file {source_json_path} does not exist!") + source_py_path: Path = source_base_path / (to_snake_case(imported_element["Name"]) + ".py") + if not source_py_path.exists(): + raise FileNotFoundError(f"Source Py file {source_py_path} does not exist!") + # Copy source to target + target_json_path: Path = target_import_path / (imported_element["Name"] + ".json") + target_json_path.write_text(source_json_path.read_text()) + target_py_path: Path = target_import_path / (to_snake_case(imported_element["Name"]) + ".py") + target_py_path.write_text(source_py_path.read_text()) + + # pylint: enable=duplicate-code + + def update_app_modules(self, model_dir: Path, app_modules: list[Path]) -> None: + """(Re-)generates the import_appmodule.py scripts for given app modules. + Args: + model_dir (Path): Path to the directory of the project model. + app_modules (list[Path]): List of absoulte paths of the application modules to update. + + Raises: + VafProjectGenerationError: If an application module does not have a model.json file or it is malformed. + """ + for project_path in app_modules: + project_path = project_path / "model/" + + # find rel_pre_path + pattern = r"\/src\/application_modules\/(.*)\/.*?\/model" + match = re.search(pattern, project_path.as_posix()) + rel_pre_path = match.group(1) if match else "." + + # call import generation + try: + ProjectCmd.generate_import_appmodule( + rel_pre_path, + app_modules_dir=model_dir / "application_modules", + export_path=project_path / "model.json", + ) + except (FileNotFoundError, ValueError) as e: + raise VafProjectGenerationError( + f"Error generating the import_appmodule script for {project_path}/model.json:\n" + f"{str(e)}\nCheck your application module configuration." + ) from e + + # update import instance + ProjectCmd._generate_import_instances( # pylint:disable=protected-access + Path.cwd(), app_modules_dir=model_dir / "application_modules", rel_pre_path=rel_pre_path + ) + + def generate(self, project_type: ProjectType, model_dir: str, mode: str) -> None: + """Calls the associated generates to generate the project. + Args: + project_type (ProjectType): VAF project type + model_dir (str): Path to the directory of the VAF model. + mode (str): Generate for PRJ or ALL projects + Raises: + ValueError: If the CaC script of a (sub-) project can't be found / executed + VafProjectGenerationError: If the app-module_import script generation fails + """ + + def _run_cac(model_file: Path) -> None: + print(f"Executing CaC for {model_file}") + # Reset runtime, remove previously loaded model, for the model-import to be triggered again + model_runtime.reset() + loaded_modules_before_cac = list(sys.modules) + + spec = importlib.util.spec_from_file_location(model_file.stem, model_file, submodule_search_locations=[]) + if spec is not None: + module = importlib.util.module_from_spec(spec) + if spec.loader is not None: + # temporarily add model_dir to sys.path to support local imports + sys.path.insert(0, model_file.parent.as_posix()) + try: + sys.modules[model_file.stem] = module + spec.loader.exec_module(module) + module.export_model() + except Exception as e: + raise ValueError(f"CaC cannot be executed: {model_file}:\n{str(e)}") from e + finally: + sys.path.pop(0) + + # unload all modules loaded during CaC execution + modules_to_unload = [mod for mod in sys.modules if mod not in loaded_modules_before_cac] + for mod in modules_to_unload: + del sys.modules[mod] + gc.collect() + + if "ALL" == mode and project_type == ProjectType.INTEGRATION: + # find all subprojects + app_modules_dir = Path(model_dir) / "application_modules" + subprojects = get_subprojects_in_path(ProjectType.APP_MODULE, app_modules_dir) + + for project_path in subprojects: + model_path = project_path / "model" / "model.py" + _run_cac(model_path) + + # call import generation + self.update_app_modules(model_dir=Path(model_dir), app_modules=subprojects) + + # call local cac + _run_cac(Path(model_dir) / "model.py") diff --git a/VAF/src/vaf/cli_core/main/project_cmd.py b/VAF/src/vaf/cli_core/main/project_cmd.py new file mode 100644 index 0000000..f5e9e42 --- /dev/null +++ b/VAF/src/vaf/cli_core/main/project_cmd.py @@ -0,0 +1,616 @@ +""" +Implements the functionality of project related commands +""" + +import importlib +import inspect +import json +import os +import pkgutil +import re +import sys +import warnings +from pathlib import Path +from shutil import rmtree +from types import ModuleType +from typing import Any, Dict, Optional + +from copier import run_copy + +from vaf import vafmodel, vafpy +from vaf.cli_core.common.exceptions import VafProjectGenerationError, VafProjectTemplateError +from vaf.cli_core.common.utils import ( + ProjectType, + get_kwargs_from_local_variables, + get_parent_ws, + get_project_type, + get_projects_in_path, + to_camel_case, + to_snake_case, +) +from vaf.constants import VAF_CFG_FILE +from vaf.vafgeneration.vaf_application_module import validate_model_app_modules +from vaf.vafgeneration.vaf_generate_application_module import generate_application_module +from vaf.vafgeneration.vaf_generate_project import generate_integration_project + +# pylint: disable=duplicate-code + + +class ProjectCmd: + """Class implementing related project commands""" + + def __init__(self, verbose_mode: bool = False) -> None: + """ + Ctor for CmdProject class + Args: + verbose_mode (bool): Flag to enable verbose mode. + """ + self.verbose_mode = verbose_mode + + def _update_project_paths_in_ws(self, ws_path: Path) -> None: + file_path = ws_path / ".vscode" / "settings.json" + + with open(file_path, "r", encoding="utf-8") as file: + data = json.load(file) + + source_dirs = set() + for pr_path, pr_type in get_projects_in_path(ws_path): + if pr_type == ProjectType.INTEGRATION: + # add nested app-modules + for nested_path, _ in get_projects_in_path(pr_path): + source_dirs.add(f"${{workspaceFolder}}/{nested_path.resolve().relative_to(ws_path).as_posix()}") + source_dirs.add(f"${{workspaceFolder}}/{pr_path.relative_to(ws_path).as_posix()}") + + data["cmake.sourceDirectory"] = sorted(source_dirs) + + with open(file_path, "w", encoding="utf-8") as file: + json.dump(data, file, indent=4) + + # pylint: disable=too-many-arguments + # pylint: disable=too-many-positional-arguments + def generate_integration( + self, + input_file: str, + project_dir: str, + mode: str, + disable_auto_merge: bool = False, + ) -> None: + """Calls the associated generates to generate the project. + Args: + input_file (str): Path to the VAF model. + project_dir (str): Path to the output directory. + mode (str): Generate for PRJ or ALL. + disable_auto_merge (bool): Flag to disable auto merging logic after generation. + Raises: + ValueError: If the path to the project root directory is invalid. + VafProjectGenerationError: If there is an error during project generation. + """ + + # validate all application modules + model = vafmodel.load_json(input_file) + validate_model_app_modules(model) + + # ALL: also regenerate app-module projects + if mode == "ALL": + print("Generate source for all application modules inside this Integration project.") + + if project_dir is None: + raise ValueError("Path to project directory cannot be None!") + + base_path: Path = Path(project_dir).absolute() + for pr_path, pr_type in get_projects_in_path(base_path / "src" / "application_modules"): + if pr_type == ProjectType.APP_MODULE: + print(f"Generate source for application module in {pr_path}") + + app_module_input_path: str = (pr_path / "model" / "model.json").as_posix() + generate_application_module( + model_file=app_module_input_path, + project_dir=pr_path.as_posix(), + verbose_mode=self.verbose_mode, + execute_merge=not disable_auto_merge, + ) + + print("Generate source for integration project.") + generate_integration_project( + model_file=input_file, + verbose_mode=self.verbose_mode, + execute_merge=not disable_auto_merge, + **(get_kwargs_from_local_variables(locals(), generate_integration_project)), # type:ignore[arg-type] + ) + + # pylint: disable=too-many-arguments + # pylint: disable=too-many-positional-arguments + def generate_app_module( + self, + input_file: str, + project_dir: str, + disable_auto_merge: bool = False, + ) -> None: + """Calls the associated generates to generate the project. + Args: + input_file (str): Path to the VAF model + project_dir (str): Path to the project directory + disable_auto_merge (bool): Flag to disable auto merging logic after generation + """ + print("Generate source for Application Module.") + generate_application_module( + model_file=input_file, + project_dir=project_dir, + verbose_mode=self.verbose_mode, + execute_merge=not disable_auto_merge, + ) + + def _validate_vaf_config(self, template: str) -> None: + """ + Validates the VAF_CFG_FILE within the template directory if any. + + Args: + template (str): Project template to be validated. + """ + expected_vafconfig = Path(template) / VAF_CFG_FILE + + if not expected_vafconfig.is_file(): + raise VafProjectTemplateError( + f""" + Template does not have a {VAF_CFG_FILE}. + Please refer to the documentation on how to create a valid {VAF_CFG_FILE} + """ + ) + + @staticmethod + def __create_next_init_py_file(sub_folder: str | Path, output_dir: Path) -> None: + """Method to create next init.py file + Args: + sub_folder: subfolder name + output_dir: output directory + """ + next_init_py_file_path = output_dir / sub_folder / "__init__.py" + if not next_init_py_file_path.exists(): + with open(next_init_py_file_path, "w", encoding="utf-8") as file: + file.write("") + + @staticmethod + def __import_by_file_name(path_to_file: Path | str, file_name: str) -> ModuleType: + """Method to import python module by it's path & fill name + Args: + path_to_file: path to the file + file_name: name of the python file without ".py" + Returns: + ModuleType: module object contained by the file + """ + spec = importlib.util.spec_from_file_location(file_name, f"{path_to_file}/{file_name}.py") + if spec: + module = importlib.util.module_from_spec(spec) + if module and spec.loader: + sys.modules[file_name] = module + spec.loader.exec_module(module) + + if not module: + raise RuntimeError(f"Failed to import module in {path_to_file}/{file_name}.py") + + return module + + @classmethod + def __get_packages_and_modules( + cls, full_module_parent_dir: Path | str, output_dir: str | Path + ) -> tuple[list[str], list[str], list[str]]: + """Method to get packages and modules + Args: + full_module_parent_dir: module parent dir + output_dir: output directory + Returns: + Tuple that contains lists of packages, imports, classes + """ + packages: set[str] = set() + imports: set[str] = set() + classes: set[str] = set() + + if isinstance(output_dir, str): + output_dir = Path(output_dir) + + if isinstance(full_module_parent_dir, str): + full_module_parent_dir = Path(full_module_parent_dir) + + # Iterate over all elements in folder + for _, element_name, is_package in pkgutil.iter_modules([str(output_dir)]): + if is_package: + packages.add(element_name) + classes.add(element_name) + elif (full_module_parent_dir / f"{element_name}.py").is_file(): + module = cls.__import_by_file_name(full_module_parent_dir, element_name) + + if module is not None: + if element_name.endswith("import_instances"): + instance_class_names = [] + for instance_class in inspect.getmembers(module, inspect.isclass): + classes.add(instance_class[0]) + instance_class_names.append(instance_class[0]) + instance_classes_import_str = ", ".join(instance_class_names) + imports.add(f"from .{element_name} import {instance_classes_import_str}") + + # check if import_application_module function is there -> import class + if any( + func_name == "import_application_module" + for func_name, _ in inspect.getmembers(module, inspect.isfunction) + ): + # add imported AppModules + for app_module_name, _ in inspect.getmembers( + module, lambda x: (isinstance(x, vafpy.ApplicationModule)) + ): + imports.add(f"from .{element_name} import {app_module_name}") + classes.add(app_module_name) + + return (list(packages), list(imports), list(classes)) + + @staticmethod + def __read_app_module_data_from_json(path_to_json: Path | str) -> tuple[str, Dict[str, Any]]: + result: Dict[str, Any] = {} + # Load name, namespace, consumed_interfacemodules, provided_interfacemodules and tasks from model.json + with open(path_to_json, "r", encoding="utf-8") as file: + model = json.load(file) + if len(model["ApplicationModules"]) != 1: + raise ValueError(f"Model file {path_to_json} contains more than one application module.") + app_module = model["ApplicationModules"][0] + name = app_module["Name"] + result["namespace"] = app_module["Namespace"] + result["tasks"] = [task["Name"] for task in app_module.get("Tasks", [])] + result["consumed_interfaces"] = [mi["InstanceName"] for mi in app_module.get("ConsumedInterfaces", [])] + result["provided_interfaces"] = [mi["InstanceName"] for mi in app_module.get("ProvidedInterfaces", [])] + + return name, result + + @classmethod + def __read_imports_from_init(cls, path_to_init: Path | str) -> Optional[str]: + """Method to replace imports in model.py with explicit imports + Args: + path_to_init: Path to application_modules/__init__.py + Returns: + list of imports + """ + if isinstance(path_to_init, str): + path_to_init = Path(path_to_init) + + imported = re.findall(r"(?<=__all__ =).+(?=\])", path_to_init.read_text(encoding="utf-8"), flags=re.S) + return ( + ", ".join( + imported[0] + .replace("[", "") + .replace("\n", "") + .replace('"', "") + .replace("]", "") + .replace(" ", "") + .split(",") + ) + if len(imported) == 1 + else None + ) + + @classmethod + def __update_model_imports(cls, path_to_model: Path | str, imports_str: str) -> None: + """Method to replace imports in model.py with explicit imports + Args: + path_to_model: Path to model.py + imports_str: import strings + """ + if isinstance(path_to_model, str): + path_to_model = Path(path_to_model) + + if path_to_model.is_file() and path_to_model.as_posix().endswith(".py"): + model_text = path_to_model.read_text(encoding="utf-8") + imports_str = "from .application_modules import " + imports_str + new_text = re.sub(r"from \.application_modules import.+", imports_str, model_text) + path_to_model.write_text(new_text, encoding="utf-8") + + @classmethod + def _generate_import_instances(cls, project_dir: Path | str, app_modules_dir: Path, rel_pre_path: str) -> None: + """Method to generate the import_instances.py script for an application module + Args: + project_dir: Root path of the integration project. + app_modules_dir (Path): Path to the application modules model directory + rel_pre_path: Relative pre-path to the app-module directory in which the app-module is to be created, + according to the following schema: + <project_root_dir>/src/application_modules/<relativ_pre_path>/<app_module_dir> + Raises: + FileNotFoundError: If the model.json file cannot be found + ValueError: If the model.json file contains more than one application module + """ + if isinstance(project_dir, str): + project_dir = Path(project_dir) + + app_modules_data: Dict[str, Dict[str, Any]] = {} + # get app modules data + app_module_src_dir = project_dir / "src/application_modules" + for app_module_dir in os.listdir(app_module_src_dir): + app_module_dir_path = app_module_src_dir / app_module_dir + model_file = app_module_dir_path / "model/model.json" + if app_module_dir_path.is_dir() and model_file.is_file(): + name, data = cls.__read_app_module_data_from_json(model_file) + app_modules_data[name] = data + + if app_modules_data: + template = str( + Path(__file__).resolve().parent / "templates" / "application_module_integration_instance_import" + ) + + run_copy( + src_path=template, + dst_path=app_modules_dir, + data={ + "app_modules_data": app_modules_data, + "to_camel_case": to_camel_case, + "generated_attributes": ["Tasks", "ConsumedInterfaces", "ProvidedInterfaces"], + }, + overwrite=True, + quiet=True, + ) + + # generate/update init.py + cls.__generate_init_py(app_modules_dir, rel_pre_path) + + # get imports strings + imports_string = cls.__read_imports_from_init(app_modules_dir / "__init__.py") + if imports_string is not None and not imports_string.isspace(): + # update explicit imports in integration project CaC model + # get name of the CaC file in integration model + path_to_cac_model = project_dir / "model/vaf" / (to_snake_case(project_dir.name) + ".py") + # update the imports there + cls.__update_model_imports(path_to_cac_model, imports_string) + + @classmethod + def generate_import_appmodule(cls, rel_pre_path: str, app_modules_dir: Path, export_path: Path) -> None: + """Method to generate the import_appmoudle.py script for an application module + Args: + rel_pre_path (str): Relative prefix path of the app-module to the app-module directory + app_modules_dir (Path): Path to the application modules model directory + export_path (Path): Path to the exported model.json of the application module + Raises: + FileNotFoundError: If the model.json file cannot be found + ValueError: If the model.json file contains more than one application module + """ + if not export_path.is_file(): + raise FileNotFoundError(f"Model file {export_path} not found.") + + # Load name, namespace, consumed_interfacemodules, provided_interfacemodules and tasks from model.json + name, app_module_data = cls.__read_app_module_data_from_json(export_path) + + go_down: str = "" + if rel_pre_path not in (".", "./"): + go_down = "../" * len(rel_pre_path.split("/")) + + template = str(Path(__file__).resolve().parent / "templates" / "application_module_integration_model_import") + + if rel_pre_path in (".", "./"): + app_module_dir = to_snake_case(name) + else: + app_module_dir = rel_pre_path + "/" + to_snake_case(name) + run_copy( + src_path=template, + dst_path=app_modules_dir / rel_pre_path, + data={ + "model_path": f"{go_down}../../../src/application_modules/{app_module_dir}/model", + "full_app_module_dir": app_module_dir, + "module_namespace": app_module_data["namespace"], + "module_name": name, + "module_name_snk": to_snake_case(name), + }, + overwrite=True, + quiet=True, + ) + + def create_appmodule(self, namespace: str, name: str, project_dir: str, rel_pre_path: str, model_dir: str) -> None: # pylint: disable=too-many-arguments, too-many-locals, too-many-statements, too-many-positional-arguments + """ + Args: + namespace: Namespace of the newly created app-module. + name: Name of the newly created app-module. + project_dir: Root path of the integration project. + rel_pre_path: Relative pre-path to the app-module directory in which the app-module is to be created, + according to the following schema: + <project_root_dir>/src/application_modules/<relativ_pre_path>/<app_module_dir> + model_dir: Path to the directory of the VAF model. + + Raises: + VafProjectGenerationError: If there is a system-related error during create app-module. + VafProjectTemplateError: If the app-module_import script generation fails + ValueError: If the name of the app module to be created contains "-". + """ + if "-" in name: + raise ValueError(f'The name {name} of the application module must not contain "-".') + if Path(rel_pre_path).is_absolute(): + raise VafProjectGenerationError("The path rel-pre-path must be relative!") + if Path(model_dir).is_absolute(): + raise VafProjectGenerationError("The path model-dir must be relative!") + + output_dir: Path = Path(project_dir) / "src/application_modules" / rel_pre_path + # check if application module already exists + full_app_module_dir: Path = output_dir / to_snake_case(name) + if full_app_module_dir.exists(): + raise VafProjectGenerationError("Other application module already exists on specified location!") + + output_dir.mkdir(parents=True, exist_ok=True) + pwd = Path(__file__).resolve().parent + template = str(pwd.parent / "bootstrap" / "templates" / "application_module") + + run_copy( + template, + output_dir, + data={ + "module_namespace": namespace, + "module_name": name, + "module_name_snk": to_snake_case(name), + "module_dir_name": to_snake_case(name), + }, + ) + + app_modules_dir = Path(project_dir) / Path(model_dir) / "application_modules" + try: + self.generate_import_appmodule(rel_pre_path, app_modules_dir, full_app_module_dir / "model/model.json") + except (FileNotFoundError, ValueError) as e: + raise VafProjectTemplateError( + f"Error generating the import_appmodule script for {namespace}::{name}:\n" + f"{str(e)}\nCheck your application module template." + ) from e + + sys.path.append(str(Path(project_dir) / Path(model_dir))) + + self._generate_import_instances(project_dir, app_modules_dir, rel_pre_path) + + # Check if app-module is added to an integration project inside of a workspace + containing_ws = get_parent_ws(Path(project_dir)) + if containing_ws: + self._update_project_paths_in_ws(containing_ws) + + @classmethod + def __generate_init_py(cls, app_modules_dir: Path, rel_pre_path: str) -> None: + """method to generate init.py + Args: + app_modules_dir: Absolute path to the application_modules dir in model/vaf + rel_pre_path: Relative pre-path to the app-module directory in which the app-module is to be created, + according to the following schema: + <project_root_dir>/src/application_modules/<relativ_pre_path>/<app_module_dir> + """ + output_dir = app_modules_dir + full_module_parent_dir = app_modules_dir + + sub_folders: list[str] = [] + if rel_pre_path not in (".", "./"): + sub_folders = rel_pre_path.split("/") + if len(sub_folders) > 0: + cls.__create_next_init_py_file(sub_folders[0], output_dir) + + pwd = Path(__file__).resolve().parent + template = str(pwd / "templates" / "application_module_integration_model_subfolder") + + packages, imports, classes = cls.__get_packages_and_modules(full_module_parent_dir, output_dir) + run_copy( + template, + output_dir, + data={ + "packages": packages, + "imports": imports, + "classes": classes, + }, + overwrite=True, + quiet=True, + ) + number_subfolders = len(sub_folders) + for index, folder in enumerate(sub_folders): + output_dir = output_dir / folder + full_module_parent_dir = full_module_parent_dir / folder + if index < (number_subfolders - 1): + cls.__create_next_init_py_file(sub_folders[0], output_dir) + + packages, imports, classes = cls.__get_packages_and_modules(full_module_parent_dir, output_dir) + run_copy( + template, + output_dir, + data={ + "packages": packages, + "imports": imports, + "classes": classes, + }, + overwrite=True, + quiet=True, + ) + + def import_appmodule(self, import_module_dir: str, project_dir: str, rel_pre_path: str, model_dir: str) -> None: # pylint: disable=too-many-arguments, too-many-locals, too-many-statements, too-many-positional-arguments, too-many-branches + """ + Args: + import_module_dir: Path to the app-module which is to be imported + project_dir: Root path of the integration project. + rel_pre_path: Relative pre-path to the app-module directory in which the app-module is to be imported, + according to the following schema: + <project_root_dir>/src/application_modules/<relative_pre_path>/<app_module_dir> + model_dir: Path to the directory of the VAF model. + + Raises: + VafProjectGenerationError: If there is a system-related error during cleanup. + VafProjectTemplateError: If the appmodule_import script generation fails + """ + if Path(rel_pre_path).is_absolute(): + raise VafProjectGenerationError("The path rel-pre-path must be relative!") + if Path(model_dir).is_absolute(): + raise VafProjectGenerationError("The path model-dir must be relative!") + + main_model = vafmodel.load_json(f"{import_module_dir}/model/model.json") + if len(main_model.ApplicationModules) != 1: + raise VafProjectGenerationError( + "Imported application module has wrong number of application modules in exported model!" + ) + + name: str = main_model.ApplicationModules[0].Name + namespace: str = main_model.ApplicationModules[0].Namespace + + output_dir: Path = Path(project_dir) / "src/application_modules" / rel_pre_path + # check if application module is already part of integration project and if not link it in + full_app_module_dir: Path = output_dir / to_snake_case(name) + if not full_app_module_dir.resolve() == Path(import_module_dir).resolve(): + if full_app_module_dir.exists(): + raise VafProjectGenerationError("Other application module already exists on specified location!") + + output_dir.mkdir(parents=True, exist_ok=True) + if Path(import_module_dir).is_absolute(): + full_app_module_dir.symlink_to(Path(import_module_dir).resolve()) + else: + full_app_module_dir.symlink_to(os.path.relpath(import_module_dir, full_app_module_dir.parent)) + + # Generate the import_appmodule.py script + app_modules_dir = Path(project_dir) / Path(model_dir) / "application_modules" + try: + self.generate_import_appmodule(rel_pre_path, app_modules_dir, full_app_module_dir / "model/model.json") + except (FileNotFoundError, ValueError) as e: + raise VafProjectTemplateError( + f"Error generating the import_appmodule script for {namespace}::{name}:\n" + f"{str(e)}\nCheck your application module's model.json." + ) from e + + sys.path.append(str(Path(project_dir) / Path(model_dir))) + self._generate_import_instances(project_dir, app_modules_dir, rel_pre_path) + + def remove_appmodule(self, project_dir: Path, model_dir: Path, app_modules: list[str]) -> None: + """ + Args: + project_dir (Path): Root path of the integration project. + model_dir (Path): Path to the directory of the VAF model. + app_modules (list[str]): List of absolute paths of the application modules to remove. + + Raises: + ValueError: If the model-dir is absolute. + RuntimeError: If import_<name>.py doesn't exist but needs to be removed + """ + + if model_dir.is_absolute(): + raise ValueError("The path model-dir must be relative!") + + project_dir = project_dir.resolve() # Ensure project_dir is absolute + + # remove the application module project from rel pre path + for app_module in app_modules: + app_module_path = Path(app_module) + # Check if path is in project_dir and an app module project + if ( + not app_module_path.is_relative_to(project_dir) + or get_project_type(app_module_path) != ProjectType.APP_MODULE + ): + warnings.warn(f"{app_module_path} is not an app-module project or part of the integration project.") + continue + + print(f"Removing App Module Project {app_module_path} from integration project.") + # use unlink to remove symlink + if app_module_path.is_symlink(): + app_module_path.unlink() + else: + rmtree(app_module_path) + + app_modules_dir = project_dir / model_dir / "application_modules" + rel_pre_path = app_module_path.relative_to(project_dir / "src/application_modules").parent + import_model_file = app_modules_dir / rel_pre_path / f"import_{app_module_path.name}.py" + if import_model_file.is_file(): + print(f"Removing App Module CaC Model from integration project: {import_model_file}") + import_model_file.unlink() + else: + raise RuntimeError(f"VAF Error: Path {import_model_file} doesn't exist") + + self.__generate_init_py(app_modules_dir, rel_pre_path.as_posix()) + + +# pylint: enable=duplicate-code diff --git a/VAF/src/vaf/cli_core/main/templates/application_module_integration_instance_import/import_instances.py.jinja b/VAF/src/vaf/cli_core/main/templates/application_module_integration_instance_import/import_instances.py.jinja new file mode 100644 index 0000000..0af62b9 --- /dev/null +++ b/VAF/src/vaf/cli_core/main/templates/application_module_integration_instance_import/import_instances.py.jinja @@ -0,0 +1,17 @@ +"""Import the instances of application modules. + +This file is generated. Do not edit manually! +""" +class Instances: +{% for app_module_name, app_module_data in app_modules_data.items() %} + class {{ app_module_name }}: + {% for attribute_name, attribute_values in app_module_data.items() -%} + {% set attribute_name_camel=to_camel_case(attribute_name) -%} + {% if attribute_values and attribute_name_camel in generated_attributes %} + class {{ attribute_name_camel }}: + {% for value in attribute_values -%} + {{ value }} = "{{ value }}" + {% endfor -%} + {% endif -%} + {% endfor -%} +{% endfor -%} diff --git a/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_import/import_{{module_name_snk}}.py.jinja b/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_import/import_{{module_name_snk}}.py.jinja new file mode 100644 index 0000000..99623fa --- /dev/null +++ b/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_import/import_{{module_name_snk}}.py.jinja @@ -0,0 +1,22 @@ +"""Import the application module. + +This file is generated. Do not edit manually! +""" + +import os +from typing import Optional +from vaf.vafpy import ApplicationModule +from vaf.vafpy.runtime import import_application_module, get_application_module + +class ImportedApplicationModule(ApplicationModule): + def __init__(self, imported_module: Optional[ApplicationModule] = None): + pass + +{{module_name}}: ImportedApplicationModule = ImportedApplicationModule() + +model_path = "{{model_path}}" + +if "IMPORT_APPLICATION_MODULES" in os.environ: + script_path = os.path.dirname(os.path.realpath(__file__)) + import_application_module(os.path.join(script_path, f"{model_path}/model.json"), "{{full_app_module_dir}}") + {{module_name}} = get_application_module("{{module_name}}", "{{module_namespace}}") diff --git a/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_subfolder/__init__.py.jinja b/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_subfolder/__init__.py.jinja new file mode 100644 index 0000000..7ac871d --- /dev/null +++ b/VAF/src/vaf/cli_core/main/templates/application_module_integration_model_subfolder/__init__.py.jinja @@ -0,0 +1,13 @@ +"""Initialize the application_modules module. + +This file is generated. Do not edit manually! +""" + +__all__ = [ + {{ classes | map("to_json") | join(',\n') | indent(4) }} +] + +{% for package in packages -%} +from . import {{ package }} +{% endfor %} +{{ imports | join('\n') }} diff --git a/VAF/src/vaf/cli_core/main/templates/interface_model_subfolder/__init__.py.jinja b/VAF/src/vaf/cli_core/main/templates/interface_model_subfolder/__init__.py.jinja new file mode 100644 index 0000000..24b130c --- /dev/null +++ b/VAF/src/vaf/cli_core/main/templates/interface_model_subfolder/__init__.py.jinja @@ -0,0 +1,12 @@ +"""Initialize the interface module. + +This file is generated. Do not edit manually! +""" + +__all__ = [ + {{ modules | map("to_json") | join(',\n') | indent(4) }} +] + +{% for module in modules -%} +from . import {{ module }} +{% endfor %} \ No newline at end of file diff --git a/VAF/src/vaf/constants.py b/VAF/src/vaf/constants.py new file mode 100644 index 0000000..b2495b5 --- /dev/null +++ b/VAF/src/vaf/constants.py @@ -0,0 +1,14 @@ +"""Constants relevant for all VAF modules""" + +from enum import Enum + + +class TruthyEnum(Enum): + """Enum that allows the usage in if/while by checking against the first entry""" + + def __bool__(self) -> bool: + first_element = list(self.__class__)[0] + return self != first_element + + +VAF_CFG_FILE = ".vafconfig.json" diff --git a/VAF/src/vaf/py.typed b/VAF/src/vaf/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/vafgeneration/__init__.py b/VAF/src/vaf/vafgeneration/__init__.py new file mode 100644 index 0000000..4a363c3 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/__init__.py @@ -0,0 +1,33 @@ +# ruff: noqa: F401 +"""Initialize the module. + +Could be used to define the public interface of the module. +""" + +# Import modules and objects that belong to the public interface # pylint: disable=W0511 +__all__ = [ + "generate_app_module_project_files", + "generate_application_communication", + "generate_application_module_project", + "generate_cac_support", + "generate_cmake_common", + "generate_conan_deps", + "generate_controller", + "generate_interface", + "generate_project", + "generate_protobuf_serdes", + "generate_silkit", + "generate_std_vaf_data_types", +] +from .vaf_application_communication import generate as generate_application_communication +from .vaf_application_module import generate_app_module_project_files +from .vaf_cac_support import generate as generate_cac_support +from .vaf_cmake_common import generate as generate_cmake_common +from .vaf_conan import generate as generate_conan_deps +from .vaf_controller import generate as generate_controller +from .vaf_generate_application_module import generate_application_module as generate_application_module_project +from .vaf_generate_project import generate_integration_project as generate_project +from .vaf_interface import generate_module_interfaces as generate_interface +from .vaf_protobuf_serdes import generate as generate_protobuf_serdes +from .vaf_silkit import generate as generate_silkit +from .vaf_std_data_types import generate as generate_std_vaf_data_types diff --git a/VAF/src/vaf/vafgeneration/generation.py b/VAF/src/vaf/vafgeneration/generation.py new file mode 100644 index 0000000..8a463b3 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/generation.py @@ -0,0 +1,573 @@ +"""Common generator functionality""" + +import filecmp +from pathlib import Path +from typing import Any + +from jinja2 import Environment, PackageLoader, select_autoescape + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_camel_case, to_snake_case + + +def data_type_to_str(data_type: vafmodel.DataType) -> str: + """Converts a DataType to string + + Args: + data_type (vafmodel.DataType): The data type + + Returns: + str: DataType as string + """ + if is_data_type_cstdint_type(data_type.Name, data_type.Namespace): + return "std::" + data_type.Name + return data_type.Namespace.lower() + "::" + data_type.Name if data_type.Namespace != "" else data_type.Name + + +def implicit_data_type_to_str(name: str, namespace: str) -> str: + """Converts a data type given by name and namespace to string + + Args: + name (str): The name of the data type + namespace (str): The namespace of the data type + + Returns: + str: DataType as string + """ + data_type: vafmodel.DataType = vafmodel.DataType(Name=name, Namespace=namespace) + if is_data_type_cstdint_type(data_type.Name, data_type.Namespace): + return "std::" + data_type.Name + return data_type.Namespace.lower() + "::" + data_type.Name if data_type.Namespace != "" else data_type.Name + + +def add_namespace_to_name(name: str, namespace: str) -> str: + """Add a namespace to name string + + Args: + name (str): Name + namespace (str): Namespace + + Returns: + str: namespace + name as string + """ + return namespace.replace("::", "_") + "_" + name if namespace != "" else name + + +def time_str_to_milliseconds(s: str) -> int: + """Converts a time string to milliseconds. Example "10ms" -> 10 + + Args: + s (str): The time string. + + Raises: + Exception: If the time string is invalid + + Returns: + int: The time in milliseconds + """ + if s.endswith("ns"): + return int(int(s.removesuffix("ns")) / 1_000_000) + if s.endswith("us"): + return int(int(s.removesuffix("us")) / 1_000) + if s.endswith("ms"): + return int(s.removesuffix("ms")) + if s.endswith("s"): + return int(s.removesuffix("s")) * 1_000 + raise ValueError("Invalid time string: " + s) + + +def time_str_to_nanoseconds(s: str) -> int: + """Converts a time string to nanoseconds. Example "10ns" -> 10 + + Args: + s (str): The time string. + + Raises: + Exception: If the time string is invalid + + Returns: + int: The time in nanoseconds + """ + if s.endswith("ns"): + return int(s.removesuffix("ns")) + if s.endswith("us"): + return int(s.removesuffix("us")) * 1_000 + if s.endswith("ms"): + return int(s.removesuffix("ms")) * 1_000_000 + if s.endswith("s"): + return int(s.removesuffix("s")) * 1_000_000_000 + raise ValueError("Invalid time string: " + s) + + +class FileHelper: + """Helper class for files to be generated""" + + def __init__(self, name: str, namespace: str, force_file_name: bool = False) -> None: + self.name = name + self.namespace = namespace + self.namespaces = namespace.split("::") if len(namespace) > 0 else [] + self.force_file_name = force_file_name + + def get_name(self) -> str: + """Gets the name of the file + + Returns: + str: The file name + """ + if self.force_file_name: + return self.name + return to_snake_case(self.name) + + def _get_relative_file_path(self) -> str: + """Gets the path to the file + + Args: + base_dir (str): A base directory which will be prefixed + + Returns: + str: The full file path + """ + path = "" + for n in self.namespaces: + path += n.lower() + "/" + path += self.get_name() + return path + + def get_file_path(self, base_dir: Path | str, postfix: str) -> Path: + """Gets the path to the file + + Args: + base_dir (Path | str): A base directory which will be prefixed + postfix (str): The file postfix + + Returns: + str: The full file path + """ + if isinstance(base_dir, str): + base_dir = Path(base_dir) + + path = base_dir + if ".h" in postfix: + path = path / "include" + elif ".cpp" in postfix: + path = path / "src" + path = path / Path(self._get_relative_file_path() + postfix) + return path + + def get_simple_file_path(self, base_dir: Path | str, postfix: str) -> Path: + """Gets the simple path to the file, i.e. without namespace structure + + Args: + base_dir (Path | str): A base directory which will be prefixed + postfix (str): The file postfix + + Returns: + str: The full file path + """ + if isinstance(base_dir, str): + base_dir = Path(base_dir) + + path = base_dir + if ".h" in postfix: + path = path / "include" + elif ".cpp" in postfix: + path = path / "src" + path = path / Path(self.get_name() + postfix) + return path + + def get_include(self) -> str: + """Gets the include of this file, so other files can include it + + Returns: + str: The include + """ + return '#include "' + self._get_relative_file_path() + '.h"' + + def get_datatype_include(self) -> str: + """Gets the include of data type file, so other files can include it + + Returns: + str: The include + """ + + path = "" + for n in self.namespaces: + path += n.lower() + "/" + path += "impl_type_" + self.name.lower() + '.h"' + + return '#include "' + path + + def get_guard(self) -> str: + """Get the include guard + + Returns: + str: The include guard + """ + ret = "" + for n in self.namespaces: + ret += n.upper() + "_" + ret += self.get_name().upper() + "_H" + ret = ret.replace(".", "_") + + return ret + + def get_include_guard_start(self) -> str: + """Gets the include guard start + + Returns: + str: The include guard start + """ + return "#ifndef {guard}\n#define {guard}\n".format(guard=self.get_guard()) + + def get_include_guard_end(self) -> str: + """Gets the include guard end + + Returns: + str: The include guard end + """ + return f"#endif // {self.get_guard()}\n" + + def get_namespace_start(self) -> str: + """Get the namespace opening + + Returns: + str: The namespace opening + """ + return "".join([f"namespace {ns} {{\n" for ns in self.namespaces]) + + def get_namespace_end(self) -> str: + """Get the namespace closing + + Returns: + str: The namespace closing + """ + return "".join([f"}} // namespace {ns}\n" for ns in reversed(self.namespaces)]) + + def get_full_type_name(self) -> str: + """Gets the full type name (including namespace) + + Returns: + str: The full type name + """ + return self.namespace + "::" + self.name if self.namespace != "" else self.name + + +def is_data_type_base_type(name: str, namespace: str) -> bool: + """Checks if a data type is a C++ base type + + Args: + name (str): The name of the data type + namespace (str): The namespace of the data type + + Returns: + bool: True if the data type is a C++ base type, False otherwise + """ + base_types = ["float", "double", "bool"] + if len(namespace) == 0 or namespace == "std": + if name in base_types: + return True + + return False + + +def is_data_type_cstdint_type(name: str, namespace: str) -> bool: + """Checks if a data type is a C++ std int type + + Args: + name (str): The name of the data type + namespace (str): The namespace of the data type + + Returns: + bool: True if the data type is a C++ std int type, False otherwise + """ + cstdint_types = [ + "uint8_t", + "uint16_t", + "uint32_t", + "uint64_t", + "int8_t", + "int16_t", + "int32_t", + "int64_t", + ] + if len(namespace) == 0 or namespace == "std": + if name in cstdint_types: + return True + + return False + + +def get_include(name: str, namespace: str) -> str: + """Gets the C++ include line to include the object + + Args: + name (str): The name of the object + namespace (str): The namespace of the object + + Returns: + str: C++ code to include the object + """ + return FileHelper(name, namespace).get_include() + + +def get_data_type_include(name: str, namespace: str) -> str: + """Gets the C++ include line to include a data type + + Args: + name (str): The name of the data type + namespace (str): The namespace of the data type + + Returns: + str: C++ code to include the data type + """ + if is_data_type_base_type(name, namespace): + return "" + if is_data_type_cstdint_type(name, namespace): + return "#include <cstdint>" + return FileHelper(name, namespace).get_datatype_include() + + +def has_operation_out_or_inout_parameter(operation: vafmodel.Operation) -> bool: + """Checks if a operations has a out or inout parameter + + Args: + operation (vafmodel.Operation): The operation + + Returns: + bool: True if the operation has a out or inout parameter, False otherwise + """ + return ( + len( + [ + p + for p in operation.Parameters + if p.Direction in (vafmodel.ParameterDirection.OUT, vafmodel.ParameterDirection.INOUT) + ] + ) + > 0 + ) + + +def has_operation_in_or_inout_parameter(operation: vafmodel.Operation) -> bool: + """Checks if a operations has a in or inout parameter + + Args: + operation (vafmodel.Operation): The operation + + Returns: + bool: True if the operation has a in or inout parameter, False otherwise + """ + return ( + len( + [ + p + for p in operation.Parameters + if p.Direction in (vafmodel.ParameterDirection.IN, vafmodel.ParameterDirection.INOUT) + ] + ) + > 0 + ) + + +def is_in_parameter(p: vafmodel.Parameter) -> bool: + """Check is a parameter is a in parameter + + Args: + p (vafmodel.Parameter): The parameter + + Returns: + bool: True if the parameter is a in parameter, False otherwise + """ + return p.Direction == vafmodel.ParameterDirection.IN + + +def operation_get_return_type(operation: vafmodel.Operation, interface: vafmodel.ModuleInterface) -> str: + """returns the operation return type + + Args: + operation (vafmodel.Operation): The operation + interface (vafmodel.ModuleInterface): The interface + + Returns: + str: operation return type + """ + + out_parameters: list[vafmodel.Parameter] = [] + for p in operation.Parameters: + if p.Direction is not vafmodel.ParameterDirection.IN: + out_parameters.append(p) + + if len(out_parameters) > 0: + out_parameter_type_namespace: str = interface.Namespace + if interface.OperationOutputNamespace is not None: + out_parameter_type_namespace = interface.OperationOutputNamespace + return out_parameter_type_namespace + "::" + operation.Name + "::Output" + + return "void" + + +def has_exactly_one_output_parameter(operation: vafmodel.Operation) -> bool: + """Check operation has exactly one out parameter + + Args: + operation (vafmodel.Operation): The operation + + Returns: + bool: True if has exactly one out parameter, False otherwise + """ + out_parameters: list[vafmodel.Parameter] = [] + for p in operation.Parameters: + if p.Direction is not vafmodel.ParameterDirection.IN: + out_parameters.append(p) + if len(out_parameters) == 1: + return True + return False + + +def is_out_parameter(p: vafmodel.Parameter) -> bool: + """Check is a parameter is a out parameter + + Args: + p (vafmodel.Parameter): The parameter + + Returns: + bool: True if the parameter is a out parameter, False otherwise + """ + return p.Direction == vafmodel.ParameterDirection.OUT + + +def split_full_type(full_type: str) -> tuple[str, str]: + """Splits a full type into name and namespace + + Args: + full_type (str): The full type + + Returns: + tuple[str, str]: The name of the type and the namespace: Example: test::Test -> Test, test + """ + separator = full_type.rfind("::") + if separator == -1: + return full_type, "" + return full_type[separator + 2 :], full_type[0:separator] + + +class Generator: + """Class for generating files.""" + + def __init__(self) -> None: + self.env = Environment( + loader=PackageLoader("vaf.vafgeneration"), + autoescape=select_autoescape(), + trim_blocks=True, + lstrip_blocks=True, + ) + self.base_directory = Path.cwd() + + def set_base_directory(self, new_dir: Path) -> None: + """Sets the base directory where files will be generated into. + + Args: + new_dir (Path): The new directory. + """ + self.base_directory = new_dir + + def _generate_to_file_common( # pylint: disable=too-many-arguments, too-many-positional-arguments + self, + file: FileHelper, + postfix: str, + template_path: str, + output_path: Path, + check_to_overwrite: bool, + **kwargs: Any, + ) -> None: + old_file_exists: bool = False + old_file_output_path: Path + if check_to_overwrite and output_path.exists() and Path.stat(output_path).st_size > 0: + old_file_exists = True + old_file_output_path = output_path + output_path = output_path.parent / (output_path.name + ".new~") + + Path.mkdir(output_path.parent, parents=True, exist_ok=True) + with open(output_path, "w", encoding="utf-8") as f: + template = self.env.get_template(template_path) + + content = template.render( + file_helper=file, + file_postfix=postfix, + to_camel_case=to_camel_case, + to_snake_case=to_snake_case, + data_type_to_str=data_type_to_str, + implicit_data_type_to_str=implicit_data_type_to_str, + add_namespace_to_name=add_namespace_to_name, + time_str_to_milliseconds=time_str_to_milliseconds, + has_operation_in_or_inout_parameter=has_operation_in_or_inout_parameter, + has_operation_out_or_inout_parameter=has_operation_out_or_inout_parameter, + operation_get_return_type=operation_get_return_type, + is_out_parameter=is_out_parameter, + is_in_parameter=is_in_parameter, + **kwargs, + ) + + f.write(content) + + if kwargs.get("verbose_mode", False): + print(f"VAF: Generating {output_path}") + + if old_file_exists: + if not filecmp.cmp(old_file_output_path, output_path): + if kwargs.get("verbose_mode", False): + print(f"File {old_file_output_path} already exists, file is generated to {output_path}") + else: + output_path.unlink() + + def generate_to_file( + self, file: FileHelper, postfix: str, template_path: str, check_to_overwrite: bool = False, **kwargs: Any + ) -> None: + """Generates a template to file. + + Args: + file (FileHelper): The file to generate + postfix (str): The file postfix + template_path (str): The template file to use + check_to_overwrite (bool): if true and already present file exits user is asked to overwrite or not + **kwargs (Any): additional parameters to the render call + """ + output_path = file.get_file_path(self.base_directory, postfix) + self._generate_to_file_common(file, postfix, template_path, output_path, check_to_overwrite, **kwargs) + + def generate_to_simple_file( + self, file: FileHelper, postfix: str, template_path: str, check_to_overwrite: bool = False, **kwargs: Any + ) -> None: + """Generates a template to file not nested in namespaces. + + Args: + file (FileHelper): The file to generate + postfix (str): The file postfix + template_path (str): The template file to use + check_to_overwrite (bool): if true and already present file exits it is aksed to overwrite or not + **kwargs (Any): additional parameters to the render call + """ + output_path = file.get_simple_file_path(self.base_directory, postfix) + self._generate_to_file_common(file, postfix, template_path, output_path, check_to_overwrite, **kwargs) + + +def is_silkit_used(model: vafmodel.MainModel) -> bool: + """Check if anybody is using silkit + + Args: + model (vafmodel.MainModel): The main model + + Returns: + bool: True if silkit is used + """ + use_silkit: bool = False + if ( + len([m for m in model.PlatformProviderModules if m.OriginalEcoSystem == vafmodel.OriginalEcoSystemEnum.SILKIT]) + > 0 + or len( + [m for m in model.PlatformConsumerModules if m.OriginalEcoSystem == vafmodel.OriginalEcoSystemEnum.SILKIT] + ) + > 0 + ): + use_silkit = True + return use_silkit diff --git a/VAF/src/vaf/vafgeneration/templates/common/cmake_copyright.jinja b/VAF/src/vaf/vafgeneration/templates/common/cmake_copyright.jinja new file mode 100644 index 0000000..a8b8641 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/cmake_copyright.jinja @@ -0,0 +1,15 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file {{ file_helper.get_name() }}{{ file_postfix }} +#]=======================================================================] diff --git a/VAF/src/vaf/vafgeneration/templates/common/cmake_interface_library.jinja b/VAF/src/vaf/vafgeneration/templates/common/cmake_interface_library.jinja new file mode 100644 index 0000000..52f5807 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/cmake_interface_library.jinja @@ -0,0 +1,22 @@ +{% include "common/cmake_copyright.jinja" %} + +set(TARGET {{target_name}}) + +add_library(${TARGET} INTERFACE) + +target_include_directories(${TARGET} + INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + {% for i in include_directories %} + {{ i }} + {% endfor %} + $<INSTALL_INTERFACE:include>) + +{% if (libraries | length) > 0 %} +target_link_libraries(${TARGET} + INTERFACE + {% for lib in libraries %} + {{ lib }} + {% endfor %} + ) +{% endif %} diff --git a/VAF/src/vaf/vafgeneration/templates/common/cmake_library.jinja b/VAF/src/vaf/vafgeneration/templates/common/cmake_library.jinja new file mode 100644 index 0000000..cfcf3a9 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/cmake_library.jinja @@ -0,0 +1,30 @@ +{% include "common/cmake_copyright.jinja" %} + +{% block packages %}{% endblock -%} + +set(TARGET {{ target_name }}) + +add_library(${TARGET} STATIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include>) + +target_sources(${TARGET} + PRIVATE + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".h")}} + {% endfor %} + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".cpp")}} + {% endfor %} + ) + +target_link_libraries(${TARGET} + PUBLIC + {% for lib in libraries %} + {{ lib }} + {% endfor %} + ) +{# dummy comment for new line at the end #} diff --git a/VAF/src/vaf/vafgeneration/templates/common/cmake_subdirs.jinja b/VAF/src/vaf/vafgeneration/templates/common/cmake_subdirs.jinja new file mode 100644 index 0000000..7582645 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/cmake_subdirs.jinja @@ -0,0 +1,5 @@ +{% include "common/cmake_copyright.jinja" %} + +{% for subdir in subdirs %} +add_subdirectory({{ subdir }}) +{% endfor %} diff --git a/VAF/src/vaf/vafgeneration/templates/common/copyright.jinja b/VAF/src/vaf/vafgeneration/templates/common/copyright.jinja new file mode 100644 index 0000000..91a31f1 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/copyright.jinja @@ -0,0 +1,17 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file {{ file_helper.get_name() }}{{ file_postfix }} + * \brief + * + *********************************************************************************************************************/ diff --git a/VAF/src/vaf/vafgeneration/templates/common/cpp_file_base.jinja b/VAF/src/vaf/vafgeneration/templates/common/cpp_file_base.jinja new file mode 100644 index 0000000..a3a107f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/cpp_file_base.jinja @@ -0,0 +1,13 @@ +{% include "common/copyright.jinja" %} + + +{{ file_helper.get_include() }} + +{% block includes %} +{% endblock -%} + +{{ file_helper.get_namespace_start() }} +{% block content %} +{% endblock %} + +{{ file_helper.get_namespace_end() }} diff --git a/VAF/src/vaf/vafgeneration/templates/common/h_file_base.jinja b/VAF/src/vaf/vafgeneration/templates/common/h_file_base.jinja new file mode 100644 index 0000000..d5c2b03 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/common/h_file_base.jinja @@ -0,0 +1,13 @@ +{% include "common/copyright.jinja" %} + + +{{ file_helper.get_include_guard_start() }} +{% block includes %} +{% endblock %} + +{{ file_helper.get_namespace_start() }} +{% block content %} +{% endblock %} + +{{ file_helper.get_namespace_end() }} +{{ file_helper.get_include_guard_end() }} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_cpp.jinja new file mode 100644 index 0000000..45e8fd3 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_cpp.jinja @@ -0,0 +1,128 @@ +{% extends "common/cpp_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include "vaf/internal/data_ptr_helper.h" +{% endblock -%} + +{% block content %} +{{ module.Name }}::{{ module.Name }}(vaf::Executor& executor, std::string name, std::vector<std::string> dependencies, vaf::ExecutableControllerInterface& executable_controller_interface) + : vaf::ControlInterface(std::move(name), std::move(dependencies), executable_controller_interface, executor), + executor_{vaf::ControlInterface::executor_} { +} + +vaf::Result<void> {{ module.Name }}::Init() noexcept { + return vaf::Result<void>{}; +} + +void {{ module.Name }}::Start() noexcept { + ReportOperational(); +} + +void {{ module.Name }}::Stop() noexcept { +} + +void {{ module.Name }}::DeInit() noexcept { +} + +void {{ module.Name }}::StartEventHandlerForModule(const std::string& module) { + {% for de in module.ModuleInterfaceRef.DataElements %} + for(auto& handler_container : {{ de.Name }}_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + {% endfor %} + + active_modules_.push_back(module); +} + +void {{ module.Name }}::StopEventHandlerForModule(const std::string& module) { + {% for de in module.ModuleInterfaceRef.DataElements %} + for(auto& handler_container : {{ de.Name }}_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + {% endfor %} + + static_cast<void>(std::remove(active_modules_.begin(), active_modules_.end(), module)); +} + +{% for de in module.ModuleInterfaceRef.DataElements %} +{% set data_type = data_type_to_str(de.TypeRef) %} + + +{{ interface.consumer_data_element_get_allocated(de, module.Name ) }} { + return vaf::Result<vaf::ConstDataPtr<const {{ data_type }} >>::FromValue( {{ de.Name }}_sample_); +} + +{{ interface.consumer_data_element_get(de, module.Name ) }} { return *{{ de.Name }}_sample_; } + +{{ interface.consumer_data_element_handler(de, module.Name ) }} { + {{ de.Name }}_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + {{ de.Name }}_handlers_.back().is_active_ = true; + } +} + +{{ interface.provider_data_element_allocate(de, module.Name ) }} { + std::unique_ptr< {{ data_type }} > ptr{ + std::make_unique< {{ data_type }} >()}; + return ::vaf::Result<vaf::DataPtr< {{ data_type }} >>::FromValue(std::move(ptr)); +} + +{{ interface.provider_data_element_set_allocated(de, module.Name ) }} { + {{ de.Name }}_sample_ = vaf::ConstDataPtr<const {{ data_type }}>{std::move(vaf::internal::DataPtrHelper<{{ data_type }}>::getRawPtr(data))}; + + for(auto& handler_container : {{ de.Name }}_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_({{ de.Name }}_sample_); + } + } + + return vaf::Result<void>{}; +} + +{{ interface.provider_data_element_set(de, module.Name ) }} { + std::unique_ptr< {{ data_type }} > ptr{ + std::make_unique< {{ data_type }} >(data)}; + {{ de.Name }}_sample_ = vaf::ConstDataPtr<const {{ data_type }}>{std::move(ptr)}; + + for(auto& handler_container : {{ de.Name }}_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_({{ de.Name }}_sample_); + } + } + + return vaf::Result<void>{}; +} + +{% endfor %} + +{% for op in module.ModuleInterfaceRef.Operations %} +{{ interface.provider_operation(op, module.ModuleInterfaceRef, module.Name) }} { + {{ op.Name }}_handler_ = std::move(f); +} + +{{ interface.consumer_operation(op, module.ModuleInterfaceRef, module.Name) }} { + ::vaf::Promise<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}> p; + + if({{ op.Name }}_handler_) { + {% if has_operation_out_or_inout_parameter(op) %} + p.set_value({{ op.Name }}_handler_({{ interface.operation_expand_in_parameters(op) }})); + {% else %} + {{ op.Name }}_handler_({{ interface.operation_expand_in_parameters(op) }}); + p.set_value(); + {% endif %} + } else { + vaf::Error error_code{::vaf::ErrorCode::kNoOperationHandlerRegistered, "No operation handler registered for {{ op.Name }}."}; + p.SetError(error_code); + } + + return p.get_future(); +} + +{% endfor %} + +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_h.jinja new file mode 100644 index 0000000..ed47577 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_communication/application_communication_module_h.jinja @@ -0,0 +1,71 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <memory> +#include <string> +#include <vector> + +#include "vaf/receiver_handler_container.h" +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +{{ consumer_interface_file.get_include() }} +{{ provider_interface_file.get_include() }} +{% endblock %} + +{% block content %} + +class {{ module.Name }} + : public {{ consumer_interface_file.get_full_type_name() }}, public {{ provider_interface_file.get_full_type_name() }}, public vaf::ControlInterface { + public: + {{ module.Name }}(vaf::Executor& executor, std::string name, std::vector<std::string> dependencies, vaf::ExecutableControllerInterface& executable_controller_interface); + ~{{ module.Name }}() override = default; + + {{ module.Name }}(const {{ module.Name }}&) = delete; + {{ module.Name }}({{ module.Name }}&&) = delete; + {{ module.Name }}& operator=(const {{ module.Name }}&) = delete; + {{ module.Name }}& operator=({{ module.Name }}&&) = delete; + + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + void StartEventHandlerForModule(const std::string& module) override; + void StopEventHandlerForModule(const std::string& module) override; + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + {{ interface.consumer_data_element_get_allocated(de) }} override; + {{ interface.consumer_data_element_get(de) }} override; + {{ interface.consumer_data_element_handler(de) }} override; + + {{ interface.provider_data_element_allocate(de) }} override; + {{ interface.provider_data_element_set_allocated(de) }} override; + {{ interface.provider_data_element_set(de) }} override; + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {{ interface.consumer_operation(op, module.ModuleInterfaceRef) }} override; + {{ interface.provider_operation(op, module.ModuleInterfaceRef) }} override; + {% endfor %} + + private: + vaf::ModuleExecutor& executor_; + std::vector<std::string> active_modules_; + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + vaf::ConstDataPtr<const {{ data_type }}> {{ de.Name }}_sample_{std::make_unique<{{ data_type }}>()}; + std::vector<vaf::ReceiverHandlerContainer<{{ interface.consumer_data_element_handler_callback(de) }}>> {{ de.Name }}_handlers_; + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {{ interface.provider_operation_callback(op, module.ModuleInterfaceRef) }} {{ op.Name }}_handler_; + {% endfor %} + +}; + +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_cpp.jinja new file mode 100644 index 0000000..d7a54f2 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_cpp.jinja @@ -0,0 +1,22 @@ + +{% extends "common/cpp_file_base.jinja" %} + +{% block content %} +{{ app_module.Name }}Base::{{ app_module.Name }}Base(ConstructorToken&& token) + : vaf::ControlInterface(token.name_, std::move(token.dependencies_), token.executable_controller_interface_, token.executor_), + executor_{vaf::ControlInterface::executor_}{% if (interfaces | length) > 0 %},{% endif %} + + {% for i in interfaces %} + {{ i["instance"] }}_{std::move(token.{{ i["instance"] }}_)}{% if not loop.last %},{% endif %} + + {% endfor %} + { + {% for r in app_module.Tasks %} + executor_.RunPeriodic("{{ r.Name }}", std::chrono::milliseconds{ {{ time_str_to_milliseconds(r.Period ) }} }, [this]() { {{ r.Name }}(); }, { + {%- for run_after_item in r.RunAfter -%} + "{{ run_after_item }}"{% if not loop.last %},{% endif %} + {%- endfor -%} + }, token.task_offset_{{ r.Name }}_, token.task_budget_{{ r.Name }}_); + {% endfor %} +} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_h.jinja new file mode 100644 index 0000000..1c1f76c --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/base_h.jinja @@ -0,0 +1,53 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <memory> + +#include "vaf/executor.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/controller_interface.h" + +{% set includes = interfaces | map(attribute="include") | unique %} +{% for i in includes %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ app_module.Name }}Base : public vaf::ControlInterface { + public: + struct ConstructorToken { + std::string name_; + std::vector<std::string> dependencies_; + vaf::ExecutableControllerInterface& executable_controller_interface_; + vaf::Executor& executor_; + {% for i in interfaces %} + std::shared_ptr<{{ i["type"] }}> {{ i["instance"] }}_; + {% endfor %} + {% for r in app_module.Tasks %} + uint64_t task_offset_{{ r.Name }}_; + std::chrono::nanoseconds task_budget_{{ r.Name }}_; + {% endfor %} + }; + + {{ app_module.Name }}Base(ConstructorToken&& token); + virtual ~{{ app_module.Name }}Base() = default; + + virtual vaf::Result<void> Init() noexcept { return vaf::Result<void>{}; } + virtual void Start() noexcept { ReportOperational(); } + virtual void Stop() noexcept {} + virtual void DeInit() noexcept {} + + virtual void OnError(const vaf::Error& error) override { static_cast<void>(error); } + + {%for r in app_module.Tasks %} + virtual void {{ r.Name }}() = 0; + {% endfor %} + + protected: + vaf::ModuleExecutor& executor_; + {% for i in interfaces %} + std::shared_ptr<{{ i["type"] }}> {{ i["instance"] }}_; + {% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/cmake_implementation.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/cmake_implementation.jinja new file mode 100644 index 0000000..4cfd34f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/cmake_implementation.jinja @@ -0,0 +1,64 @@ +{% include "common/cmake_copyright.jinja" %} + +cmake_minimum_required(VERSION 3.21) + +find_package(Threads) +find_package(GTest) + +set(TARGET {{ target_name }}) + +add_library(${TARGET} STATIC "") + +target_compile_options(${TARGET} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${TARGET} PUBLIC cxx_std_14) + +target_compile_definitions(${TARGET} PUBLIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_sources(${TARGET} + PRIVATE + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".h")}} + {% endfor %} + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_simple_file_path("", ".cpp")}} + {% endfor %} + ) + +# cmake-format: off +target_link_libraries(${TARGET} + PUBLIC + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_module_interfaces + + {% for lib in libraries %} + {{ lib }} + {% endfor %} +) +# cmake-format: on + +if(VAF_BUILD_TESTS) + add_subdirectory(test) +endif() +{# dummy comment for new line at the end #} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_cpp.jinja new file mode 100644 index 0000000..8160cca --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_cpp.jinja @@ -0,0 +1,89 @@ +{% extends "common/cpp_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block content %} + +/* + Generated based on configuration in ../../model/{{ to_snake_case(app_module.Name).lower() }}.py + + {% if (app_module.ConsumedInterfaces | length) > 0 %} + Consumer interfaces + =================== + {% set i = app_module.ConsumedInterfaces[0] %} + {% if (i.ModuleInterfaceRef.DataElements | length) > 0 %} + {% set data_element = i.ModuleInterfaceRef.DataElements[0] %} + Data element API example for {{ data_element.Name }} of type {{ data_type_to_str(data_element.TypeRef) }} + - {{ interface.consumer_data_element_get_allocated(data_element) }} + - {{ interface.consumer_data_element_get(data_element) }} + - {{ interface.consumer_data_element_handler(data_element) }} + + {% endif %} + {% endif %} + {% for i in app_module.ConsumedInterfaces %} + - {{ i.InstanceName }}_ : {{ get_interface_type_by_instance(interfaces, i.InstanceName) }} + {% if (i.ModuleInterfaceRef.DataElements | length) > 0 %} + - Data elements + {% for data_element in i.ModuleInterfaceRef.DataElements %} + - {{ data_element.Name }} : {{ data_type_to_str(data_element.TypeRef) }} + {% endfor %} + {% endif %} + {% if (i.ModuleInterfaceRef.Operations | length) > 0 %} + - Operations + {% for operation in i.ModuleInterfaceRef.Operations %} + - {{ interface.consumer_operation(operation, i.ModuleInterfaceRef) }} + {% endfor %} + {% endif %} + {% endfor %} + {% if (app_module.ProvidedInterfaces | length) > 0 %} + {% if (app_module.ConsumedInterfaces | length) > 0 %} + + {% endif %} + Provider interfaces + =================== + {% set i = app_module.ProvidedInterfaces[0] %} + {% if (i.ModuleInterfaceRef.DataElements | length) > 0 %} + {% set data_element = i.ModuleInterfaceRef.DataElements[0] %} + Data element API example for {{ data_element.Name }} of type {{ data_type_to_str(data_element.TypeRef) }} + - {{ interface.provider_data_element_allocate(data_element) }} + - {{ interface.provider_data_element_set_allocated(data_element) }} + - {{ interface.provider_data_element_set(data_element) }} + + {% endif %} + {% endif %} + {% for i in app_module.ProvidedInterfaces %} + - {{ i.InstanceName }}_ : {{ get_interface_type_by_instance(interfaces, i.InstanceName) }} + {% if (i.ModuleInterfaceRef.DataElements | length) > 0 %} + - Data elements + {% for data_element in i.ModuleInterfaceRef.DataElements %} + - {{ data_element.Name }} : {{ data_type_to_str(data_element.TypeRef) }} + {% endfor %} + {% endif %} + {% if (i.ModuleInterfaceRef.Operations | length) > 0 %} + - Operations + {% for operation in i.ModuleInterfaceRef.Operations %} + - {{ interface.provider_operation(operation, i.ModuleInterfaceRef) }} + {% endfor %} + {% endif %} + {% endfor %} +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +{{ app_module.Name }}::{{ app_module.Name }}(ConstructorToken&& token) + : {{ app_module.Name }}Base(std::move(token)) +{ + // Insert your code here... +} + +/********************************************************************************************************************** + {{ app_module.Tasks|count }} periodic task(s) +**********************************************************************************************************************/ +{% for r in app_module.Tasks %} +// Task with name {{ r.Name }} and a period of {{ r.Period }}. +void {{ app_module.Name }}::{{ r.Name }}() { + // Insert your code for periodic execution here... +} + +{% endfor %} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_h.jinja new file mode 100644 index 0000000..607631d --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/module_h.jinja @@ -0,0 +1,18 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{{ base_include }} +{% endblock %} + +{% block content %} +class {{ app_module.Name }} : public {{ app_module.Name }}Base { + public: + {{ app_module.Name }}(ConstructorToken&& token); + + {% for r in app_module.Tasks %} + void {{ r.Name }}() override; + {% endfor %} + + private: +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_cpp.jinja new file mode 100644 index 0000000..e68f8bf --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_cpp.jinja @@ -0,0 +1,10 @@ + +{% extends "common/cpp_file_base.jinja" %} + +{% block content %} +{{ app_module.Name }}Base::{{ app_module.Name }}Base(ConstructorToken&& token){% if (interfaces | length) > 0 %}:{% endif %} + +{% for i in interfaces %} + {{ i["instance"] }}_{std::move(token.{{ i["instance"] }}_)}{% if not loop.last %}, +{% endif %}{% endfor %} {} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_h.jinja new file mode 100644 index 0000000..ce9f2a3 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_base_h.jinja @@ -0,0 +1,38 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <memory> +#include "vaf/controller_interface.h" + +{% set includes = interfaces | map(attribute="include") | unique %} +{% for i in includes %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ app_module.Name }}Base { + public: + struct ConstructorToken { + {% for i in interfaces %} + std::shared_ptr<{{ i["type"] }}> {{ i["instance"] }}_; + {% endfor %} + }; + + {{ app_module.Name }}Base(ConstructorToken&& token); + virtual ~{{ app_module.Name }}Base() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + + {%for r in app_module.Tasks %} + virtual void {{ r.Name }}() = 0; + {% endfor %} + + protected: + {% for i in interfaces %} + std::shared_ptr<{{ i["type"] }}> {{ i["instance"] }}_; + {% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_cmake.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_cmake.jinja new file mode 100644 index 0000000..2b3b093 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_cmake.jinja @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.21) +project({{ target_name }}) + +find_package(Threads) +find_package(GTest REQUIRED) +if (NOT GTest_FOUND) + message(FATAL_ERROR "Cannot find Google Test Framework!") +endif() + +include(GoogleTest) + +add_executable(${PROJECT_NAME}) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) + +target_compile_definitions(${PROJECT_NAME} PUBLIC) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src +) + +target_sources( + ${PROJECT_NAME} + PRIVATE + {% for f in app_files %} + ${CMAKE_CURRENT_SOURCE_DIR}/../../{{f.get_file_path("", ".h")}} + {% endfor %} + {% for f in app_files %} + ${CMAKE_CURRENT_SOURCE_DIR}/../../{{f.get_simple_file_path("", ".cpp")}} + {% endfor %} + {% for f in base_files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".h")}} + {% endfor %} + {% for f in base_files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".cpp")}} + {% endfor %} + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tests.cpp +) + +# cmake-format: off +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + gmock + gtest::gtest + $<TARGET_NAME_IF_EXISTS:vaf_data_types> + $<TARGET_NAME_IF_EXISTS:vaf_module_interfaces> + $<TARGET_NAME_IF_EXISTS:vaf_module_interface_mocks> +) +# cmake-format: on + +gtest_discover_tests(${PROJECT_NAME}) +{# dummy comment for new line #} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_main_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_main_cpp.jinja new file mode 100644 index 0000000..ddf18a9 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_main_cpp.jinja @@ -0,0 +1,20 @@ +{% include "common/copyright.jinja" %} + +{% block content %} +#include "gtest/gtest.h" +#include <iostream> +#include <fstream> + +int main(int argc, char **argv) { + int gtest_ret{0}; + ::testing::InitGoogleTest(&argc, argv); + + // Set death tests to threadsafe globally because logging uses a separate thread. + //::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + // Execute tests via gtest + gtest_ret = RUN_ALL_TESTS(); + + return gtest_ret; +} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_module_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_module_cpp.jinja new file mode 100644 index 0000000..0dbeb0f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_application_module/test_module_cpp.jinja @@ -0,0 +1,72 @@ +{% include "common/copyright.jinja" %} + +#include <cstddef> +#include <cstdint> +#include <csignal> +#include <iostream> +#include "gtest/gtest.h" +#include "gmock/gmock.h" +{% set includes = interfaces | map(attribute="include_mock") | unique %} +{% for i in includes %} +{{ i }} +{% endfor %} +{{ app_include }} + +{% block content %} +// Put inside test to skip +//GTEST_SKIP() << "Skipping single test"; +using ::testing::Return; +using ::testing::_; + +namespace vaf { + /*! + * \brief Initializes the signal handling. + * \return void. + */ + void InitializeSignalHandling() noexcept { + bool success{true}; + sigset_t signals; + + /* Block all signals except the SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV signals because blocking them will lead to + * undefined behavior. Their default handling shall not be changed (dependent on underlying POSIX environment, usually + * process is killed and a dump file is written). Signal mask will be inherited by subsequent threads. */ + + success = success && (0 == sigfillset(&signals)); + success = success && (0 == sigdelset(&signals, SIGABRT)); + success = success && (0 == sigdelset(&signals, SIGBUS)); + success = success && (0 == sigdelset(&signals, SIGFPE)); + success = success && (0 == sigdelset(&signals, SIGILL)); + success = success && (0 == sigdelset(&signals, SIGSEGV)); + success = success && (0 == pthread_sigmask(SIG_SETMASK, &signals, nullptr)); + + if (!success) { + // Exit + } + } + + class {{ app_module.Name }}UnitTest : public ::testing::Test { + protected: + {{ app_module.Name }}UnitTest() {} + + virtual ~{{ app_module.Name }}UnitTest() {} + + virtual void SetUp() { + InitializeSignalHandling(); + } + + virtual void TearDown() { + } + }; + + TEST_F({{ app_module.Name }}UnitTest, Test_1) { + {% for i in interfaces %} + auto {{ i["instance"] }}Mock = std::make_shared<{{ i["type"] }}Mock>(); + {% endfor %} + + auto {{ app_module.Name }} = std::make_shared<{{ app_module.Namespace }}::{{ app_module.Name }}>({{ app_module.Namespace }}::{{ app_module.Name }} ::ConstructorToken{ + {% for i in interfaces %} + {{ i["instance"] }}Mock{% if not loop.last %}, +{% endif %}{% endfor %}}); + } +} // namespace vaf +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_cac_support/platform.py.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_cac_support/platform.py.jinja new file mode 100644 index 0000000..b84d573 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_cac_support/platform.py.jinja @@ -0,0 +1,32 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_datatype, + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "{{ model_name }}")) + +{% for namespace, class_data in cac_model.items() %} + {%- set class_name = namespace.rsplit("::", 1)[-1] if "::" in namespace else namespace %} + {%- set level = class_data["level"] %} +{{" " * 4 * level}}class {{to_camel_case(class_name)}}: + {% for element_type in class_data["set_elements"] %} +{{" " * 4 * (level + 1)}}# {{to_snake_case(element_type).replace("_", " ").title()}} + {% for element_name in class_data["data"][element_type] %} + {% if element_type in data_types %} +{{" " * 4 * (level + 1)}}{{ to_snake_case(element_name) }} = get_datatype("{{element_name}}", "{{namespace}}", "{{element_type.removesuffix("s")}}") + {% else %} +{{" " * 4 * (level + 1)}}{{to_snake_case(element_name)}} = get_{{to_snake_case(element_type.removesuffix("s"))}}( +{{" " * 4 * (level + 2)}}"{{element_name}}", "{{namespace}}" +{{" " * 4 * (level + 1)}}) + {% endif %} + {% endfor %} + {% endfor %} +{% endfor %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_cmake_common/data_types_cmake.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_cmake_common/data_types_cmake.jinja new file mode 100644 index 0000000..a830f42 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_cmake_common/data_types_cmake.jinja @@ -0,0 +1,10 @@ +{% include "common/cmake_copyright.jinja" %} + +set(TARGET vaf_data_types) + +add_library(${TARGET} INTERFACE) + +target_include_directories(${TARGET} + INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include>) diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_conan/conan_deps.list.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_conan/conan_deps.list.jinja new file mode 100644 index 0000000..3dc13c5 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_conan/conan_deps.list.jinja @@ -0,0 +1,3 @@ +{% for dep in dependencies -%} +{{ dep }} +{% endfor -%} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/CMakeLists_txt.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/CMakeLists_txt.jinja new file mode 100644 index 0000000..c65a1a4 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/CMakeLists_txt.jinja @@ -0,0 +1,68 @@ +cmake_minimum_required(VERSION 3.21) +project({{ target_name }}) + +find_package(Threads) + +add_executable(${PROJECT_NAME}) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) + +target_compile_definitions(${PROJECT_NAME} PUBLIC) + +set(target ${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${PROJECT_NAME}/bin) + +target_include_directories(${PROJECT_NAME} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_sources( + ${PROJECT_NAME} + PRIVATE + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".h")}} + {% endfor %} + {% for f in files %} + ${CMAKE_CURRENT_SOURCE_DIR}/{{f.get_file_path("", ".cpp")}} + {% endfor %} + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp +) + +# cmake-format: off +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + {% for lib in libraries %} + {{ lib }} + {% endfor %} + vaf_{{ target_name }}_user_controller +) +# cmake-format: on + +# Define files to be installed +install(TARGETS ${PROJECT_NAME} DESTINATION "opt/${PROJECT_NAME}/bin") + +{% if uses_silkit %} +install(PROGRAMS "/usr/local/bin/sil-kit-registry" DESTINATION "opt/silkit/bin") +{% endif %} +{# dummy comment for new line #} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_cpp.jinja new file mode 100644 index 0000000..afc1adf --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_cpp.jinja @@ -0,0 +1,93 @@ +{% extends "common/cpp_file_base.jinja" %} + +{% block includes %} +{%- for i in get_includes_of_platform_modules(communication_modules) %} +{{ i }} +{% endfor %} +{% for am in executable.ApplicationModules %} +{{ get_include_of_application_module(am) }} +{% endfor %} + + +#include "vaf/result.h" + +{% endblock %} + +{% block content %} +ExecutableController::ExecutableController() + : ExecutableControllerBase(), + executor_{} { +} + +void ExecutableController::DoInitialize() { + executor_ = std::make_unique<vaf::Executor>(std::chrono::milliseconds{ {{time_str_to_milliseconds(executable.ExecutorPeriod) }} }); + +{% for m in communication_modules %} +{% if not is_internal_communication_module(executable, m)%} + + auto {{ m.Name }} = std::make_shared<{{ get_full_type_of_platform_module(m) }}>( + *executor_, + "{{ m.Name }}", + *this); +{% endif %} +{% endfor %} +{%for m in communication_modules %} +{% if is_internal_communication_module(executable, m)%} + + auto {{ m.Name }} = std::make_shared<{{ get_full_type_of_platform_module(m) }}>( + *executor_, + "{{ m.Name }}", + std::vector<std::string>{}, + *this); +{% endif%} +{% endfor %} +{% for am in executable.ApplicationModules %} + +{% set am_name = am.ApplicationModuleRef.Name %} +{% set am_type = get_full_type_of_application_module(am) %} +{% set execution_dependency, module_dependency = get_dependencies_of_application_module(executable, am) %} + auto {{ am_name }} = std::make_shared<{{ am_type }}>( {{ am_type }}::ConstructorToken{ + "{{ am_name }}", + std::vector<std::string>{ + {% for d in execution_dependency %} + {"{{ d }}"}{% if not loop.last %},{% endif %} + + {% endfor %} + }, + *this, + *executor_{% if (module_dependency | length) > 0 %},{% endif %} + + {% for d in module_dependency %} + {{d}}{% if not loop.last %},{% endif %} + + {% endfor %} + {%- if (am.TaskMapping | length) > 0 %},{% endif %} + {% for r in am.TaskMapping %} + {% set offset, budget = get_task_mapping(r, am) %} + {{offset}}, + std::chrono::nanoseconds{ {{budget}} }{% if not loop.last %},{% endif %} + + {% endfor %} + }); +{% endfor %} +{% for m in communication_modules %} + + RegisterModule({{ m.Name }}); +{% endfor %} +{% for am in executable.ApplicationModules %} + + RegisterModule({{ am.ApplicationModuleRef.Name }}); +{% endfor %} + + ExecutableControllerBase::DoInitialize(); +} + +void ExecutableController::DoStart() { + ExecutableControllerBase::DoStart(); +} + +void ExecutableController::DoShutdown() { + ExecutableControllerBase::DoShutdown(); +} + +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_h.jinja new file mode 100644 index 0000000..b302c15 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/executable_controller_h.jinja @@ -0,0 +1,24 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <memory> + +#include "vaf/executable_controller_base.h" +#include "vaf/executor.h" +{% endblock %} + +{% block content %} +class ExecutableController final : public vaf::ExecutableControllerBase { + public: + ExecutableController(); + ~ExecutableController() override = default; + + protected: + void DoInitialize() override; + void DoStart() override; + void DoShutdown() override; + + private: + std::unique_ptr<vaf::Executor> executor_; +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/main_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/main_cpp.jinja new file mode 100644 index 0000000..c3316fd --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/main_cpp.jinja @@ -0,0 +1,11 @@ +{% include "common/copyright.jinja" %} + +{{ controller_file.get_include() }} + +int main() { + {{ controller_file.get_full_type_name() }} executable_controller; + executable_controller.Run(false); + + return 0; +} +{# dumm coment for new line #} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_CMakeLists_txt.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_CMakeLists_txt.jinja new file mode 100644 index 0000000..5ceb44d --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_CMakeLists_txt.jinja @@ -0,0 +1,16 @@ +set(TARGET vaf_{{ target_name }}_user_controller) + +add_library(${TARGET} INTERFACE) + +target_include_directories(${TARGET} +INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> +) + +target_sources(${TARGET} +INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/include/user_controller.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/user_controller.cpp +) diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_cpp.jinja new file mode 100644 index 0000000..aa58915 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_cpp.jinja @@ -0,0 +1,43 @@ +{% extends "common/cpp_file_base.jinja" %} + +{% block includes %} +#include <iostream> +{% endblock %} + +{% block content %} +std::unique_ptr<vaf::UserControllerInterface> CreateUserController() { + return std::make_unique<UserController>(); +} + +void UserController::PreInitialize() { + std::cout << "UserController::PreInitialize\n"; +} + +void UserController::PostInitialize() { + std::cout << "UserController::PostInitialize\n"; +} + +void UserController::PreStart() { + std::cout << "UserController::PreStart\n"; +} + +void UserController::PostStart() { + std::cout << "UserController::PostStart\n"; +} + +void UserController::PreShutdown() { + std::cout << "UserController::PreShutdown\n"; +} + +void UserController::PostShutdown() { + std::cout << "UserController::PostShutdown\n"; +} + +void UserController::OnError(vaf::Error error, std::string name, bool critical) { + std::cout << "UserController::OnError: name: " << name << ", Message: " << error.Message() << ", critical: " << critical << "\n"; + if(critical){ + std::cout << "UserController::OnError: Critical call, aborting execution!" << std::endl; + std::abort(); + } +} +{%- endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_h.jinja new file mode 100644 index 0000000..48fd61d --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_controller/user_controller_h.jinja @@ -0,0 +1,21 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include "vaf/user_controller_interface.h" +{% endblock %} + +{% block content %} +class UserController : public vaf::UserControllerInterface { +public: + void PreInitialize() override; + void PostInitialize() override; + void PreStart() override; + void PostStart() override; + void PreShutdown() override; + void PostShutdown() override; + + void OnError(vaf::Error error, std::string name, bool critical) override; + +private: +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros.jinja new file mode 100644 index 0000000..18ecf66 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros.jinja @@ -0,0 +1,64 @@ +{# Data elements macros #} + +{% macro provider_data_element_allocate(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<::vaf::DataPtr<{{ data_type }}>> {% if class_name %}{{ class_name }}::{% endif %}Allocate_{{ data_element.Name }}() +{%- endmacro %} + +{% macro provider_data_element_set_allocated(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<void> {% if class_name %}{{ class_name }}::{% endif %}SetAllocated_{{ data_element.Name }}(::vaf::DataPtr<{{ data_type }}>&& data) +{%- endmacro %} + +{%- macro provider_data_element_set(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<void> {% if class_name %}{{ class_name }}::{% endif %}Set_{{ data_element.Name }}(const {{ data_type }}& data) +{%- endmacro %} + +{%- macro consumer_data_element_get_allocated(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<::vaf::ConstDataPtr<const {{ data_type }}>> {% if class_name %}{{ class_name }}::{% endif %}GetAllocated_{{ data_element.Name }}() +{%- endmacro %} + +{%- macro consumer_data_element_get(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +{{ data_type }} {% if class_name %}{{ class_name }}::{% endif %}Get_{{ data_element.Name }}() +{%- endmacro %} + +{%- macro consumer_data_element_handler_callback(data_element) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +std::function<void(const ::vaf::ConstDataPtr<const {{ data_type }}>)> +{%- endmacro %} + +{%- macro consumer_data_element_handler(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +void {% if class_name %}{{ class_name }}::{% endif %}RegisterDataElementHandler_{{ data_element.Name }}(std::string owner, {{ consumer_data_element_handler_callback(data_element) }}&& f) +{%- endmacro %} + +{%- macro operation_expand_in_parameters(operation) -%} + {%- for p in operation.Parameters if not is_out_parameter(p) -%} + {{ p.Name }}{% if not loop.last %}, {% endif %} + {%- endfor -%} +{%- endmacro -%} + +{%- macro operation_parameters(operation) -%} + {%- for p in operation.Parameters if not is_out_parameter(p) -%} + const {{ data_type_to_str(p.TypeRef) }}& {{ p.Name }}{% if not loop.last %}, {% endif %} + {%- endfor -%} +{%- endmacro -%} + +{%- macro consumer_operation(operation, interface, class_name = none) -%} +::vaf::Future<{{ operation_get_return_type(operation, interface) }}> {% if class_name %}{{ class_name }}::{% endif %}{{ operation.Name }}({{ operation_parameters(operation) }}) +{%- endmacro %} + +{%- macro provider_operation_callback(operation, interface) -%} +std::function<{{ operation_get_return_type(operation, interface) }}( + {%- for p in operation.Parameters if not is_out_parameter(p) -%} + const {{ data_type_to_str(p.TypeRef) }}&{% if not loop.last %}, {% endif %} + {%- endfor -%} + )> +{%- endmacro %} + +{%- macro provider_operation(operation, interface, class_name = none) -%} +void {% if class_name %}{{ class_name }}::{% endif %}RegisterOperationHandler_{{ operation.Name }}({{ provider_operation_callback(operation, interface) }}&& f) +{%- endmacro %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros_mocks.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros_mocks.jinja new file mode 100644 index 0000000..ae2ffe4 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/macros_mocks.jinja @@ -0,0 +1,58 @@ +{# Data elements macros #} + +{% macro mock_provider_data_element_allocate(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<::vaf::DataPtr<{{ data_type }}>>, {% if class_name %}{{ class_name }}::{% endif %}Allocate_{{ data_element.Name }}, () +{%- endmacro %} + +{% macro mock_provider_data_element_set_allocated(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<void>, {% if class_name %}{{ class_name }}::{% endif %}SetAllocated_{{ data_element.Name }}, (::vaf::DataPtr<{{ data_type }}>&& data) +{%- endmacro %} + +{%- macro mock_provider_data_element_set(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<void>, {% if class_name %}{{ class_name }}::{% endif %}Set_{{ data_element.Name }}, (const {{ data_type }}& data) +{%- endmacro %} + +{%- macro mock_consumer_data_element_get_allocated(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +::vaf::Result<::vaf::ConstDataPtr<const {{ data_type }}>>, {% if class_name %}{{ class_name }}::{% endif %}GetAllocated_{{ data_element.Name }}, () +{%- endmacro %} + +{%- macro mock_consumer_data_element_get(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +{{ data_type }}, {% if class_name %}{{ class_name }}::{% endif %}Get_{{ data_element.Name }}, () +{%- endmacro %} + +{%- macro mock_consumer_data_element_handler_callback(data_element) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +std::function<void(const ::vaf::ConstDataPtr<const {{ data_type }}>)> +{%- endmacro %} + +{%- macro mock_consumer_data_element_handler(data_element, class_name = none) -%} +{%- set data_type = data_type_to_str(data_element.TypeRef) %} +void, {% if class_name %}{{ class_name }}::{% endif %}RegisterDataElementHandler_{{ data_element.Name }}, (std::string owner, {{ mock_consumer_data_element_handler_callback(data_element) }}&& f) +{%- endmacro %} + +{%- macro mock_operation_parameters(operation) -%} + {%- for p in operation.Parameters if not is_out_parameter(p) -%} + const {{ data_type_to_str(p.TypeRef) }}& {{ p.Name }}{% if not loop.last %}, {% endif %} + {%- endfor -%} +{%- endmacro -%} + +{%- macro mock_consumer_operation(operation, interface, class_name = none) -%} +::vaf::Future<{{ operation_get_return_type(operation, interface) }}>, {% if class_name %}{{ class_name }}::{% endif %}{{ operation.Name }}, ({{ mock_operation_parameters(operation) }}) +{%- endmacro %} + +{%- macro mock_provider_operation_callback(operation, interface) -%} +std::function<{{ operation_get_return_type(operation, interface) }}( + {%- for p in operation.Parameters if not is_out_parameter(p) -%} + const {{ data_type_to_str(p.TypeRef) }}&{% if not loop.last %}, {% endif %} + {%- endfor -%} + )> +{%- endmacro %} + +{%- macro mock_provider_operation(operation, interface, class_name = none) -%} +void, {% if class_name %}{{ class_name }}::{% endif %}RegisterOperationHandler_{{ operation.Name }}, ({{ mock_provider_operation_callback(operation, interface) }}&& f) +{%- endmacro %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_h.jinja new file mode 100644 index 0000000..1096847 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_h.jinja @@ -0,0 +1,33 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <string> +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" + +{% for i in include_files | sort %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ name }}Consumer { +public: + virtual ~{{ name }}Consumer() = default; + +{% for de in data_elements %} +{%- set data_type = data_type_to_str(de.TypeRef) %} + virtual {{ interface.consumer_data_element_get_allocated(de) }} = 0; + virtual {{ interface.consumer_data_element_get(de) }} = 0; + virtual {{ interface.consumer_data_element_handler(de) }} = 0; +{% endfor %} + +{% for op in operations %} + virtual {{ interface.consumer_operation(op, module_interface) }} = 0; +{% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_mock_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_mock_h.jinja new file mode 100644 index 0000000..31f0457 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_consumer_mock_h.jinja @@ -0,0 +1,32 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros_mocks.jinja" as interface with context %} + +{% block includes %} +#include <string> +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" +#include "gmock/gmock.h" + +{% for i in include_files | sort %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ name }}ConsumerMock : public {{ name }}Consumer{ +public: +{% for de in data_elements %} +{%- set data_type = data_type_to_str(de.TypeRef) %} + MOCK_METHOD({{ interface.mock_consumer_data_element_get_allocated(de) }}, (override)); + MOCK_METHOD({{ interface.mock_consumer_data_element_get(de) }}, (override)); + MOCK_METHOD({{ interface.mock_consumer_data_element_handler(de) }}, (override)); +{% endfor %} + +{% for op in operations %} + MOCK_METHOD({{ interface.mock_consumer_operation(op, module_interface) }}, (override)); +{% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_h.jinja new file mode 100644 index 0000000..43e75db --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_h.jinja @@ -0,0 +1,32 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" + +{% for i in include_files | sort %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ name }}Provider { +public: + virtual ~{{ name }}Provider() = default; + +{% for de in data_elements %} +{%- set data_type = data_type_to_str(de.TypeRef) %} + virtual {{ interface.provider_data_element_allocate(de) }} = 0; + virtual {{ interface.provider_data_element_set_allocated(de) }} = 0; + virtual {{ interface.provider_data_element_set(de) }} = 0; +{% endfor %} + +{% for op in operations %} + virtual {{ interface.provider_operation(op, module_interface) }} = 0; +{% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_mock_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_mock_h.jinja new file mode 100644 index 0000000..f0be8bc --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/module_interface_provider_mock_h.jinja @@ -0,0 +1,31 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros_mocks.jinja" as interface with context %} + +{% block includes %} +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" +#include "gmock/gmock.h" + +{% for i in include_files | sort %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{ name }}ProviderMock : public {{ name }}Provider{ +public: +{% for de in data_elements %} +{%- set data_type = data_type_to_str(de.TypeRef) %} + MOCK_METHOD({{ interface.mock_provider_data_element_allocate(de) }}, (override)); + MOCK_METHOD({{ interface.mock_provider_data_element_set_allocated(de) }}, (override)); + MOCK_METHOD({{ interface.mock_provider_data_element_set(de) }}, (override)); +{% endfor %} + +{% for op in operations %} + MOCK_METHOD({{ interface.mock_provider_operation(op, module_interface) }}, (override)); +{% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_interface/operation_output.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_interface/operation_output.jinja new file mode 100644 index 0000000..087fc4f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_interface/operation_output.jinja @@ -0,0 +1,18 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{% for i in includes | sort %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +class {{operation_name}} final { + public: + struct Output { + {% for p in parameters %} + {{ data_type_to_str(p.TypeRef) }} {{ p.Name }}; + {% endfor %} + }; + }; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/basetypes_proto.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/basetypes_proto.jinja new file mode 100644 index 0000000..8922562 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/basetypes_proto.jinja @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package protobuf.basetypes; + +{% for proto, basetype in proto_translate_dict.items() %} +message {{proto}} { + {{basetype}} vaf_value_internal = 1; +} +{% endfor %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_proto.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_proto.jinja new file mode 100644 index 0000000..f82612b --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_proto.jinja @@ -0,0 +1,60 @@ +syntax = "proto3"; + +{% for import in imports %} +import "protobuf_{{ import.replace("::","_") }}.proto"; +{% endfor %} + +package protobuf.{{ package }}; + +{% for array in namespace_data.get("Arrays", {}).values() %} +{% set type=data_type_to_proto_type(array.TypeRef) %} +message {{ array.Name }} { + repeated {{ type }} vaf_value_internal = 1; +} +{% endfor %} +{% for vector in namespace_data.get("Vectors", {}).values() %} +{% set type=data_type_to_proto_type(vector.TypeRef) %} +message {{ vector.Name }} { + repeated {{ type }} vaf_value_internal = 1; +} +{% endfor %} +{% for map_entry in namespace_data.get("Maps", {}).values() %} +{% set key_type=data_type_to_proto_type(map_entry.MapKeyTypeRef) %} +{% set value_type=data_type_to_proto_type(map_entry.MapValueTypeRef) %} +message {{ map_entry.Name }}Entry { + {{ key_type }} vaf_key_internal = 1; + {{ value_type }} vaf_value_internal = 2; +} +message {{ map_entry.Name }} { + repeated {{ map_entry.Name }}Entry vaf_entry_internal = 1; +} +{% endfor %} +{% for string in namespace_data.get("Strings", {}).values() %} +message {{ string.Name }} { + string vaf_value_internal = 1; +} +{% endfor %} +{% for enum in namespace_data.get("Enums", {}).values() %} +message {{ enum.Name }} { +{% if enum.BaseType is none%} + uint32 vaf_value_internal = 1; +{% else %} +{% set type=data_type_to_proto_type(enum.BaseType) %} + {{ type }} vaf_value_internal = 1; +{% endif %} +} +{% endfor %} +{% for struct in namespace_data.get("Structs", {}).values() %} +message {{ struct.Name }} { +{% for sub_element in struct.SubElements %} +{% set type=data_type_to_proto_type(sub_element.TypeRef) %} + {{ type }} {{ sub_element.Name }} = {{ loop.index }}; +{% endfor %} +} +{% endfor %} +{% for type_ref in namespace_data.get("TypeRefs", {}).values() %} +{% set type=data_type_to_proto_type(type_ref.TypeRef) %} +message {{ type_ref.Name }} { + {{ type }} vaf_value_internal = 1; +} +{% endfor %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_transformer.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_transformer.jinja new file mode 100644 index 0000000..1320a8a --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/data_type_transformer.jinja @@ -0,0 +1,181 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{% for include in includes%} +{{include}} +{% endfor%} +{% endblock %} + +{% block content %} +{% for array in namespace_data.get("Arrays", {}).values() %} +void {{ array.Name }}VafToProto(const ::{{ implicit_data_type_to_str(array.Name, namespace ) }} &in, {{ array.Name }} &out); +void {{ array.Name }}ProtoToVaf(const {{ array.Name }} &in, ::{{ implicit_data_type_to_str(array.Name, namespace) }} &out); +{% endfor %} +{% for vector in namespace_data.get("Vectors", {}).values() %} +void {{ vector.Name }}VafToProto(const ::{{ implicit_data_type_to_str(vector.Name, namespace ) }} &in, {{ vector.Name }} &out); +void {{ vector.Name }}ProtoToVaf(const {{ vector.Name }} &in, ::{{ implicit_data_type_to_str(vector.Name, namespace) }} &out); +{% endfor %} +{% for map_entry in namespace_data.get("Maps", {}).values() %} +void {{ map_entry.Name }}VafToProto(const ::{{ implicit_data_type_to_str(map_entry.Name, namespace ) }} &in, {{ map_entry.Name }} &out); +void {{ map_entry.Name }}ProtoToVaf(const {{ map_entry.Name }} &in, ::{{ implicit_data_type_to_str(map_entry.Name, namespace) }} &out); +{% endfor %} +{% for string in namespace_data.get("Strings", {}).values() %} +void {{ string.Name }}VafToProto(const ::{{ implicit_data_type_to_str(string.Name, namespace ) }} &in, {{ string.Name }} &out); +void {{ string.Name }}ProtoToVaf(const {{ string.Name }} &in, ::{{ implicit_data_type_to_str(string.Name, namespace) }} &out); +{% endfor %} +{% for enum in namespace_data.get("Enums", {}).values() %} +void {{ enum.Name }}VafToProto(const ::{{ implicit_data_type_to_str(enum.Name, namespace ) }} &in, {{ enum.Name }} &out); +void {{ enum.Name }}ProtoToVaf(const {{ enum.Name }} &in, ::{{ implicit_data_type_to_str(enum.Name, namespace) }} &out); +{% endfor %} +{% for struct in namespace_data.get("Structs", {}).values() %} +void {{ struct.Name }}VafToProto(const ::{{ implicit_data_type_to_str(struct.Name, namespace ) }} &in, {{ struct.Name }} &out); +void {{ struct.Name }}ProtoToVaf(const {{ struct.Name }} &in, ::{{ implicit_data_type_to_str(struct.Name, namespace) }} &out); +{% endfor %} +{% for type_ref in namespace_data.get("TypeRefs", {}).values() %} +void {{ type_ref.Name }}VafToProto(const ::{{ implicit_data_type_to_str(type_ref.Name, namespace ) }} &in, {{ type_ref.Name }} &out); +void {{ type_ref.Name }}ProtoToVaf(const {{ type_ref.Name }} &in, ::{{ implicit_data_type_to_str(type_ref.Name, namespace) }} &out); +{% endfor %} +{% for array in namespace_data.get("Arrays", {}).values() %} +inline void {{ array.Name }}VafToProto(const ::{{ implicit_data_type_to_str(array.Name, namespace ) }} &in, {{ array.Name }} &out) { + out.Clear(); + for (int i=0;i<in.size();i++) { +{% if not is_data_type_base_type(array.TypeRef.Name, array.TypeRef.Namespace) and not is_data_type_cstdint_type(array.TypeRef.Name, array.TypeRef.Namespace)%} + ::protobuf::{{array.TypeRef.Namespace}}::{{array.TypeRef.Name}} element_out{}; + ::protobuf::{{array.TypeRef.Namespace}}::{{array.TypeRef.Name}}VafToProto(in[i], element_out); + out.mutable_vaf_value_internal()->Add(std::move(element_out)); +{% else %} + out.mutable_vaf_value_internal()->Add(in[i]); +{% endif %} + } +} +inline void {{ array.Name }}ProtoToVaf(const {{ array.Name }} &in, ::{{ implicit_data_type_to_str(array.Name, namespace) }} &out) { + for (int i=0;i<out.size();i++) { +{% if not is_data_type_base_type(array.TypeRef.Name, array.TypeRef.Namespace) and not is_data_type_cstdint_type(array.TypeRef.Name, array.TypeRef.Namespace)%} + ::protobuf::{{array.TypeRef.Namespace}}::{{array.TypeRef.Name}}ProtoToVaf(in.vaf_value_internal()[i], out[i]); +{% else %} + out[i]=in.vaf_value_internal()[i]; +{% endif %} + } +} +{% endfor %} +{% for vector in namespace_data.get("Vectors", {}).values() %} +inline void {{ vector.Name }}VafToProto(const ::{{ implicit_data_type_to_str(vector.Name, namespace ) }} &in, {{ vector.Name }} &out) { + out.Clear(); + for (auto element_in :in) { +{% if not is_data_type_base_type(vector.TypeRef.Name, vector.TypeRef.Namespace) and not is_data_type_cstdint_type(vector.TypeRef.Name, vector.TypeRef.Namespace)%} + ::protobuf::{{vector.TypeRef.Namespace}}::{{vector.TypeRef.Name}} element_out{}; + ::protobuf::{{vector.TypeRef.Namespace}}::{{vector.TypeRef.Name}}VafToProto(element_in, element_out); + out.mutable_vaf_value_internal()->Add(std::move(element_out)); +{% else %} + out.mutable_vaf_value_internal()->Add(element_in); +{% endif %} + } +} +inline void {{ vector.Name }}ProtoToVaf(const {{ vector.Name }} &in, ::{{ implicit_data_type_to_str(vector.Name, namespace) }} &out) { + out.clear(); + for (auto element_in :in.vaf_value_internal()) { +{% if not is_data_type_base_type(vector.TypeRef.Name, vector.TypeRef.Namespace) and not is_data_type_cstdint_type(vector.TypeRef.Name, vector.TypeRef.Namespace)%} + ::{{vector.TypeRef.Namespace}}::{{vector.TypeRef.Name}} element_out{}; + ::protobuf::{{vector.TypeRef.Namespace}}::{{vector.TypeRef.Name}}ProtoToVaf(element_in, element_out); + out.push_back(std::move(element_out)); +{% else %} + out.push_back(element_in); +{% endif %} + } +} +{% endfor %} +{% for map_entry in namespace_data.get("Maps", {}).values() %} +inline void {{ map_entry.Name }}EntryVafToProto(const {% if not is_data_type_base_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace ) }} &in_key, {% if not is_data_type_base_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace ) }} &in_value, {{ map_entry.Name }}Entry &out) { +{% if not is_data_type_base_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace) and not is_data_type_cstdint_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace)%} + ::protobuf::{{map_entry.MapKeyTypeRef.Namespace}}::{{map_entry.MapKeyTypeRef.Name}}VafToProto(in_key, *out.mutable_vaf_key_internal()); +{% else %} + out.set_vaf_key_internal(in_key); +{% endif %} +{% if not is_data_type_base_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace) and not is_data_type_cstdint_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace)%} + ::protobuf::{{map_entry.MapValueTypeRef.Namespace}}::{{map_entry.MapValueTypeRef.Name}}VafToProto(in_value, *out.mutable_vaf_value_internal()); +{% else %} + out.set_vaf_value_internal(in_value); +{% endif %} +} +inline void {{ map_entry.Name }}EntryProtoToVaf(const {{ map_entry.Name }}Entry &in, {% if not is_data_type_base_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace ) }} &out_key, {% if not is_data_type_base_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace ) }} &out_value) { +{% if not is_data_type_base_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace) and not is_data_type_cstdint_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace)%} + ::protobuf::{{map_entry.MapKeyTypeRef.Namespace}}::{{map_entry.MapKeyTypeRef.Name}}ProtoToVaf(in.vaf_key_internal(), out_key); +{% else %} + out_key = in.vaf_key_internal(); +{% endif %} +{% if not is_data_type_base_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace) and not is_data_type_cstdint_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace)%} + ::protobuf::{{map_entry.MapValueTypeRef.Namespace}}::{{map_entry.MapValueTypeRef.Name}}ProtoToVaf(in.vaf_value_internal(), out_value); +{% else %} + out_value = in.vaf_value_internal(); +{% endif %} +} +inline void {{ map_entry.Name }}VafToProto(const ::{{ implicit_data_type_to_str(map_entry.Name, namespace ) }} &in, {{ map_entry.Name }} &out) { + out.Clear(); + for (auto in_entry: in) { + {{ map_entry.Name }}Entry out_entry{}; + {{ map_entry.Name }}EntryVafToProto(in_entry.first, in_entry.second, out_entry); + out.mutable_vaf_entry_internal()->Add(std::move(out_entry)); + } +} +inline void {{ map_entry.Name }}ProtoToVaf(const {{ map_entry.Name }} &in, ::{{ implicit_data_type_to_str(map_entry.Name, namespace) }} &out) { + out.clear(); + for (auto in_entry: in.vaf_entry_internal()) { + std::pair<{% if not is_data_type_base_type(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapKeyTypeRef.Name, map_entry.MapKeyTypeRef.Namespace ) }}, {% if not is_data_type_base_type(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace) %}::{% endif %}{{ implicit_data_type_to_str(map_entry.MapValueTypeRef.Name, map_entry.MapValueTypeRef.Namespace ) }}> out_entry{}; + {{ map_entry.Name }}EntryProtoToVaf(in_entry, out_entry.first, out_entry.second); + out.insert(std::move(out_entry)); + } +} +{% endfor %} +{% for string in namespace_data.get("Strings", {}).values() %} +inline void {{ string.Name }}VafToProto(const ::{{ implicit_data_type_to_str(string.Name, namespace ) }} &in, {{ string.Name }} &out) { + (*out.mutable_vaf_value_internal()) = in.c_str(); +} +inline void {{ string.Name }}ProtoToVaf(const {{ string.Name }} &in, ::{{ implicit_data_type_to_str(string.Name, namespace) }} &out) { + out = in.vaf_value_internal(); +} +{% endfor %} +{% for enum in namespace_data.get("Enums", {}).values() %} +inline void {{ enum.Name }}VafToProto(const ::{{ implicit_data_type_to_str(enum.Name, namespace ) }} &in, {{ enum.Name }} &out) { + out.set_vaf_value_internal(static_cast<typename std::underlying_type<::{{ implicit_data_type_to_str(enum.Name, namespace ) }}>::type>(in)); +} +inline void {{ enum.Name }}ProtoToVaf(const {{ enum.Name }} &in, ::{{ implicit_data_type_to_str(enum.Name, namespace) }} &out) { + out = static_cast<::{{ implicit_data_type_to_str(enum.Name, namespace ) }}>(in.vaf_value_internal()); +} +{% endfor %} +{% for struct in namespace_data.get("Structs", {}).values() %} +inline void {{ struct.Name }}VafToProto(const ::{{ implicit_data_type_to_str(struct.Name, namespace ) }} &in, {{ struct.Name }} &out) { +{% for sub_element in struct.SubElements %} +{% if not is_data_type_base_type(sub_element.TypeRef.Name, sub_element.TypeRef.Namespace) and not is_data_type_cstdint_type(sub_element.TypeRef.Name, sub_element.TypeRef.Namespace)%} + ::protobuf::{{sub_element.TypeRef.Namespace}}::{{sub_element.TypeRef.Name}}VafToProto(in.{{sub_element.Name}}, *out.mutable_{{sub_element.Name.lower()}}()); +{% else %} + out.set_{{sub_element.Name.lower()}}(in.{{sub_element.Name}}); +{% endif %} +{% endfor%} +} +inline void {{ struct.Name }}ProtoToVaf(const {{ struct.Name }} &in, ::{{ implicit_data_type_to_str(struct.Name, namespace) }} &out) { +{% for sub_element in struct.SubElements %} +{% if not is_data_type_base_type(sub_element.TypeRef.Name, sub_element.TypeRef.Namespace) and not is_data_type_cstdint_type(sub_element.TypeRef.Name, sub_element.TypeRef.Namespace)%} + ::protobuf::{{sub_element.TypeRef.Namespace}}::{{sub_element.TypeRef.Name}}ProtoToVaf(in.{{sub_element.Name.lower()}}(), out.{{sub_element.Name}}); +{% else %} + out.{{sub_element.Name}} = in.{{sub_element.Name.lower()}}(); +{% endif %} +{% endfor%} +} +{% endfor %} +{% for type_ref in namespace_data.get("TypeRefs", {}).values() %} +inline void {{ type_ref.Name }}VafToProto(const ::{{ implicit_data_type_to_str(type_ref.Name, namespace ) }} &in, {{ type_ref.Name }} &out) { +{% if not is_data_type_base_type(type_ref.TypeRef.Name, type_ref.TypeRef.Namespace) and not is_data_type_cstdint_type(type_ref.TypeRef.Name, type_ref.TypeRef.Namespace)%} + {{type_ref.TypeRef.Namespace}}::{{type_ref.TypeRef.Name}}VafToProto(in, *out.mutable_vaf_value_internal()); +{% else %} + out.set_vaf_value_internal(in); +{% endif %} +} +inline void {{ type_ref.Name }}ProtoToVaf(const {{ type_ref.Name }} &in, ::{{ implicit_data_type_to_str(type_ref.Name, namespace) }} &out) { +{% if not is_data_type_base_type(type_ref.TypeRef.Name, type_ref.TypeRef.Namespace) and not is_data_type_cstdint_type(type_ref.TypeRef.Name, type_ref.TypeRef.Namespace)%} + {{type_ref.TypeRef.Namespace}}::{{type_ref.TypeRef.Name}}ProtoToVaf(in.vaf_value_internal(), out); +{% else %} + out = in.vaf_value_internal(); +{% endif %} +} +{% endfor %} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_proto.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_proto.jinja new file mode 100644 index 0000000..c147708 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_proto.jinja @@ -0,0 +1,28 @@ +syntax = "proto3"; + +{% for import in imports %} +import "protobuf_{{ import.replace("::","_") }}.proto"; +{% endfor %} + +package protobuf.{{ package }}; + +{% for de in interface.DataElements %} +{% set data_type = data_type_to_proto_type(de.TypeRef) %} +message {{ de.Name }} { + {{ data_type }} vaf_value_internal = 1; +} +{% endfor %} +{% for op in interface.Operations %} +message {{ op.Name }}_out { +{% for p in op.Parameters if not is_in_parameter(p) %} +{% set data_type = data_type_to_proto_type(p.TypeRef) %} + {{ data_type }} {{ p.Name }} = {{loop.index}}; +{% endfor %} +} +message {{ op.Name }}_in { +{% for p in op.Parameters if not is_out_parameter(p) %} +{% set data_type = data_type_to_proto_type(p.TypeRef) %} + {{ data_type }} {{ p.Name }} = {{loop.index}}; +{% endfor %} +} +{% endfor %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_transformer.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_transformer.jinja new file mode 100644 index 0000000..4460edd --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/interface_transformer.jinja @@ -0,0 +1,72 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{% for import in imports %} +#include "protobuf/{{ import.replace("::","/")}}/protobuf_transformer.h" +{% endfor %} +#include "protobuf_interface_{{interface.Namespace.replace("::", "_")}}_{{interface.Name}}.pb.h" +{% for operation in operation_with_out_parameters %} +#include "{{ out_parameter_type_namespace.replace("::", "/").lower() }}/{{ to_snake_case(operation.Name) }}.h" +{% endfor %} +{% endblock %} + +{% block content %} +{% for de in interface.DataElements %} +inline void {{ de.Name }}VafToProto(const {{ add_double_colon(de.TypeRef.Name, de.TypeRef.Namespace ) }}{{ implicit_data_type_to_str(de.TypeRef.Name, de.TypeRef.Namespace ) }} &in, {{ de.Name }} &out) { +{% if not is_data_type_base_type(de.TypeRef.Name, de.TypeRef.Namespace) and not is_data_type_cstdint_type(de.TypeRef.Name, de.TypeRef.Namespace)%} + protobuf::{{ implicit_data_type_to_str(de.TypeRef.Name, de.TypeRef.Namespace ) }}VafToProto(in,*out.mutable_vaf_value_internal()); +{% else %} + out.set_vaf_value_internal(in); +{% endif%} +} +inline void {{ de.Name }}ProtoToVaf(const {{ de.Name }} &in, {{ add_double_colon(de.TypeRef.Name, de.TypeRef.Namespace ) }}{{ implicit_data_type_to_str(de.TypeRef.Name, de.TypeRef.Namespace) }} &out) { +{% if not is_data_type_base_type(de.TypeRef.Name, de.TypeRef.Namespace) and not is_data_type_cstdint_type(de.TypeRef.Name, de.TypeRef.Namespace)%} + protobuf::{{ implicit_data_type_to_str(de.TypeRef.Name, de.TypeRef.Namespace ) }}ProtoToVaf(in.vaf_value_internal(),out); +{% else %} + out = in.vaf_value_internal(); +{% endif%} +} +{% endfor %} +{% for op in interface.Operations %} +{% if has_operation_out_or_inout_parameter(op) %} +inline void {{ op.Name }}OutVafToProto(const {{ add_double_colon(op.Name, out_parameter_type_namespace ) }}{{ out_parameter_type_namespace }}::{{ op.Name }}::Output &in, {{ op.Name }}_out &out) { +{% for p in op.Parameters if not is_in_parameter(p) %} +{% if not is_data_type_base_type(p.TypeRef.Name, p.TypeRef.Namespace) and not is_data_type_cstdint_type(p.TypeRef.Name, p.TypeRef.Namespace)%} + protobuf::{{p.TypeRef.Namespace}}::{{p.TypeRef.Name}}VafToProto(in.{{ p.Name }},*out.mutable_{{ p.Name.lower() }}()); +{% else %} + out.set_{{ p.Name.lower() }}(in.{{ p.Name }}); +{% endif%} +{% endfor %} +} +inline void {{ op.Name }}OutProtoToVaf(const {{ op.Name }}_out &in, {{ add_double_colon(op.Name, out_parameter_type_namespace ) }}{{ out_parameter_type_namespace }}::{{ op.Name }}::Output &out) { +{% for p in op.Parameters if not is_in_parameter(p) %} +{% if not is_data_type_base_type(p.TypeRef.Name, p.TypeRef.Namespace) and not is_data_type_cstdint_type(p.TypeRef.Name, p.TypeRef.Namespace)%} + protobuf::{{p.TypeRef.Namespace}}::{{p.TypeRef.Name}}ProtoToVaf(in.{{ p.Name.lower() }}(),out.{{ p.Name }}); +{% else %} + out.{{ p.Name }} = in.{{ p.Name.lower() }}(); +{% endif%} +{% endfor %} +} +{% endif %} +{% if has_operation_in_or_inout_parameter(op) %} +inline void {{ op.Name }}InVafToProto({{ get_operation_parameter_list_with_in(op) }}, {{ op.Name }}_in &out){ +{% for p in op.Parameters if not is_out_parameter(p) %} +{% if not is_data_type_base_type(p.TypeRef.Name, p.TypeRef.Namespace) and not is_data_type_cstdint_type(p.TypeRef.Name, p.TypeRef.Namespace)%} + protobuf::{{p.TypeRef.Namespace}}::{{p.TypeRef.Name}}VafToProto(in_{{ p.Name }},*out.mutable_{{ p.Name.lower() }}()); +{% else %} + out.set_{{ p.Name.lower() }}(in_{{ p.Name }}); +{% endif%} +{% endfor %} +} +inline void {{ op.Name }}InProtoToVaf(const {{ op.Name }}_in &in, {{ get_operation_parameter_list_with_out(op) }}) { +{% for p in op.Parameters if not is_out_parameter(p) %} +{% if not is_data_type_base_type(p.TypeRef.Name, p.TypeRef.Namespace) and not is_data_type_cstdint_type(p.TypeRef.Name, p.TypeRef.Namespace)%} + protobuf::{{p.TypeRef.Namespace}}::{{p.TypeRef.Name}}ProtoToVaf(in.{{ p.Name.lower() }}(),out_{{ p.Name }}); +{% else %} + out_{{ p.Name }} = in.{{ p.Name.lower() }}(); +{% endif%} +{% endfor %} +} +{% endif %} +{% endfor %} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/protobuf_cmake.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/protobuf_cmake.jinja new file mode 100644 index 0000000..27e7b06 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_protobuf/protobuf_cmake.jinja @@ -0,0 +1,23 @@ +{% include "common/cmake_copyright.jinja" %} + +FIND_PACKAGE(protobuf REQUIRED) + +set(TARGET {{ target_name }}) + +file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.proto) +protobuf_generate_cpp(PROTO_SRC PROTO_HEADER ${SOURCES}) + +add_library(${TARGET} STATIC ${PROTO_HEADER} ${PROTO_SRC}) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> + $<INSTALL_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>) + +target_link_libraries(${TARGET} + PUBLIC + {% for lib in libraries %} + {{ lib }} + {% endfor %} + ) +{# dummy comment for new line at the end #} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_cpp.jinja new file mode 100644 index 0000000..31d7fe4 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_cpp.jinja @@ -0,0 +1,196 @@ +{% extends "common/cpp_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <chrono> + +#include "vaf/error_domain.h" +#include "protobuf/interface/{{ module.ModuleInterfaceRef.Namespace.replace("::","/").lower()}}/{{module.ModuleInterfaceRef.Name.lower()}}/protobuf_transformer.h" +{% endblock %} + +{% block content %} +{{ module.Name }}::{{ module.Name }}(::vaf::Executor& executor, std::string name, ::vaf::ExecutableControllerInterface& executable_controller_interface) + : ::vaf::ControlInterface(std::move(name), {}, executable_controller_interface, executor), + executor_{ControlInterface::executor_} { +} + +::vaf::Result<void> {{ module.Name }}::Init() noexcept { + return ::vaf::Result<void>{}; +} + +void {{ module.Name }}::Start() noexcept { + const auto registry_uri = "{{registry_uri}}"; + const std::string participant_config_text = R"( + Description: My participant configuration + Logging: + Sinks: + - Type: Stdout + Level: Info + )"; + auto config = SilKit::Config::ParticipantConfigurationFromString(participant_config_text); + {% set participant_name = add_namespace_to_name(module.Name, module.Namespace) %} + participant_ = SilKit::CreateParticipant(config, "{{ participant_name }}", registry_uri); + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + {% if module.ModuleInterfaceRef.Namespace != "" %} + {% set de_name = module.ModuleInterfaceRef.Namespace + "::" + de.Name %} + {% else %} + {% set de_name = de.Name %} + {% endif %} + SilKit::Services::PubSub::PubSubSpec pubsubspec_{{ de_name.replace("::","_") }}{"{{ service_interface_name }}_{{ de.Name }}", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_{{ de_name.replace("::","_") }}.AddLabel("Instance", "{{ service_interface_name }}_{{ de.Name }}", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto receptionHandler_{{ de_name.replace("::","_") }} = [&](auto* subscriber, const auto& dataMessageEvent) { + const std::lock_guard<std::mutex> lock(cached_{{ de_name.replace("::","_") }}_mutex_); + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(dataMessageEvent.data)); + std::vector<std::uint8_t> eventData = deserializer.Deserialize<std::vector<uint8_t>>(); + + std::unique_ptr< {{ data_type }} > ptr; + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ de.Name }} deserialized; + deserialized.ParseFromArray( eventData.data(), eventData.size() ); + ptr = std::make_unique< {{ data_type }} >(); + ::protobuf::interface::{{ module.ModuleInterfaceRef.Namespace}}::{{ module.ModuleInterfaceRef.Name}}::{{ de.Name }}ProtoToVaf(deserialized,*ptr); + this->cached_{{ de_name.replace("::","_") }}_ = vaf::ConstDataPtr<const {{ data_type }}>{std::move(ptr)}; + + for(auto& handler_container : registered_{{ de_name.replace("::","_") }}_event_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(cached_{{ de_name.replace("::","_") }}_); + } + } + }; + subscriber_{{ de_name.replace("::","_") }}_= participant_->CreateDataSubscriber("Subscriber_{{ de_name.replace("::","_") }}", pubsubspec_{{ de_name.replace("::","_") }}, receptionHandler_{{ de_name.replace("::","_") }}); + + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {% if module.ModuleInterfaceRef.Namespace != "" %} + {% set op_name = module.ModuleInterfaceRef.Namespace + "::" + op.Name %} + {% else %} + {% set op_name = op.Name %} + {% endif %} + SilKit::Services::Rpc::RpcSpec rpcspec_{{ op_name.replace("::","_") }}{"{{ service_interface_name }}_{{ op.Name }}", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_{{ op_name.replace("::","_") }}.AddLabel("Instance", "{{ service_interface_name }}_{{ op.Name }}", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto ReturnFunc_{{ op_name.replace("::","_") }} = [&](auto* /*client*/, const auto& event) { + ::vaf::Promise<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}>* + promise_pointer = static_cast< + ::vaf::Promise<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}>*>( + event.userContext); + if (event.callStatus == SilKit::Services::Rpc::RpcCallStatus::Success) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.resultData)); + std::vector<std::uint8_t> result_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + {% if has_operation_out_or_inout_parameter(op) %} + {% set return_type = operation_get_return_type(op, module.ModuleInterfaceRef) %} + {{ return_type }} output; + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}_out deserialized; + deserialized.ParseFromArray( result_vector.data(), result_vector.size() ); + {% if has_operation_out_or_inout_parameter(op) %} + ::protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}OutProtoToVaf(deserialized, output); + {% endif%} + promise_pointer->set_value(output); + {% else %} + promise_pointer->set_value(); + {% endif %} + } else { + vaf::Error error_code{::vaf::ErrorCode::kDefaultErrorCode, "Rpc call failed"}; + promise_pointer->SetError(error_code); + } + delete promise_pointer; + }; + rpc_client_{{ op_name.replace("::","_") }}_= participant_->CreateRpcClient("{{ op_name.replace("::","_") }}", rpcspec_{{ op_name.replace("::","_") }}, ReturnFunc_{{ op_name.replace("::","_") }}); + + {% endfor %} + ReportOperational(); +} + +void {{ module.Name }}::Stop() noexcept { +} + +void {{ module.Name }}::DeInit() noexcept { +} + +void {{ module.Name }}::StartEventHandlerForModule(const std::string& module) { + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + for(auto& handler_container : registered_{{ de_name }}_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + {% endfor %} + active_modules_.push_back(module); +} + +void {{ module.Name }}::StopEventHandlerForModule(const std::string& module) { + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + for(auto& handler_container : registered_{{ de_name }}_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + {% endfor %} + static_cast<void>(std::remove(active_modules_.begin(), active_modules_.end(), module)); +} + +{% for de in module.ModuleInterfaceRef.DataElements %} +{% set data_type = data_type_to_str(de.TypeRef) %} +{% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + +{{ interface.consumer_data_element_get_allocated(de, module.Name ) }} { + ::vaf::Result<::vaf::ConstDataPtr<const {{ data_type }}>> result_value{ + ::vaf::Error{::vaf::ErrorCode::kNoSampleAvailable, "No sample available"}}; + const std::lock_guard<std::mutex> lock(cached_{{ de_name }}_mutex_); + if (cached_{{ de_name }}_) { + result_value = ::vaf::Result<::vaf::ConstDataPtr<const {{ data_type }}>>{cached_{{ de_name }}_}; + } + return result_value; +} + +{{ interface.consumer_data_element_get(de, module.Name ) }} { + {{ data_type }} return_value{}; + const std::lock_guard<std::mutex> lock(cached_{{ de_name }}_mutex_); + if (cached_{{ de_name }}_) { + return_value = *cached_{{ de_name }}_; + } + return return_value; +} + +{{ interface.consumer_data_element_handler(de, module.Name ) }} { + registered_{{ de_name }}_event_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + registered_{{ de_name }}_event_handlers_.back().is_active_ = true; + } +} + +{% endfor %} + + +{% for op in module.ModuleInterfaceRef.Operations %} +{% if module.ModuleInterfaceRef.Namespace != "" %} +{% set op_name = module.ModuleInterfaceRef.Namespace + "::" + op.Name %} +{% else %} +{% set op_name = op.Name %} +{% endif %} +{{ interface.consumer_operation(op, module.ModuleInterfaceRef, module.Name) }} { + ::vaf::Future<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}> return_value; + ::vaf::Promise<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}>* promise_pointer = + new ::vaf::Promise<{{ operation_get_return_type(op, module.ModuleInterfaceRef) }}>(); + return_value = promise_pointer->get_future(); + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}_in request; +{% if has_operation_in_or_inout_parameter(op) %} + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}InVafToProto({{ get_in_parameter_list_comma_separated(op) }}, request); +{% endif %} + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + + rpc_client_{{ op_name.replace("::","_") }}_->Call(serializer.ReleaseBuffer(), promise_pointer); + + return return_value; +} +{% endfor %} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_h.jinja new file mode 100644 index 0000000..3154844 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/consumer_module_h.jinja @@ -0,0 +1,81 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <atomic> +#include <mutex> +#include <memory> +#include <string> +#include <vector> + +#include "vaf/receiver_handler_container.h" +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +#include "silkit/SilKit.hpp" +#include "silkit/services/all.hpp" +#include "silkit/services/orchestration/string_utils.hpp" +#include "silkit/util/serdes/Serialization.hpp" +#include "protobuf_interface_{{ module.ModuleInterfaceRef.Namespace.replace("::", "_") }}_{{ module.ModuleInterfaceRef.Name }}.pb.h" + +{{ interface_file.get_include() }} + +{% endblock %} + + +{% block content %} +class {{ module.Name }} final : public {{ interface_file.get_full_type_name() }}, public vaf::ControlInterface { + public: + {{ module.Name }}(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface); + ~{{ module.Name }}() override = default; + + {{ module.Name }}(const {{ module.Name }}&) = delete; + {{ module.Name }}({{ module.Name }}&&) = delete; + {{ module.Name }}& operator=(const {{ module.Name }}&) = delete; + {{ module.Name }}& operator=({{ module.Name }}&&) = delete; + + // Management related operations + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + void StartEventHandlerForModule(const std::string& module) override; + void StopEventHandlerForModule(const std::string& module) override; + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + {{ interface.consumer_data_element_get_allocated(de) }} override; + {{ interface.consumer_data_element_get(de) }} override; + {{ interface.consumer_data_element_handler(de) }} override; + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {{ interface.consumer_operation(op, module.ModuleInterfaceRef) }} override; + {% endfor %} + + private: + vaf::ModuleExecutor& executor_; + std::vector<std::string> active_modules_; + std::unique_ptr<SilKit::IParticipant> participant_; + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + {% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + {% if de.InitialValue is none %} + ::vaf::ConstDataPtr<const {{ data_type }}> cached_{{ de_name }}_{}; + {% else %} + ::vaf::ConstDataPtr<const {{ data_type }}> cached_{{ de_name }}_{std::make_unique<const {{ data_type }}>({{ data_type }}{{ de.InitialValue }})}; + {% endif %} + std::vector<::vaf::ReceiverHandlerContainer<{{ interface.consumer_data_element_handler_callback(de) }}>> registered_{{ de_name }}_event_handlers_{}; + std::mutex cached_{{ de_name }}_mutex_; + SilKit::Services::PubSub::IDataSubscriber* subscriber_{{ de_name }}_; + {% endfor %} + {% for op in module.ModuleInterfaceRef.Operations %} + {% set op_name = add_namespace_to_name(op.Name, module.ModuleInterfaceRef.Namespace) %} + SilKit::Services::Rpc::IRpcClient* rpc_client_{{ op_name }}_; + {% endfor %} +}; + +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_silkit/module_cmake.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/module_cmake.jinja new file mode 100644 index 0000000..b81d71a --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/module_cmake.jinja @@ -0,0 +1,6 @@ +{% extends "common/cmake_library.jinja" %} + +{% block packages %} +find_package(SilKit REQUIRED MODULE) +find_package(Threads REQUIRED) +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_cpp.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_cpp.jinja new file mode 100644 index 0000000..07b378c --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_cpp.jinja @@ -0,0 +1,166 @@ +{% extends "common/cpp_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <memory> + +#include "vaf/internal/data_ptr_helper.h" +#include "vaf/result.h" +#include "vaf/controller_interface.h" +#include "vaf/error_domain.h" +#include "protobuf/interface/{{ module.ModuleInterfaceRef.Namespace.replace("::","/").lower()}}/{{module.ModuleInterfaceRef.Name.lower()}}/protobuf_transformer.h" +{% endblock %} + +{% block content %} +{{ module.Name }}::{{ module.Name }}(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface) + : vaf::ControlInterface(std::move(name), {}, executable_controller_interface, executor) { +} + +vaf::Result<void> {{ module.Name }}::Init() noexcept { + return vaf::Result<void>{}; +} + +void {{ module.Name }}::Start() noexcept { + const auto registry_uri = "{{registry_uri}}"; + const std::string participant_config_text = R"( + Description: My participant configuration + Logging: + Sinks: + - Type: Stdout + Level: Info + )"; + auto config = SilKit::Config::ParticipantConfigurationFromString(participant_config_text); + {% set participant_name = add_namespace_to_name(module.Name, module.Namespace) %} + participant_ = SilKit::CreateParticipant(config, "{{ participant_name }}", registry_uri); + + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set data_type = data_type_to_str(de.TypeRef) %} + {% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + SilKit::Services::PubSub::PubSubSpec pubsubspec_{{ de_name }}{"{{ service_interface_name }}_{{ de.Name }}", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_{{ de_name }}.AddLabel("Instance", "{{ service_interface_name }}_{{ de.Name }}", SilKit::Services::MatchingLabel::Kind::Mandatory); + publisher_{{ de_name.replace("::","_") }}_= participant_->CreateDataPublisher("Publisher_{{ de_name.replace("::","_") }}", pubsubspec_{{ de_name.replace("::","_") }}); + + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {% if module.ModuleInterfaceRef.Namespace != "" %} + {% set op_name = module.ModuleInterfaceRef.Namespace + "::" + op.Name %} + {% else %} + {% set op_name = op.Name %} + {% endif %} + SilKit::Services::Rpc::RpcSpec rpcspec_{{ op_name.replace("::","_") }}{"{{ service_interface_name }}_{{ op.Name }}", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_{{ op_name.replace("::","_") }}.AddLabel("Instance", "{{ service_interface_name }}_{{ op.Name }}", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto RemoteFunc_{{ op_name.replace("::","_") }} = [&](auto* server, const auto& event) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.argumentData)); + std::vector<std::uint8_t> argument_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}_in deserialized; + deserialized.ParseFromArray( argument_vector.data(), argument_vector.size() ); + {% for p in op.Parameters if not is_out_parameter(p) %} + {% set data_type = data_type_to_str(p.TypeRef) %} + {{ data_type }} {{ p.Name }}{}; + {% endfor %} + {% if has_operation_in_or_inout_parameter(op) %} + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}InProtoToVaf(deserialized, {{ get_in_parameter_list_comma_separated(op) }}); + {% endif %} + {% if has_operation_out_or_inout_parameter(op) %} + {{ operation_get_return_type(op, module.ModuleInterfaceRef) }} result; + {% endif %} + if (CbkFunction_{{ op_name.replace("::","_") }}_) { + {% if has_operation_out_or_inout_parameter(op) %} + result = CbkFunction_{{ op_name.replace("::","_") }}_( + {%- for p in op.Parameters if not is_out_parameter(p) -%} + {{ p.Name }}{% if not loop.last %}, {% endif %} + {%- endfor -%} + {% else %} + CbkFunction_{{ op_name.replace("::","_") }}_( + {%- for p in op.Parameters if not is_out_parameter(p) -%} + {{ p.Name }}{% if not loop.last %}, {% endif %} + {%- endfor -%} + {%- endif -%} + ); + } + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}_out request; + {% if has_operation_out_or_inout_parameter(op) %} + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ op.Name }}OutVafToProto(result, request); + {% endif %} + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + server->SubmitResult(event.callHandle, serializer.ReleaseBuffer()); + }; + server_{{ op_name.replace("::","_") }}_= participant_->CreateRpcServer("{{ op_name }}", rpcspec_{{ op_name.replace("::","_") }}, RemoteFunc_{{ op_name.replace("::","_") }}); + + {% endfor %} + ReportOperational(); +} + +void {{ module.Name }}::Stop() noexcept { +} + +void {{ module.Name }}::DeInit() noexcept { +} + +{% for de in module.ModuleInterfaceRef.DataElements %} +{% set data_type = data_type_to_str(de.TypeRef) %} +{% if module.ModuleInterfaceRef.Namespace != "" %} +{% set de_name = module.ModuleInterfaceRef.Namespace + "::" + de.Name %} +{% else %} +{% set de_name = de.Name %} +{% endif %} +{{ interface.provider_data_element_allocate(de, module.Name ) }} { + std::unique_ptr< {{ data_type }} > ptr{ + std::make_unique< {{ data_type }} >()}; + return ::vaf::Result<vaf::DataPtr< {{ data_type }} >>::FromValue(std::move(ptr)); +} + +{{ interface.provider_data_element_set_allocated(de, module.Name) }} { + {% set data_type_def = get_data_type_definition_of_parameter(de.TypeRef, model) %} + {% set data_type = data_type_to_str(de.TypeRef) %} + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ de.Name }} request; + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ de.Name }}VafToProto(*vaf::internal::DataPtrHelper<{{ data_type }}>::getRawPtr(data), request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_{{ de_name.replace("::","_") }}_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} + +{{ interface.provider_data_element_set(de, module.Name) }} { + {% set data_type_def = get_data_type_definition_of_parameter(de.TypeRef, model) %} + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ de.Name }} request; + protobuf::interface::{{ module.ModuleInterfaceRef.Namespace }}::{{ module.ModuleInterfaceRef.Name }}::{{ de.Name }}VafToProto(data, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_{{ de_name.replace("::","_") }}_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} +{% endfor %} + +{% for op in module.ModuleInterfaceRef.Operations %} +{% if module.ModuleInterfaceRef.Namespace != "" %} +{% set op_name = module.ModuleInterfaceRef.Namespace + "::" + op.Name %} +{% else %} +{% set op_name = op.Name %} +{% endif %} +{{ interface.provider_operation(op, module.ModuleInterfaceRef, module.Name) }} { + CbkFunction_{{ op_name.replace("::","_") }}_ = std::move(f); +} + +{% endfor %} +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_h.jinja new file mode 100644 index 0000000..1d2ee22 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_silkit/provider_module_h.jinja @@ -0,0 +1,57 @@ +{% extends "common/h_file_base.jinja" %} +{% import "vaf_interface/macros.jinja" as interface with context %} + +{% block includes %} +#include <memory> +#include <string> +#include <vector> + +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +#include "silkit/SilKit.hpp" +#include "silkit/services/all.hpp" +#include "silkit/services/orchestration/string_utils.hpp" +#include "silkit/util/serdes/Serialization.hpp" +#include "protobuf_interface_{{ module.ModuleInterfaceRef.Namespace.replace("::", "_") }}_{{ module.ModuleInterfaceRef.Name }}.pb.h" + +{{ interface_file.get_include() }} +{% endblock %} + +{% block content %} +class {{ module.Name }} final : public {{ interface_file.get_full_type_name() }}, public vaf::ControlInterface { + public: + explicit {{ module.Name }}(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface); + ~{{ module.Name }}() override = default; + + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + + {% for de in module.ModuleInterfaceRef.DataElements %} + {{ interface.provider_data_element_allocate(de) }} override; + {{ interface.provider_data_element_set_allocated(de) }} override; + {{ interface.provider_data_element_set(de) }} override; + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {{ interface.provider_operation(op, module.ModuleInterfaceRef) }} override; + {% endfor %} + + private: + std::unique_ptr<SilKit::IParticipant> participant_; + {% for de in module.ModuleInterfaceRef.DataElements %} + {% set de_name = add_namespace_to_name(de.Name, module.ModuleInterfaceRef.Namespace) %} + SilKit::Services::PubSub::IDataPublisher* publisher_{{ de_name }}_; + {% endfor %} + + {% for op in module.ModuleInterfaceRef.Operations %} + {% set op_name = add_namespace_to_name(op.Name, module.ModuleInterfaceRef.Namespace) %} + {{ interface.provider_operation_callback(op, module.ModuleInterfaceRef) }} CbkFunction_{{ op_name }}_{}; + SilKit::Services::Rpc::IRpcServer* server_{{ op_name }}_; + {% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/array_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/array_h.jinja new file mode 100644 index 0000000..7dd9fd7 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/array_h.jinja @@ -0,0 +1,12 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <array> + +{{ get_data_type_include_from_type_ref(array.TypeRef) }} +{% endblock %} + +{% set ref_type = get_file_helper(array.TypeRef) %} +{% block content %} +using {{ array.Name }} = std::array<{{ ref_type.get_full_type_name() }}, {{ array.Size }}>; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/enum_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/enum_h.jinja new file mode 100644 index 0000000..e56d8e5 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/enum_h.jinja @@ -0,0 +1,11 @@ +{% extends "common/h_file_base.jinja" %} + +{% block content %} +enum {{ vaf_enum.Name }} { + +{% for l in vaf_enum.Literals %} +{{ l.Label }} = {{ l.Value}}, +{% endfor %} + +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/map_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/map_h.jinja new file mode 100644 index 0000000..49d8025 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/map_h.jinja @@ -0,0 +1,14 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <map> + +{{ get_data_type_include_from_type_ref(vaf_map.MapKeyTypeRef) }} +{{ get_data_type_include_from_type_ref(vaf_map.MapValueTypeRef) }} +{% endblock %} + +{% set type_ref_type = get_file_helper(vaf_map.MapKeyTypeRef) %} +{% set value_ref_type = get_file_helper(vaf_map.MapValueTypeRef) %} +{% block content %} +using {{ vaf_map.Name }} = std::map<{{ type_ref_type.get_full_type_name() }}, {{ value_ref_type.get_full_type_name() }}>; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/string_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/string_h.jinja new file mode 100644 index 0000000..9fdf0ba --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/string_h.jinja @@ -0,0 +1,9 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <string> +{% endblock %} + +{% block content %} +using {{ vaf_string.Name }} = std::string; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/struct_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/struct_h.jinja new file mode 100644 index 0000000..3efa523 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/struct_h.jinja @@ -0,0 +1,15 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{% for i in includes | unique %} +{{ i }} +{% endfor %} +{% endblock %} + +{% block content %} +struct {{ vaf_struct.Name }} { +{% for s in vaf_struct.SubElements %} + {{ get_file_helper(s.TypeRef).get_full_type_name() }} {{ s.Name }}; +{% endfor %} +}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/type_ref_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/type_ref_h.jinja new file mode 100644 index 0000000..17cedea --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/type_ref_h.jinja @@ -0,0 +1,10 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +{{ get_data_type_include_from_type_ref(vaf_type_ref.TypeRef) }} +{% endblock %} + +{% set ref_type = get_file_helper(vaf_type_ref.TypeRef) %} +{% block content %} +using {{ vaf_type_ref.Name }} = {{ ref_type.get_full_type_name() }}; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/vector_h.jinja b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/vector_h.jinja new file mode 100644 index 0000000..36315db --- /dev/null +++ b/VAF/src/vaf/vafgeneration/templates/vaf_std_data_types/vector_h.jinja @@ -0,0 +1,12 @@ +{% extends "common/h_file_base.jinja" %} + +{% block includes %} +#include <vector> + +{{ get_data_type_include_from_type_ref(vaf_vector.TypeRef) }} +{% endblock %} + +{% set ref_type = get_file_helper(vaf_vector.TypeRef) %} +{% block content %} +using {{ vaf_vector.Name }} = std::vector<{{ ref_type.get_full_type_name() }}>; +{% endblock %} diff --git a/VAF/src/vaf/vafgeneration/vaf_application_communication.py b/VAF/src/vaf/vafgeneration/vaf_application_communication.py new file mode 100644 index 0000000..3a8024f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_application_communication.py @@ -0,0 +1,82 @@ +"""Generator for application communication modules +Generates + - module.h + - module.cpp + - CMakeLists.txt + - Top level CMakeLists.txt +""" + +from pathlib import Path + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_snake_case + +from .generation import FileHelper, Generator + + +def generate(model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False) -> None: + """Generate files for application communication modules + + Args: + model (vafmodel.MainModel): The model + output_dir (Path): Base output directory + verbose_mode: flag to enable verbose_mode mode + """ + output_path = output_dir / "src-gen/libs/platform_vaf" + + generator = Generator() + + module_dir_names: list[str] = [] + for executable in model.Executables: + for sm in executable.InternalCommunicationModules: + module_dir_name = to_snake_case(sm.Name) + module_dir_names.append(module_dir_name) + generator.set_base_directory(output_path / module_dir_name) + + provider_interface_file = FileHelper( + sm.ModuleInterfaceRef.Name + "Provider", sm.ModuleInterfaceRef.Namespace + ) + consumer_interface_file = FileHelper( + sm.ModuleInterfaceRef.Name + "Consumer", sm.ModuleInterfaceRef.Namespace + ) + + file = FileHelper(sm.Name, sm.Namespace) + generator.generate_to_file( + file, + ".h", + "vaf_application_communication/application_communication_module_h.jinja", + module=sm, + provider_interface_file=provider_interface_file, + consumer_interface_file=consumer_interface_file, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + file, + ".cpp", + "vaf_application_communication/application_communication_module_cpp.jinja", + module=sm, + verbose_mode=verbose_mode, + ) + + cmake = FileHelper("CMakeLists", "", True) + cmake_target_name = to_snake_case("Vaf" + sm.Name) + generator.generate_to_file( + cmake, + ".txt", + "common/cmake_library.jinja", + target_name=cmake_target_name, + files=[file], + libraries=[ + "$<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core>", + "vaf_module_interfaces", + ], + verbose_mode=verbose_mode, + ) + + generator.set_base_directory(output_path) + subdir_cmake = FileHelper("CMakeLists", "", True) + module_dir_names = list(set(module_dir_names)) + generator.generate_to_file( + subdir_cmake, ".txt", "common/cmake_subdirs.jinja", subdirs=module_dir_names, verbose_mode=verbose_mode + ) diff --git a/VAF/src/vaf/vafgeneration/vaf_application_module.py b/VAF/src/vaf/vafgeneration/vaf_application_module.py new file mode 100644 index 0000000..4565ffb --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_application_module.py @@ -0,0 +1,477 @@ +"""Generator for application modules +Generates + - framework/AppModuleBase.h + - framework/AppModuleBase.cpp + - framework/CMakeLists.txt + - AppModule.h + - AppModule.cpp + - CMakeLists.txt + - unittest/* +""" + +import collections +from pathlib import Path +from typing import Any, Dict, List + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_snake_case +from vaf.vafmodel import ApplicationModule + +from .generation import FileHelper, Generator +from .vaf_generate_common import get_ancestor_file_suffix + +# pylint: disable=duplicate-code + + +# dir name for user files +user_files_dir_name = "implementation" +test_files_dir_name = "test" + + +def _get_interface_type_by_instance(interfaces: list[Any], instance_name: str) -> str: + for i in interfaces: + if i["instance"] == instance_name: + assert isinstance(i["type"], str) + return i["type"] + raise ValueError(f"Could not find interfaces on module: ${instance_name}") + + +# pylint:disable=too-many-locals +def generate_app_module_base( + am: ApplicationModule, app_module_path_base: Path, generator: Generator, verbose_mode: bool = False +) -> None: + """Generate base files for application modules + + Args: + am (ApplicationModule): The model + app_module_path_base (Path): Output directory for base modules + generator (Generator): The generator + verbose_mode: flag to enable verbose_mode mode + """ + base_output_directory: Path = app_module_path_base / to_snake_case(am.Name) + if am.ImplementationProperties is not None: + if am.ImplementationProperties.InstallationPath is not None: + base_output_directory = app_module_path_base / am.ImplementationProperties.InstallationPath + + generator.set_base_directory(base_output_directory) + + interfaces_c = [] + interfaces_p = [] + for consumed_interface in am.ConsumedInterfaces: + interface_file = FileHelper( + consumed_interface.ModuleInterfaceRef.Name + "Consumer", consumed_interface.ModuleInterfaceRef.Namespace + ) + interfaces_c.append( + { + "include": interface_file.get_include(), + "instance": consumed_interface.InstanceName, + "type": interface_file.get_full_type_name(), + } + ) + for provided_interface in am.ProvidedInterfaces: + interface_file = FileHelper( + provided_interface.ModuleInterfaceRef.Name + "Provider", provided_interface.ModuleInterfaceRef.Namespace + ) + interfaces_p.append( + { + "include": interface_file.get_include(), + "instance": provided_interface.InstanceName, + "type": interface_file.get_full_type_name(), + } + ) + + interfaces = interfaces_c + interfaces_p + + base_file = FileHelper(am.Name + "Base", am.Namespace) + generator.generate_to_file( + base_file, + ".h", + "vaf_application_module/base_h.jinja", + app_module=am, + interfaces=interfaces, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + base_file, + ".cpp", + "vaf_application_module/base_cpp.jinja", + app_module=am, + interfaces=interfaces, + verbose_mode=verbose_mode, + ) + + base_cmake_target_name = to_snake_case("Vaf" + am.Name + "Base") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_library.jinja", + target_name=base_cmake_target_name, + files=[base_file], + libraries=["$<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core>", "vaf_module_interfaces"], + verbose_mode=verbose_mode, + ) + + +def __read_interfaces_cplusplus_refs(am: vafmodel.ApplicationModule) -> List[Dict[str, str]]: + """Method to collect interfaces reference in c++ + Args: + am: ApplicationModule object + Returns: + List of dictionary that contains interface reference in c++ + """ + + consumed_interfaces: List[Dict[str, str]] = [] + provided_interfaces: List[Dict[str, str]] = [] + for interface_type_attr in ["ConsumedInterfaces", "ProvidedInterfaces"]: + for interface in getattr(am, interface_type_attr): + # get a string for "Consumer"/"Provider" + interface_type_string = interface_type_attr.replace("dInterfaces", "r") + # build data for include & type for both mock & non mock + interface_cplusplus_ref_data: Dict[str, str] = { + to_snake_case(f"{key}{mock_type}"): getattr( + FileHelper( + interface.ModuleInterfaceRef.Name + f"{interface_type_string}{mock_type}", + interface.ModuleInterfaceRef.Namespace, + ), + method_name, + )() + # include calls get_include() method from FileHelper + # type calls get_full_type_name() method from FileHelper + for key, method_name in [("include", "get_include"), ("type", "get_full_type_name")] + for mock_type in ["", "Mock"] # Mock only needed by unittest but no harm for include & src + } + # append to the respective interfaces + locals()[to_snake_case(interface_type_attr)].append( + interface_cplusplus_ref_data + | { + "instance": interface.InstanceName, + "name": interface.ModuleInterfaceRef.Name + interface_type_string, + } + ) + + return consumed_interfaces + provided_interfaces + + +def generate_app_module_user( + am: ApplicationModule, + app_module_path: Path, + generator: Generator, + is_ancestor: bool, + verbose_mode: bool = False, +) -> List[str]: + """Generate user files for application modules + + Args: + am (ApplicationModule): The model + app_module_path (Path): Output directory + generator (Generator): The generator + is_ancestor: Flag to trigger generation for ancestor + verbose_mode (bool): Flag to enable verbose mode + Returns + List of all strings of relative path to user files + """ + # collect interfaces c++ references for jinja files + interfaces = __read_interfaces_cplusplus_refs(am) + + base_file = FileHelper(am.Name + "Base", am.Namespace) + generator.set_base_directory(app_module_path) + app_file = FileHelper(am.Name, am.Namespace) + generator.generate_to_file( + app_file, + f".h{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/module_h.jinja", + check_to_overwrite=True, + app_module=am, + base_include=base_file.get_include(), + verbose_mode=(verbose_mode and not is_ancestor), + ) + generator.generate_to_simple_file( + FileHelper(am.Name, am.Namespace), + f".cpp{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/module_cpp.jinja", + check_to_overwrite=True, + app_module=am, + interfaces=interfaces, + get_interface_type_by_instance=_get_interface_type_by_instance, + dummy_data_element=vafmodel.DataElement( + Name="MyDataElement", TypeRef=vafmodel.DataTypeRef(Name="uint64_t", Namespace="std") + ), + verbose_mode=(verbose_mode and not is_ancestor), + ) + base_cmake_target_name = to_snake_case("Vaf" + am.Name + "Base") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/cmake_implementation.jinja", + target_name=to_snake_case(am.Name), + files=[app_file], + libraries=[base_cmake_target_name], + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + # return list of user files' relative path to app_module + return [ + user_files_dir_name + + str(getattr(app_file, method_str)(generator.base_directory, file_ext)).removeprefix(str(app_module_path)) + for method_str, file_ext in [("get_file_path", ".h"), ("get_simple_file_path", ".cpp")] + ] + [f"{user_files_dir_name}/CMakeLists.txt"] + + +def generate_app_unittest( + am: ApplicationModule, + app_module_path_test: Path, + generator: Generator, + is_ancestor: bool, + verbose_mode: bool = False, +) -> List[str]: + """Generate files for application modules + + Args: + am (vafmodel.MainModel.ApplicationModules): The model + app_module_path_test (Path): Output directory for unit tests + generator (Generator): The generator + is_ancestor: Flag to trigger generation for ancestor + verbose_mode (bool): Flag to enable verbose mode + Returns: + List of strings that represent relative path to app_module's unit test + """ + generator.set_base_directory(app_module_path_test) + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "common/cmake_subdirs.jinja", + subdirs=["unittest"], + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + generator.set_base_directory(app_module_path_test / "unittest") + app_file = FileHelper(am.Name, am.Namespace) + base_file = FileHelper(am.Name + "Base", am.Namespace) + + # collect interfaces c++ references for jinja files + interfaces = __read_interfaces_cplusplus_refs(am) + + generator.generate_to_file( + base_file, + f".h{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/test_base_h.jinja", + app_module=am, + interfaces=interfaces, + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + generator.generate_to_file( + base_file, + f".cpp{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/test_base_cpp.jinja", + app_module=am, + interfaces=interfaces, + len=len, + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/test_cmake.jinja", + application_module_name=to_snake_case(am.Name), + target_name=to_snake_case(am.Name) + "_unittest", + app_files=[app_file], + base_files=[base_file], + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + base_file = FileHelper("main", "", True) + generator.generate_to_file( + base_file, + f".cpp{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/test_main_cpp.jinja", + app_module=am, + interfaces=interfaces, + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + base_file = FileHelper("tests", "", True) + generator.generate_to_file( + base_file, + f".cpp{get_ancestor_file_suffix(is_ancestor)}", + "vaf_application_module/test_module_cpp.jinja", + app_module=am, + interfaces=interfaces, + app_include=FileHelper(am.Name, am.Namespace).get_include(), + check_to_overwrite=True, + verbose_mode=(verbose_mode and not is_ancestor), + ) + + # return List of strings that represent relative path to app_module's unit test + return [ + f"{user_files_dir_name}/{test_files_dir_name}" + + str(base_file.get_file_path(generator.base_directory, file_ext)).removeprefix(str(app_module_path_test)) + for base_file, file_exts in [ + (FileHelper(am.Name + "Base", am.Namespace), [".cpp", ".h"]), + (FileHelper("main", "", True), [".cpp"]), + (FileHelper("tests", "", True), [".cpp"]), + (FileHelper("CMakeLists", "", True), [".txt"]), + ] + for file_ext in file_exts + ] + [f"{user_files_dir_name}/{test_files_dir_name}/CMakeLists.txt"] + + +def generate_app_module_project_files( + app_module: vafmodel.ApplicationModule, + output_dir: Path, + is_ancestor: bool = False, + verbose_mode: bool = False, +) -> List[str]: + """Generate files for application modules + + Args: + app_module (vafmodel.ApplicationModule): The application model + output_dir (Path): Base output directory + is_ancestor (bool): Flag to trigger generation for ancestor + verbose_mode (bool): Flag to enable verbose mode + Returns: + List of paths for user-editable files + """ + # collect list of merge relevant files + list_merge_relevant_files: List[str] = [] + + app_modules_path_base = "src-gen/libs/application_modules_base" + + generator = Generator() + + # don't generate app module base for ancestors + if not is_ancestor: + generate_app_module_base(app_module, output_dir / app_modules_path_base, generator, verbose_mode=verbose_mode) + + list_merge_relevant_files += generate_app_module_user( + app_module, output_dir / user_files_dir_name, generator, is_ancestor=is_ancestor, verbose_mode=verbose_mode + ) + list_merge_relevant_files += generate_app_unittest( + app_module, + output_dir / user_files_dir_name / test_files_dir_name, + generator, + is_ancestor=is_ancestor, + verbose_mode=verbose_mode, + ) + + # generate CMakeLists in src-gen/libs/application_modules_base + generator.set_base_directory(output_dir / app_modules_path_base) + if not is_ancestor: + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=[ + app_module.ImplementationProperties.InstallationPath + if app_module.ImplementationProperties is not None + and app_module.ImplementationProperties.InstallationPath is not None + else to_snake_case(app_module.Name) + ], + verbose_mode=verbose_mode, + ) + + # return list of str for relative paths of user files + return list_merge_relevant_files + + +def generate_app_module_files_for_integration_project( + application_modules: List[vafmodel.ApplicationModule], + output_dir: Path, + is_ancestor: bool = False, + verbose_mode: bool = False, +) -> List[str]: + """Generate files for application modules + + Args: + application_modules: List of all app modules in integration project + output_dir (Path): Base output directory + is_ancestor (bool): Flag to trigger generation for ancestor + verbose_mode: flag to enable verbose_mode mode + Returns: + List of paths for user-editable files + """ + app_modules_path_base = "src-gen/libs/application_modules_base" + list_merge_relevant_files: List[str] = [] + + generator = Generator() + app_modules_for_base: list[str] = [] + app_modules_for_src: list[str] = [] + for am in application_modules: + inserted_base: bool = False + if am.ImplementationProperties is not None: + if am.ImplementationProperties.InstallationPath is not None: + inserted_base = True + app_modules_for_base.append(am.ImplementationProperties.InstallationPath) + app_modules_for_src.append(am.ImplementationProperties.InstallationPath) + if not inserted_base: + app_modules_for_base.append(to_snake_case(am.Name)) + if not is_ancestor: + generate_app_module_base(am, output_dir / app_modules_path_base, generator, verbose_mode) + + # generate CMakeLists in src/application_modules + generator.set_base_directory(output_dir / "src" / "application_modules") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "common/cmake_subdirs.jinja", + subdirs=app_modules_for_src, + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + list_merge_relevant_files.append("src/application_modules/CMakeLists.txt") + + # generate CMakeLists in src-gen/libs/application_modules_base + generator.set_base_directory(output_dir / app_modules_path_base) + if not is_ancestor: + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=app_modules_for_base, + verbose_mode=verbose_mode, + ) + + return list_merge_relevant_files + + +def validate_model_app_modules(model: vafmodel.MainModel) -> None: + """Function to validate a model's app modules + Args: + model (vafmodel.MainModel): Current VAF Model + Raises: + RuntimeError: Duplicate app modules name install path pairs + """ + # get tuples of name, install_path + app_module_names_with_install_path = [ + ( + am.Name, + am.ImplementationProperties.InstallationPath + if am.ImplementationProperties is not None and am.ImplementationProperties.InstallationPath is not None + else "", + ) + for am in model.ApplicationModules + ] + # placeholder for error msgs + error_msg = [] + + for item, count in collections.Counter(app_module_names_with_install_path).items(): + if count > 1: + error_msg.append( + " ".join( + [ + f"ERROR: There are {count} application modules", + f"with name {item[0]} and install path '{item[1]}'. Application Module must have a unique pair of name and install path!", # pylint: disable = line-too-long + ] + ) + ) + + if error_msg: + error_msg.insert(0, f"{len(error_msg)} Errors are found in the Application Modules' modelling:") + raise RuntimeError("\n".join(error_msg)) diff --git a/VAF/src/vaf/vafgeneration/vaf_cac_support.py b/VAF/src/vaf/vafgeneration/vaf_cac_support.py new file mode 100644 index 0000000..306bb0f --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_cac_support.py @@ -0,0 +1,119 @@ +"""Generator for CaC support +Generates CaC Support for a model +""" + +from pathlib import Path +from typing import Any, Dict, List, Optional + +from vaf import vafmodel +from vaf.vafpy import import_model +from vaf.vafpy.core import VafpyAbstractBase +from vaf.vafpy.model_runtime import model_runtime + +from ..cli_core.common.utils import ProjectType +from .generation import FileHelper, Generator + + +def __consolidate_namespaces( + element_by_namespace: Dict[str, Dict[str, Dict[str, VafpyAbstractBase]]], generate_elements: List[str] +) -> Dict[str, Any]: + """Consolidate namespaces' data into common classes for CaC generation + Args: + element_by_namespace: dictionary that stores the model data by namespaces + generate_elements: list of elements to be generated + Returns: + dictionary that can be easily accessable by CaC generation + """ + result: Dict[str, Any] = {} + # loop over namespace models + for namespace in sorted(element_by_namespace.keys()): + # check if current data has relevant information for CaC + # this is important to prevent creation of empty classes in CaC + set_elements = [ + key for key, value in element_by_namespace[namespace].items() if value and key in generate_elements + ] + # add to CaC result if set_elements is not empty + if set_elements: + # get namespace parts -> classes in CaC + ns_parts = namespace.split("::") + for level in range(len(ns_parts)): + # get identifier + identifier = "::".join(ns_parts[: level + 1]) + # add identifier to dictionary if it hasn't exists + if identifier not in result: + result[identifier] = { + "level": level, + "set_elements": set_elements if level == len(ns_parts) - 1 else [], + "data": element_by_namespace[namespace] if level == len(ns_parts) - 1 else {}, + } + + return result + + +def __write_cac_support_file(file_base_name: str, output_dir: Path, **kwargs: Any) -> None: + """Generates the CaC support file + + Args: + file_base_name (str): The base name of the generated file (e.g. SIL Kit -> silkit.py) + output_dir (Path): The output directory + """ + generator = Generator() + generator.set_base_directory(output_dir) + python_cac_support = FileHelper(file_base_name, "") + generator.generate_to_file(python_cac_support, ".py", **kwargs) + + +def __read_model(input_dir: Path, model_file_name: str) -> None: + """Read model as model_runtime + + Args: + input_dir (Path): The input directory + model_file_name (str): The model file name inside the input directory + Returns: + model data as dictionary + """ + # Read in model + model_path: Path = input_dir / model_file_name + + model_runtime.reset() + import_model(str(model_path)) + + +def generate( + input_dir: Path, + model_file_name: str, + file_base_name: str, + output_dir: Path, + project_type: Optional[ProjectType] = None, +) -> None: + """Generates Vanilla CaC support file + + Args: + input_dir (Path): The input directory + model_file_name (str): The model file name inside the input directory + file_base_name (str): The base name of the generated file (e.g. SIL Kit -> silkit.py) + output_dir (Path): The output directory + project_type (ProjectType): type of project that affects the jinja generation + """ + __read_model(input_dir, model_file_name) + + __write_cac_support_file( + file_base_name, + output_dir, + **{ + "template_path": "vaf_cac_support/platform.py.jinja", + "cac_model": __consolidate_namespaces( + model_runtime.element_by_namespace, + generate_elements=[ + *(vafmodel.data_types if project_type == ProjectType.INTERFACE else []), + "Executables", + "ModuleInterfaces", + "PlatformConsumerModules", + "PlatformProviderModules", + ], + ), + "model": model_runtime.main_model, + "model_name": model_file_name, + "data_types": vafmodel.data_types, + }, + ) diff --git a/VAF/src/vaf/vafgeneration/vaf_cmake_common.py b/VAF/src/vaf/vafgeneration/vaf_cmake_common.py new file mode 100644 index 0000000..63994af --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_cmake_common.py @@ -0,0 +1,258 @@ +"""Generator for shared cmake files +Generates + - CMakeLists.txt + - executables/CMakeLists.txt + - libs/CMakeLists.txt + - libs/data_types/CMakeLists.txt +""" + +from pathlib import Path +from typing import List + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_snake_case + +from .generation import ( + FileHelper, + Generator, + is_silkit_used, +) +from .vaf_generate_common import get_ancestor_file_suffix + + +def _generate_data_types_cmake(generator: Generator, output_dir: Path, verbose_mode: bool = False) -> None: + data_types_path = output_dir / "src-gen/libs/data_types" + generator.set_base_directory(data_types_path) + generator.generate_to_file( + FileHelper("CMakeLists", "", True), ".txt", "vaf_cmake_common/data_types_cmake.jinja", verbose_mode=verbose_mode + ) + + +def _generate_executables_cmake( + generator: Generator, model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False +) -> None: + if len(model.Executables) > 0: + generator.set_base_directory(output_dir / "src-gen/executables") + exe_subdirs: set[str] = set() + for e in model.Executables: + exe_subdirs.add(to_snake_case(e.Name)) + # add existing folders + if (output_dir / "src-gen/executables").exists(): + exe_subdirs = exe_subdirs.union( + {it.parts[-1] for it in (output_dir / "src-gen/executables").iterdir() if it.is_dir()} + ) + exe_subdirs_list = list(exe_subdirs) + exe_subdirs_list.sort() + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=exe_subdirs_list, + verbose_mode=verbose_mode, + ) + + +# pylint: disable=too-many-arguments +# pylint: disable=too-many-positional-arguments +def _generate_src_and_src_gen_cmake( + generator: Generator, + model: vafmodel.MainModel, + output_dir: Path, + is_ancestor: bool, + generate_for_application_module: bool, + verbose_mode: bool = False, +) -> List[str]: + subdirs_src_gen: list[str] = [] + subdirs_src: list[str] = [] + merge_relevant_files: List[str] = [] + + subdirs_src_gen.append("libs") + if len(model.Executables) > 0: + subdirs_src.append("executables") + subdirs_src_gen.append("executables") + if len(model.ApplicationModules) > 0: + subdirs_src.append("application_modules") + + generator.set_base_directory(output_dir / "src-gen") + if not is_ancestor: + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs_src_gen, + verbose_mode=verbose_mode, + ) + + if not generate_for_application_module: + generator.set_base_directory(output_dir / "src") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "common/cmake_subdirs.jinja", + subdirs=subdirs_src, + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + merge_relevant_files.append("src/CMakeLists.txt") + + return merge_relevant_files + + +def _generate_test_cmake( + generator: Generator, model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False +) -> None: + subdirs_test: list[str] = [] + if len(model.ModuleInterfaces) > 0: + subdirs_test.append("mocks") + + generator.set_base_directory(output_dir / "test-gen") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs_test, + verbose_mode=verbose_mode, + ) + + +def _generate_test_mocks_cmake( + generator: Generator, model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False +) -> None: + subdirs_test: list[str] = [] + if len(model.ModuleInterfaces) > 0: + subdirs_test.append("interfaces") + + if len(subdirs_test) > 0: + generator.set_base_directory(output_dir / "test-gen" / "mocks") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs_test, + verbose_mode=verbose_mode, + ) + + +# pylint:disable=too-many-arguments +# pylint:disable=too-many-positional-arguments +def _generate_src_gen_libs_cmake( # pylint: disable=too-many-branches + generator: Generator, + model: vafmodel.MainModel, + output_dir: Path, + does_data_type_definition_exist: bool, + generate_for_application_module: bool, + verbose_mode: bool = False, +) -> None: # pylint: disable=line-too-long + libs_subdirs: list[str] = [] + + if does_data_type_definition_exist: + libs_subdirs.append("data_types") + libs_subdirs.append("interfaces") + if is_silkit_used(model): + libs_subdirs.append("protobuf_serdes") + if len(model.ApplicationModules) > 0: + libs_subdirs.append("application_modules_base") + if not generate_for_application_module: + for e in model.Executables: + if len(e.InternalCommunicationModules) > 0: + libs_subdirs.append("platform_vaf") + break + + if is_silkit_used(model): + libs_subdirs.append("platform_silkit") + + if len(libs_subdirs) > 0: + generator.set_base_directory(output_dir / "src-gen/libs") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=libs_subdirs, + verbose_mode=verbose_mode, + ) + + +def _generate_src_executables_cmake( + generator: Generator, model: vafmodel.MainModel, output_dir: Path, is_ancestor: bool, verbose_mode: bool = False +) -> List[str]: + libs_subdirs: list[str] = [] + merge_relevant_files: List[str] = [] + + for e in model.Executables: + libs_subdirs.append(to_snake_case(e.Name)) + + if len(model.Executables) > 0: + generator.set_base_directory(output_dir / "src/executables") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "common/cmake_subdirs.jinja", + subdirs=libs_subdirs, + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + merge_relevant_files.append("src/executables/CMakeLists.txt") + return merge_relevant_files + + +def generate( + model: vafmodel.MainModel, + output_dir: Path, + is_ancestor: bool = False, + generate_for_application_module: bool = False, + verbose_mode: bool = False, +) -> List[str]: + """Generate shared cmake files + + Args: + model (vafmodel.MainModel): The model + output_dir (Path): Base output directory + is_ancestor (bool): Flag to trigger generation for ancestor + generate_for_application_module (bool, optional): Generate for application module + verbose_mode (bool, optional): Flag to enable verbose_mode mode + Returns: + List of paths for user-editable files + """ + # collect list of merge relevant files + list_merge_relevant_files: List[str] = [] + + generator = Generator() + + does_data_type_definition_exist: bool = bool( + model.DataTypeDefinitions.Arrays + or model.DataTypeDefinitions.Enums + or model.DataTypeDefinitions.Maps + or model.DataTypeDefinitions.Strings + or model.DataTypeDefinitions.Structs + or model.DataTypeDefinitions.TypeRefs + ) + + list_merge_relevant_files += _generate_src_and_src_gen_cmake( + generator, + model, + output_dir, + is_ancestor, + generate_for_application_module, + verbose_mode=verbose_mode, + ) + if not is_ancestor: + _generate_src_gen_libs_cmake( + generator, + model, + output_dir, + does_data_type_definition_exist, + generate_for_application_module, + verbose_mode=verbose_mode, + ) + list_merge_relevant_files += _generate_src_executables_cmake( + generator, model, output_dir, is_ancestor, verbose_mode=verbose_mode + ) + if not is_ancestor: + _generate_executables_cmake(generator, model, output_dir, verbose_mode=verbose_mode) + _generate_test_cmake(generator, model, output_dir, verbose_mode=verbose_mode) + _generate_test_mocks_cmake(generator, model, output_dir, verbose_mode=verbose_mode) + + if does_data_type_definition_exist and not is_ancestor: + _generate_data_types_cmake(generator, output_dir, verbose_mode=verbose_mode) + + return list_merge_relevant_files diff --git a/VAF/src/vaf/vafgeneration/vaf_conan.py b/VAF/src/vaf/vafgeneration/vaf_conan.py new file mode 100644 index 0000000..b1fa8ac --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_conan.py @@ -0,0 +1,43 @@ +"""Generator for conan dependencies based on used VAF features +Generates + - src-gen/conan_deps.list +""" + +from pathlib import Path + +from vaf import vafmodel + +from .generation import FileHelper, Generator, is_silkit_used + +CONAN_DEPENDENCY_MAP = { + "protobuf": ["protobuf/5.27.0"], +} + + +def _generate_dependencies(generator: Generator, model: vafmodel.MainModel, verbose_mode: bool) -> None: + deps: set[str] = set() + + if is_silkit_used(model): + deps.update(CONAN_DEPENDENCY_MAP["protobuf"]) + + generator.generate_to_file( + FileHelper("conan_deps", "", True), + ".list", + "vaf_conan/conan_deps.list.jinja", + dependencies=deps, + verbose_mode=verbose_mode, + ) + + +def generate(model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False) -> None: + """Generate files for conan + + Args: + model (vafmodel.MainModel): The model + output_dir (Path): Base output directory + verbose_mode: flag to enable verbose_mode mode + """ + generator = Generator() + + generator.set_base_directory(output_dir / "src-gen") + _generate_dependencies(generator, model, verbose_mode) diff --git a/VAF/src/vaf/vafgeneration/vaf_controller.py b/VAF/src/vaf/vafgeneration/vaf_controller.py new file mode 100644 index 0000000..501ddba --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_controller.py @@ -0,0 +1,386 @@ +"""Generator for controller +Generates + - executable_controller.h + - executable_controller.cpp + - user_controller.h + - user_controller.cpp + - CMakeLists.txt +""" +# pylint: disable=too-many-locals + +from pathlib import Path +from typing import List + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_snake_case +from vaf.vafgeneration.vaf_generate_common import get_ancestor_file_suffix + +from .generation import ( + FileHelper, + Generator, + is_silkit_used, + time_str_to_nanoseconds, +) + + +def _is_vsf_platform_module(executable: vafmodel.Executable, module: vafmodel.PlatformModule) -> bool: + for m in executable.InternalCommunicationModules: + if m == module: + return True + return False + + +def get_full_type_of_application_module( + am: vafmodel.ExecutableApplicationModuleMapping, +) -> str: + """Get the full type of an application module from its mapping + + Args: + am (vafmodel.ExecutableApplicationModuleMapping): The application module mapping + + Returns: + str: The full type of the application module + """ + return FileHelper(am.ApplicationModuleRef.Name, am.ApplicationModuleRef.Namespace).get_full_type_name() + + +def get_include_of_application_module( + am: vafmodel.ExecutableApplicationModuleMapping, +) -> str: + """Get the include of an application module from its mapping + + Args: + am (vafmodel.ExecutableApplicationModuleMapping): The application module mapping + + Returns: + str: The include of the application module + """ + return FileHelper(am.ApplicationModuleRef.Name, am.ApplicationModuleRef.Namespace).get_include() + + +def get_full_type_of_platform_module(sm: vafmodel.PlatformModule) -> str: + """Get the full type of a platform module + + Args: + sm (vafmodel.PlatformModule): The platform module + + Returns: + str: The full type of the platform module + """ + return FileHelper(sm.Name, sm.Namespace).get_full_type_name() + + +def get_includes_of_platform_modules( + platform_modules: list[vafmodel.PlatformModule], +) -> list[str]: + """Gets the list of unique platform module includes + + Args: + platform_modules (list[vafmodel.PlatformModule]): List of platform modules. + + Returns: + list[str]: The unique includes for the platform modules + """ + includes: list[str] = [] + for sm in platform_modules: + includes.append(FileHelper(sm.Name, sm.Namespace).get_include()) + includes = list(set(includes)) + includes.sort() + return includes + + +def is_internal_communication_module(exe: vafmodel.Executable, sm: vafmodel.PlatformModule) -> bool: + """Returns True if platform module is internal communication module, otherwise False + + Args: + exe (vafmodel.Executable): The executable + sm (vafmodel.PlatformModule): The platform module + + Returns: + bool: True if internal communication module + """ + if not _is_vsf_platform_module(exe, sm): + return False + return True + + +def _get_provided_modules_of_application_module( + eamm: vafmodel.ExecutableApplicationModuleMapping, +) -> list[vafmodel.PlatformModule]: + modules: list[vafmodel.PlatformModule] = [] + am = eamm.ApplicationModuleRef + for ami in am.ProvidedInterfaces: + found_iitmm = [iitm for iitm in eamm.InterfaceInstanceToModuleMappings if iitm.InstanceName == ami.InstanceName] + if len(found_iitmm) == 1: + modules.append(found_iitmm[0].ModuleRef) + else: + raise ValueError( + f"Error: The application module interface instance: {ami.InstanceName}" + f" defined for application module: {am.Namespace}::{am.Name} is not mapped/connected." + "Consider using the 'connect_interfaces()' method to connect the interfaces internally." + ) + return modules + + +def _get_consumed_modules_of_application_module( + eamm: vafmodel.ExecutableApplicationModuleMapping, +) -> list[vafmodel.PlatformModule]: + modules: list[vafmodel.PlatformModule] = [] + am = eamm.ApplicationModuleRef + for ami in am.ConsumedInterfaces: + found_iitmm = [iitm for iitm in eamm.InterfaceInstanceToModuleMappings if iitm.InstanceName == ami.InstanceName] + if len(found_iitmm) == 1: + modules.append(found_iitmm[0].ModuleRef) + else: + raise ValueError( + f"Error: The application module interface instance: {ami.InstanceName}" + f" defined for application module: {am.Namespace}::{am.Name} is not mapped/connected." + "Consider using the 'connect_interfaces()' method to connect the interfaces internally." + ) + return modules + + +def _get_consumed_interface( + am: vafmodel.ExecutableApplicationModuleMapping, m: vafmodel.PlatformModule +) -> vafmodel.ApplicationModuleConsumedInterface: + for iitmm in am.InterfaceInstanceToModuleMappings: + if iitmm.ModuleRef == m: + for ci in am.ApplicationModuleRef.ConsumedInterfaces: + if ci.InstanceName == iitmm.InstanceName: + return ci + raise ValueError(f"Error: could not find consumed interface of platform module {m.Namespace}::{m.Name}") + + +# pylint: disable=too-many-branches +def get_dependencies_of_application_module( + exe: vafmodel.Executable, + am: vafmodel.ExecutableApplicationModuleMapping, +) -> tuple[list[str], list[str]]: + """Gets the execution and module dependencies of a application module by its mapping + + Args: + exe (vafmodel.Executable): The executable the application module is mapped to + am (vafmodel.ExecutableApplicationModuleMapping): The application module mapping + + Returns: + tuple[list[str], list[str]]: The execution and module dependencies + """ + execution_dependencies: list[str] = [] + module_dependencies_c: list[str] = [] + module_dependencies_p: list[str] = [] + + provided_modules = _get_provided_modules_of_application_module(am) + for m in provided_modules: + module_dependencies_p.append(m.Name) + if not _is_vsf_platform_module(exe, m): + execution_dependencies.append(m.Name) + + consumed_modules = _get_consumed_modules_of_application_module(am) + for m in consumed_modules: + module_dependencies_c.append(m.Name) + + if not _get_consumed_interface(am, m).IsOptional: + execution_dependencies.append(m.Name) + + return (execution_dependencies, module_dependencies_c + module_dependencies_p) + + +# pylint: enable=too-many-branches + + +def get_task_mapping( + mapping: vafmodel.ExecutableTaskMapping, + am: vafmodel.ExecutableApplicationModuleMapping, +) -> tuple[int, int]: + """Gets the offset and budget of a task by its mapping + + Args: + mapping (vafmodel.ExecutableTaskMapping): The task mapping + am (vafmodel.ExecutableApplicationModuleMapping): The application module the task is mapped to + + Raises: + ValueError: If the mapped task is not found in the application module + + Returns: + tuple[int, int]: The offset and budget of the task + """ + offset = mapping.Offset if mapping.Offset is not None else 0 + budget = time_str_to_nanoseconds(mapping.Budget) if mapping.Budget is not None else 0 + + task = [r for r in am.ApplicationModuleRef.Tasks if r.Name == mapping.TaskName] + if len(task) == 0: + raise ValueError( + f"Error: could not find mapped task {mapping.TaskName} in application module" + f"{am.ApplicationModuleRef.Namespace}::{am.ApplicationModuleRef.Name}" + ) + + preferred_offset = task[0].PreferredOffset + if preferred_offset is not None: + if mapping.Offset is None: + offset = preferred_offset + elif mapping.Offset != preferred_offset: + print(f"Warning: offset for task {mapping.TaskName} is different then its preferred offset") + + return (offset, budget) + + +# Locals use seems reasonable. Generator could become an argument but not really a benefit there + + +def generate( # pylint: disable=too-many-locals, too-many-branches, too-many-statements + model: vafmodel.MainModel, output_dir: Path, is_ancestor: bool = False, verbose_mode: bool = False +) -> List[str]: + """Generate the VAF controller + + Args: + model (vafmodel.MainModel): The main model + output_dir (Path): The output directory + is_ancestor (bool): Flag to trigger generation for ancestor + verbose_mode: flag to enable verbose_mode mode + + Raises: + ValueError: If there is a interface mapping problem + """ + generator = Generator() + + # collect list of merge relevant files + list_merge_relevant_files: List[str] = [] + + for e in model.Executables: # pylint: disable=too-many-branches, too-many-nested-blocks + output_path = output_dir / "src-gen/executables" + provided_modules: list[vafmodel.PlatformModule] = [] + consumed_modules: list[vafmodel.PlatformModule] = [] + + for am in e.ApplicationModules: + for mapping in am.InterfaceInstanceToModuleMappings: + if ( + len( + [ + ci + for ci in am.ApplicationModuleRef.ConsumedInterfaces + if ci.InstanceName == mapping.InstanceName + ] + ) + > 0 + ): + if not _is_vsf_platform_module(e, mapping.ModuleRef): + consumed_modules.append(mapping.ModuleRef) + elif ( + len( + [ + ci + for ci in am.ApplicationModuleRef.ProvidedInterfaces + if ci.InstanceName == mapping.InstanceName + ] + ) + > 0 + ): + provided_modules.append(mapping.ModuleRef) + + else: + raise ValueError( + f"Mapped interface instance {mapping.InstanceName} not found in application module: " + ) + + folder_name = to_snake_case(e.Name) + generator.set_base_directory(output_path / folder_name) + + exe_controller_file = FileHelper("ExecutableController", "executable_controller") + if not is_ancestor: + generator.generate_to_file(exe_controller_file, ".h", "vaf_controller/executable_controller_h.jinja") + generator.generate_to_file( + exe_controller_file, + ".cpp", + "vaf_controller/executable_controller_cpp.jinja", + get_full_type_of_application_module=get_full_type_of_application_module, + get_dependencies_of_application_module=get_dependencies_of_application_module, + get_includes_of_platform_modules=get_includes_of_platform_modules, + get_full_type_of_platform_module=get_full_type_of_platform_module, + is_internal_communication_module=is_internal_communication_module, + get_include_of_application_module=get_include_of_application_module, + get_task_mapping=get_task_mapping, + executable=e, + communication_modules=consumed_modules + provided_modules, + vafmodel=vafmodel, + isinstance=isinstance, + verbose_mode=verbose_mode, + ) + + output_path = output_dir / "src/executables" + generator.set_base_directory(output_path / folder_name) + + user_controller_file = FileHelper("UserController", "") + generator.generate_to_file( + user_controller_file, + f".h{get_ancestor_file_suffix(is_ancestor)}", + "vaf_controller/user_controller_h.jinja", + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + list_merge_relevant_files.append(f"src/executables/{folder_name}/UserController.h") + generator.generate_to_file( + user_controller_file, + f".cpp{get_ancestor_file_suffix(is_ancestor)}", + "vaf_controller/user_controller_cpp.jinja", + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + list_merge_relevant_files.append(f"src/executables/{folder_name}/UserController.cpp") + + output_path = output_dir / "src-gen/executables" + generator.set_base_directory(output_path / folder_name) + + main_file = FileHelper("Main", "") + if not is_ancestor: + generator.generate_to_file( + main_file, + ".cpp", + "vaf_controller/main_cpp.jinja", + controller_file=exe_controller_file, + verbose_mode=verbose_mode, + ) + + def __generate_platform_modules_library_list(modules: List[vafmodel.PlatformModule]) -> List[str]: + result = [] + for module in modules: + target_name_list = [ + "vaf", + to_snake_case(module.Name), + ] + result.append("_".join(target_name_list)) + return result + + libraries = __generate_platform_modules_library_list( + consumed_modules + ) + __generate_platform_modules_library_list(provided_modules) + + for a in e.ApplicationModules: + libraries.append(to_snake_case(a.ApplicationModuleRef.Name)) + + if not is_ancestor: + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "vaf_controller/CMakeLists_txt.jinja", + target_name=e.Name, + files=[exe_controller_file], + libraries=libraries, + uses_silkit=is_silkit_used(model), + verbose_mode=verbose_mode, + ) + output_path = output_dir / "src/executables" + generator.set_base_directory(output_path / folder_name) + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + f".txt{get_ancestor_file_suffix(is_ancestor)}", + "vaf_controller/user_controller_CMakeLists_txt.jinja", + target_name=e.Name, + check_to_overwrite=True, + verbose_mode=verbose_mode, + ) + list_merge_relevant_files.append(f"src/executables/{folder_name}/CMakeLists.txt") + + return list_merge_relevant_files + + +# pylint: enable=too-many-locals diff --git a/VAF/src/vaf/vafgeneration/vaf_generate_application_module.py b/VAF/src/vaf/vafgeneration/vaf_generate_application_module.py new file mode 100644 index 0000000..0311ce6 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_generate_application_module.py @@ -0,0 +1,145 @@ +"""Generator library for generating the complete VAF project""" + +import shutil +from pathlib import Path +from typing import List + +from vaf import vafmodel +from vaf.cli_core.common.exceptions import VafProjectGenerationError +from vaf.vafpy import import_model +from vaf.vafpy.model_runtime import model_runtime + +from .generation import is_silkit_used + +# Utils +from .vaf_application_module import generate_app_module_project_files + +# Build system files generators +from .vaf_cmake_common import generate as generate_cmake_common +from .vaf_conan import generate as generate_conan_deps +from .vaf_generate_common import get_ancestor_model, merge_after_regeneration + +# VAF generators +from .vaf_interface import generate_module_interfaces as generate_interface +from .vaf_protobuf_serdes import generate as generate_protobuf_serdes +from .vaf_std_data_types import generate as generate_vaf_std_data_types + + +def validate_application_module(app_module: vafmodel.ApplicationModule) -> None: + """Function to validate a single application model + Args: + app_module: Application Module to be validated + Raises: + VafProjectGenerationError: If InstallationPath is not defined + """ + if app_module.ImplementationProperties is None: + raise VafProjectGenerationError(f"ImplementationProperties for application module {app_module.Name} missing!") + if app_module.ImplementationProperties.InstallationPath is None: + raise VafProjectGenerationError(f"InstallationPath for application module {app_module.Name} missing!") + + +def _print_info(header: str, content: str = "") -> None: + columns = shutil.get_terminal_size().columns + remaining_columns = columns - len(header) - 2 # Two spaces around the header + if remaining_columns <= 0: + prefix_cnt = postfix_cnt = 0 + else: + prefix_cnt = remaining_columns // 2 + postfix_cnt = remaining_columns // 2 + (remaining_columns % 2 > 0) + + print(f"\n{prefix_cnt * '-'} {header} {postfix_cnt * '-'}") + if content: + print("\n".join([content, f"{columns * '-'}\n"])) + + +def generate_application_module( # pylint: disable=too-many-arguments, too-many-positional-arguments, too-many-branches + model_file: str, + project_dir: str, + execute_merge: bool = True, + verbose_mode: bool = False, +) -> None: + """Generates all app modules files & operations + Args: + model_file (str): Path to the VAF model JSON + project_dir (str): Path to the output directory + execute_merge (bool): Flag to enable/disable automatic merge changes after regeneration + verbose_mode (bool): Flag to enable verbose mode + Raises: + SystemError: If there is a system-related error during cleanup. + ValueError: If the given model contains more or less application modules than one. + """ + list_merge_relevant_files: List[str] = [] + + # clean model runtime before every run + model_runtime.reset() + # import json as model_runtime + import_model(model_file) + main_model = model_runtime.main_model + path_output_dir = Path(project_dir) + if len(main_model.ApplicationModules) != 1: + raise ValueError( + "".join( + [ + "An application module model needs exactly one application module, ", + f"but found {len(main_model.ApplicationModules)}", + ] + ) + ) + print(f"Generate app-module in {path_output_dir}\n\n") + + # define flag for merge: execute merge == True and not first time + # (first time: if src-gen folder only contains one file - conan_deps.list) + execute_merge &= len(list((path_output_dir / "src-gen").glob("*"))) != 1 + + for subdir_name in ["src-gen", "test"]: + if (path_output_dir / subdir_name).is_dir(): + try: + shutil.rmtree(path_output_dir / subdir_name) + except OSError as e: + raise SystemError( + f'Folder "{(path_output_dir / subdir_name).absolute().as_posix()}" could not be removed due to {e}!' + ) from e + + # This generator needs to run before calling get_paths() + generate_conan_deps(main_model, path_output_dir, verbose_mode) + + _print_info("VAF GENERATE APP-MODULE: STEP 1", "Generating module interfaces files") + generate_interface(main_model, path_output_dir, verbose_mode) + + _print_info("VAF GENERATE APP-MODULE: STEP 2", f"Generating source files based on: {model_file}") + list_merge_relevant_files = generate_app_module_project_files( + main_model.ApplicationModules[0], path_output_dir, is_ancestor=False, verbose_mode=verbose_mode + ) + print("SUCCESS: Source files generated!") + # check for "ancestor" model.json (model.json~) + ancestor_model = get_ancestor_model(model_file) if execute_merge else None + # generate ancestor files if this exists and merge will be performed + if ancestor_model is not None: + if verbose_mode: + print("VERBOSE: Generating ancestor files for auto-merge") + generate_app_module_project_files( + ancestor_model.ApplicationModules[0], + path_output_dir, + is_ancestor=True, + verbose_mode=verbose_mode, + ) + + _print_info("VAF GENERATE APP-MODULE: STEP 3", "Generating datatypes using std generator") + generate_vaf_std_data_types(model_runtime, path_output_dir, verbose_mode) + + if is_silkit_used(main_model): + generate_protobuf_serdes(model_runtime, path_output_dir, verbose_mode) + + # must run as last generator + # No files to merge when generating for app-modules + _ = generate_cmake_common( + main_model, path_output_dir, generate_for_application_module=True, verbose_mode=verbose_mode + ) + print("SUCCESS: Datatypes generated!") + + # execute merge if list of user files are not empty + if execute_merge and list_merge_relevant_files: + _print_info("VAF GENERATE APP-MODULE: STEP 4", "Merging existing source files with results from step 1") + # solve conflicts for user files + merge_after_regeneration(path_output_dir, list_merge_relevant_files, verbose_mode) + _print_info("SUCCESS: MERGE EXECUTED!") diff --git a/VAF/src/vaf/vafgeneration/vaf_generate_common.py b/VAF/src/vaf/vafgeneration/vaf_generate_common.py new file mode 100644 index 0000000..0334ff7 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_generate_common.py @@ -0,0 +1,227 @@ +"""Generator library for generating the complete VAF project""" + +import shutil +import subprocess +from pathlib import Path +from typing import List + +from vaf import vafmodel + +# Utils +from vaf.cli_core.common.utils import ( + concat_str_to_path, +) + +# suffix for ancestor of model.json +from vaf.vafpy.runtime import old_json_suffix + +# suffix for old source file +suffix_old_source = "~" +ancestor_file_suffix = "~ancestor" +new_file_suffix = ".new~" + + +def __file_has_conflict(file_path: Path) -> bool: + """Function to check if file contains conflicts + Args: + file_path: Path to the file + Return: + boolean if file contains conflicts + """ + with open(file_path, "r", encoding="utf-8") as file: + file_content = file.read() + return all(conflict_sign in file_content for conflict_sign in ["<<<<<<<", "=======", ">>>>>>>"]) + + +def __get_ancestor_file_rel_path(real_file_rel_path: str | Path) -> str | Path: + """Function to get rel path of the ancestor of a user file as str + Args: + real_file_rel_path: rel path of the real file + Returns: + respective rel path of the ancestor + """ + return ( + concat_str_to_path(real_file_rel_path, ancestor_file_suffix) + if isinstance(real_file_rel_path, Path) + else real_file_rel_path + ancestor_file_suffix + ) + + +def __get_newly_generated_file_path(real_file_rel_path: str | Path) -> str | Path: + """Function to get rel path of the newly generated file (.new~) + Args: + real_file_rel_path: rel path of the real file + Returns: + respective rel path of the newly generated file + """ + return ( + concat_str_to_path(real_file_rel_path, new_file_suffix) + if isinstance(real_file_rel_path, Path) + else real_file_rel_path + new_file_suffix + ) + + +def __get_backup_file_path(real_file_rel_path: str | Path) -> str | Path: + """Function to get rel path of the backup file (~) + Args: + real_file_rel_path: rel path of the real file + Returns: + respective rel path of the backup file + """ + return ( + concat_str_to_path(real_file_rel_path, suffix_old_source) + if isinstance(real_file_rel_path, Path) + else real_file_rel_path + suffix_old_source + ) + + +def __merge_files( + newly_generated_file: Path, + patched_file_path: Path, + common_ancestor_file_path: Path, + verbose_mode: bool = False, +) -> None: + """Function to perform three-way files merge through subprocess + Documentation for git merge-file: https://git-scm.com/docs/git-merge-file + Args: + newly_generated_file: path to the newly generated file (ends w/ .new~) + patched_file_path: path to the patched file (older generated file + patch) + common_ancestor_file_path: path to the common ancestor of current & patched (older generated file) + verbose_mode (bool): Flag to enable verbose mode + """ + # build cmd to perform git merge-file: + # merge newly generated file to current file (patched_file) + args = [ + "git", + "merge-file", + "-p", # -p to send results to stdout + str(patched_file_path), + str(common_ancestor_file_path), + str(newly_generated_file), + ] + # run the cmd + merge = subprocess.run(args, capture_output=True, text=True, check=False) + + old_file_path = concat_str_to_path(patched_file_path, suffix_old_source) + + # check if merge results has conflicts + msg_list = [] + if merge.returncode == 0: + msg_list += ( + [ + "\nMERGE INFO", + f" Merge of {newly_generated_file} with {patched_file_path} successfully without conflicts!", + f" Merge result is saved in {patched_file_path}.", + ] + if verbose_mode + else [] + ) + elif merge.returncode == 1: + msg_list += [ + "\nMERGE WARNING:", + f" Merge of {newly_generated_file} with {patched_file_path} has conflicts!", + f" Merge result is saved in {patched_file_path}. Please resolve the conflicts before moving on.", + ] + + msg_list += ( + [ + f" Original state of {patched_file_path} before merge is saved as backup in {old_file_path}\n", + ] + if msg_list + else [] + ) + + if merge.returncode in (0, 1): + print("\n".join(msg_list)) + # save merge results + with open(patched_file_path, "w", encoding="utf-8") as out_file: + out_file.write(merge.stdout) + else: + # Inform user if merge fails: Don't abort the whole workflow! + print(f"Auto file mechanism for file {patched_file_path} failed! Reason: {merge.stderr}") + + +def merge_after_regeneration(out_dir: Path, list_of_user_files_rel_path: List[str], verbose_mode: bool = False) -> None: + """Function to perform three-way files merge after regeneration of app_module + Args: + out_dir: Path to the output directory + list_of_user_files_rel_path: List of relative path from out_dir to user files (files that users can edit) + verbose_mode (bool): Flag to enable verbose mode + """ + for rel_path_to_file in list_of_user_files_rel_path: + newly_generated_file_path = out_dir / __get_newly_generated_file_path(rel_path_to_file) + ancestor_file_path = out_dir / __get_ancestor_file_rel_path(rel_path_to_file) + # merge needed if there is a copy of .new~ file is created + # merge can only be performed if ancestor exists + if newly_generated_file_path.is_file(): + if ancestor_file_path.is_file(): + # backup current file + current_file = out_dir / rel_path_to_file + backup_file = __get_backup_file_path(current_file) + # if current file has conflict, then check if backup is valid to be used + if __file_has_conflict(current_file): + print( + "\n".join( + [ + "WARNING:", + f" The file {current_file} contains unresolved merge conflicts and will be ignored!", + f" Using the backup file {backup_file} for the merge instead.", + ] + ) + ) + assert isinstance(backup_file, Path) # Are you satisfied now, mypy? + if backup_file.is_file() and not __file_has_conflict(backup_file): + shutil.copyfile(backup_file, current_file) + else: + # current file has no conflict, overwrite backup + shutil.copyfile(out_dir / rel_path_to_file, __get_backup_file_path(out_dir / rel_path_to_file)) + + # perform three way merge + __merge_files( + newly_generated_file=newly_generated_file_path, + patched_file_path=out_dir / rel_path_to_file, + common_ancestor_file_path=ancestor_file_path, + verbose_mode=verbose_mode, + ) + else: + # warning only if newly generated file exists, + msg_list = [ + "WARNING:", + f" Cannot merge {newly_generated_file_path} to {out_dir / rel_path_to_file} automatically!", + " Can't find old model.json~", + ( + " Please merge both files manually. The auto merge will be available " + + "the next time the model is updated." + ), + ] + print("\n".join(msg_list)) + + # remove newly generated file only if merge took place + # else no old model.json~ -> new file is identical with current, remove it + newly_generated_file_path.unlink() + + # remove ancestor file regardless of the merge + if ancestor_file_path.is_file(): + ancestor_file_path.unlink() + + +def get_ancestor_file_suffix(is_ancestor: bool) -> str: + """Method to get file's suffix for ancestor + Args: + is_ancestor: boolean for ancestor + Returns: + file suffix if it's ancestor + """ + return ancestor_file_suffix if is_ancestor else "" + + +def get_ancestor_model(input_file: str) -> vafmodel.MainModel | None: + """Function to get old model + Args: + input_file: Path to current model file + Returns: + Old vafmodel, if old model.json file exists + """ + # check for "ancestor" model.json (model.json~) + ancestor_json = concat_str_to_path(Path(input_file), old_json_suffix) + return vafmodel.load_json(ancestor_json) if ancestor_json.is_file() else None diff --git a/VAF/src/vaf/vafgeneration/vaf_generate_project.py b/VAF/src/vaf/vafgeneration/vaf_generate_project.py new file mode 100644 index 0000000..d5a87d6 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_generate_project.py @@ -0,0 +1,163 @@ +"""Generator library for generating the complete VAF project""" + +import shutil +from pathlib import Path +from typing import Any, Callable, Dict, List + +from vaf import vafmodel +from vaf.vafpy import import_model +from vaf.vafpy.model_runtime import model_runtime + +from .generation import is_silkit_used +from .vaf_application_communication import generate as generate_application_communication +from .vaf_application_module import generate_app_module_files_for_integration_project + +# Build system files generators +from .vaf_cmake_common import generate as generate_cmake_common +from .vaf_conan import generate as generate_conan_deps +from .vaf_controller import generate as generate_controller + +# VAF generators +from .vaf_generate_common import get_ancestor_model, merge_after_regeneration +from .vaf_interface import generate_module_interfaces as generate_interface +from .vaf_protobuf_serdes import generate as generate_protobuf_serdes +from .vaf_silkit import generate as generate_silkit +from .vaf_std_data_types import generate as generate_vaf_std_data_types + +# pylint: disable=duplicate-code + + +def get_ecosystems(model: vafmodel.MainModel) -> List[str]: + """Get All Ecosystems in the model + Args: + model: VAF MainModel + Returns: + List of all found Ecosystems in the platform + """ + list_of_relevant_attrs = [ + "PlatformConsumerModules", + "PlatformProviderModules", + "ServiceConsumerModules", + "ServiceProviderModules", + ] + return list( + { + module.OriginalEcoSystem.value + for modules in [getattr(model, attr, "") for attr in list_of_relevant_attrs] + for module in modules + if hasattr(module, "OriginalEcoSystem") + } + ) + + +ECOSYSTEM_FUNCTION_DICT: Dict[str, Callable[[vafmodel.MainModel, Path, bool], Any]] = { + "SILKIT": generate_silkit, +} + + +# pylint: disable=too-many-arguments +# pylint: disable=too-many-positional-arguments +# pylint: disable=too-many-locals +# pylint: disable=too-many-branches +# pylint: disable=too-many-statements +def generate_integration_project( + model_file: str, + project_dir: str, + execute_merge: bool = True, + verbose_mode: bool = False, +) -> None: + """ + Generate the code for the project. + + Args: + model_file (str): The path to the input file. + project_dir (str): The path to project root directory. + execute_merge (bool): Flag to enable/disable automatic merge changes after regeneration + verbose_mode (bool): Flag to enable verbose mode + Raises: + ValueError: If the path to the project root directory is invalid. + SystemError: If there is a system-related error during cleanup. + + """ + # clean model runtime before every run + model_runtime.reset() + + if project_dir is None: + raise ValueError("Üath to project directory cannot be None!") + + path_project_dir = Path(project_dir) + import_model(model_file) + main_model = model_runtime.main_model + + delete_folder_src_gen: Path = path_project_dir / "src-gen" + if delete_folder_src_gen.exists(): + try: + shutil.rmtree(delete_folder_src_gen) + except OSError as e: + raise SystemError( + f'Folder "{delete_folder_src_gen.absolute().as_posix()}" could not be removed because of {e}!' + ) from e + + delete_folder_test_gen: Path = path_project_dir / "test-gen" + if delete_folder_test_gen.exists(): + try: + shutil.rmtree(delete_folder_test_gen) + except OSError as e: + raise SystemError( + f'Folder "{delete_folder_test_gen.absolute().as_posix()}" could not be removed because of {e}!' + ) from e + + # This generator needs to run before calling get_paths() + generate_conan_deps(main_model, path_project_dir, verbose_mode) + + generate_interface(main_model, path_project_dir, verbose_mode) + + # Load "ancestor" model.json if available and 3-way-merge is enabled + ancestor_model = get_ancestor_model(model_file) if execute_merge else None + # collect list of merge relevant files + list_merge_relevant_files: List[str] = [] + + # only generate platform_vaf in case of application module is modelled + if getattr(main_model, "ApplicationModules"): + # generate files for app modules + ancestor + list_merge_relevant_files += generate_app_module_files_for_integration_project( + application_modules=main_model.ApplicationModules, output_dir=path_project_dir, verbose_mode=verbose_mode + ) + if ancestor_model is not None: + generate_app_module_files_for_integration_project( + application_modules=ancestor_model.ApplicationModules, + output_dir=path_project_dir, + is_ancestor=True, + verbose_mode=verbose_mode, + ) + + generate_application_communication(main_model, path_project_dir, verbose_mode) + + list_merge_relevant_files += generate_controller(main_model, path_project_dir, verbose_mode=verbose_mode) + if ancestor_model is not None: + generate_controller(ancestor_model, path_project_dir, is_ancestor=True, verbose_mode=verbose_mode) + + # only generate platform dir for used ecosystems + for ecosystem in get_ecosystems(main_model): + ECOSYSTEM_FUNCTION_DICT[ecosystem](main_model, path_project_dir, verbose_mode) + + generate_vaf_std_data_types(model_runtime, path_project_dir, verbose_mode) + if is_silkit_used(main_model): + generate_protobuf_serdes(model_runtime, path_project_dir, verbose_mode) + + # must run as last generator + list_merge_relevant_files += generate_cmake_common( + main_model, path_project_dir, generate_for_application_module=False, verbose_mode=verbose_mode + ) + if ancestor_model is not None: + generate_cmake_common( + ancestor_model, + path_project_dir, + is_ancestor=True, + generate_for_application_module=False, + verbose_mode=verbose_mode, + ) + + if execute_merge and list_merge_relevant_files: + # solve conflicts for user files + merge_after_regeneration(path_project_dir, list_merge_relevant_files, verbose_mode) diff --git a/VAF/src/vaf/vafgeneration/vaf_interface.py b/VAF/src/vaf/vafgeneration/vaf_interface.py new file mode 100644 index 0000000..e0a4194 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_interface.py @@ -0,0 +1,195 @@ +"""Generator library for module interface generation.""" + +# pylint: disable=duplicate-code +from pathlib import Path + +from vaf import vafmodel + +from .generation import FileHelper, Generator, get_data_type_include, get_include + + +def _get_file_helper(data_type: vafmodel.DataType) -> FileHelper: + return FileHelper(data_type.Name, data_type.Namespace) + + +def generate_interfaces(interface: vafmodel.ModuleInterface, generator: Generator, verbose_mode: bool = False) -> None: + """Generates the module interfaces + + Args: + interface (ModuleInterface): The model + generator (Generator): The generator + verbose_mode: flag to enable verbose_mode mode + """ + include_files: list[str] = [] + for d in interface.DataElements: + include_files.append(get_data_type_include(d.TypeRef.Name, d.TypeRef.Namespace)) + + out_parameter_type_namespace: str = interface.Namespace + if interface.OperationOutputNamespace is not None: + out_parameter_type_namespace = interface.OperationOutputNamespace + + for o in interface.Operations: + out_paramter_includes: list[str] = [] + out_parameters: list[vafmodel.Parameter] = [] + for p in o.Parameters: + if p.Direction is not vafmodel.ParameterDirection.OUT: + include_files.append(get_data_type_include(p.TypeRef.Name, p.TypeRef.Namespace)) + if p.Direction is not vafmodel.ParameterDirection.IN: + out_paramter_includes.append(get_data_type_include(p.TypeRef.Name, p.TypeRef.Namespace)) + out_parameters.append(p) + + if len(out_parameters) > 0: + include_files.append(FileHelper(o.Name, out_parameter_type_namespace).get_include()) + generator.generate_to_file( + FileHelper(o.Name, out_parameter_type_namespace), + ".h", + "vaf_interface/operation_output.jinja", + includes=set(out_paramter_includes), + parameters=out_parameters, + operation_name=o.Name, + get_file_helper=_get_file_helper, + verbose_mode=verbose_mode, + ) + + include_files = list(set(include_files)) + + consumer_file = FileHelper(interface.Name + "Consumer", interface.Namespace) + generator.generate_to_file( + consumer_file, + ".h", + "vaf_interface/module_interface_consumer_h.jinja", + name=interface.Name, + module_interface=interface, + data_elements=interface.DataElements, + operations=interface.Operations, + include_files=include_files, + verbose_mode=verbose_mode, + ) + + provided_file = FileHelper(interface.Name + "Provider", interface.Namespace) + generator.generate_to_file( + provided_file, + ".h", + "vaf_interface/module_interface_provider_h.jinja", + name=interface.Name, + module_interface=interface, + data_elements=interface.DataElements, + operations=interface.Operations, + include_files=include_files, + verbose_mode=verbose_mode, + ) + + +def generate_interfaces_mocks( + interface: vafmodel.ModuleInterface, generator: Generator, verbose_mode: bool = False +) -> None: + """Generates the module interfaces + + Args: + interface (ModuleInterface): The model + generator (Generator): The generator + verbose_mode: flag to enable verbose_mode mode + """ + out_parameter_type_namespace: str = interface.Namespace + if interface.OperationOutputNamespace is not None: + out_parameter_type_namespace = interface.OperationOutputNamespace + + include_files: list[str] = [] + for d in interface.DataElements: + include_files.append(get_data_type_include(d.TypeRef.Name, d.TypeRef.Namespace)) + + for o in interface.Operations: + out_parameters: list[vafmodel.Parameter] = [] + for p in o.Parameters: + if p.Direction is not vafmodel.ParameterDirection.OUT: + include_files.append(get_data_type_include(p.TypeRef.Name, p.TypeRef.Namespace)) + if p.Direction is not vafmodel.ParameterDirection.IN: + out_parameters.append(p) + + if len(out_parameters) > 0: + include_files.append(FileHelper(o.Name, out_parameter_type_namespace).get_include()) + + include_files.append(get_include(interface.Name + "_consumer", interface.Namespace)) + include_files = list(set(include_files)) + + consumer_file = FileHelper(interface.Name + "ConsumerMock", interface.Namespace) + generator.generate_to_file( + consumer_file, + ".h", + "vaf_interface/module_interface_consumer_mock_h.jinja", + name=interface.Name, + module_interface=interface, + data_elements=interface.DataElements, + operations=interface.Operations, + include_files=include_files, + verbose_mode=verbose_mode, + ) + + include_files.remove(get_include(interface.Name + "_consumer", interface.Namespace)) + include_files.append(get_include(interface.Name + "_provider", interface.Namespace)) + provided_file = FileHelper(interface.Name + "ProviderMock", interface.Namespace) + generator.generate_to_file( + provided_file, + ".h", + "vaf_interface/module_interface_provider_mock_h.jinja", + name=interface.Name, + module_interface=interface, + data_elements=interface.DataElements, + operations=interface.Operations, + include_files=include_files, + verbose_mode=verbose_mode, + ) + + +def generate_module_interfaces(model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False) -> None: + """Generates the module interfaces + + Args: + model (vafmodel.MainModel): The model + output_dir (str): The output directory + verbose_mode: flag to enable verbose_mode mode + """ + + generator = Generator() + generator.set_base_directory(output_dir / "src-gen/libs/interfaces") + + cmake_file = FileHelper("CMakeLists", "", True) + + data_type_definition_not_empty: bool = any( + bool(getattr(model.DataTypeDefinitions, data_type)) for data_type in vafmodel.data_types + ) + + libraries: list[str] = ["vaf_data_types"] if data_type_definition_not_empty else [] + + generator.generate_to_file( + cmake_file, + ".txt", + "common/cmake_interface_library.jinja", + target_name="vaf_module_interfaces", + libraries=libraries, + verbose_mode=verbose_mode, + ) + + if not model.ModuleInterfaces: + include_path: Path = output_dir / "src-gen/libs/interfaces/include" + include_path.mkdir(parents=False, exist_ok=True) + + if len(model.ModuleInterfaces) > 0: + generator.set_base_directory(output_dir / "test-gen/mocks/interfaces") + generator.generate_to_file( + cmake_file, + ".txt", + "common/cmake_interface_library.jinja", + target_name="vaf_module_interface_mocks", + libraries=libraries, + verbose_mode=verbose_mode, + ) + + for interface in model.ModuleInterfaces: + generator.set_base_directory(output_dir / "src-gen/libs/interfaces") + generate_interfaces(interface, generator, verbose_mode) + generator.set_base_directory(output_dir / "test-gen/mocks/interfaces") + generate_interfaces_mocks(interface, generator, verbose_mode) + + +# pylint: enable=duplicate-code diff --git a/VAF/src/vaf/vafgeneration/vaf_protobuf_serdes.py b/VAF/src/vaf/vafgeneration/vaf_protobuf_serdes.py new file mode 100644 index 0000000..ba86fa3 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_protobuf_serdes.py @@ -0,0 +1,465 @@ +"""Generator library for protbuf serialization/deserialization.""" + +from pathlib import Path +from typing import Dict, List + +from vaf import vafmodel +from vaf.vafpy.core import VafpyAbstractBase +from vaf.vafpy.model_runtime import ModelRuntime + +from .generation import ( + FileHelper, + Generator, + data_type_to_str, + is_data_type_base_type, + is_data_type_cstdint_type, + is_out_parameter, +) + + +def data_type_to_proto_type(data_type: vafmodel.DataType) -> str: + """Converts a DataType to string + + Args: + data_type (vafmodel.DataType): The data type + + Returns: + str: DataType as string + """ + result = "" + if is_data_type_cstdint_type(data_type.Name, data_type.Namespace): + match data_type.Name: + case "uint8_t": + result = "uint32" + case "uint16_t": + result = "uint32" + case "uint32_t": + result = "uint32" + case "uint64_t": + result = "uint64" + case "int8_t": + result = "int32" + case "int16_t": + result = "int32" + case "int32_t": + result = "int32" + case "int64_t": + result = "int64" + case _: + result = "data_type.Name" + else: + result = ( + "protobuf." + data_type.Namespace.replace("::", ".") + "." + data_type.Name + if data_type.Namespace != "" + else data_type.Name + ) + + return result + + +def _prepend_double_colon(datatype: vafmodel.DataType) -> str: + if not is_data_type_base_type(datatype.Name, datatype.Namespace): + return "::" + return "" + + +def _add_double_colon(name: str, namespace: str) -> str: + if not is_data_type_base_type(name, namespace): + return "::" + return "" + + +def _get_operation_parameter_list_with_in(operation: vafmodel.Operation) -> str: + parameter_str = "" + is_first = True + for parameter in operation.Parameters: + if not is_out_parameter(parameter): + if is_first: + parameter_str = ( + "const " + + _prepend_double_colon(parameter.TypeRef) + + data_type_to_str(parameter.TypeRef) + + "& in_" + + parameter.Name + ) + is_first = False + else: + parameter_str = ( + parameter_str + + ", const " + + _prepend_double_colon(parameter.TypeRef) + + data_type_to_str(parameter.TypeRef) + + "& in_" + + parameter.Name + ) + return parameter_str + + +def _get_operation_parameter_list_with_out(operation: vafmodel.Operation) -> str: + parameter_str = "" + is_first = True + for parameter in operation.Parameters: + if not is_out_parameter(parameter): + if is_first: + parameter_str = ( + _prepend_double_colon(parameter.TypeRef) + + data_type_to_str(parameter.TypeRef) + + "& out_" + + parameter.Name + ) + is_first = False + else: + parameter_str = ( + parameter_str + + ", " + + _prepend_double_colon(parameter.TypeRef) + + data_type_to_str(parameter.TypeRef) + + "& out_" + + parameter.Name + ) + return parameter_str + + +def _is_base_type(data_type: vafmodel.DataType) -> bool: + result = False + if is_data_type_base_type(data_type.Name, data_type.Namespace) or is_data_type_cstdint_type( + data_type.Name, data_type.Namespace + ): + result = True + return result + + +def _add_namespace_to_import(data_type: vafmodel.DataTypeRef, namespace: str, used_namespaces: List[str]) -> bool: + return ( + not _is_base_type(data_type) and data_type.Namespace != namespace and data_type.Namespace not in used_namespaces + ) + + +def _get_namespace_imports( + namespace_object_Dict: Dict[str, Dict[str, Dict[str, VafpyAbstractBase]]], +) -> Dict[str, List[str]]: + namespace_imports: Dict[str, List[str]] = {} + + for namespace, data in namespace_object_Dict.items(): + if namespace not in namespace_imports: + namespace_imports[namespace] = [] + for data_type in vafmodel.data_types: + for dt in data.get(data_type, {}).values(): + if isinstance(dt, vafmodel.Struct): + namespace_imports[namespace] += [ + x.TypeRef.Namespace + for x in dt.SubElements + if _add_namespace_to_import(x.TypeRef, namespace, namespace_imports[namespace]) + ] + elif isinstance(dt, vafmodel.Map): + namespace_imports[namespace] += [ + *( + [dt.MapKeyTypeRef.Namespace] + if _add_namespace_to_import(dt.MapKeyTypeRef, namespace, namespace_imports[namespace]) + else [] + ), + *( + [dt.MapValueTypeRef.Namespace] + if _add_namespace_to_import(dt.MapValueTypeRef, namespace, namespace_imports[namespace]) + else [] + ), + ] + elif isinstance(dt, (vafmodel.Array, vafmodel.TypeRef, vafmodel.Vector)): + namespace_imports[namespace] += ( + [dt.TypeRef.Namespace] + if _add_namespace_to_import(dt.TypeRef, namespace, namespace_imports[namespace]) + else [] + ) + # make imports List unique + namespace_imports[namespace] = list(set(namespace_imports[namespace])) + + return namespace_imports + + +def _get_used_namespaces_by_interface(interface: vafmodel.ModuleInterface) -> List[str]: + used_namespaces: List[str] = [] + for x in interface.DataElements: + if _add_namespace_to_import(x.TypeRef, "", used_namespaces): + used_namespaces.append(x.TypeRef.Namespace) + for op in interface.Operations: + for x in op.Parameters: # type: ignore[assignment] + if _add_namespace_to_import(x.TypeRef, "", used_namespaces): + used_namespaces.append(x.TypeRef.Namespace) + return used_namespaces + + +def _generate_proto_files( + model_runtime: ModelRuntime, + output_path: Path, + generator: Generator, + verbose_mode: bool = False, +) -> None: + generator.set_base_directory(output_path) + + proto_translate_dict = {} + proto_translate_dict["UInt64"] = "uint64" + proto_translate_dict["UInt32"] = "uint32" + proto_translate_dict["UInt16"] = "uint32" + proto_translate_dict["UInt8"] = "uint32" + proto_translate_dict["Int64"] = "int64" + proto_translate_dict["Int32"] = "int32" + proto_translate_dict["Int16"] = "int32" + proto_translate_dict["Int8"] = "int32" + proto_translate_dict["Bool"] = "bool" + proto_translate_dict["Float"] = "float" + proto_translate_dict["Double"] = "double" + + generator.generate_to_file( + FileHelper("protobuf_basetypes", "", True), + ".proto", + "vaf_protobuf/basetypes_proto.jinja", + proto_translate_dict=proto_translate_dict, + verbose_mode=verbose_mode, + ) + + namespace_imports = _get_namespace_imports(model_runtime.element_by_namespace) + + for namespace, data in model_runtime.element_by_namespace.items(): + generator.generate_to_file( + FileHelper("protobuf_" + namespace.replace("::", "_"), "", True), + ".proto", + "vaf_protobuf/data_type_proto.jinja", + str=str, + package=namespace.replace("::", "."), + namespace_data=data, + len=len, + data_type_to_proto_type=data_type_to_proto_type, + imports=namespace_imports[namespace], + verbose_mode=verbose_mode, + ) + + for interface in model_runtime.main_model.ModuleInterfaces: + import_datatype_namespaces = _get_used_namespaces_by_interface(interface) + + generator.generate_to_file( + FileHelper("protobuf_interface_" + interface.Namespace.replace("::", "_") + "_" + interface.Name, "", True), + ".proto", + "vaf_protobuf/interface_proto.jinja", + str=str, + interface=interface, + package="interface." + interface.Namespace.replace("::", ".") + "." + interface.Name, + len=len, + data_type_to_proto_type=data_type_to_proto_type, + imports=import_datatype_namespaces, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "vaf_protobuf/protobuf_cmake.jinja", + target_name="vaf_protobuf", + libraries=[ + "protobuf::protobuf", + ], + verbose_mode=verbose_mode, + ) + + +def _get_impl_type_include(data: vafmodel.ModelDataType) -> str: + return '#include "' + data.Namespace.replace("::", "/") + "/impl_type_" + data.Name.lower() + '.h"' + + +def _get_array_vector_type_ref_includes(data: vafmodel.Array | vafmodel.Vector | vafmodel.TypeRef) -> List[str]: + includes: List[str] = [_get_impl_type_include(data)] + if not is_data_type_base_type(data.TypeRef.Name, data.TypeRef.Namespace) and not is_data_type_cstdint_type( + data.TypeRef.Name, data.TypeRef.Namespace + ): + includes.append( + '#include "' + data.TypeRef.Namespace.replace("::", "/") + "/impl_type_" + data.TypeRef.Name.lower() + '.h"' + ) + if not data.Namespace == data.TypeRef.Namespace: + includes.append( + '#include "protobuf/' + data.TypeRef.Namespace.replace("::", "/") + '/protobuf_transformer.h"' + ) + includes.append('#include "protobuf_' + data.TypeRef.Namespace.replace("::", "_") + '.pb.h"') + + return includes + + +def _get_struct_includes(data: vafmodel.Struct) -> List[str]: + includes: List[str] = [_get_impl_type_include(data)] + for sub_element in data.SubElements: + if not is_data_type_base_type( + sub_element.TypeRef.Name, sub_element.TypeRef.Namespace + ) and not is_data_type_cstdint_type(sub_element.TypeRef.Name, sub_element.TypeRef.Namespace): + includes.append( + '#include "' + + sub_element.TypeRef.Namespace.replace("::", "/") + + "/impl_type_" + + sub_element.TypeRef.Name.lower() + + '.h"' + ) + if not data.Namespace == sub_element.TypeRef.Namespace: + includes.append( + '#include "protobuf/' + + sub_element.TypeRef.Namespace.replace("::", "/") + + '/protobuf_transformer.h"' + ) + includes.append('#include "protobuf_' + sub_element.TypeRef.Namespace.replace("::", "_") + '.pb.h"') + + return includes + + +def _get_map_includes(data: vafmodel.Map) -> List[str]: + includes: List[str] = [_get_impl_type_include(data)] + + for map_attr in ["MapKeyTypeRef", "MapValueTypeRef"]: + map_type_ref = getattr(data, map_attr) + if not is_data_type_base_type(map_type_ref.Name, map_type_ref.Namespace) and not is_data_type_cstdint_type( + map_type_ref.Name, map_type_ref.Namespace + ): + includes.append( + '#include "' + + map_type_ref.Namespace.replace("::", "/") + + "/impl_type_" + + map_type_ref.Name.lower() + + '.h"' + ) + if not data.Namespace == map_type_ref.Namespace: + includes.append( + '#include "protobuf/' + map_type_ref.Namespace.replace("::", "/") + '/protobuf_transformer.h"' + ) + includes.append('#include "protobuf_' + map_type_ref.Namespace.replace("::", "_") + '.pb.h"') + + return includes + + +# pylint:disable=too-many-locals +# pylint:disable=too-many-branches +# pylint:disable=too-many-statements +def _generate_transfomer_files( + model_runtime: ModelRuntime, + output_path: Path, + generator: Generator, + verbose_mode: bool = False, +) -> None: + generator.set_base_directory(output_path) + + for namespace, data in model_runtime.element_by_namespace.items(): + if not namespace: + raise ValueError("Input json contains 'DataTypeDefinition' with empty namespace ") + + includes: List[str] = [ + '#include "protobuf_' + namespace.replace("::", "_") + '.pb.h"', + "#include <cstdlib>", + "#include <iostream>", + ] + for vector_array_typeref in ( + list(data.get("Arrays", {}).values()) + + list(data.get("Vectors", {}).values()) + + list(data.get("TypeRefs", {}).values()) + ): + if isinstance(vector_array_typeref, (vafmodel.Array, vafmodel.Vector, vafmodel.TypeRef)): + includes += _get_array_vector_type_ref_includes(vector_array_typeref) + for map_entry in data.get("Maps", {}).values(): + if isinstance(map_entry, vafmodel.Map): + includes += _get_map_includes(map_entry) + for string in data.get("Strings", {}).values(): + if isinstance(string, vafmodel.String): + includes += _get_impl_type_include(string) + for enum in data.get("Enums:", {}).values(): + if isinstance(enum, vafmodel.VafEnum): + includes += _get_impl_type_include(enum) + for struct in data.get("Structs", {}).values(): + if isinstance(struct, vafmodel.Struct): + includes += _get_struct_includes(struct) + + includes = list(set(includes)) + + generator.generate_to_file( + FileHelper("protobuf_transformer", "protobuf::" + namespace, False), + ".h", + "vaf_protobuf/data_type_transformer.jinja", + includes=includes, + namespace=namespace, + proto_namespace=namespace.replace("::", "_"), + include_namespace=namespace.replace("::", "/"), + namespace_data=data, + data_type_to_proto_type=data_type_to_proto_type, + is_data_type_base_type=is_data_type_base_type, + is_data_type_cstdint_type=is_data_type_cstdint_type, + verbose_mode=verbose_mode, + ) + + for interface in model_runtime.main_model.ModuleInterfaces: + includes = [] + import_datatype_namespaces = _get_used_namespaces_by_interface(interface) + + operation_with_out_parameters: List[vafmodel.Operation] = [] + for o in interface.Operations: + out_parameters: List[vafmodel.Parameter] = [] + for p in o.Parameters: + if p.Direction is not vafmodel.ParameterDirection.IN: + out_parameters.append(p) + + if len(out_parameters) > 0: + operation_with_out_parameters.append(o) + + out_parameter_type_namespace: str = interface.Namespace + if interface.OperationOutputNamespace is not None: + out_parameter_type_namespace = interface.OperationOutputNamespace + + generator.generate_to_file( + FileHelper( + "protobuf_transformer", "protobuf::interface::" + interface.Namespace + "::" + interface.Name, False + ), + ".h", + "vaf_protobuf/interface_transformer.jinja", + interface=interface, + out_parameter_type_namespace=out_parameter_type_namespace, + operation_with_out_parameters=operation_with_out_parameters, + data_type_to_proto_type=data_type_to_proto_type, + generate_types=False, + imports=import_datatype_namespaces, + is_data_type_base_type=is_data_type_base_type, + is_data_type_cstdint_type=is_data_type_cstdint_type, + get_operation_parameter_list_with_in=_get_operation_parameter_list_with_in, + get_operation_parameter_list_with_out=_get_operation_parameter_list_with_out, + add_double_colon=_add_double_colon, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_interface_library.jinja", + target_name="vaf_protobuf_transformer", + libraries=["vaf_module_interfaces"], + verbose_mode=verbose_mode, + ) + + +# pylint: disable=duplicate-code +def generate(model_runtime: ModelRuntime, output_dir: Path, verbose_mode: bool = False) -> None: + """Generates the middleware wrappers for protobuf + + Args: + model_runtime (ModelRuntime): The main model + output_dir (Path): The output path + verbose_mode: flag to enable verbose_mode mode + """ + output_path = output_dir / "src-gen/libs/protobuf_serdes" + generator = Generator() + + subdirs: List[str] = [] + subdirs.append("proto") + subdirs.append("transformer") + generator.set_base_directory(output_path) + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs, + verbose_mode=verbose_mode, + ) + + output_path = output_dir / "src-gen/libs/protobuf_serdes/proto" + _generate_proto_files(model_runtime, output_path, generator, verbose_mode=verbose_mode) + output_path = output_dir / "src-gen/libs/protobuf_serdes/transformer" + _generate_transfomer_files(model_runtime, output_path, generator, verbose_mode=verbose_mode) diff --git a/VAF/src/vaf/vafgeneration/vaf_silkit.py b/VAF/src/vaf/vafgeneration/vaf_silkit.py new file mode 100644 index 0000000..3ea2d71 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_silkit.py @@ -0,0 +1,244 @@ +"""Generator library for SILKIT communication modules.""" +# pylint: disable=duplicate-code + +from pathlib import Path + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_snake_case + +from .generation import ( + FileHelper, + Generator, + has_exactly_one_output_parameter, + is_data_type_base_type, + is_data_type_cstdint_type, + is_out_parameter, +) + + +# pylint: disable=too-many-branches +# pylint: disable=too-many-nested-blocks +def get_data_type_definition_of_parameter(data_type: vafmodel.DataType, model: vafmodel.MainModel) -> str: + """Get type definition of a DataType + + Args: + data_type (vafmodel.DataType): The data type + model (vafmodel.MainModel): The model + + Returns: + str: type def as string + """ + result = "NOT_FOUND" + if is_data_type_base_type(data_type.Name, data_type.Namespace) or is_data_type_cstdint_type( + data_type.Name, data_type.Namespace + ): + match data_type.Name: + case "uint8_t": + result = "uint32" + case "uint16_t": + result = "uint32" + case "uint32_t": + result = "uint32" + case "uint64_t": + result = "uint64" + case "int8_t": + result = "int32" + case "int16_t": + result = "int32" + case "int32_t": + result = "int32" + case "int64_t": + result = "int64" + case _: + result = "data_type.Name" + else: + if model.DataTypeDefinitions: + for datatype in vafmodel.data_types: + for data in getattr(model.DataTypeDefinitions, datatype): + if data_type.Name == data.Name and data_type.Namespace == data.Namespace: + result = datatype + break + return result + + +# pylint: enable=too-many-branches +# pylint: enable=too-many-nested-blocks + + +def _get_in_parameter_list_comma_separated(operation: vafmodel.Operation) -> str: + parameter_str = "" + is_first = True + for parameter in operation.Parameters: + if not is_out_parameter(parameter): + if is_first: + parameter_str = parameter.Name + is_first = False + else: + parameter_str = parameter_str + ", " + parameter.Name + return parameter_str + + +def _generate_provider_modules( + model: vafmodel.MainModel, output_path: Path, generator: Generator, verbose_mode: bool = False +) -> None: + subdirs: list[str] = [] + + for m in model.PlatformProviderModules: + if m.OriginalEcoSystem == vafmodel.OriginalEcoSystemEnum.SILKIT: + assert m.ConnectionPointRef + assert isinstance(m.ConnectionPointRef, vafmodel.SILKITConnectionPoint) + subdirs.append(to_snake_case(m.Name)) + generator.set_base_directory(output_path / "platform_provider_modules" / to_snake_case(m.Name)) + interface_file = FileHelper(m.ModuleInterfaceRef.Name + "Provider", m.ModuleInterfaceRef.Namespace) + module_file = FileHelper(m.Name, m.Namespace) + service_interface_name = m.ConnectionPointRef.ServiceInterfaceName + registry_uri = m.ConnectionPointRef.RegistryUri + + generator.generate_to_file( + module_file, + ".h", + "vaf_silkit/provider_module_h.jinja", + module=m, + interface_file=interface_file, + service_interface_name=service_interface_name, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + module_file, + ".cpp", + "vaf_silkit/provider_module_cpp.jinja", + module=m, + interface_file=interface_file, + service_interface_name=service_interface_name, + has_exactly_one_output_parameter=has_exactly_one_output_parameter, + get_data_type_definition_of_parameter=get_data_type_definition_of_parameter, + str=str, + model=model, + get_in_parameter_list_comma_separated=_get_in_parameter_list_comma_separated, + verbose_mode=verbose_mode, + registry_uri=registry_uri, + ) + + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "vaf_silkit/module_cmake.jinja", + target_name="vaf_" + to_snake_case(m.Name), + files=[module_file], + libraries=[ + "$<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core>", + "vaf_module_interfaces", + "vaf_module_interfaces", + "SilKit::SilKit", + "vaf_protobuf", + "vaf_protobuf_transformer", + ], + verbose_mode=verbose_mode, + ) + + generator.set_base_directory(output_path / "platform_provider_modules") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs, + verbose_mode=verbose_mode, + ) + + +def _generate_consumer_modules( + model: vafmodel.MainModel, output_path: Path, generator: Generator, verbose_mode: bool = False +) -> None: + subdirs: list[str] = [] + + for m in model.PlatformConsumerModules: + if m.OriginalEcoSystem == vafmodel.OriginalEcoSystemEnum.SILKIT: + assert m.ConnectionPointRef + assert isinstance(m.ConnectionPointRef, vafmodel.SILKITConnectionPoint) + subdirs.append(to_snake_case(m.Name)) + + generator.set_base_directory(output_path / "platform_consumer_modules" / to_snake_case(m.Name)) + + interface_file = FileHelper(m.ModuleInterfaceRef.Name + "Consumer", m.ModuleInterfaceRef.Namespace) + module_file = FileHelper(m.Name, m.Namespace) + service_interface_name = m.ConnectionPointRef.ServiceInterfaceName + registry_uri = m.ConnectionPointRef.RegistryUri + + generator.generate_to_file( + module_file, + ".h", + "vaf_silkit/consumer_module_h.jinja", + module=m, + interface_file=interface_file, + service_interface_name=service_interface_name, + verbose_mode=verbose_mode, + ) + + generator.generate_to_file( + module_file, + ".cpp", + "vaf_silkit/consumer_module_cpp.jinja", + module=m, + service_interface_name=service_interface_name, + has_exactly_one_output_parameter=has_exactly_one_output_parameter, + get_data_type_definition_of_parameter=get_data_type_definition_of_parameter, + str=str, + model=model, + get_in_parameter_list_comma_separated=_get_in_parameter_list_comma_separated, + verbose_mode=verbose_mode, + registry_uri=registry_uri, + ) + + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "vaf_silkit/module_cmake.jinja", + target_name="vaf_" + to_snake_case(m.Name), + files=[module_file], + libraries=[ + "$<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core>", + "vaf_module_interfaces", + "SilKit::SilKit", + "vaf_protobuf", + "vaf_protobuf_transformer", + ], + verbose_mode=verbose_mode, + ) + + generator.set_base_directory(output_path / "platform_consumer_modules") + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs, + verbose_mode=verbose_mode, + ) + + +def generate(model: vafmodel.MainModel, output_dir: Path, verbose_mode: bool = False) -> None: + """Generates the middleware wrappers for silkit + + Args: + model (vafmodel.MainModel): The main model + output_dir (Path): The output path + verbose_mode: flag to enable verbose_mode mode + """ + output_path = output_dir / "src-gen/libs/platform_silkit" + generator = Generator() + _generate_consumer_modules(model, output_path, generator, verbose_mode) + _generate_provider_modules(model, output_path, generator, verbose_mode) + + subdirs: list[str] = [] + if len(model.PlatformConsumerModules) > 0: + subdirs.append("platform_consumer_modules") + if len(model.PlatformProviderModules) > 0: + subdirs.append("platform_provider_modules") + generator.set_base_directory(output_path) + generator.generate_to_file( + FileHelper("CMakeLists", "", True), + ".txt", + "common/cmake_subdirs.jinja", + subdirs=subdirs, + verbose_mode=verbose_mode, + ) diff --git a/VAF/src/vaf/vafgeneration/vaf_std_data_types.py b/VAF/src/vaf/vafgeneration/vaf_std_data_types.py new file mode 100644 index 0000000..f8172e5 --- /dev/null +++ b/VAF/src/vaf/vafgeneration/vaf_std_data_types.py @@ -0,0 +1,118 @@ +"""Generator for VAF data types +Generates + - data_type.h + - CMakeLists.txt +""" + +from pathlib import Path + +from vaf import vafmodel +from vaf.vafpy.model_runtime import ModelRuntime + +from .generation import FileHelper, Generator, get_data_type_include + + +def _get_file_helper(data_type: vafmodel.DataType) -> FileHelper: + return FileHelper(data_type.Name, data_type.Namespace) + + +def _get_data_type_include_from_type_ref(type_ref: vafmodel.DataType) -> str: + return get_data_type_include(type_ref.Name, type_ref.Namespace) + + +# pylint: disable-next=too-many-locals,too-many-branches +def generate(model_runtime: ModelRuntime, output_dir: Path, verbose_mode: bool = False) -> None: + """Generate VAF data types + + Args: + model_runtime (ModelRuntime): The main model + output_dir (Path): The output directory + verbose_mode: flag to enable verbose_mode mode + """ + generator = Generator() + + generator.set_base_directory(output_dir / "src-gen/libs/data_types") + + for namespace, data in model_runtime.element_by_namespace.items(): + for array in data.get("Arrays", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + array.Name.lower(), namespace), + ".h", + "vaf_std_data_types/array_h.jinja", + array=array, + get_file_helper=_get_file_helper, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_enum in data.get("Enums", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + vaf_enum.Name.lower(), namespace), + ".h", + "vaf_std_data_types/enum_h.jinja", + vaf_enum=vaf_enum, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_map in data.get("Maps", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + vaf_map.Name.lower(), namespace), + ".h", + "vaf_std_data_types/map_h.jinja", + vaf_map=vaf_map, + get_file_helper=_get_file_helper, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_string in data.get("Strings", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + vaf_string.Name.lower(), namespace), + ".h", + "vaf_std_data_types/string_h.jinja", + vaf_string=vaf_string, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_struct in data.get("Structs", {}).values(): + assert isinstance(vaf_struct, vafmodel.Struct) + includes: list[str] = [] + for sub in vaf_struct.SubElements: + includes.append(get_data_type_include(sub.TypeRef.Name, sub.TypeRef.Namespace)) + includes = list(set(includes)) + if "" in includes: + includes.remove("") + generator.generate_to_file( + FileHelper("impl_type_" + vaf_struct.Name.lower(), namespace), + ".h", + "vaf_std_data_types/struct_h.jinja", + vaf_struct=vaf_struct, + get_file_helper=_get_file_helper, + includes=includes, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_type_ref in data.get("TypeRefs", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + vaf_type_ref.Name.lower(), namespace), + ".h", + "vaf_std_data_types/type_ref_h.jinja", + vaf_type_ref=vaf_type_ref, + get_file_helper=_get_file_helper, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) + + for vaf_vector in data.get("Vectors", {}).values(): + generator.generate_to_file( + FileHelper("impl_type_" + vaf_vector.Name.lower(), namespace), + ".h", + "vaf_std_data_types/vector_h.jinja", + vaf_vector=vaf_vector, + get_file_helper=_get_file_helper, + get_data_type_include_from_type_ref=_get_data_type_include_from_type_ref, + verbose_mode=verbose_mode, + ) diff --git a/VAF/src/vaf/vafmodel/__init__.py b/VAF/src/vaf/vafmodel/__init__.py new file mode 100644 index 0000000..aa5f501 --- /dev/null +++ b/VAF/src/vaf/vafmodel/__init__.py @@ -0,0 +1,8 @@ +# ruff: noqa: F401 +"""Initialize the module. + +Could be used to define the public interface of the module. +""" + +# Import modules and objects that belong to the public interface # pylint: disable=W0511 +from .vafmodel import * # NOQA diff --git a/VAF/src/vaf/vafmodel/vafmodel.py b/VAF/src/vaf/vafmodel/vafmodel.py new file mode 100644 index 0000000..40c1df2 --- /dev/null +++ b/VAF/src/vaf/vafmodel/vafmodel.py @@ -0,0 +1,733 @@ +"""Base data model library of Vehicle Application Framework""" # pylint: disable=too-many-lines + +import json +from enum import Enum +from pathlib import Path +from typing import Optional + +from pydantic import BaseModel, Field, ValidationInfo, WithJsonSchema, field_validator, model_validator +from pydantic.config import ConfigDict +from pydantic.functional_serializers import PlainSerializer +from typing_extensions import Annotated, Self + +# pylint: disable=missing-class-docstring + + +class VafBaseModel(BaseModel): + """Base model calls to propagate common model config""" + + model_config = ConfigDict(extra="forbid") + + +class ModelReferenceError(Exception): + """Error for invalid references""" + + def __init__(self, msg: str) -> None: + super().__init__(msg) + + +class DataType(VafBaseModel): + Name: str + Namespace: str + + +def serialize_data_type_ref(m: DataType) -> str: + """Serializes a DataType reference + + Args: + m (DataType): The DataType + + Returns: + str: The DataType reference + """ + return m.Namespace + "::" + m.Name if len(m.Namespace) != 0 else m.Name + + +DataTypeRef = Annotated[ + DataType, + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_data_type_ref, return_type=str), +] + + +base_types = [ + "int8_t", + "int16_t", + "int32_t", + "int64_t", + "uint8_t", + "uint16_t", + "uint32_t", + "uint64_t", + "float", + "double", + "bool", +] + + +data_types = [ + "Strings", + "Enums", + "Arrays", + "Vectors", + "Maps", + "Structs", + "TypeRefs", +] + + +def validate_type_ref(raw: str | DataType, info: ValidationInfo) -> DataType: + """Validates a data type reference. + + Args: + raw (str): The data type reference. + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + str: The reference unmodified. + """ + if not isinstance(raw, str): + return raw + splitted = raw.split("::") + name = splitted[-1] + namespace = "" + if len(splitted) > 1: + namespace = "::".join(splitted[0 : len(splitted) - 1]) + + if (len(namespace) == 0 or namespace == "std") and name in base_types: + return DataType(Name=name, Namespace=namespace) + + assert isinstance(info.context, dict) + data_type_definition = info.context["DataTypeDefinitions"] + for data_type in data_types: + if data_type in data_type_definition and data_type_definition[data_type] is not None: + for element in data_type_definition[data_type]: + if element["Name"] == name: + return DataType(Name=name, Namespace=namespace) + + raise ModelReferenceError("Reference not found: " + raw) + + +###################### model ###################### +class BaseType(str, Enum): + """Enum of all C++ base types""" + + INT8_T = "int8_t" + INT16_T = "int16_t" + INT32_T = "int32_t" + INT64_T = "int64_t" + UINT8_T = "uint8_t" + UINT16_T = "uint16_t" + UINT32_T = "uint32_t" + UINT64_T = "uint64_t" + FLOAT = "float" + DOUBLE = "double" + BOOL = "bool" + + +class OriginalEcoSystemEnum(str, Enum): + SILKIT = "SILKIT" + + +class String(DataType): + pass + + +class EnumLiteral(VafBaseModel): + Label: str + Value: int + + +class VafEnum(DataType): + BaseType: Optional[DataTypeRef] = None + Literals: list[EnumLiteral] + _validate_BaseType = field_validator("BaseType", mode="before")(validate_type_ref) + + +class Array(DataType): + TypeRef: DataTypeRef + Size: int + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +class Map(DataType): + MapKeyTypeRef: DataTypeRef + MapValueTypeRef: DataTypeRef + _validate_MapKeyTypeRef = field_validator("MapKeyTypeRef", mode="before")(validate_type_ref) + _validate_MapValueTypeRef = field_validator("MapValueTypeRef", mode="before")(validate_type_ref) + + +class TypeRef(DataType): + TypeRef: DataTypeRef + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +class SubElement(VafBaseModel): + Name: str + TypeRef: DataTypeRef + Min: Optional[float] = None + Max: Optional[float] = None + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +class Struct(DataType): + Name: str + SubElements: list[SubElement] + + +class Vector(DataType): + Name: str + TypeRef: DataTypeRef + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +ModelDataType = Array | VafEnum | Map | String | Struct | TypeRef | Vector + + +class DataTypeDefinition(VafBaseModel): + Strings: list[String] = [] + Enums: list[VafEnum] = [] + Arrays: list[Array] = [] + Maps: list[Map] = [] + TypeRefs: list[TypeRef] = [] + Structs: list[Struct] = [] + Vectors: list[Vector] = [] + + def extend(self, new_data_type_def: Self) -> None: + """Function to extend DataTypeDefinition by further DataTypeDefinition + Args: + new_data_type_def: to be appended DataTypeDefinition + """ + + for data_type in data_types: + current_data = getattr(self, data_type) + new_data = getattr(new_data_type_def, data_type) + if getattr(new_data_type_def, data_type): + setattr(self, data_type, current_data + new_data) + + +class DataElement(VafBaseModel): + Name: str + TypeRef: DataTypeRef + InitialValue: Optional[str] = None + Min: Optional[float] = None + Max: Optional[float] = None + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +class ParameterDirection(str, Enum): + IN = "IN" + OUT = "OUT" + INOUT = "INOUT" + + +class Parameter(VafBaseModel): + Name: str + TypeRef: DataTypeRef + Direction: ParameterDirection + _validate_TypeRef = field_validator("TypeRef", mode="before")(validate_type_ref) + + +class Operation(VafBaseModel): + Name: str + Parameters: list[Parameter] = [] + + +class ModuleInterface(VafBaseModel): + Name: str + Namespace: str = Field( + description="The value of this Tag is applicable when the interface is used for \ + generation of code. For C++, this will be the namespace while for \ + Java this will be the package hierarchy. When generating the code \ + representing the interface, it should be placed in the namespace \ + given by this parameter. Format: xxx::yyy::zzz." + ) + OperationOutputNamespace: Optional[str] = None + DataElements: Annotated[ + list[DataElement], + Field( + description="This array contains the definition of the data elements that \ + are available for the users of the interface. The data element \ + could either represent a pure data area (attribute/property/field \ + as in OO terminology) or it can correspond to an event occurring \ + because of some specific activity inside the module providing the interface." + ), + ] = [] + Operations: Annotated[ + list[Operation], + Field( + description="This array contains the definition of the operations that \ + are available for the users of the interface." + ), + ] = [] + + def __hash__(self) -> int: + return hash(repr(self)) + + +def serialize_module_interface_ref(m: ModuleInterface) -> str: + """Serializes a ModuleInterface reference + + Args: + m (ModuleInterface): The ModuleInterface + + Returns: + str: The ModuleInterface reference + """ + return m.Namespace + "::" + m.Name + + +ModuleInterfaceRefType = Annotated[ + ModuleInterface, + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_module_interface_ref, return_type=str), +] + + +def resolve_module_interface_ref(raw: str | ModuleInterface, info: ValidationInfo) -> ModuleInterface: + """Resolves a module interface reference and returns it. + + Args: + raw (str | ModuleInterface): A module interface reference or a module interface + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + ModuleInterface: The module interface. + """ + if isinstance(raw, str): + assert isinstance(info.context, dict) + for m in info.context["ModuleInterfaces"]: + if m["Namespace"] + "::" + m["Name"] == raw: + return ModuleInterface.model_validate(m, context=info.context) + raise ModelReferenceError("Reference not found: " + raw) + return raw + + +class DataElementRef(VafBaseModel): + DataElement: DataElement + ModuleInterface: ModuleInterface + + +def serialize_data_element_ref(d: DataElementRef) -> str: + """Serializes a DataElement reference + + Args: + d (DataElement): The DataElement + + Returns: + str: The DataElement reference + """ + return d.ModuleInterface.Namespace + "::" + d.ModuleInterface.Name + "::" + d.DataElement.Name + + +DataElementRefType = Annotated[ + DataElementRef, + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_data_element_ref, return_type=str), +] + + +def resolve_data_element_ref(raw: str | DataElementRef, info: ValidationInfo) -> DataElementRef: + """Resolves a data element reference and returns it. + + Args: + raw (str | DataElementRef): A data element reference or a data element + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + DataElementRef: The data element reference. + """ + if isinstance(raw, str): + assert isinstance(info.context, dict) + for m in info.context["ModuleInterfaces"]: + if m["Namespace"] + "::" + m["Name"] == "::".join(raw.split("::")[:-1]): + for d in m["DataElements"]: + if d["Name"] == raw.split("::")[-1]: + de = DataElement.model_validate(d, context=info.context) + mi = ModuleInterface.model_validate(m, context=info.context) + return DataElementRef(DataElement=de, ModuleInterface=mi) + raise ModelReferenceError("Reference not found: " + raw) + return raw + + +class OperationRef(VafBaseModel): + Operation: Operation + ModuleInterface: ModuleInterface + + +def serialize_operation_ref(o: OperationRef) -> str: + """Serializes a Operation reference + + Args: + o (Operation): The Operation + + Returns: + str: The Operation reference + """ + return o.ModuleInterface.Namespace + "::" + o.ModuleInterface.Name + "::" + o.Operation.Name + + +OperationRefType = Annotated[ + OperationRef, + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_operation_ref, return_type=str), +] + + +def resolve_operation_ref(raw: str | OperationRef, info: ValidationInfo) -> OperationRef: + """Resolves a operation reference and returns it. + + Args: + raw (str | OperationRef): A operation reference or a operation + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + OperationRef: The OperationRef. + """ + if isinstance(raw, str): + assert isinstance(info.context, dict) + for m in info.context["ModuleInterfaces"]: + if m["Namespace"] + "::" + m["Name"] == "::".join(raw.split("::")[:-1]): + for o in m["Operations"]: + if o["Name"] == raw.split("::")[-1]: + o = Operation.model_validate(o, context=info.context) + mi = ModuleInterface.model_validate(m, context=info.context) + return OperationRef(Operation=o, ModuleInterface=mi) + raise ModelReferenceError("Reference not found: " + raw) + return raw + + +class ApplicationModuleProvidedInterface(VafBaseModel): + InstanceName: str + ModuleInterfaceRef: ModuleInterfaceRefType + _resolve_ModuleInterfaceRef = field_validator("ModuleInterfaceRef", mode="before")(resolve_module_interface_ref) + + +class ApplicationModuleConsumedInterface(VafBaseModel): + InstanceName: str + ModuleInterfaceRef: ModuleInterfaceRefType + IsOptional: bool = False + _resolve_ModuleInterfaceRef = field_validator("ModuleInterfaceRef", mode="before")(resolve_module_interface_ref) + + +class SILKITConnectionPoint(VafBaseModel): + Name: str + ServiceInterfaceName: str = Field( + description="The concept of a service is not defined in SILKIT. This means that we need \ + to create a service based on the artifacts that are available in SILIT. \ + This tag defines the name of the service interface that is used by the service." + ) + RegistryUri: str = Field( + description="The registry's URI specifies where the registry can be reached. It defaults to \ + silkit://localhost:8500, that is, the registry is reachable via TCP/IP on the 'localhost' on port 8500." + ) + + +class SILKITAdditionalConfigurationType(VafBaseModel): + ConnectionPoints: list[SILKITConnectionPoint] = Field( + description="A connection point in SILKIT is a unique name mapping." + ) + + +def serialize_connection_point_ref(m: SILKITConnectionPoint) -> str: + """Serializes a ConnectionPoint reference + + Args: + m (SILKITConnectionPoint): The ConnectionPoint + + Returns: + str: The ConnectionPoint reference + """ + return m.Name + + +ConnectionPointRefType = Annotated[ + Optional[SILKITConnectionPoint], + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_connection_point_ref, return_type=str), +] + + +def resolve_connection_point_ref( + raw: str | None | SILKITConnectionPoint, info: ValidationInfo +) -> SILKITConnectionPoint | None: + """Resolves a ConnectionPoint reference + + Args: + raw (str | None | SILKITConnectionPoint): A ConnectionPoint + reference or a ConnectionPoint + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + SILKITConnectionPoint | None: The ConnectionPoint or None if the + input was None + """ + if raw is None: + return raw + if isinstance(raw, str): + assert isinstance(info.context, dict) + if "SILKITAdditionalConfiguration" in info.context and info.context["SILKITAdditionalConfiguration"]: + for m in info.context["SILKITAdditionalConfiguration"]["ConnectionPoints"]: + if m["Name"] == raw: + return SILKITConnectionPoint.model_validate(m, context=info.context) + raise ModelReferenceError("Reference not found: " + raw) + + return raw + + +class PlatformModule(VafBaseModel): + Name: str + Namespace: str + ModuleInterfaceRef: ModuleInterfaceRefType + OriginalEcoSystem: Optional[OriginalEcoSystemEnum] = None + ConnectionPointRef: Optional[ConnectionPointRefType] = None + _resolve_ModuleInterfaceRef = field_validator("ModuleInterfaceRef", mode="before")(resolve_module_interface_ref) + _resolve_ConnectionPointRef = field_validator("ConnectionPointRef", mode="before")(resolve_connection_point_ref) + + @model_validator(mode="after") + def check_platform_module(self) -> Self: + """Checks the platform module for validity + + Raises: + ValueError: Raised if the connection point reference is of unexpected type + + Returns: + The Platform Module + """ + expected = "Undefined" + if self.OriginalEcoSystem == OriginalEcoSystemEnum.SILKIT: + expected = "SILKITConnectionPoint" + if isinstance(self.ConnectionPointRef, SILKITConnectionPoint): + return self + if self.OriginalEcoSystem is None: + expected = "None" + if self.ConnectionPointRef is None: + return self + raise ValueError( + "Invalid connection point reference set: " + str(self.ConnectionPointRef) + " expected: " + str(expected) + ) + + +class ImplementationProperty(VafBaseModel): + GenerateUnitTestStubs: Optional[bool] = None + InstallationPath: Optional[str] = None + + +class ApplicationModuleTasks(VafBaseModel): + Name: str + Period: str + PreferredOffset: Optional[int] = None + RunAfter: list[str] = [] + + +class ApplicationModule(VafBaseModel): + Name: str + Namespace: str + ConsumedInterfaces: list[ApplicationModuleConsumedInterface] = Field( + description="This array contains the definition of the interfaces \ + that is used by the module and the modules providing the implementation of the interface." + ) + ProvidedInterfaces: list[ApplicationModuleProvidedInterface] = Field( + description="This array defines the interfaces which are provided \ + by the Application Module. An application can provide 0..N interfaces." + ) + ImplementationProperties: Annotated[ + Optional[ImplementationProperty], + Field(description="Includes implementation properties for the Application Module."), + ] = None + Tasks: list[ApplicationModuleTasks] = [] + + +def serialize_application_module_ref(m: ApplicationModule) -> str: + """Serializes a ApplicationModule reference + + Args: + m (ApplicationModule): The ApplicationModule + + Returns: + str: The ApplicationModule reference + """ + return m.Namespace + "::" + m.Name + + +ApplicationModuleRefType = Annotated[ + ApplicationModule, + WithJsonSchema( + {"type": "string"}, + ), + PlainSerializer(serialize_application_module_ref, return_type=str), +] + + +def resolve_application_module_ref(raw: str | ApplicationModule, info: ValidationInfo) -> ApplicationModule: + """Resolves a ApplicationModule reference + + Args: + raw (str): The ApplicationModule reference + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + ApplicationModule: The ApplicationModule + """ + if isinstance(raw, str): + assert isinstance(info.context, dict) + for m in info.context["ApplicationModules"]: + if m["Namespace"] + "::" + m["Name"] == raw: + return ApplicationModule.model_validate(m, context=info.context) + raise ModelReferenceError("Reference not found: " + raw) + return raw + + +def serialize_platform_module_ref(m: PlatformModule) -> str: + """Serializes a PlatformModule reference + + Args: + m (PlatformModule): The PlatformModule + + Returns: + str: The PlatformModule reference + """ + return m.Namespace + "::" + m.Name + + +PlatformModuleRefType = Annotated[ + PlatformModule, + WithJsonSchema({"type": "string"}), + PlainSerializer(serialize_platform_module_ref, return_type=str), +] + + +def resolve_platform_module_ref(raw: str | PlatformModule, info: ValidationInfo) -> PlatformModule: + """Resolves a PlatformModule reference + + Args: + raw (str): The PlatformModule reference + info (ValidationInfo): The validation info. + + Raises: + ModelReferenceError: If the reference was not found. + + Returns: + PlatformModule: The PlatformModule + """ + if isinstance(raw, str): + assert isinstance(info.context, dict) + for m in info.context.get("PlatformConsumerModules", []) + info.context.get("PlatformProviderModules", []): + if m["Namespace"] + "::" + m["Name"] == raw: + return PlatformModule.model_validate(m, context=info.context) + # TODO(virmlj) how is checking if the the reference is in the same executable? + # eventually consolidate together with PlatformModule + for e in info.context["Executables"]: + if "InternalCommunicationModules" in e: + for m in e["InternalCommunicationModules"]: + if m["Namespace"] + "::" + m["Name"] == raw: + return PlatformModule.model_validate(m, context=info.context) + raise ModelReferenceError("Reference not found: " + raw) + return raw + + +class InterfaceInstanceToModuleMapping(VafBaseModel): + InstanceName: str + ModuleRef: PlatformModuleRefType + _resolve_ModuleRef = field_validator("ModuleRef", mode="before")(resolve_platform_module_ref) + + +class ExecutableTaskMapping(VafBaseModel): + TaskName: str + Offset: Optional[int] = None + Budget: Optional[str] = None + + +class ExecutableApplicationModuleMapping(VafBaseModel): + ApplicationModuleRef: ApplicationModuleRefType + InterfaceInstanceToModuleMappings: list[InterfaceInstanceToModuleMapping] + TaskMapping: list[ExecutableTaskMapping] = [] + _resolve_ApplicationModuleRef = field_validator("ApplicationModuleRef", mode="before")( + resolve_application_module_ref + ) + + +class Executable(VafBaseModel): + Name: str + ExecutorPeriod: str + InternalCommunicationModules: list[PlatformModule] = [] + ApplicationModules: list[ExecutableApplicationModuleMapping] + + +# all model element that have namespace & name +ModelElement = ModelDataType | ModuleInterface | PlatformModule | ApplicationModule + + +class MainModel(VafBaseModel): + model_config = ConfigDict( + title="VAF schema", + arbitrary_types_allowed=True, + extra="forbid", + json_schema_extra={"version": "v0.6.0"}, + ) + + schema_reference: Annotated[Optional[str], Field(alias="$schema")] = None + BaseTypes: list[BaseType] = [] + DataTypeDefinitions: DataTypeDefinition = DataTypeDefinition() + ModuleInterfaces: list[ModuleInterface] = [] + ApplicationModules: list[ApplicationModule] = [] + PlatformConsumerModules: list[PlatformModule] = [] + PlatformProviderModules: list[PlatformModule] = [] + Executables: list[Executable] = [] + SILKITAdditionalConfiguration: Annotated[ + Optional[SILKITAdditionalConfigurationType], + Field( + description="This information is used stage 2 of the Application Framework \ + generation. For SIL Kit, we will use the artifacts defined \ + to generate unique interface names" + ), + ] = None + + +###################### functions ###################### +def generate_json_schema(path: str) -> None: + """Generates the JSON schema from the data model. + + Args: + path (str): Path where the schema will be stored. + """ + main_model_schema = MainModel.model_json_schema() + with open(path, "w", encoding="utf-8") as f: + json.dump(main_model_schema, f, indent=2) + + +def load_json(path: str | Path) -> MainModel: + """Loads a model from JSON. + + Args: + path (str | Path): Path to the JSON file. + + Returns: + MainModel: The imported model. + """ + with open(path, encoding="utf-8") as fh: + raw_model = json.load(fh) + + return MainModel.model_validate(raw_model, context=raw_model) + + +if __name__ == "__main__": + generate_json_schema("./vaf_schema.json") diff --git a/VAF/src/vaf/vafpy/__init__.py b/VAF/src/vaf/vafpy/__init__.py new file mode 100644 index 0000000..1a414db --- /dev/null +++ b/VAF/src/vaf/vafpy/__init__.py @@ -0,0 +1,44 @@ +# ruff: noqa: F401 +"""Initialize the module. + +Could be used to define the public interface of the module. +""" + +# Import modules and objects that belong to the public interface +from .core import BaseTypes +from .datatypes import Array, Enum, Map, String, Struct, TypeRef, Vector +from .elements import ( + ApplicationModule, + ModuleInterface, + PlatformConsumerModule, + PlatformProviderModule, +) +from .executable import Executable +from .runtime import import_model, save_main_model, save_part_of_main_model +from .task import Task + +__all__ = [ + # datatypes + "Array", + "Enum", + "Map", + "String", + "Struct", + "TypeRef", + "Vector", + # core + "BaseTypes", + # executable + "Executable", + # elements + "ApplicationModule", + "ModuleInterface", + "PlatformConsumerModule", + "PlatformProviderModule", + # runtime + "save_main_model", + "save_part_of_main_model", + "import_model", + # task + "Task", +] diff --git a/VAF/src/vaf/vafpy/core.py b/VAF/src/vaf/vafpy/core.py new file mode 100644 index 0000000..b25a97f --- /dev/null +++ b/VAF/src/vaf/vafpy/core.py @@ -0,0 +1,58 @@ +"""Module providing config as code for VAF projects.""" + +from vaf import vafmodel + +# pylint: disable=too-few-public-methods + + +class ModelError(Exception): + """Exception class for modeling errors""" + + def __init__(self, message: str) -> None: + super().__init__(message) + + +class BaseTypesWrapper: + """Wrapper for std types""" + + def _get_type_ref(self) -> vafmodel.DataTypeRef: + """Method to get typeref from current instance + Returns: + Respective string typeref of current instance + """ + return vafmodel.DataType(Name=self.Name, Namespace=self.Namespace) + + def __init__(self, name: str, namespace: str = "") -> None: + self.Name = name + self.Namespace = namespace + self.TypeRef = vafmodel.DataType(Name=name, Namespace=namespace) + + +class BaseTypes: + """All c++ std base types""" + + INT8_T = BaseTypesWrapper("int8_t") + INT16_T = BaseTypesWrapper("int16_t") + INT32_T = BaseTypesWrapper("int32_t") + INT64_T = BaseTypesWrapper("int64_t") + UINT8_T = BaseTypesWrapper("uint8_t") + UINT16_T = BaseTypesWrapper("uint16_t") + UINT32_T = BaseTypesWrapper("uint32_t") + UINT64_T = BaseTypesWrapper("uint64_t") + FLOAT = BaseTypesWrapper("float", "") + DOUBLE = BaseTypesWrapper("double", "") + BOOL = BaseTypesWrapper("bool", "") + STRING = BaseTypesWrapper("string", "vaf") + + +# pylint: disable=too-few-public-methods +# pylint: disable=super-init-not-called +class VafpyAbstractBase(vafmodel.DataType, BaseTypesWrapper): + """Base Abstract class for VafpyObject""" + + def __init__(self) -> None: + """ + Raises: + ModelError: if initialized + """ + raise ModelError("Dude, who told you to construct this forbidden class?") diff --git a/VAF/src/vaf/vafpy/datatypes.py b/VAF/src/vaf/vafpy/datatypes.py new file mode 100644 index 0000000..16e3fb2 --- /dev/null +++ b/VAF/src/vaf/vafpy/datatypes.py @@ -0,0 +1,202 @@ +"""Abstraction layer for the datatypes in Config as Code""" + +from typing import Any, List, Optional + +from typing_extensions import Self + +from vaf import vafmodel + +from .core import BaseTypes, BaseTypesWrapper, ModelError, VafpyAbstractBase +from .factory import VafpyAbstractElement + +# pylint: disable = too-few-public-methods +# pylint: disable = unused-private-member # Used via decorators +# pylint: disable = super-init-not-called # DUE to decorators' use +# pylint: disable = unused-argument # DUE to overload in decorator +# pylint: disable = protected-access +# mypy: disable-error-code="misc" + +VafpyDataTypeRef = VafpyAbstractBase | BaseTypesWrapper + + +class Enum(vafmodel.VafEnum, VafpyAbstractElement): + """The VAF::Enum datatype""" + + def __init__(self, name: str, namespace: str, literals: Optional[List[vafmodel.EnumLiteral]] = None) -> None: + literals = literals or [] + self._validate_literals(literals) # ↠Validate before anything else + self._build_instance(self, Name=name, Namespace=namespace, Literals=literals) + + def add_entry(self, label: str, value: int) -> None: + """Add an entry to the enum definition. + + Args: + label (str): The label of the enum entry + value (int): The value of the enum entry + + Raises: + ModelError: If entry labels are invalid or duplicated + """ + self._validate_entry(label, value) + + self.Literals.append(vafmodel.EnumLiteral(Label=label, Value=value)) + + def _validate_label(self, label: str) -> None: + """Validate label for no spaces. + + Args: + label (str): The label of the enum entry + + Raises: + ModelError: If entry label is invalid + """ + if " " in label: + raise ModelError(f"Enum - Label cannot contain spaces: '{label}'") + + def _validate_entry(self, label: str, value: int) -> None: + """Validate the enum entries. + + Args: + label (str): The label of the enum entry + value (int): The value of the enum entry + + Raises: + ModelError: If entry labels or values are invalid or duplicated + """ + self._validate_label(label) + + if any(literal.Label == label for literal in self.Literals): + raise ModelError(f"Enum - Duplicate label not allowed: '{label}'") + if any(literal.Value == value for literal in self.Literals): + raise ModelError(f"Enum - Duplicate value not allowed: {value}") + + def _validate_literals(self, literals: List[vafmodel.EnumLiteral]) -> None: + """Validate the list of the enum literals. + + Args: + literrals (List[vafmodel.EnumLiteral]): The list of the EnumLiterals. + + Raises: + ModelError: If entry labels or values are invalid or duplicated + """ + seen_labels = set() + seen_values = set() + + for literal in literals: + self._validate_label(literal.Label) + + if literal.Label in seen_labels: + raise ModelError(f"Enum - Duplicate label in constructor: '{literal.Label}'") + if literal.Value in seen_values: + raise ModelError(f"Enum - Duplicate value in constructor: '{literal.Value}'") + + seen_labels.add(literal.Label) + seen_values.add(literal.Value) + + +class Map(vafmodel.Map, VafpyAbstractElement): + """The VAF::Map datatype""" + + def __init__( + self, + name: str, + namespace: str, + key_type: VafpyDataTypeRef, + value_type: VafpyDataTypeRef, + ) -> None: + self._build_instance( + self, + Name=name, + Namespace=namespace, + MapKeyTypeRef=key_type._get_type_ref(), + MapValueTypeRef=value_type._get_type_ref(), + ) + + +class String(vafmodel.String, VafpyAbstractElement): + """The VAF::String datatype""" + + def __init__(self, name: str, namespace: str) -> None: + self._build_instance(self, Name=name, Namespace=namespace) + + +class Struct(vafmodel.Struct, VafpyAbstractElement): + """The VAF::Struct datatype""" + + def __init__(self, name: str, namespace: str, sub_elements: Optional[List[vafmodel.SubElement]] = None) -> None: + self._build_instance( + self, Name=name, Namespace=namespace, SubElements=sub_elements if sub_elements is not None else [] + ) + + def add_subelement(self, name: str, datatype: VafpyDataTypeRef) -> None: + """Add a subelement to the struct definition + + Args: + name (str): The name of the subelement + datatype (VafpyDataTypeRef): The type of the subelement + + Raises: + ModelError: If subelement names are duplicated + """ + if any(element.Name == name for element in self.SubElements): + raise ModelError(f"Struct - Duplicated subelement: {name}") + # borrow check typeref from VafpyAbstractDatatypeTyperef + VafpyAbstractDatatypeTyperef._check_typeref(datatype) + self.SubElements.append(vafmodel.SubElement(Name=name, TypeRef=datatype._get_type_ref())) + + +class VafpyAbstractDatatypeTyperef(VafpyAbstractElement): + """Generic Abstract type for Vafpy datatypes that have typeref""" + + @classmethod + def _check_typeref(cls, typeref: VafpyDataTypeRef) -> None: + """Method to checkf if typeref needs construction + Args: + typeref: typeref as cac object + """ + # construct typeref + if typeref == BaseTypes.STRING: + cls._construct_typeref_object(typeref, String) + + @classmethod + def _build_instance(cls, obj: Optional[Self] = None, **kwargs: Any) -> None: + # only for CaC: process given typeref + if not kwargs.get("imported", False): + assert isinstance(kwargs["TypeRef"], VafpyDataTypeRef) + # store CaC typeref + cac_typeref = kwargs["TypeRef"] + # convert typeref in kwargs to vafmodel typeref + kwargs["TypeRef"] = kwargs["TypeRef"]._get_type_ref() + # construct typeref if needed + cls._check_typeref(cac_typeref) + + # call parent build instance m + super()._build_instance(obj, **kwargs) + + +# pylint: disable = too-many-ancestors +class TypeRef(vafmodel.TypeRef, VafpyAbstractDatatypeTyperef): + """The VAF::TypeRef datatype""" + + def __init__(self, name: str, namespace: str, datatype: VafpyDataTypeRef) -> None: + self._build_instance(self, Name=name, Namespace=namespace, TypeRef=datatype) + + +class Vector(vafmodel.Vector, VafpyAbstractDatatypeTyperef): + """The VAF::Vector datatype""" + + def __init__( + self, + name: str, + namespace: str, + datatype: VafpyDataTypeRef, + ) -> None: + self._build_instance(self, Name=name, Namespace=namespace, TypeRef=datatype) + + +class Array(vafmodel.Array, VafpyAbstractDatatypeTyperef): + """The VAF::Array datatype""" + + # Array must have size compared to Vector + def __init__(self, name: str, namespace: str, datatype: VafpyDataTypeRef, size: int): + self._build_instance(self, Name=name, Namespace=namespace, TypeRef=datatype, Size=size) diff --git a/VAF/src/vaf/vafpy/elements.py b/VAF/src/vaf/vafpy/elements.py new file mode 100644 index 0000000..bf3a5d3 --- /dev/null +++ b/VAF/src/vaf/vafpy/elements.py @@ -0,0 +1,274 @@ +"""Abstraction layer for vafmodel.ModuleInterfaces in Config as Code""" + +from copy import deepcopy +from typing import Any, List, Optional + +from typing_extensions import Self + +from vaf import vafmodel +from vaf.cli_core.common.utils import create_name_namespace_full_name + +from .core import ModelError +from .datatypes import VafpyAbstractDatatypeTyperef, VafpyDataTypeRef +from .factory import VafpyAbstractElement +from .model_runtime import model_runtime +from .task import Task + +# pylint: disable = too-few-public-methods +# pylint: disable = unused-private-member # Used via decorators +# pylint: disable = super-init-not-called # DUE to decorators' use +# pylint: disable = unused-argument # DUE to overload in decorator +# pylint: disable = protected-access +# mypy: disable-error-code="misc" + +ElementType = vafmodel.ApplicationModule | vafmodel.PlatformModule + + +class ModuleInterface(vafmodel.ModuleInterface, VafpyAbstractElement): + """Represents a VAF module interface""" + + @classmethod + def _build_instance(cls, obj: Optional[Self] = None, **kwargs: Any) -> Optional[Self]: + """Method to build an vafpy module interface + Args: + obj: object to be built + kwargs: attributes of the object + """ + # call parent's build + obj = super()._build_instance(obj, **kwargs) + assert obj is not None + # append element name to internal interfaces + model_runtime.internal_interfaces.append(obj.Name) + + return obj + + def __init__(self, name: str, namespace: str, operation_output_namespace: Optional[str] = None) -> None: + self._build_instance(self, Name=name, Namespace=namespace, OperationOutputNamespace=operation_output_namespace) + + def add_data_element(self, name: str, datatype: VafpyDataTypeRef) -> None: + """Add a data element to the module interface + + Args: + name (str): Unique name for the data element + datatype (VafpyDataTypeRef): VAF Datatype of the element + + Raises: + ModelError: If a data element with the same name already exists. + """ + data_element_names = [da.Name for da in self.DataElements] + if name in data_element_names: + raise ModelError(f"Duplicated DataElement {name} for inter face {self.Namespace}:{self.Name}.") + + self.DataElements.append( + vafmodel.DataElement( + Name=name, + TypeRef=datatype._get_type_ref(), + ) + ) + + # borrow check typeref from VafpyAbstractDatatypeTyperef + VafpyAbstractDatatypeTyperef._check_typeref(datatype) + + model_runtime.used_module_interfaces[create_name_namespace_full_name(self.Name, self.Namespace)].append( + create_name_namespace_full_name(datatype.Name, datatype.Namespace) + ) + + def add_operation( + self, + name: str, + in_parameter: dict[str, VafpyDataTypeRef] | None = None, + out_parameter: dict[str, VafpyDataTypeRef] | None = None, + inout_parameter: dict[str, VafpyDataTypeRef] | None = None, + ) -> None: + """ + Add an operation to the module interface. + + Args: + name (str): Unique name for the operation. + in_parameter (dict[str, VafpyDataTypeRef], optional): Dictionary of input parameters. + Defaults to None. + out_parameter (dict[str, VafpyDataTypeRef], optional): Dictionary of output parameters. + Defaults to None. + inout_parameter (dict[str, VafpyDataTypeRef], optional): Dictionary of input/output + parameters. Defaults to None. + + Raises: + ModelError: If an operation with the same name already exists. + """ + # consolidate parameters + params: dict[vafmodel.ParameterDirection, dict[str, VafpyDataTypeRef]] = { + vafmodel.ParameterDirection.IN: in_parameter if in_parameter is not None else {}, + vafmodel.ParameterDirection.OUT: out_parameter if out_parameter is not None else {}, + vafmodel.ParameterDirection.INOUT: inout_parameter if inout_parameter is not None else {}, + } + + operation_names = [op.Name for op in self.Operations] + if name in operation_names: + raise ModelError(f"Duplicated operation {name} for interface {self.Namespace}:{self.Name}.") + + function_parameters: List[vafmodel.Parameter] = [] + + for param_direction, param_dict in params.items(): + for param_name, datatype in param_dict.items(): + function_parameters.append( + vafmodel.Parameter(Name=param_name, TypeRef=datatype._get_type_ref(), Direction=param_direction) + ) + # borrow check typeref from VafpyAbstractDatatypeTyperef + VafpyAbstractDatatypeTyperef._check_typeref(datatype) + + self.Operations.append(vafmodel.Operation(Name=name, Parameters=function_parameters)) + + +class ApplicationModule(vafmodel.ApplicationModule, VafpyAbstractElement): + """Represents a VAF application module""" + + # pylint: disable-next=too-many-positional-arguments,too-many-arguments + def __init__( + self, + name: str, + namespace: str, + consumed_interfaces: Optional[List[vafmodel.ApplicationModuleConsumedInterface]] = None, + provided_interfaces: Optional[List[vafmodel.ApplicationModuleProvidedInterface]] = None, + tasks: Optional[List[vafmodel.ApplicationModuleTasks]] = None, + ) -> None: + self._build_instance( + self, + Name=name, + Namespace=namespace, + ConsumedInterfaces=consumed_interfaces if consumed_interfaces is not None else [], + ProvidedInterfaces=provided_interfaces if provided_interfaces is not None else [], + ImplementationProperties=vafmodel.ImplementationProperty(GenerateUnitTestStubs=True), + Tasks=tasks if tasks is not None else [], + ) + + def __add_interface( + self, instance_name: str, interface: ModuleInterface, interface_type: str, is_optional: bool = False + ) -> None: + """Add a consumed interface to the AppModule + + Args: + instance_name (str): Unique name for the interface instance + interface (vafpy.ModuleInterface): The module interface to add + interface_type (str): consumed/provided + is_optional (bool): Wheter the interface is mandatory for the AppModule to start + + Raises: + ModelError: If a consumed interface with the same name already exists. + """ + vafmodel_interfaces = getattr(self, f"{interface_type.capitalize()}Interfaces") + assert isinstance(vafmodel_interfaces, List) + mi_names = [mi.InstanceName for mi in vafmodel_interfaces] + if instance_name in mi_names: + raise ModelError( + f"Duplicated {interface_type} interface {instance_name}for AppModule {self.Namespace}::{self.Name}." + ) + + vafmodel_interfaces.append( + # vafmodel.ApplicationModuleConsumedInterface or vafmodel.ApplicationModuleProvidedInterface + getattr(vafmodel, f"ApplicationModule{interface_type.capitalize()}Interface")( + InstanceName=instance_name, + ModuleInterfaceRef=interface, + # IsOptional is only available for Consumed + **({"IsOptional": is_optional} if interface_type == "consumed" else {}), + ) + ) + model_runtime.add_used_module_interfaces(interface) + + def add_consumed_interface(self, instance_name: str, interface: ModuleInterface, is_optional: bool = False) -> None: + """Add a consumed interface to the AppModule + + Args: + instance_name (str): Unique name for the interface instance + interface (vafpy.ModuleInterface): The module interface to add + is_optional (bool): Wheter the interface is mandatory for the AppModule to start + + Raises: + ModelError: If a consumed interface with the same name already exists. + """ + self.__add_interface(instance_name, interface, interface_type="consumed", is_optional=is_optional) + + def add_provided_interface(self, instance_name: str, interface: ModuleInterface) -> None: + """Add a provided interface to the app module + + Args: + instance_name (str): Unique name for the interface instance + interface (vafpy.ModuleInterface): The module interface to add + + Raises: + ModelError: If a provided interface with the same name already exists. + """ + self.__add_interface(instance_name, interface, interface_type="provided") + + def _get_task_ref(self, task: vafmodel.ApplicationModuleTasks | Task) -> vafmodel.ApplicationModuleTasks: + if isinstance(task, vafmodel.ApplicationModuleTasks): + return task + return task.model + + def add_task(self, task: vafmodel.ApplicationModuleTasks | Task) -> None: + """Add a task to the app module + + Args: + task (vafmodel.ApplicationModuleTasks | vafpy.Task): Task to add + + Raises: + ModelError: If a task with the same name already exists. + """ + task_names = [task.Name for task in self.Tasks] + task_ref = self._get_task_ref(task) + if task_ref.Name in task_names: + raise ModelError(f"Duplicated task {task_ref.Name} for AppModule {self.Namespace}::{self.Name}.") + + self.Tasks.append(task_ref) + + def add_task_chain( + self, + tasks: List[vafmodel.ApplicationModuleTasks | Task], + run_after: List[vafmodel.ApplicationModuleTasks | Task] | None = None, + increment_preferred_offset: bool = False, + ) -> None: + """ + Add multiple tasks with a strict execution order to the app module + + Args: + tasks (List[vafmodel.ApplicationModuleTasks | vafpy.Task]): Tasks to add + run_after (List[vafmodel.ApplicationModuleTasks | vafpy.Task]): Tasks that should run before this one + increment_preferred_offset (bool): Uses the preferred offset of the first task as base value and increments + it for every following task + + Raises: + ModelError: If a task with the same name already exists. + """ + task_names = [task.Name for task in self.Tasks] + last_name = None + current_offset = self._get_task_ref(tasks[0]).PreferredOffset or 0 + for task in tasks: + task_ref = self._get_task_ref(task) + if task_ref.Name in task_names: + raise ModelError(f"Duplicated task {task_ref.Name} for AppModule {self.Namespace}::{self.Name}.") + + run_after_ = task_ref.RunAfter + [self._get_task_ref(task_).Name for task_ in run_after or []] + if last_name: + run_after_.append(last_name) + + local_task = deepcopy(task_ref) + local_task.RunAfter = run_after_ + if increment_preferred_offset: + local_task.PreferredOffset = current_offset + self.Tasks.append(local_task) + + if increment_preferred_offset: + current_offset += 1 + last_name = task_ref.Name + task_names.append(task_ref.Name) + + +# pylint: disable = too-many-ancestors +class PlatformConsumerModule(vafmodel.PlatformModule, VafpyAbstractElement): + """Represents a VAF platform consumer module""" + + def __init__(self, name: str, namespace: str, module_interface: ModuleInterface) -> None: + self._build_instance(self, Name=name, Namespace=namespace, ModuleInterfaceRef=module_interface) + + +class PlatformProviderModule(PlatformConsumerModule): + """Represents a VAF platform provider module""" diff --git a/VAF/src/vaf/vafpy/executable.py b/VAF/src/vaf/vafpy/executable.py new file mode 100644 index 0000000..5d1e96a --- /dev/null +++ b/VAF/src/vaf/vafpy/executable.py @@ -0,0 +1,305 @@ +"""Executable integration calls and helper functions""" # pylint: disable=too-many-lines + +# pylint bug, see https://github.com/pylint-dev/pylint/issues/4899 and https://github.com/pylint-dev/pylint/issues/10087 +# marked with # pylint-bug (29.01.25, lwiesner) + +from datetime import timedelta + +from vaf import vafmodel + +from .core import ModelError +from .elements import ApplicationModule +from .model_runtime import model_runtime + + +class Executable(vafmodel.Executable): + """Represents a VAF executable""" + + def __init__(self, name: str, executor_period: timedelta | None = None) -> None: + """Initialize an Executable with an optional executor_period + + Args: + name (str): Executable name + executor_period (datetime.timedelta, optional): Executor period. Defaults to an ideal value calculated using + the tasks of all AppModules. + """ + period_str = f"{int(executor_period.total_seconds() * 1000)}ms" if executor_period else "Default" + + super().__init__(Name=name, ExecutorPeriod=period_str, ApplicationModules=[]) + + model_runtime.main_model.Executables.append(self) + + def set_executor_period(self, executor_period: timedelta) -> None: + """Method to set ExecutorPeriod + Args: + executor_period (datetime.timedelta): Executor period as timedelta + """ + self.ExecutorPeriod = f"{int(executor_period.total_seconds() * 1000)}ms" + + def add_application_module( + self, + module: ApplicationModule, + task_mapping_info: list[tuple[str, timedelta, int]], + ) -> None: + """Add an application module to the executable + + Args: + module (vafpy.ApplicationModule): Application module instance to add + task_mapping_info (list[tuple[str, timedelta, int]]): Mapping info for tasks a list of tuples with + (task_name, budget, offset) + """ + task_mappings: list[vafmodel.ExecutableTaskMapping] = [] + for r in task_mapping_info: + budget_str = f"{int(r[1].total_seconds() * 1000)}ms" + task_mappings.append(vafmodel.ExecutableTaskMapping(TaskName=r[0], Offset=r[2], Budget=budget_str)) + self.ApplicationModules.append( + vafmodel.ExecutableApplicationModuleMapping( + ApplicationModuleRef=module, + InterfaceInstanceToModuleMappings=[], + TaskMapping=task_mappings, + ) + ) + + # FIXME(virmlj) refactor + # pylint: disable-next=too-many-locals, too-many-branches + def connect_interfaces( + self, + module_a: ApplicationModule, + instance_name_a: str, + module_b: ApplicationModule, + instance_name_b: str, + ) -> None: + """Connects two interfaces of two application modules in this executable + + Args: + module_a (vafpy.ApplicationModule): The provider application module + instance_name_a (str): The instance name of the provided interface + module_b (vafpy.ApplicationModule): The consumer application module + instance_name_b (str): The instance name of the consumed interface + + Raises: + ModelError: If any of the modules are not mapped to the executable, + if any of the instances names is not found + or if the interfaces are not compatible + """ + found_pi = [pi for pi in module_a.ProvidedInterfaces if pi.InstanceName == instance_name_a] + found_ci = [ci for ci in module_b.ConsumedInterfaces if ci.InstanceName == instance_name_b] + + if len(found_pi) != 1: + raise ModelError( + "Could not find interface instance " + + instance_name_a + + " on a provided interface of module " + + module_a.Name + ) + + if len(found_ci) != 1: + raise ModelError( + "Could not find interface instance " + + instance_name_b + + " on a consumed interface of module " + + module_b.Name + ) + + if found_pi[0].ModuleInterfaceRef != found_ci[0].ModuleInterfaceRef: + raise ModelError( + "Interfaces do not match: " + + found_pi[0].ModuleInterfaceRef.Namespace + + "::" + + found_pi[0].ModuleInterfaceRef.Name + + " and " + + found_ci[0].ModuleInterfaceRef.Namespace + + "::" + + found_ci[0].ModuleInterfaceRef.Name + ) + + found_am_a = [ + a + for a in self.ApplicationModules + if a.ApplicationModuleRef.Name == module_a.Name and a.ApplicationModuleRef.Namespace == module_a.Namespace + ] + found_am_b = [ + a + for a in self.ApplicationModules + if a.ApplicationModuleRef.Name == module_b.Name and a.ApplicationModuleRef.Namespace == module_b.Namespace + ] + + if len(found_am_a) != 1: + raise ModelError("Could not find application module " + module_a.Name + " mapped on executable") + + if len(found_am_b) != 1: + raise ModelError("Could not find application module " + module_b.Name + " mapped on executable") + + already_mapped_on_provider = False + for instance in found_am_a[0].InterfaceInstanceToModuleMappings: + if instance.InstanceName == instance_name_a: + already_mapped_on_provider = True + sm = instance.ModuleRef + + if not already_mapped_on_provider: + sm = vafmodel.PlatformModule( + Name=found_pi[0].ModuleInterfaceRef.Name + "Module", + Namespace="application_communication", + ModuleInterfaceRef=found_pi[0].ModuleInterfaceRef, + ) + self.InternalCommunicationModules.append(sm) + + mapping_a = vafmodel.InterfaceInstanceToModuleMapping(InstanceName=instance_name_a, ModuleRef=sm) + mapping_b = vafmodel.InterfaceInstanceToModuleMapping(InstanceName=instance_name_b, ModuleRef=sm) + + if not already_mapped_on_provider: + found_am_a[0].InterfaceInstanceToModuleMappings.append(mapping_a) + found_am_b[0].InterfaceInstanceToModuleMappings.append(mapping_b) + + model_runtime.connected_interfaces[f"{module_a.Namespace}::{module_a.Name}"].append(found_pi[0].InstanceName) + model_runtime.connected_interfaces[f"{module_b.Namespace}::{module_b.Name}"].append(found_ci[0].InstanceName) + + def __connect_interface_to_silkit( # pylint: disable=too-many-arguments, too-many-positional-arguments + self, + app_module: ApplicationModule, + instance_name: str, + silkit_address_instance_name: str, + registry_uri: str, + interface_type: str, + ) -> None: + """Connects a consumer interface of an application module with the user-provided platform consumer module + Use this CaC support for platform-centric projects where the platform is already known + + Args: + app_module (vafpy.ApplicationModule): Application module instance to + connect + instance_name (str): The interface instance name + silkit_address_instance_name (str): The silkit instance address + registry_uri (str): The silkit registry uri to use + interface_type (str): type of interface "consumed" or "provided" + + Raises: + ModelError: If the application module was not found, + if the instance was not found + or if the interfaces do not match + """ + # found the corresponding app module + found_am = [ + a + for a in self.ApplicationModules + if a.ApplicationModuleRef.Name == app_module.Name + and a.ApplicationModuleRef.Namespace == app_module.Namespace + ] + + if len(found_am) != 1: + raise ModelError("Could not find application module " + app_module.Name + " mapped on executable") + + # get interface type: "Consumed"/"Provided" from Platform<type>rModule + assert interface_type in ("Consumed", "Provided") + # check if interfaces are the same + found_interface = [ + pi for pi in getattr(app_module, f"{interface_type}Interfaces") if pi.InstanceName == instance_name + ] + if len(found_interface) != 1: + raise ModelError(f"No {interface_type}Interface with instance {instance_name} in Module {app_module.Name}") + + if silkit_address_instance_name == "": + silkit_address_instance_name = f"Silkit_{found_interface[0].ModuleInterfaceRef.Name}" + + # Consumed -> Consumer, Provided -> Provider + interface_type = interface_type.removesuffix("d") + "r" + + # check the found consumer/provider modules + found_module = [ + interface_module + for interface_module in getattr(model_runtime.main_model, f"Platform{interface_type}Modules") + if interface_module.ModuleInterfaceRef == found_interface[0].ModuleInterfaceRef + and isinstance(interface_module.ConnectionPointRef, vafmodel.SILKITConnectionPoint) + and interface_module.ConnectionPointRef.ServiceInterfaceName == silkit_address_instance_name + ] + + if len(found_module) > 1: + raise ModelError( + ( + f"Found missconfiguration of Silkit {interface_type} modules for module interface" + f" {found_interface[0].ModuleInterfaceRef.Namespace}" + f"::{found_interface[0].ModuleInterfaceRef.Name} with silkit instance address" + f" {silkit_address_instance_name}" + ) + ) + if len(found_module) == 1: + # use the found module + module = found_module[0] + else: + # no module found + scp = vafmodel.SILKITConnectionPoint( + Name=f"ConnectionPoint_{interface_type.lower()}_{instance_name}", + ServiceInterfaceName=silkit_address_instance_name, + RegistryUri=registry_uri, + ) + if model_runtime.main_model.SILKITAdditionalConfiguration is None: + model_runtime.main_model.SILKITAdditionalConfiguration = vafmodel.SILKITAdditionalConfigurationType( + ConnectionPoints=[] + ) + # pylint-bug + # pylint: disable-next=no-member + model_runtime.main_model.SILKITAdditionalConfiguration.ConnectionPoints.append(scp) + module = vafmodel.PlatformModule( + Name=f"{interface_type}Module_{found_interface[0].ModuleInterfaceRef.Name}_{instance_name}", + Namespace=found_interface[0].ModuleInterfaceRef.Namespace, + ModuleInterfaceRef=found_interface[0].ModuleInterfaceRef, + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=scp, + ) + getattr(model_runtime.main_model, f"Platform{interface_type}Modules").append(module) + + # add the mapping + mapping = vafmodel.InterfaceInstanceToModuleMapping(InstanceName=instance_name, ModuleRef=module) + found_am[0].InterfaceInstanceToModuleMappings.append(mapping) + model_runtime.connected_interfaces[f"{app_module.Namespace}::{app_module.Name}"].append(instance_name) + + def connect_consumed_interface_to_silkit( + self, + app_module: ApplicationModule, + instance_name: str, + silkit_address_instance_name: str = "", + registry_uri: str = "silkit://localhost:8500", + ) -> None: + """Connects a module interface of an application module as a silkit consumer + + Args: + app_module (vafpy.ApplicationModule): Application module instance to + connect + instance_name (str): The interface instance name + silkit_address_instance_name (str): The silkit instance address + registry_uri (str): The silkit registry uri to use + + Raises: + ModelError: If the application module was not found, + if the instance was not found, + or if there is a missconfiguration of silkit consumer modules + """ + self.__connect_interface_to_silkit( + app_module, instance_name, silkit_address_instance_name, registry_uri, interface_type="Consumed" + ) + + def connect_provided_interface_to_silkit( + self, + app_module: ApplicationModule, + instance_name: str, + silkit_address_instance_name: str = "", + registry_uri: str = "silkit://localhost:8500", + ) -> None: + """Connects a module interface of an application module as a silkit provider + + Args: + app_module (vafpy.ApplicationModule): Application module instance to + connect + instance_name (str): The interface instance name + silkit_address_instance_name (str): The silkit instance address + registry_uri (str): The silkit registry uri to use + + Raises: + ModelError: If the application module was not found, + if the instance was not found, + or if there is a missconfiguration of silkit provider modules + """ + + self.__connect_interface_to_silkit( + app_module, instance_name, silkit_address_instance_name, registry_uri, interface_type="Provided" + ) diff --git a/VAF/src/vaf/vafpy/factory.py b/VAF/src/vaf/vafpy/factory.py new file mode 100644 index 0000000..925b95b --- /dev/null +++ b/VAF/src/vaf/vafpy/factory.py @@ -0,0 +1,124 @@ +"""Factory to build""" + +from typing import Any, Optional + +from pydantic._internal._model_construction import ModelMetaclass +from typing_extensions import Self + +from vaf import vafmodel + +from .core import BaseTypesWrapper, ModelError, VafpyAbstractBase +from .model_runtime import model_runtime + +# pylint: disable=too-few-public-methods + + +class VafpyAbstractElement(VafpyAbstractBase): + """Generic Abstract type for Vafpy Element""" + + @classmethod + def __ensure_name_ns(cls, name: str | None, namespace: str | None) -> None: + """Method to ensure name & namespaces of the object + Args: + kwargs: attributes to be checked + Raises: + ModelError: if name and namespace is not valid + """ + if name is None and namespace is None: + type_str = cls.__name__ + error_msg = "".join( + [f"Dude, why do you want to initialize {type_str}", "with name = None & namespace = None?"] + ) + raise ModelError(error_msg) + + assert isinstance(name, str) and isinstance(namespace, str) + + invalid_name_bs: bool = "::" in name + + if "::" in name: + reason = "Name must not contain character '::'!" + else: + reason = "The first character of name and namespace must not be a number!" + if namespace == "": + invalid_name_bs |= name[0].isdigit() + else: + invalid_name_bs |= name[0].isdigit() or namespace[0].isdigit() + + if invalid_name_bs: + raise ModelError(reason) + + @classmethod + def __get_vafmodel_parent(cls) -> ModelMetaclass: + """Method to get first vafmodel parent from class + Returns: + vafmodel class + Raises: + ModelError: if class is not a children of a vafmodel class + """ + tmp_cls: Any = cls + + looping_louie: bool = True + while looping_louie: + tmp_cls = getattr(tmp_cls, "__base__", None) + looping_louie = tmp_cls is not None and not tmp_cls.__module__.endswith("vafmodel") + + if type(tmp_cls) is not ModelMetaclass or not tmp_cls.__module__.endswith("vafmodel"): # pylint: disable=unidiomatic-typecheck + raise ModelError("Dude, your class has the wrong parent!") + + return tmp_cls + + @classmethod + def _construct_typeref_object(cls, typeref: VafpyAbstractBase | BaseTypesWrapper, object_class: type) -> None: + """Method to construct typeref object + Args: + typeref: typeref as cac object + object_class: class of the typeref + """ + # assert typeref hasn't constructed yet + if ( + model_runtime.element_by_namespace.get(typeref.Namespace, {}) + .get(object_class.__name__ + "s", {}) + .get(typeref.Name, None) + is None + ): + # construct the typeref as vafpy object + object_class(typeref.Name, typeref.Namespace) + + @classmethod + def _build_instance(cls, obj: Optional[Self] = None, **kwargs: Any) -> Optional[Self]: + """Method to build an instance of a vafpy element + Args: + obj: object if it's already built + kwargs: attributes of the object + Returns: + constructed object that can be fetched by caller + """ + # construct empty instance if obj is none + if obj is None: + obj = cls.__new__(cls) + # ensure validity of attributes + cls.__ensure_name_ns(name=kwargs.get("Name", None), namespace=kwargs.get("Namespace", None)) + # construct via vafmodel constructor + vafmodel_parent = cls.__get_vafmodel_parent() + vafmodel_parent.__init__( # type:ignore[misc] + obj, + **{ + init_args: kwargs[init_args] for init_args in vafmodel_parent.model_fields.keys() if init_args in kwargs + }, + ) + # add to model runtime + model_runtime.add_element(obj, imported=kwargs.get("imported", False)) + + return obj + + @classmethod + def _from_vaf_model(cls, vaf_model: vafmodel.ModelElement, **kwargs: Any) -> None: + """Method to init vafpy object from a vaf_model + Args: + vaf_model: vafmodel object as input + kwargs: Other variables + """ + # append vaf_model attributes to kwargs + kwargs |= {init_args: getattr(vaf_model, init_args) for init_args in vaf_model.model_fields_set} + # construct object from kwargs + cls._build_instance(**kwargs) diff --git a/VAF/src/vaf/vafpy/model_runtime.py b/VAF/src/vaf/vafpy/model_runtime.py new file mode 100644 index 0000000..986d6f7 --- /dev/null +++ b/VAF/src/vaf/vafpy/model_runtime.py @@ -0,0 +1,216 @@ +"""Runtime for building a complete model with config as code""" + +from collections import defaultdict +from typing import Dict, List, Tuple + +from vaf import vafmodel +from vaf.cli_core.common.utils import create_name_namespace_full_name + +from .core import ModelError, VafpyAbstractBase + + +class ModelRuntime: + """Runtime to store modeling progress""" + + # Dict that stores namespace & name of used module interfaces + # and their respectives data_elements & operations typerefs + used_module_interfaces: Dict[str, List[str]] = {} + # List that stores the name of internal interfaces + internal_interfaces: List[str] = [] + # List that stores the name of connected internal interfaces + connected_interfaces: defaultdict[str, List[str]] = defaultdict(list) + # dictionary that stores vafpy elements by namespace (for CaC) + # Reason: getter function in runtime.py can get the vafpy elements + # CaC and some generations are namespace-based: One can access the model + # by calling <vafpy_element>.vafmodel + element_by_namespace: Dict[str, Dict[str, Dict[str, VafpyAbstractBase]]] = {} + + def __init__(self) -> None: + self.main_model = vafmodel.MainModel() + + def reset(self) -> None: + """Resets the model runtime""" + self.main_model = vafmodel.MainModel() + self.used_module_interfaces.clear() + self.internal_interfaces.clear() + self.connected_interfaces.clear() + self.element_by_namespace.clear() + + @staticmethod + def __get_element_type(vaf_model_obj: VafpyAbstractBase) -> str: + """Method to get element type of a vafmodel object + Args: + vaf_model_obj: vafmodel obj + Return: + data type of vafmodel in plural (Enums instead of VafEnums) + """ + return type(vaf_model_obj).__name__.removeprefix("Vaf") + "s" + + def __get_element_data(self, element: VafpyAbstractBase) -> Tuple[str, str, str]: + """Method to get data of a vafpy/vafmodel object + Args: + element: vafpy/vafmodel object + Return: + Tuple that contains: object's name, object's namespace, element's type + """ + return ( + element.Name, + element.Namespace, + self.__get_element_type(element), + ) + + def add_element(self, element: VafpyAbstractBase, imported: bool = False) -> None: + """Adds an element to the model + Args: + element: element to be added to the model + imported: boolean to define if it's addition for import/load + Raises: + ModelError: if element already exists + """ + if isinstance(element, VafpyAbstractBase): + # get element data + name, namespace, element_type = self.__get_element_data(element) + + # add to main model if not yet recorded + if self.element_by_namespace.get(namespace, {}).get(element_type, {}).get(name, None) is None: + getattr( + self.main_model.DataTypeDefinitions if element_type in vafmodel.data_types else self.main_model, + element_type, + ).append(element) + + # add vafpy objects to element_by_namespace database + if namespace not in self.element_by_namespace: + self.element_by_namespace[namespace] = {} + if element_type not in self.element_by_namespace[namespace]: + self.element_by_namespace[namespace][element_type] = {name: element} + else: + duplicate = name in self.element_by_namespace[namespace][element_type] + if not duplicate: + self.element_by_namespace[namespace][element_type][name] = element + elif not imported: + # raise ModelError for duplicates if not imported + # means: user wrongly modelled an object twice + # This must be simply silently ignored in import + # operations (via import_json()) + raise ModelError( + "".join( + [ + f"Failed to add a duplicate for MainModel Element {element_type}:" + f" with Identifier: {namespace}::{name}" + ] + ) + ) + + # special operations for specific elements + # ModuleInterface, PlatformModule, Executable + if isinstance(element, vafmodel.PlatformModule): + self.add_used_module_interfaces(element.ModuleInterfaceRef) + elif not imported: + if isinstance(element, vafmodel.ModuleInterface): + self.add_used_module_interfaces(element) + elif isinstance(element, vafmodel.ApplicationModule): + self.add_used_module_interfaces( + [mi.ModuleInterfaceRef for mi in element.ConsumedInterfaces + element.ProvidedInterfaces] + ) + + def remove_element(self, element: VafpyAbstractBase) -> None: + """Remove an element from the model + Args: + element: element to be removed from the model + """ + if isinstance(element, VafpyAbstractBase): + name, namespace, element_type = self.__get_element_data(element) + + if name in self.element_by_namespace[namespace][element_type]: + # remove from main_model via model from internal lookup + # reason: element is a deepcopy and might not the same object + # like the one in the model that needs to be deleted + getattr( + self.main_model.DataTypeDefinitions if element_type in vafmodel.data_types else self.main_model, + element_type, + ).remove(self.element_by_namespace[namespace][element_type][name]) + # remove element from internal lookup + del self.element_by_namespace[namespace][element_type][name] + + if not self.element_by_namespace[namespace][element_type]: + del self.element_by_namespace[namespace][element_type] + + if not self.element_by_namespace[namespace]: + del self.element_by_namespace[namespace] + + # special operations for specific elements + # ModuleInterface, PlatformModule, Executable + if isinstance(element, vafmodel.ModuleInterface): + self.remove_used_module_interfaces(element) + elif isinstance(element, vafmodel.PlatformModule): + self.remove_used_module_interfaces(element.ModuleInterfaceRef) + elif isinstance(element, vafmodel.ApplicationModule): + self.remove_used_module_interfaces( + [mi.ModuleInterfaceRef for mi in element.ConsumedInterfaces + element.ProvidedInterfaces] + ) + + def replace_element(self, element: VafpyAbstractBase) -> None: + """Replace an element with same name & namespace + Args: + element: element to be replaced in the model + """ + if isinstance(element, VafpyAbstractBase): + # replace element from model by namespace + name, namespace, element_type = self.__get_element_data(element) + if name in self.element_by_namespace[namespace][element_type]: + self.element_by_namespace[namespace][element_type][name] = element + # replace in main model + element_list = getattr( + self.main_model.DataTypeDefinitions if element_type in vafmodel.data_types else self.main_model, + element_type, + ) + for idx, el in enumerate(element_list): + if el.Name == element.Name and el.Namespace == element.Namespace: + element_list[idx] = element + break + + def add_used_module_interfaces( + self, module_interfaces: List[vafmodel.ModuleInterface] | vafmodel.ModuleInterface + ) -> None: + """Adds a module interface to the used module interface + Args: + module_interfaces (vafmodel.ModuleInterface): list of module interface + """ + if not isinstance(module_interfaces, List): + module_interfaces = [module_interfaces] + for mi in module_interfaces: + module_interface_id = create_name_namespace_full_name(mi.Name, mi.Namespace) + if module_interface_id not in self.used_module_interfaces: + self.used_module_interfaces[module_interface_id] = list( + set( + [ + create_name_namespace_full_name(data_el.TypeRef.Name, data_el.TypeRef.Namespace) + for data_el in mi.DataElements + ] + + [ + create_name_namespace_full_name( + surgery_parameter.TypeRef.Name, surgery_parameter.TypeRef.Namespace + ) + for surgery in mi.Operations + for surgery_parameter in surgery.Parameters + ] + ) + ) + + def remove_used_module_interfaces( + self, module_interfaces: List[vafmodel.ModuleInterface] | vafmodel.ModuleInterface + ) -> None: + """Adds a module interface to the used module interface + Args: + module_interfaces (vafmodel.ModuleInterface): list of module interface + """ + if not isinstance(module_interfaces, List): + module_interfaces = [module_interfaces] + for mi in module_interfaces: + module_interface_id = create_name_namespace_full_name(mi.Name, mi.Namespace) + if module_interface_id in self.used_module_interfaces: + del self.used_module_interfaces[module_interface_id] + + +# prevent cylic dependency +model_runtime = ModelRuntime() diff --git a/VAF/src/vaf/vafpy/runtime.py b/VAF/src/vaf/vafpy/runtime.py new file mode 100644 index 0000000..e907777 --- /dev/null +++ b/VAF/src/vaf/vafpy/runtime.py @@ -0,0 +1,559 @@ +"""Runtime for building a complete model with config as code""" + +import json +from copy import deepcopy +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple + +import networkx as nx + +from vaf import vafmodel +from vaf.cli_core.common.utils import ProjectType, concat_str_to_path, create_name_namespace_full_name + +from .core import ModelError, VafpyAbstractBase +from .datatypes import Array, Enum, Map, String, Struct, TypeRef, Vector +from .elements import ( + ApplicationModule, + ModuleInterface, + PlatformConsumerModule, + PlatformProviderModule, +) +from .model_runtime import ModelRuntime, model_runtime +from .validator import Validator + +# List of data types for cleanups +## Special: Structs & Maps +## Generic: Arrays, Enums (VafEnums -> Enums), Strings, TypeRefs, Vectors +special_dtd_cleanup_data_types = ["Structs", "Maps"] + +generic_dtd_cleanup_data_types = [ + data_type for data_type in vafmodel.data_types if data_type not in special_dtd_cleanup_data_types +] + + +# Dictionary that translates a string of element type to its actual class +model_element_converter: Dict[str, Any] = { + "ApplicationModule": ApplicationModule, + "Array": Array, + "Enum": Enum, + "Map": Map, + "ModuleInterface": ModuleInterface, + "PlatformConsumerModule": PlatformConsumerModule, + "PlatformProviderModule": PlatformProviderModule, + "String": String, + "Struct": Struct, + "TypeRef": TypeRef, + "Vector": Vector, +} + + +def _add_struct_to_graph(graph: nx.DiGraph, structs: List[VafpyAbstractBase]) -> Tuple[nx.DiGraph, List[str]]: + """Function to add a list of struct to graph and collect base types from their subelements + Args: + graph: Directional Graph + structs: List of structs + dtd_namespace: namespace of current DataTypeDef + Returns: + updated Directional Graph + list of new base types + """ + new_base_types: List[str] = [] + for struct in structs: + assert isinstance(struct, Struct) + # add struct to graph + struct_identifier = create_name_namespace_full_name(struct.Name, struct.Namespace) + graph.add_node(struct_identifier) + + # add subelements to struct + for subelement in struct.SubElements: + subelement_identifier = create_name_namespace_full_name(subelement.Name, struct_identifier) + graph.add_edge(struct_identifier, subelement_identifier) + typeref_identifier = create_name_namespace_full_name(subelement.TypeRef.Name, subelement.TypeRef.Namespace) + + # typeref non base types: connect typeref to subelements + graph.add_edge(subelement_identifier, typeref_identifier) + if not subelement.TypeRef.Namespace: + # add base types + new_base_types.append(typeref_identifier) + return graph, new_base_types + + +def _add_generic_data_types_to_graph( + graph: nx.DiGraph, + generic_data: List[VafpyAbstractBase], +) -> Tuple[nx.DiGraph, List[str]]: + """Function to add a list of generic data types to graph + Generic Data Types: All Data Types that has TypeRef as direct attribute + -> Arrays, Enums, Strings, TypeRefs, Vectors + Args: + graph: Directional Graph + generic_data: List of Generic Data + dtd_namespace: namespace of current DataTypeDef + Returns: + updated Directional Graph + list of new base types + """ + new_base_types: List[str] = [] + + for data in generic_data: + assert isinstance(data, (Array, Enum, String, TypeRef, Vector)) + # add data to graph + data_identifier = create_name_namespace_full_name(data.Name, data.Namespace) + graph.add_node(data_identifier) + + # if data has typeref then create the typeref node and connect it to the data + if isinstance(data, (Array, TypeRef, Vector)): + # typeref non base types: connect typeref to data + graph.add_edge( + data_identifier, + create_name_namespace_full_name(data.TypeRef.Name, data.TypeRef.Namespace), + ) + # Vectors, Arrays, TypeRefs: if TypeRef.Namespace is empty -> base types + if data.TypeRef.Namespace == "": + new_base_types.append(data_identifier) + else: + # Not Vectors, Arrays, TypeRefs: base types + new_base_types.append(data_identifier) + + return graph, new_base_types + + +def _add_maps_to_graph(graph: nx.DiGraph, maps: List[VafpyAbstractBase]) -> Tuple[nx.DiGraph, List[str]]: + """Function to add a list of maps to graph + Args: + graph: Directional Graph + maps: List of Maps + dtd_namespace: namespace of current DataTypeDef + Returns: + updated Directional Graph + list of new base types + """ + new_base_types: List[str] = [] + for map_data in maps: + assert isinstance(map_data, Map) + map_identifier = create_name_namespace_full_name(map_data.Name, map_data.Namespace) + for type_ref in [ + getattr(map_data, f"Map{which_type_ref.capitalize()}TypeRef") for which_type_ref in ["key", "value"] + ]: + # connect both typerefs to data + graph.add_edge(map_identifier, create_name_namespace_full_name(type_ref.Name, type_ref.Namespace)) + # add to base types if typeref namespace is empty + if type_ref.Namespace == "": + new_base_types.append(map_identifier) + return graph, new_base_types + + +# suffix for old json +old_json_suffix = "~" + + +def __get_all_nested_namespaces_references(model: ModelRuntime) -> Tuple[nx.DiGraph, List[str]]: + """Get all namespaces references + E.g.: a::b::c refers to a::b::d -> if one needs a::b::c, a::b::d is also needed + + Args: + model: ModelRuntime whose artifacts are to be reduced + + Returns: + Directional Graph of nested references of namespaces + List of all strings of base types data + """ + graph = nx.DiGraph() + base_types: List[str] = [] + + for ns_elements_data in model.element_by_namespace.values(): + # Special Data Types: Structs & Maps + + ## Structs due to the real type refs referenced in the subelements level + ## add structs & their subelements reference to graph + graph, new_base_types = _add_struct_to_graph(graph, list(ns_elements_data.get("Structs", {}).values())) + base_types += new_base_types + + ## Maps due to typerefs referenced in key & value + ## add key & value reference to graph + graph, new_base_types = _add_maps_to_graph(graph, list(ns_elements_data.get("Maps", {}).values())) + base_types += new_base_types + + # Generic Data Types: All Data Types that have TypeRef as direct attribute + ## arrays, vectors, strings, typeref, enums + for data_type in generic_dtd_cleanup_data_types: + graph, new_base_types = _add_generic_data_types_to_graph( + graph, list(ns_elements_data.get(data_type, {}).values()) + ) + base_types += new_base_types + + return graph, list(set(base_types)) + + +def __get_used_namespaces( + module_interfaces_data: Dict[str, List[str]], nested_references_graph: nx.DiGraph, base_types_list: List[str] +) -> List[str]: + """Get lists of all used namespaces by using tree + Args: + module_interfaces_data: Dictionary that contains id of used module interfaces and + typerefs of their data elements + nested_references_graph: graph object that represents all references between namespaces + base_types_list: list that contains all base types + Returns: + Lists of all used namespaces + """ + used_namespaces: List[str] = [] + + # loop over data elements in module interfaces + for data_element_typeref_ids in module_interfaces_data.values(): + # add all data elements' typeref to used namespaces + used_namespaces += data_element_typeref_ids + for data_element_typeref_id in data_element_typeref_ids: + ### DEBUGGING nx.DiGraphs ### + # getting list of all paths + # list(nx.all_simple_paths(graph, node1, node2)) + + # getting all direct "neighbour" nodes pointed out by a node + # list(graph.out_edges(node)) + ############################# + + # check graph only if data_element_identifier is a node in the graph + if nested_references_graph.has_node(data_element_typeref_id): + # get all nested references by checking all paths between data element and all base types + used_namespaces += [ + referenced_nodes + for base_type in base_types_list # loop over all base types + for path in list( + nx.all_simple_paths(nested_references_graph, data_element_typeref_id, base_type) + ) # get all paths + for referenced_nodes in path[1:] # ignore first element (data_element), since already added + ] + + return list(set(used_namespaces)) + + +def __remove_unused_artifacts(model: ModelRuntime) -> ModelRuntime: + """Remove unused artifacts of a model + Args: + model: ModelRuntime whose artifacts are to be reduced + + Returns: + ModelRuntime with reduced artifacts + """ + # get all nested references of namespaces + namespace_references, all_base_types = __get_all_nested_namespaces_references(model) + # get all needed custom namespaces + used_namespaces: List[str] = __get_used_namespaces( + model.used_module_interfaces, namespace_references, all_base_types + ) + + # deepcopy since the real dictionary might change dynamically during the loop + for ns_elements_data in deepcopy(model.element_by_namespace).values(): + # Structs: Special Case due to possible reference by their SubElements + # structs need to be looped also in the Subelements + for struct in ns_elements_data.get("Structs", {}).values(): + assert isinstance(struct, Struct) + struct_identifier = create_name_namespace_full_name(struct.Name, struct.Namespace) + # check if whole struct is needed + if struct_identifier not in used_namespaces: + used_subelements = [ + subelement + for subelement in struct.SubElements + if create_name_namespace_full_name(subelement.Name, subelement.TypeRef.Namespace) in used_namespaces + ] + # remove struct if it's not needed + if used_subelements: + struct.SubElements = used_subelements + model.replace_element(struct) + else: + model.remove_element(struct) + + # get used arrays, enums, vectors, strings, typerefs, maps + ## Maps is not special here: since they can't be referenced by their children attribute + for dtd_type_str in [*generic_dtd_cleanup_data_types, "Maps"]: + for data in ns_elements_data.get(dtd_type_str, {}).values(): + assert isinstance(data, (Array, Enum, Map, String, TypeRef, Vector)) + if create_name_namespace_full_name(data.Name, data.Namespace) not in used_namespaces: + model.remove_element(data) + + # loop module interfaces + for module_interface in ns_elements_data.get("ModuleInterfaces", {}).values(): + assert isinstance(module_interface, ModuleInterface) + module_interface_identifier = create_name_namespace_full_name( + module_interface.Name, module_interface.Namespace + ) + # ignore if already listed as used module interfaces + # only check if not listed as used module interfaces and identifier not in used_namespaces + if ( + module_interface_identifier not in model.used_module_interfaces + and module_interface_identifier not in used_namespaces + ): + # check if module interface is not used (possibility as needed parents or grandparents) + # get used module interface data elements + # first data element also needed as it's for itself + used_data_elements = module_interface.DataElements[0:1] + [ + data_element + for data_element in module_interface.DataElements + if (data_element.Name == data_element.TypeRef.Name) + and ( + create_name_namespace_full_name(data_element.TypeRef.Name, data_element.TypeRef.Namespace) + in used_namespaces + ) + ] + + # if found used data element == itself/empty then it's unused + if len(used_data_elements) <= 1: + # remove module interface + model.remove_element(module_interface) + # if data elements differ then replace + elif len(used_data_elements) != len(module_interface.DataElements): + module_interface.DataElements = used_data_elements + model.replace_element(module_interface) + + return model + + +def get_main_model() -> Any: + """Get the main model as JSON + + Returns: + Any: The model + """ + return json.loads(model_runtime.main_model.model_dump_json(indent=2, exclude_none=True, exclude_defaults=True)) + + +def __save_model_artifacts( + path: Path, project_type: ProjectType, keys: Optional[List[str]] = None, cleanup: bool = False +) -> None: + """Saves the main model to file + + Args: + path (Path): Path to the file + project_type (ProjectType): Type of the current project + cleanup: (bool): Boolean flag to remove unused data elements & module interfaces in model + keys: (list[str]): Key to be saved in the export for partial save + """ + if path.exists(): + print(f"File {path.name} already exists. Backup existing file to {path.name}{old_json_suffix}") + backup_output_path = concat_str_to_path(path, old_json_suffix) + backup_output_path.write_bytes(path.read_bytes()) + + if cleanup: + __remove_unused_artifacts(model_runtime) + Validator(project_type).validate_model(model_runtime) + + if keys is not None: + target_model: vafmodel.MainModel = vafmodel.MainModel() + for key in keys: + if hasattr(target_model, key): + getattr(target_model, key).extend(getattr(model_runtime.main_model, key)) + + with open(path, "w", encoding="utf-8") as f: + f.write( + (model_runtime.main_model if keys is None else target_model).model_dump_json( + indent=2, exclude_none=True, exclude_defaults=True, by_alias=True + ) + ) + + +def save_main_model(path: Path, project_type: ProjectType, cleanup: bool = False) -> None: + """Saves the main model to file + + Args: + path (Path): Path to the file + project_type (ProjectType): Type of the current project + cleanup: (bool): Boolean flag to remove unused data elements & module interfaces in model + """ + __save_model_artifacts(path, project_type, keys=None, cleanup=cleanup) + + +def save_part_of_main_model(path: Path, keys: list[str], project_type: ProjectType, cleanup: bool = False) -> None: + """Saves the main model to file + + Args: + path (Path): Path to the file + keys: (list[str]): Key to be saved in the export + project_type (ProjectType): Type of the current project + cleanup: (bool): Boolean flag to remove unused data elements & module interfaces in model + """ + __save_model_artifacts(path, project_type, keys=keys, cleanup=cleanup) + + +def __create_vafpy_from_imported_vafmodel(data: vafmodel.ModelElement, element_type: str) -> None: + # construct vafpy object from vafmodel + # vafpy.<Element>.(vafmodel.ModelElement) + assert element_type in model_element_converter, f"ERROR: invalid Element {element_type}" + model_element_converter[element_type]._from_vaf_model(vaf_model=data, imported=True) # pylint:disable=protected-access + + +def __read_model(path: str, import_type: str, am_path: Optional[str] = None) -> None: + """Function to read model_runtime from a model file + Args: + path: path to model file + import_type: type of import: "model" or "app-module" + """ + imported_model = vafmodel.load_json(path) + + assert import_type in ("app-module", "model") + if import_type == "app-module": + assert am_path is not None + + for key, value in vars(imported_model).items(): + if key == "DataTypeDefinitions": + for dtd_type_str in vafmodel.data_types: + for new_data in getattr(value, dtd_type_str): + # create vafpy object in model_runtime based on vafmodel object + __create_vafpy_from_imported_vafmodel(new_data, dtd_type_str.removesuffix("s")) + elif key in ["ModuleInterfaces", "PlatformConsumerModules", "PlatformProviderModules", "ApplicationModules"]: + for val in value: + # if import_app_module -> add installation paths to app modules + if import_type == "app-module" and isinstance(val, vafmodel.ApplicationModule): + if val.ImplementationProperties is None: + val.ImplementationProperties = vafmodel.ImplementationProperty() + val.ImplementationProperties.InstallationPath = am_path + # create vafpy object in model_runtime based on vafmodel object + __create_vafpy_from_imported_vafmodel(val, key.removesuffix("s")) + else: # other keys + if import_type == "model": + if isinstance(value, List) and len(value) > 0: + setattr( + model_runtime.main_model, + key, + getattr(model_runtime.main_model, key) + value, + ) + + +def import_model(path: str) -> None: + """Imports a module from json. + Merges existing lists, does not overwrite other members. + + Args: + path (str): Path to the json file + """ + __read_model(path, import_type="model") + + +def import_application_module(model_path: str, am_path: str) -> None: # pylint: disable=too-many-locals, too-many-branches + """Imports a module from json. + Merges existing lists, does not overwrite other members. + + Args: + model_path (str): Path to the json file + am_path (str): Relative path to the application module + """ + __read_model(model_path, import_type="app-module", am_path=am_path) + + +def __get_model_runtime_element( + name: str, namespace: str, element_type: str, assert_result: bool = True +) -> Optional[VafpyAbstractBase]: + """Generic function to get element type from model_runtime + Args: + name: name of the element + namespace: namespace of the element + element_type: type of the element + assert_result: flag to activate result assertion + + Raises: + ModelError: if no element found + + Returns: + Vafpy type belongs to the element + """ + found = model_runtime.element_by_namespace.get(namespace, {}).get(element_type, {}).get(name, None) + if assert_result: + if found is None: + raise ModelError(f"Could not find {element_type}: {namespace}::{name}!") + return found + + +def get_datatype(name: str, namespace: str, datatype: Optional[str] = None) -> VafpyAbstractBase: + """Gets a datatype + + Args: + name (str): The name of the datatype + namespace (str): The namespace of the datatype + datatype (str): Type of the searched datatype, e.g.: Structs or Vectors + Raises: + ModelError: no corresponding datatype is found + Returns: + VafpyAbstractDataType: The vafpy datatype object which has vafmodel obj and its reference + """ + plural_datatype = datatype + "s" if isinstance(datatype, str) else "" + # if datatypes defined, then look specifically for this data type: + if datatype is not None and plural_datatype in vafmodel.data_types: + result = __get_model_runtime_element(name, namespace, plural_datatype) + assert result.__class__.__name__ == datatype + else: # not defined, look over all data types + for dt_type in vafmodel.data_types: + # don't raise errors if nothing found! + result = __get_model_runtime_element(name, namespace, dt_type.removesuffix("s"), assert_result=False) + if result is not None: + break + if not isinstance(result, VafpyAbstractBase): + raise ModelError(f"Gotten datatype {namespace}::{name} has invalid type: {type(result)}") + return result + + +def get_module_interface(name: str, namespace: str) -> ModuleInterface: + """Gets a module interface by full name + + Args: + name (str): The name of the module interface + namespace (str): The namespace of the module interface + + Returns: + vafmodel.ModuleInterface: The interface + """ + result = __get_model_runtime_element(name, namespace, "ModuleInterfaces") + assert isinstance(result, ModuleInterface) + return result + + +def get_platform_consumer_module(name: str, namespace: str) -> PlatformConsumerModule: + """Gets a platform consumer module by full name + + Args: + name (str): The name of the module + namespace (str): The namespace of the module + + Raises: + ModelError: If the module was not found + + Returns: + vafmodel.PlatformModule: The found module + """ + result = __get_model_runtime_element(name, namespace, "PlatformConsumerModules") + assert isinstance(result, PlatformConsumerModule) + return result + + +def get_platform_provider_module(name: str, namespace: str) -> PlatformProviderModule: + """Gets a platform provider module by full name + + Args: + name (str): The name of the module + namespace (str): The namespace of the module + + Raises: + ModelError: If the module was not found + + Returns: + vafmodel.PlatformModule: The found module + """ + result = __get_model_runtime_element(name, namespace, "PlatformProviderModules") + assert isinstance(result, PlatformProviderModule) + return result + + +def get_application_module(name: str, namespace: str) -> ApplicationModule: + """Gets an application module by full name + + Args: + name (str): The name of the application module + namespace (str): The namespace of the application module + + Raises: + ModelError: If the module is not found + + Returns: + vafmodel.ApplicationModule: The application module + """ + result = __get_model_runtime_element(name, namespace, "ApplicationModules") + assert isinstance(result, ApplicationModule) + return result diff --git a/VAF/src/vaf/vafpy/task.py b/VAF/src/vaf/vafpy/task.py new file mode 100644 index 0000000..e87e977 --- /dev/null +++ b/VAF/src/vaf/vafpy/task.py @@ -0,0 +1,37 @@ +"""Abstraction layer for vafmodel.Task in Config as Code""" + +from __future__ import annotations + +from datetime import timedelta + +from typing_extensions import Self + +from vaf import vafmodel + + +# pylint: disable-next=too-few-public-methods +class Task(vafmodel.ApplicationModuleTasks): + """Represents a VAF Task""" + + def __init__( + self, + name: str, + period: timedelta, + preferred_offset: int | None = None, + run_after: list[Self] | None = None, + ): + vafmodel.ApplicationModuleTasks.__init__( + self, + Name=name, + Period=f"{int(period.total_seconds() * 1000)}ms", + PreferredOffset=preferred_offset, + RunAfter=[task_.Name for task_ in run_after or []], + ) + + def add_run_after(self, task: Self) -> None: + """Add a task to the run_after dependency + + Args: + task (Task): Task to add + """ + self.RunAfter.append(task.Name) diff --git a/VAF/src/vaf/vafpy/validator.py b/VAF/src/vaf/vafpy/validator.py new file mode 100644 index 0000000..3958ff2 --- /dev/null +++ b/VAF/src/vaf/vafpy/validator.py @@ -0,0 +1,279 @@ +"""Validator to raise Errors in case of Configuration Error before generating JSON""" + +import math +import warnings +from collections.abc import Hashable +from typing import Callable, Dict, List, Tuple + +from vaf.cli_core.common.utils import ProjectType as PType +from vaf.cli_core.common.utils import create_name_namespace_full_name +from vaf.vafmodel import ApplicationModule, Executable + +from .core import ModelError +from .model_runtime import ModelRuntime + + +def make_list_unique(list_input: List[Hashable] | List[str]) -> List[Hashable] | List[str]: + """Method to make list unique + Args: + list_input: List to be made unique + Return: + List without any duplicates + """ + return list(set(list_input)) + + +def format_warning( + message: Warning | str, + category: type[Warning], + filename: str, + lineno: int, + line: str | None = None, +) -> str: + # pylint: disable=unused-argument + """Format the warnings to be more user-friendly. + Args: + message (Warning | str): The warning message to format. + category (type[Warning]): The category of the warning. + filename (str): The name of the file where the warning occurred. + lineno (int): The line number where the warning occurred. + line (str, optional): The line of code where the warning occurred (default is None). + Returns: + str: Formatted warning message. + """ + return "\n" + str(filename) + ":" + str(lineno) + ": " + category.__name__ + ":\n" + str(message) + "\n" + + +class Validator: + # pylint: disable=too-few-public-methods + """Handling Config Validation""" + + msg_str: Dict[str, str] = { + "error": "Identical Duplicates for {WHAT} Name = {DTD_NAME} : {DATA}", + "warning": "Possible {DTD_N} duplicates for {WHAT} Name = {DTD_NAME} with different namespaces {DATA}", + } + + def __init__(self, project_type: PType) -> None: + # List that defines which validation methods will be executed for which project-type + self.__executor_manager: List[Tuple[List[PType], Callable[[ModelRuntime], Tuple[List[str], List[str]]]]] = [ + ([PType.INTEGRATION], self.__validate_executables), + ([PType.INTEGRATION], self.__validate_interface_connections), + ([PType.INTEGRATION, PType.APP_MODULE], self.__validate_application_module), + ([PType.INTEGRATION, PType.APP_MODULE, PType.INTERFACE], self.__validate_interface_definition), + ] + self.project_type = project_type + + def validate_model(self, runtime_model: ModelRuntime) -> ModelRuntime: + """Method to validate CaC model + Args: + runtime_model: ModelRuntime to be validated + Returns: + Updated ModelRuntime + Raises: + ModelError: hard modelling list_errors + """ + warnings.formatwarning = format_warning + + hard_errors: List[str] = [] + light_warnings: List[str] = [] + + for project_types, validate_method in self.__executor_manager: + if self.project_type in project_types: + err, wrn = validate_method(runtime_model) + hard_errors += err + light_warnings += wrn + + if light_warnings: + warnings.warn("\n".join(light_warnings)) + if hard_errors: + raise ModelError("\n".join(hard_errors)) + + # returns runtime_model so it can be used in one-liner + return runtime_model + + def __validate_executable_executor_period(self, executable: Executable) -> Tuple[List[str], List[str]]: + """Method to validate an executable's executor period + Args: + exec: Executable to be validated + Returns: + List of errors & warnings for Executable modelling + """ + list_errors: List[str] = [] + + # get all periodic tasks from all app modules belonging to the executable + periodic_tasks_data = [ + [ + create_name_namespace_full_name( + app_module.ApplicationModuleRef.Name, app_module.ApplicationModuleRef.Namespace + ), + task.Name, + int(task.Period.rstrip("ms")), + ] + for app_module in executable.ApplicationModules + for task in app_module.ApplicationModuleRef.Tasks + if task.Period.rstrip("ms").isdigit() + ] + if periodic_tasks_data: + app_module_names, tasks_names, all_tasks_period = zip(*periodic_tasks_data) + + error_msg = "" + if executable.ExecutorPeriod == "Default": + # calculate the common denominators of all PeriodicTasks + executable.ExecutorPeriod = f"{math.gcd(*all_tasks_period)}ms" + elif executable.ExecutorPeriod.rstrip("ms").isdigit(): + # ensure Executor Period <= the smallest task period + executor_period = int(executable.ExecutorPeriod.rstrip("ms")) + if executor_period > min(all_tasks_period): + # get tasks with the minimum + error_msg = "\n".join( + [ + f"Invalid ExecutorPeriod of Executable {executable.Name}: {executable.ExecutorPeriod}!", + f"Executor Period {executable.ExecutorPeriod} is longer than its Task(s)' period:", + ] + + [ + f" AppModule: {app_module_names[idx]} - Task: {tasks_names[idx]} with period {task_period}ms" # pylint:disable=line-too-long + for idx, task_period in enumerate(all_tasks_period) + if executor_period > task_period + ] + ) + + if error_msg: + list_errors.append(error_msg) + + return list_errors, [] + + def __validate_executables(self, runtime_model: ModelRuntime) -> Tuple[List[str], List[str]]: + """Method to validate model's executables + Also: Clean unused application modules from model + Args: + runtime_model: ModelRuntime to be validated + Returns: + List of errors & warnings for Executable modelling + """ + # set placeholder to collect all errors & warnings + list_errors: List[str] = [] + + # create placeholder for valid executables + valid_executables: List[Executable] = [] + # create placeholder for all executables name + valid_executables_name: List[str] = [] + # create placeholder for connected application modules + connected_app_modules: List[ApplicationModule] = [] + + for executable in runtime_model.main_model.Executables: + # raise error if duplicates are discovered + if executable.Name in valid_executables_name: + list_errors.append(f"Executable {executable.Name} is defined multiple times!") + + # valid executables have at least 1 ApplicationModule + if executable.ApplicationModules: + # add to valid executables + valid_executables.append(executable) + valid_executables_name.append(executable.Name) + # add connected app modules + connected_app_modules += [ + app_module_obj.ApplicationModuleRef for app_module_obj in executable.ApplicationModules + ] + + # verify periodic task + exec_periodic_task_err, _ = self.__validate_executable_executor_period(executable) + list_errors += exec_periodic_task_err + + # replace model.Executables with valid_executables + runtime_model.main_model.Executables = valid_executables + + # get unconnected app modules for warning message + unconnected_app_modules: List[ApplicationModule] = [ + app_module + for app_module in runtime_model.main_model.ApplicationModules + if app_module not in connected_app_modules + ] + # overwrite model's app modules + runtime_model.main_model.ApplicationModules = connected_app_modules + + # build warnings + list_warnings = [ + f"App Module '{unconnected_am.Namespace}::{unconnected_am.Name}' is defined, " + "but not connected in any Executable" + for unconnected_am in unconnected_app_modules + ] + + return list_errors, list_warnings + + # pylint: enable=too-many-nested-blocks + + @staticmethod + def __validate_interface_connections(runtime_model: ModelRuntime) -> Tuple[List[str], List[str]]: + """Method to validate model's interface connections + Args: + runtime_model: ModelRuntime to be validated + Returns: + List of list_errors & warnings for unconnected interfaces + """ + # placeholder for all warnings + list_warnings: List[str] = [] + unconnected_interfaces = [] + + for app_module in runtime_model.main_model.ApplicationModules: + module_str = f"{app_module.Namespace}::{app_module.Name}" + for ci in app_module.ConsumedInterfaces: + if not ci.IsOptional and ci.InstanceName not in runtime_model.connected_interfaces[module_str]: + unconnected_interfaces.append(f"{module_str} - {ci.InstanceName}") + for pi in app_module.ProvidedInterfaces: + if pi.InstanceName not in runtime_model.connected_interfaces[module_str]: + unconnected_interfaces.append(f"{module_str} - {pi.InstanceName}") + + if unconnected_interfaces: + list_warnings.append(f"Following interfaces are defined but not connected: {unconnected_interfaces}") + + return [], list_warnings + + @staticmethod + def __validate_interface_definition(runtime_model: ModelRuntime) -> Tuple[List[str], List[str]]: + """Method to validate model's interface definitions + Args: + runtime_model: ModelRuntime to be validated + Returns: + List of list_errors & warnings for empty interfaces + """ + # placeholder for all warnings + list_warnings: List[str] = [] + empty_interfaces = [] + + # use module interface from main model since validation takes place after cleanup + for module_interaface in runtime_model.main_model.ModuleInterfaces: + if not module_interaface.DataElements and not module_interaface.Operations: + empty_interfaces.append(f"{module_interaface.Namespace}::{module_interaface.Name}") + + if empty_interfaces: + list_warnings.append( + f"Following interfaces are defined without data elements and operations: {empty_interfaces}" + ) + + return [], list_warnings + + @staticmethod + def __validate_application_module(runtime_model: ModelRuntime) -> Tuple[List[str], List[str]]: + """Method to validate model's application modules + Args: + runtime_model: ModelRuntime to be validated + Returns: + List of errors & warnings for application module modelling + """ + # placeholder for all errors + list_errors: List[str] = [] + for app_module in runtime_model.main_model.ApplicationModules: + all_task_names: list[str] = [] + all_run_afters: set[str] = set() + for task in app_module.Tasks: + all_task_names.append(task.Name) + all_run_afters.update(task.RunAfter) + + for run_after in all_run_afters: + if run_after not in all_task_names: + list_errors.append( + f"Task {run_after} is used in as a 'run_after' dependency in ApplicationModule" + f" {app_module.Namespace}::{app_module.Name}, but is not part of it." + ) + + return list_errors, [] diff --git a/VAF/src/vaf/vafvssimport/vss/__init__.py b/VAF/src/vaf/vafvssimport/vss/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/src/vaf/vafvssimport/vss/vss_model.py b/VAF/src/vaf/vafvssimport/vss/vss_model.py new file mode 100644 index 0000000..71de5ba --- /dev/null +++ b/VAF/src/vaf/vafvssimport/vss/vss_model.py @@ -0,0 +1,234 @@ +"""Module containing the VSS model""" + +from collections import defaultdict +from typing import Any + +from vaf import vafmodel + +from . import vss_types + + +class VSS: + """Class representing the VSS model""" + + # pylint: disable=too-few-public-methods + class ModuleInterface: + """Class representing a ModuleInterface in the VSS model""" + + def __init__(self, full_name: str, vss_branch: dict[str, Any]) -> None: + """Instanciates a VSS ModuleInterface + + Args: + full_name (str): The name of the module interface including the namespace + vss_branch (dict[str, Any]): The VSS branch containing the details as JSON dict + + Raises: + ValueError: If the type of a DataElement is not supported and cannot be resolved. + """ + self.namespace, self.name = full_name.rsplit("::", 1) + self.namespace = self.namespace.lower() + self.data_elements: list[vafmodel.DataElement] = [] + + # Add DataElements for the child elements + # The temporary DataElements are only used to create the TypeRef in the resulting json. + # Therefore not all fields have to be set for these instances (e.g. min_value is not required). + for element_name, element in vss_branch["children"].items(): + if "branch" == element["type"]: + # Complex types + type_ref = vafmodel.DataType(Name=element_name, Namespace=f"{self.namespace}::{self.name}".lower()) + self.data_elements.append(vafmodel.DataElement(Name=element_name, TypeRef=type_ref)) + continue + + datatype = element["datatype"] + if "allowed" in element and "string" == datatype: + # Enums + type_ref = vafmodel.DataType(Name=element_name, Namespace=full_name.lower()) + self.data_elements.append(vafmodel.DataElement(Name=element_name, TypeRef=type_ref)) + + elif "[]" in datatype: + primitive_type_name = datatype[:-2] + tmp: vss_types.VectorType | vss_types.ArrayType + if "arraysize" in element: + # Arrays + tmp = vss_types.ArrayType("_", primitive_type_name, element["arraysize"]) + else: + # Vectors + tmp = vss_types.VectorType("_", primitive_type_name) + type_ref = vafmodel.DataType(Name=tmp.getTypeRefStr(), Namespace=tmp.namespace) + self.data_elements.append(vafmodel.DataElement(Name=element_name, TypeRef=type_ref)) + + else: + # Generic primitive types + if element["datatype"] not in vss_types.type_translation: + raise ValueError(f"Unsupported type '{element['datatype']}' for DataElement '{element_name}'") + type_ref = vss_types.type_translation[element["datatype"]] + + if vss_types.is_numeric(datatype): + # Add VSS ranges + self.data_elements.append( + vafmodel.DataElement( + Name=element_name, TypeRef=type_ref, Min=element.get("min"), Max=element.get("max") + ) + ) + else: + self.data_elements.append(vafmodel.DataElement(Name=element_name, TypeRef=type_ref)) + + def export(self) -> vafmodel.ModuleInterface: + """Exports VSS ModuleInterface to VAF model ModuleInterface + + Returns: + vafmodel.ModuleInterface: ModuleInterface containing the VSS data + """ + return vafmodel.ModuleInterface( + Name=self.name + "_If", Namespace=self.namespace, DataElements=self.data_elements + ) + + def __init__(self, vss_json: dict[str, Any]) -> None: + """Instanciates a VSS Model + + Args: + vss_json (dict[str, Any]): The complete VSS input as JSON dict + """ + + self.datatypes_per_namespace: defaultdict[str, set[vss_types.BaseType]] = defaultdict(set) + self.module_interfaces: list[VSS.ModuleInterface] = [] + + self._import_vss(vss_json) + + def export(self) -> vafmodel.MainModel: + """Exports the VSS model to a VAF model + + Returns: + vafmodel.MainModel: complete model containing VSS data + """ + + model = vafmodel.MainModel() + + model.ModuleInterfaces = [if_.export() for if_ in self.module_interfaces] + + data_type_definitions = vafmodel.DataTypeDefinition() + for _, datatypes in self.datatypes_per_namespace.items(): + structs = [dt.export() for dt in datatypes if isinstance(dt, vss_types.StructType)] + enums = [dt.export() for dt in datatypes if isinstance(dt, vss_types.EnumType)] + data_type_definitions.Arrays += [dt.export() for dt in datatypes if isinstance(dt, vss_types.ArrayType)] + data_type_definitions.Vectors += [dt.export() for dt in datatypes if isinstance(dt, vss_types.VectorType)] + + data_type_definitions.Structs += structs + data_type_definitions.Enums += enums + + # Add vaf::string + data_type_definitions.Strings = [vafmodel.String(Name="string", Namespace="vaf")] + + model.DataTypeDefinitions = data_type_definitions + + return model + + def _import_vss(self, vss_json: dict[str, Any]) -> None: + self.module_interfaces.clear() + self.datatypes_per_namespace.clear() + + for name, branch in vss_json.items(): + self._process_branch(branch, "vss::" + name) + + def _process_branch(self, branch: dict[str, Any], full_name: str) -> None: + # check for existence before + if branch["type"] == "branch": + self.module_interfaces.append(self.ModuleInterface(full_name=full_name, vss_branch=branch)) + # Create DataType for specific branch + self._create_datatype_for_branch(vss_branch=branch, namespace_with_name=full_name) + + # Recursion for deeper branches + for name, child in branch["children"].items(): + self._process_branch(child, f"{full_name}::{name}") + + def _create_datatype_for_branch(self, vss_branch: dict[str, Any], namespace_with_name: str) -> None: + """ + Creates a data type for a VSS (Vehicle Signal Specification) branch. + + Raises: + ValueError: If the 'type' in the vss_branch is not 'branch', or if required keys are missing or invalid. + """ + ns, dt_name = namespace_with_name.rsplit("::", 1) + + if "branch" != vss_branch["type"]: + raise ValueError("JSON does not contain a 'branch' type.") + result_type = vss_types.StructType(name=dt_name, namespace=ns) + + for subelement_name, data_type in vss_branch["children"].items(): + subelement = self._create_subelement(subelement_name, data_type, namespace_with_name) + result_type.subelements.append(subelement) + + self.datatypes_per_namespace[ns.lower()].add(result_type) + + def _create_subelement( + self, subelement_name: str, data_type: dict[str, Any], namespace_with_name: str + ) -> vss_types.BaseType: + """ + Creates a subelement based on its type and the associated data type. + """ + if "branch" == data_type["type"]: + return self._create_struct(subelement_name, namespace_with_name) + + if "allowed" in data_type and "string" == data_type["datatype"]: + return self._create_enum(subelement_name, data_type, namespace_with_name) + + if "[]" in data_type["datatype"]: + if "arraysize" in data_type: + return self._create_array(subelement_name, data_type) + return self._create_vector(subelement_name, data_type) + + return self._create_primitive_type(subelement_name, data_type) + + def _create_struct(self, subelement_name: str, namespace_with_name: str) -> vss_types.StructType: + """Handles struct creation.""" + return vss_types.StructType(name=subelement_name, namespace=namespace_with_name) + + def _create_enum( + self, subelement_name: str, data_type: dict[str, Any], namespace_with_name: str + ) -> vss_types.EnumType: + """Handles enum creation.""" + + enum_type = vss_types.EnumType(name=subelement_name, namespace=namespace_with_name.lower()) + allowed_values = data_type["allowed"] + + for idx, literal in enumerate(allowed_values, start=1): + enum_type.add_literal(label=literal, value=idx) + + self.datatypes_per_namespace[namespace_with_name.lower()].add(enum_type) + return enum_type + + def _create_array(self, subelement_name: str, data_type: dict[str, Any]) -> vss_types.ArrayType: + """Handles array creation.""" + primitive_type_name = data_type["datatype"][:-2] # Remove "[]" + subelement = vss_types.ArrayType( + name=subelement_name, type_name=primitive_type_name, array_size=data_type["arraysize"] + ) + + self.datatypes_per_namespace["vss"].add(subelement) + return subelement + + def _create_vector(self, subelement_name: str, data_type: dict[str, Any]) -> vss_types.VectorType: + """Handles vector creation.""" + primitive_type_name = data_type["datatype"][:-2] # Remove "[]" + subelement = vss_types.VectorType(name=subelement_name, type_name=primitive_type_name) + + self.datatypes_per_namespace["vss"].add(subelement) + return subelement + + def _create_primitive_type(self, subelement_name: str, data_type: dict[str, Any]) -> vss_types.PrimitiveType: + """Handles primitive type creation.""" + min_value = data_type.get("min") + max_value = data_type.get("max") + + if vss_types.is_numeric(datatype=data_type["datatype"]): + return vss_types.PrimitiveType( + name=subelement_name, + type_name=data_type["datatype"], + min_value=min_value, + max_value=max_value, + ) + + return vss_types.PrimitiveType(name=subelement_name, type_name=data_type["datatype"]) + + +# pylint: enable=too-few-public-methods diff --git a/VAF/src/vaf/vafvssimport/vss/vss_types.py b/VAF/src/vaf/vafvssimport/vss/vss_types.py new file mode 100644 index 0000000..feb1fc5 --- /dev/null +++ b/VAF/src/vaf/vafvssimport/vss/vss_types.py @@ -0,0 +1,233 @@ +"""Module containing the VSS data types""" + +from abc import ABC, abstractmethod +from types import NotImplementedType + +from vaf import vafmodel + +type_translation: dict[str, vafmodel.DataType] = { + "int8": vafmodel.DataType(Name=vafmodel.BaseType.INT8_T, Namespace=""), + "int16": vafmodel.DataType(Name=vafmodel.BaseType.INT16_T, Namespace=""), + "int32": vafmodel.DataType(Name=vafmodel.BaseType.INT32_T, Namespace=""), + "int64": vafmodel.DataType(Name=vafmodel.BaseType.INT64_T, Namespace=""), + "uint8": vafmodel.DataType(Name=vafmodel.BaseType.UINT8_T, Namespace=""), + "uint16": vafmodel.DataType(Name=vafmodel.BaseType.UINT16_T, Namespace=""), + "uint32": vafmodel.DataType(Name=vafmodel.BaseType.UINT32_T, Namespace=""), + "uint64": vafmodel.DataType(Name=vafmodel.BaseType.UINT64_T, Namespace=""), + "boolean": vafmodel.DataType(Name=vafmodel.BaseType.BOOL, Namespace=""), + "float": vafmodel.DataType(Name=vafmodel.BaseType.FLOAT, Namespace=""), + "double": vafmodel.DataType(Name=vafmodel.BaseType.DOUBLE, Namespace=""), + "string": vafmodel.DataType(Name="string", Namespace="vaf"), +} + + +def is_numeric(datatype: str) -> bool: + """Checks wether a VSS datatype is numeric + + Args: + datatype (str): The string representation of the datatype + + Returns: + bool: True if the datatype is numeric, false otherwise + """ + return datatype in [ + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "float", + "double", + ] + + +# pylint: disable=too-few-public-methods +class BaseType(ABC): + """Base class representing a VSS data type""" + + def __init__(self, name: str, namespace: str, type_name: str = "") -> None: + self.name: str = name + self.namespace: str = namespace.lower() + self.type: str = type_name + + @abstractmethod + def export(self) -> vafmodel.VafBaseModel: + """Exports VSS type to VAF model type + + Raises: + ValueError: Raised when a type cannot be exported + + Returns: + vafmodel.VafBaseModel: Parent class for the VAF model types + """ + + +class PrimitiveType(BaseType): + """Primitive types used in the VSS catalog""" + + def __init__( + self, name: str, type_name: str, min_value: float | None = None, max_value: float | None = None + ) -> None: + super().__init__(name, "", type_name) + self.min_value = min_value + self.max_value = max_value + + def export(self) -> vafmodel.VafBaseModel: + raise ValueError("PrimitiveType cannot be exported.") + + +class StructType(BaseType): + """Struct type used in the VSS catalog""" + + def __init__(self, name: str, namespace: str) -> None: + super().__init__(name, namespace) + self.subelements: list[BaseType] = [] + + def getTypeRefStr(self) -> str: + """Returns the VAF TypeRef for this StructType""" + return self.name + + def export(self) -> vafmodel.Struct: + """Exports VSS struct to VAF model struct + + Raises: + ValueError: Raised when a struct subelement is malformed in the VSS model + + Returns: + vafmodel.Struct: struct containing the VSS data + """ + subelements = [] + for subelement in self.subelements: + if isinstance(subelement, (StructType, EnumType)): + subelements.append( + vafmodel.SubElement( + Name=subelement.name, + TypeRef=vafmodel.DataType(Name=subelement.name, Namespace=subelement.namespace), + ) + ) + elif isinstance(subelement, (ArrayType, VectorType)): + subelements.append( + vafmodel.SubElement( + Name=subelement.name, + TypeRef=vafmodel.DataType(Name=subelement.getTypeRefStr(), Namespace="vss"), + ) + ) + elif isinstance(subelement, PrimitiveType): + type_ref = type_translation.get(subelement.type) + if type_ref is None: + raise ValueError(f"Unsupported type '{subelement.type}' for subelement '{subelement.name}'") + subelement_data = vafmodel.SubElement( + Name=subelement.name, + TypeRef=type_ref, + ) + + # Include min and max values if defined + if subelement.min_value is not None: + subelement_data.Min = subelement.min_value + if subelement.max_value is not None: + subelement_data.Max = subelement.max_value + + subelements.append(subelement_data) + else: + raise ValueError("Subelement has no valid Datatype set.") + return vafmodel.Struct(Name=self.name, Namespace=self.namespace, SubElements=subelements) + + +# pylint: enable=too-few-public-methods +class ArrayType(BaseType): + """Array type used in VSS catalog""" + + def __init__(self, name: str, type_name: str, array_size: int) -> None: + super().__init__(name, "vss", type_name) + self.array_size = array_size + + def __hash__(self) -> int: + return hash((self.type, self.array_size)) + + def __eq__(self, other: object) -> bool | NotImplementedType: + if not isinstance(other, ArrayType): + return NotImplemented + return self.type == other.type and self.array_size == other.array_size + + def getTypeRefStr(self) -> str: + """Returns the VAF TypeRef for this ArrayType""" + return f"{self.type}ArraySize{self.array_size}" + + def export(self) -> vafmodel.Array: + """Exports a fixed-size array to a VAF model array""" + array = vafmodel.Array( + Name=self.getTypeRefStr(), + Namespace=self.namespace, + TypeRef=type_translation[self.type], + Size=self.array_size, + ) + return array + + +class VectorType(BaseType): + """Vector type used in VSS catalog""" + + def __init__(self, name: str, type_name: str) -> None: + super().__init__(name, "vss", type_name) + + def __hash__(self) -> int: + return hash(self.type) + + def __eq__(self, other: object) -> bool | NotImplementedType: + if not isinstance(other, VectorType): + return NotImplemented + return self.type == other.type + + def getTypeRefStr(self) -> str: + """Returns the VAF TypeRef for this VectorType""" + return f"{self.type}Vector" + + def export(self) -> vafmodel.Vector: + """Exports a dynamic vector to a VAF model vector""" + vec = vafmodel.Vector(Name=self.getTypeRefStr(), Namespace=self.namespace, TypeRef=type_translation[self.type]) + return vec + + +class EnumType(BaseType): + """Enum type used in VSS catalog""" + + def __init__(self, name: str, namespace: str) -> None: + super().__init__(name, namespace) + self.literals: list[dict[str, int]] = [] + + def add_literal(self, label: str, value: int) -> None: + """ + Adds a literal to the enum. + + Args: + label (str): The label or name of the literal. + value (int): The numeric value associated with the literal. + """ + self.literals.append({"label": label, "value": value}) # type: ignore + + def export(self) -> vafmodel.VafEnum: + """ + Exports the EnumType to a VAF model EnumType. + + Raises: + ValueError: If the EnumType has no literals defined, a ValueError is raised. + """ + + if not self.literals: + print(f"[ERROR] EnumType '{self.name}' has no literals defined.") + raise ValueError(f"EnumType '{self.name}' cannot be exported without literals.") + + vaf_enum = vafmodel.VafEnum( + Name=self.name, + Namespace=self.namespace, + BaseType=vafmodel.DataType(Name="uint8_t", Namespace=""), + Literals=[ + vafmodel.EnumLiteral(Label=lit["label"], Value=lit["value"]) # type: ignore + for lit in self.literals + ], + ) + + return vaf_enum diff --git a/VAF/src/vaf/vafvssimport/vss_import.py b/VAF/src/vaf/vafvssimport/vss_import.py new file mode 100644 index 0000000..42768f5 --- /dev/null +++ b/VAF/src/vaf/vafvssimport/vss_import.py @@ -0,0 +1,45 @@ +"""VSS import.""" + +import json +from pathlib import Path + +from vaf.vafvssimport.vss.vss_model import VSS + + +def run_import(out_dir: str, input_file: str) -> bool: + """Runs JSON import for the VSS catalog + + Args: + out_dir (str): The output directory for the vss.json model. + input_file (str): JSON file to import. + + Raises: + OSError: Raised when files cannot be written + OSError: Raised when JSON file cannot be found + + Returns: + bool: Indicates whether the import succeeded + """ + + path_to_json = out_dir + "/vss-derived-model.json" + with open(path_to_json, "w+", encoding="utf-8") as json_file: + if not json_file.writable(): + raise OSError("Can not write to file " + str(path_to_json)) + + # Import type definitions from IDLs + if Path(input_file).is_file(): + with open(input_file, "r", encoding="utf-8") as f: + vss_json = json.load(f) + vss_model = VSS(vss_json) + + json_model = vss_model.export().model_dump_json( + indent=2, by_alias=True, exclude_unset=True, exclude_defaults=True + ) + json_file.write(json_model) + + else: + raise OSError("VSS JSON file " + str(input_file) + " not found") + + print(f"VSS Catalogue imported to '{Path(path_to_json).absolute()}'.") + + return True diff --git a/VAF/tests/Makefile b/VAF/tests/Makefile new file mode 100644 index 0000000..a60a76d --- /dev/null +++ b/VAF/tests/Makefile @@ -0,0 +1,68 @@ +# GENERAL UNIT TESTS + +UNIT_TESTS = cli_core vafgeneration vafmodel vafvssimport +define make-unit-test-target + test-unit-$(subst _,-,$1): install-all + pdm run pytest --junitxml=tests/unit/results/$1_report.xml \ + --cov-report=xml:tests/unit/results/$1_cov.xml \ + --cov=vaf.$1 \ + -vv tests/unit/$1/ $(PYTEST_FLAGS) + test-unit:: test-unit-$(subst _,-,$1) +endef + +$(foreach element,$(UNIT_TESTS),$(eval $(call make-unit-test-target,$(element)))) + +# vafpy UNIT TESTS + +## Example in test_example.py ## +test-unit-vafpy:: + pdm run pytest --junitxml=tests/unit/results/vafpy_report.xml \ + --cov-report=xml:tests/unit/results/vafpy_cov.xml \ + --cov=vaf.vafpy \ + tests/unit/vafpy/test_example.py $(PYTEST_FLAGS) + +## CaC UT: Run every test in test_cac.py separately so ModelRuntime() will be not polluted ## +CAC_UT = test_generate_vss_model \ + test_bug_ftaf_260_app_module \ + test_error_duplicate_executables \ + test_validation_unconnected_interfaces \ + test_validation_duplicate_datatype_interface \ + test_bug_remove_unused_artifacts \ + test_bug2_remove_unused_artifacts \ + test_consolidation_fixed_size_array_vector \ + test_consolidation_fixed_size_array_vector_reference \ + test_bug_cleanup_vss_model \ + test_bug_cleanup_ftaf_422 \ + test_validation_empty_interfaces \ + test_invalid_exec_periodic_tasks \ + test_bug_ftaf_553 + +define make-vafpy-cac-unit-test + vafpy-cac-unit-$(subst _,-,$1): install-all + pdm run pytest --junitxml=tests/unit/results/vafpy_report.xml \ + --cov-report=xml:tests/unit/results/vafpy_cov.xml \ + --cov=vaf.vafpy \ + tests/unit/vafpy/test_cac.py::$1 $(PYTEST_FLAGS) + test-unit-vafpy:: vafpy-cac-unit-$(subst _,-,$1) +endef +$(foreach element,$(CAC_UT),$(eval $(call make-vafpy-cac-unit-test,$(element)))) + +# update test unit with vafpy +test-unit:: test-unit-vafpy + +# COMPONENT TESTS + +COMP_TEST = cli +define make-component-test-target + test-component-$(subst _,-,$1): install-all + pdm run pytest --junitxml=tests/component/results/$1_report.xml \ + --cov-report=xml:tests/component/results/$1_cov.xml \ + --cov=vaf.$1 \ + -vv tests/component/$1/ $(PYTEST_FLAGS) + test-component:: test-component-$(subst _,-,$1) +endef + +$(foreach element,$(COMP_TEST),$(eval $(call make-component-test-target,$(element)))) + +# all TESTS +test: test-unit test-component diff --git a/VAF/tests/ModelValidation/.schema-infos.json b/VAF/tests/ModelValidation/.schema-infos.json new file mode 100644 index 0000000..1207bd8 --- /dev/null +++ b/VAF/tests/ModelValidation/.schema-infos.json @@ -0,0 +1,10 @@ +{ + "schemaInfos": [ + { + "name": "Vehicle Application Framework (VAF)", + "description": "VAF Configuration Schema", + "currentVersion": "0.6.0", + "schemaFile": "./vaf_schema.json" + } + ] +} diff --git a/VAF/tests/ModelValidation/test_schema_release_version.py b/VAF/tests/ModelValidation/test_schema_release_version.py new file mode 100644 index 0000000..d8c2feb --- /dev/null +++ b/VAF/tests/ModelValidation/test_schema_release_version.py @@ -0,0 +1,31 @@ +import json +import unittest +from pathlib import Path + +import vaf.vafmodel as vafmodel + + +class TestSchemReleaseVersion(unittest.TestCase): + SCHEMA_INFO = ".schema-infos.json" + + def test_schema_version_consistency(self) -> None: + """ + Test: Verify that the version referenced in `.schema-infos.json` + matches with the version in the model + """ + mmodel = vafmodel.vafmodel.MainModel() + version = mmodel.model_config.get("json_schema_extra")["version"] # type: ignore + # remove the trailing 'v' + version = str(version).replace("v", "") + + schema_info_file = Path(__file__).parent / self.SCHEMA_INFO + assert schema_info_file.is_file() + + with open(str(schema_info_file)) as fh: + schema_info = json.load(fh) + + assert version == schema_info["schemaInfos"][0]["currentVersion"] + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/ModelValidation/test_validate_to_vaf_schema.py b/VAF/tests/ModelValidation/test_validate_to_vaf_schema.py new file mode 100644 index 0000000..fb95bb9 --- /dev/null +++ b/VAF/tests/ModelValidation/test_validate_to_vaf_schema.py @@ -0,0 +1,52 @@ +import json +import sys +import unittest +from pathlib import Path + +import pydantic + +sys.path.append("../MetaModel") +import vaf.vafmodel as vafmodel + + +class TestValidateConfigToSchema(unittest.TestCase): + REPO_ROOT = Path(__file__).parent / "../../.." + + def test_platform_first_demo_config(self) -> None: + """ + Test: Checks all VAF Configuration files if they are according to the + schema. + - Search all model.json files. + - If the model file contains a $schema key which point to the + VAF schema that file is selected for the check. + """ + # glob all json files which might be a candidate for schema checking + model_candidates = Path(self.REPO_ROOT).rglob("model.json") + + # Remove all json files in the Concepts folder + filtered_candidates = [f for f in model_candidates if "Concepts" not in f.parts] + for f in filtered_candidates: + print(f) + + # Search for the "$schema": key in each found json file + for file in filtered_candidates: + plt_model = None + with open(file) as fh: + plt_model = json.load(fh) + + # file contains "$schema" key and ... + if "$schema" in plt_model: + # ... point to VAF schema + if plt_model["$schema"] is not None and Path(plt_model["$schema"]).name == "vaf_schema.json": + print(f"Checking {str(file)}") + + try: + vafmodel.load_json(file) + except pydantic.ValidationError: + self.fail("Configuration is not according to VAF schema") + else: + print(f"Skipping {str(file)}, as it doesn't contain a valid value for $schema") + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/__init__.py b/VAF/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/component/cli/test_main.py b/VAF/tests/component/cli/test_main.py new file mode 100644 index 0000000..a046ed8 --- /dev/null +++ b/VAF/tests/component/cli/test_main.py @@ -0,0 +1,79 @@ +""" +Test cli +""" + +# from unittest import mock + +from click.testing import CliRunner + +from vaf.__main__ import cli + + +class TestMain: + """ + TestMain class + """ + + def test_cli(self) -> None: + """test without subcommand. + + .. test:: unit test cli() + :id: TCASE-CLI_001 + :links: CLI-001 + + unit test for cli() + """ + runner = CliRunner() + result = runner.invoke(cli, []) + assert result.exit_code == 0, result.output + + def test_help(self) -> None: + """test help parameter. + + .. test:: unit test --help + :id: TCASE-CLI_002 + :links: CLI-001 + + unit test for --help + """ + runner = CliRunner() + result = runner.invoke(cli, ["--help"]) + assert result.exit_code == 0, result.output + + def test_version(self) -> None: + """test version subcommand. + + .. test:: unit test version() + :id: TCASE-CLI_003 + :links: CLI-001 + + unit test for version() + """ + runner = CliRunner() + result = runner.invoke(cli, ["--version"]) + assert result.exit_code == 0, result.output + # + # Test version with short option + result = runner.invoke(cli, ["-"]) + assert result.exit_code == 0, result.output + + # @mock.patch("vaf.example.greet") + # def test_execute(self, mocked_example_greet: mock.MagicMock) -> None: + # """test execute subcommand. + + # Args: + # mocked_example_greet (mock.MagicMock):mocked greet function + + # .. test:: Example unit test execute() + # :id: TCASE-CLI_004 + # :links: CLI-002 + + # Example unit test for execute() + # """ + # mocked_example_greet.return_value = "testing" + + # runner = CliRunner() + # result = runner.invoke(cli, ["execute"]) + + # assert result.exit_code == 0 + # mocked_example_greet.assert_called_with("default-name") diff --git a/VAF/tests/conftest.py b/VAF/tests/conftest.py new file mode 100644 index 0000000..62a2548 --- /dev/null +++ b/VAF/tests/conftest.py @@ -0,0 +1,18 @@ +# pylint: skip-file +# type: ignore + +import pytest + + +def pytest_addoption(parser): + parser.addoption("--runslow", action="store_true", default=False, help="run slow tests") + + +def pytest_collection_modifyitems(config, items): + if config.getoption("--runslow"): + # --runslow given in cli: do not skip slow tests + return + skip_slow = pytest.mark.skip(reason="needs --runslow option to run") + for item in items: + if "slow" in item.keywords: + item.add_marker(skip_slow) diff --git a/VAF/tests/unit/__init__.py b/VAF/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_263/model/vaf/model.json b/VAF/tests/unit/cli_core/test_data/ftaf_263/model/vaf/model.json new file mode 100644 index 0000000..6c1f484 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_263/model/vaf/model.json @@ -0,0 +1,254 @@ +{ + "$schema": "../../../VafEntrySchema.json", + "DataTypeDefinitions": + { + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "data_types", + "TypeRef": "data_types::MyStruct" + } + ], + "Structs": [ + { + "Name": "MyStruct", + "Namespace": "data_types", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + } + ] + } + ], + "Arrays": [ + { + "Name": "MyArray", + "Namespace": "data_types", + "TypeRef": "data_types::MyVector", + "Size": 100 + } + ], + "Strings": [ + { + "Name": "MyString", + "Namespace": "data_types" + } + ], + "TypeRefs": [ + { + "Name": "MyTypeRef", + "Namespace": "data_types", + "TypeRef": "data_types::MyString" + } + ], + "Enums": [ + { + "Name": "MyEnum", + "Namespace": "data_types", + "Literals": [ + { + "Label": "A", + "Value": 0 + }, + { + "Label": "B", + "Value": 1 + } + ] + } + ], + "Maps": [ + { + "Name": "MyMap", + "Namespace": "data_types", + "MapKeyTypeRef": "data_types::MyTypeRef", + "MapValueTypeRef": "data_types::MyEnum" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "MyInterface", + "Namespace": "interfaces", + "DataElements": [ + { + "Name": "a", + "TypeRef": "data_types::MyVector" + }, + { + "Name": "b", + "TypeRef": "data_types::MyStruct" + }, + { + "Name": "c", + "TypeRef": "data_types::MyMap" + } + ], + "Operations": [ + { + "Name": "MyOperation", + "Parameters": [ + { + "Name": "in1", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "in2", + "TypeRef": "data_types::MyEnum", + "Direction": "IN" + }, + { + "Name": "out", + "TypeRef": "data_types::MyString", + "Direction": "OUT" + }, + { + "Name": "inout", + "TypeRef": "data_types::MyVector", + "Direction": "INOUT" + } + ] + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModuleTwin", + "Namespace": "app_modules", + "ProvidedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ConsumedInterfaces": [ ], + "Tasks": [ + { + "Name": "Step", + "Period": "10ms", + "PreferredOffset": 0 + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + }, + { + "Name": "AppModuleTwin", + "Namespace": "app_modules", + "ProvidedInterfaces": [ ], + "ConsumedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "Tasks": [ + { + "Name": "Step", + "Period": "20ms" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + } + ], + "PlatformConsumerModules": [ + { + "Name": "ServiceConsumerSilkit", + "Namespace": "service_consumer_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_MyInterfaceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "ServiceProviderSilkit", + "Namespace": "service_provider_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_MyInterfaceProvider" + } + ], + "Executables": [ + { + "Name": "exe1", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "ServiceModuleVaf", + "Namespace": "service_modules", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "app_modules::AppModuleTwin", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_provider_modules::ServiceProviderSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "app_modules::AppModuleTwin", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_consumer_modules::ServiceConsumerSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms", + "Offset": 1 + } + ] + } + ] + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_MyInterfaceConsumer", + "ServiceInterfaceName": "Silkit_MyInterfaceConsumer", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_MyInterfaceProvider", + "ServiceInterfaceName": "Silkit_MyInterfaceProvider", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model.json b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model.json new file mode 100644 index 0000000..789b5f8 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model.json @@ -0,0 +1,112 @@ +{ + "$schema": "../../../MetaModel/VafEntrySchema.json", + "ModuleInterfaces": [ + { + "Name": "DataExchangeInterface", + "Namespace": "demo::interfaces", + "DataElements": [ + { + "Name": "MyValue", + "TypeRef": "uint32_t" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "demo", + "ProvidedInterfaces": [ + { + "InstanceName": "DataExchangeProvider", + "ModuleInterfaceRef": "demo::interfaces::DataExchangeInterface" + } + ], + "ConsumedInterfaces": [ + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true, + "InstallationPath": "app_module1" + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + }, + { + "Name": "AppModule2", + "Namespace": "demo", + "ProvidedInterfaces": [ + ], + "ConsumedInterfaces": [ + { + "InstanceName": "DataExchangeConsumer", + "ModuleInterfaceRef": "demo::interfaces::DataExchangeInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true, + "InstallationPath": "demo/app_module2" + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ], + "PlatformConsumerModules": [ + ], + "PlatformProviderModules": [ + ], + "Executables": [ + { + "Name": "DemoExecutable", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "DataExchangeInterfaceModule", + "Namespace": "application_communication", + "ModuleInterfaceRef": "demo::interfaces::DataExchangeInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "demo::AppModule1", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "DataExchangeProvider", + "ModuleRef": "application_communication::DataExchangeInterfaceModule" + } + ], + "TaskMapping": [ + { + "TaskName": "PeriodicTask", + "Offset": 0, + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "demo::AppModule2", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "DataExchangeConsumer", + "ModuleRef": "application_communication::DataExchangeInterfaceModule" + } + ], + "TaskMapping": [ + { + "TaskName": "PeriodicTask", + "Offset": 1, + "Budget": "1ms" + } + ] + } + ] + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module1.json b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module1.json new file mode 100644 index 0000000..8991593 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module1.json @@ -0,0 +1,16 @@ +{ + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "demo", + "ConsumedInterfaces": [ ], + "ProvidedInterfaces": [ ], + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module2.json b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module2.json new file mode 100644 index 0000000..066122d --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_305/model/vaf/model_module2.json @@ -0,0 +1,16 @@ +{ +"ApplicationModules": [ + { + "Name": "AppModule2", + "Namespace": "demo", + "ConsumedInterfaces": [], + "ProvidedInterfaces": [], + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_460/goal-model.json b/VAF/tests/unit/cli_core/test_data/ftaf_460/goal-model.json new file mode 100644 index 0000000..52953d3 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_460/goal-model.json @@ -0,0 +1,112 @@ +{ + "DataTypeDefinitions": { + "Strings": [ + { + "Name": "ObjectDetectionMode", + "Namespace": "adas::interfaces" + } + ], + "Structs": [ + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + }, + { + "Name": "status", + "TypeRef": "adas::interfaces::ObjectDetectionStatus" + }, + { + "Name": "YellowWorld", + "TypeRef": "float" + }, + { + "Name": "Camelot", + "TypeRef": "adas::interfaces::ObjectDetectionMode" + } + ] + }, + { + "Name": "ObjectDetectionStatus", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "Active", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "adas::interfaces::ObjectDetectionMode" + } + ] + } + ], + "Vectors": [ + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "ObjectDetectionListInterface", + "Namespace": "adas::interfaces", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + }, + { + "Name": "OriginalCola", + "Namespace": "Soft::Drinks::Aint::Beer", + "DataElements": [ + { + "Name": "BadGuysDetector", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SchocaCola", + "Namespace": "Soft::Drinks::Aint::Beer", + "ConsumedInterfaces": [ + { + "InstanceName": "OriginalCola", + "ModuleInterfaceRef": "Soft::Drinks::Aint::Beer::OriginalCola" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ColaZeerow", + "ModuleInterfaceRef": "adas::interfaces::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_460/interfaces.py b/VAF/tests/unit/cli_core/test_data/ftaf_460/interfaces.py new file mode 100644 index 0000000..1ddf4cd --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_460/interfaces.py @@ -0,0 +1,28 @@ +from vaf import BaseTypes, vafpy + + +# Define the required datatypes +od_struct = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +od_struct.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector( + name="ObjectDetectionList", + namespace="adas::interfaces", + datatype=od_struct, +) + +# Define the interface +od_interface = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", + namespace="adas::interfaces", +) +od_interface.add_data_element(name="object_detection_list", datatype=od_list) + +# Define datatype as interface (importables) +od_mode = vafpy.datatypes.String(name="ObjectDetectionMode", namespace="adas::interfaces") + +od_status = vafpy.datatypes.Struct(name="ObjectDetectionStatus", namespace="adas::interfaces") +od_status.add_subelement(name="Active", datatype=BaseTypes.BOOL) +od_status.add_subelement(name="Mode", datatype=od_mode) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_460/schoca_cola.py b/VAF/tests/unit/cli_core/test_data/ftaf_460/schoca_cola.py new file mode 100644 index 0000000..a4b8ecc --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_460/schoca_cola.py @@ -0,0 +1,26 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes, vafmodel + +# Import the CaC support from platform derive or interface import +from .imported_models import interfaces + +schoca_cola = vafpy.ApplicationModule( + name="SchocaCola", namespace="Soft::Drinks::Aint::Beer" +) + +original = vafpy.ModuleInterface( + name="OriginalCola", namespace="Soft::Drinks::Aint::Beer", +) +interfaces.Adas.Interfaces.object_detection.add_subelement("status", interfaces.Adas.Interfaces.object_detection_status) +interfaces.Adas.Interfaces.object_detection.add_subelement("YellowWorld", BaseTypes.FLOAT) +interfaces.Adas.Interfaces.object_detection.SubElements.append(vafmodel.SubElement(Name="Camelot", TypeRef=vafmodel.DataType(Name="ObjectDetectionMode", Namespace="adas::interfaces"))) + +original.add_data_element("BadGuysDetector", interfaces.Adas.Interfaces.object_detection) +schoca_cola.add_consumed_interface("OriginalCola", original) + +# Add consumed and provided interfaces using the ApplicationModule API +schoca_cola.add_provided_interface("ColaZeerow", interfaces.Adas.Interfaces.object_detection_list_interface) + + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +schoca_cola.add_task(task=periodic_task) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/fake.py b/VAF/tests/unit/cli_core/test_data/ftaf_467/fake.py new file mode 100644 index 0000000..c707899 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/fake.py @@ -0,0 +1,8 @@ +from datetime import timedelta + +from .imported_models import interfaces +from vaf import vafpy + +fake = vafpy.ApplicationModule(name="Fake", namespace="Snuggle") +fake.add_provided_interface(instance_name="KentuckyFriedChicken", interface=interfaces.Adas.Interfaces.object_detection_list_interface) +fake.add_task(vafpy.Task(name="SweetHomeAlabama", period=timedelta(milliseconds=67))) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/goal-model.json b/VAF/tests/unit/cli_core/test_data/ftaf_467/goal-model.json new file mode 100644 index 0000000..a2e8ec8 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/goal-model.json @@ -0,0 +1,138 @@ +{ + "DataTypeDefinitions": { + "Structs": [ + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "ObjectDetectionListInterface", + "Namespace": "adas::interfaces", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "Mockery", + "Namespace": "Snuggle", + "ConsumedInterfaces": [ + { + "InstanceName": "McDonalds", + "ModuleInterfaceRef": "adas::interfaces::ObjectDetectionListInterface" + } + ], + "ProvidedInterfaces": [ ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true, + "InstallationPath": "mockery" + }, + "Tasks": [ + { + "Name": "California", + "Period": "121ms" + }, + { + "Name": "Yorkies", + "Period": "322ms" + } + ] + }, + { + "Name": "Fake", + "Namespace": "Snuggle", + "ConsumedInterfaces": [ ], + "ProvidedInterfaces": [ + { + "InstanceName": "KentuckyFriedChicken", + "ModuleInterfaceRef": "adas::interfaces::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true, + "InstallationPath": "fake" + }, + "Tasks": [ + { + "Name": "SweetHomeAlabama", + "Period": "67ms" + } + ] + } + ], + "Executables": [ + { + "Name": "Pulp-A-Tine", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "ObjectDetectionListInterfaceModule", + "Namespace": "application_communication", + "ModuleInterfaceRef": "adas::interfaces::ObjectDetectionListInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "Snuggle::Fake", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "KentuckyFriedChicken", + "ModuleRef": "application_communication::ObjectDetectionListInterfaceModule" + } + ], + "TaskMapping": [ + { + "TaskName": "SweetHomeAlabama", + "Offset": 0, + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "Snuggle::Mockery", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "McDonalds", + "ModuleRef": "application_communication::ObjectDetectionListInterfaceModule" + } + ], + "TaskMapping": [ + { + "TaskName": "California", + "Offset": 1, + "Budget": "1ms" + } + ] + } + ] + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/interfaces.py b/VAF/tests/unit/cli_core/test_data/ftaf_467/interfaces.py new file mode 100644 index 0000000..ebb9b14 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/interfaces.py @@ -0,0 +1,27 @@ +from vaf import BaseTypes, vafpy + +# Define the required datatypes +od_struct = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +od_struct.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +od_struct.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector( + name="ObjectDetectionList", + namespace="adas::interfaces", + datatype=od_struct, +) + +# Define the interface +od_interface = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", + namespace="adas::interfaces", +) +od_interface.add_data_element(name="object_detection_list", datatype=od_list) + +# Define datatype as interface (importables) +od_mode = vafpy.datatypes.String(name="ObjectDetectionMode", namespace="adas::interfaces") + +od_status = vafpy.datatypes.Struct(name="ObjectDetectionStatus", namespace="adas::interfaces") +od_status.add_subelement(name="Active", datatype=BaseTypes.BOOL) +od_status.add_subelement(name="Mode", datatype=od_mode) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/invisible.py b/VAF/tests/unit/cli_core/test_data/ftaf_467/invisible.py new file mode 100644 index 0000000..9068d85 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/invisible.py @@ -0,0 +1,10 @@ +from datetime import timedelta + +from .imported_models import interfaces +from vaf import vafpy + +invisible = vafpy.ApplicationModule(name="Invisible", namespace="Snuggle") +invisible.add_provided_interface(instance_name="NakedStar", interface=interfaces.Adas.Interfaces.object_detection_list_interface) +invisible.add_consumed_interface(instance_name="AureliaBoriolis", interface=interfaces.Adas.Interfaces.object_detection_list_interface) +invisible.add_task(vafpy.Task(name="AllMyExes", period=timedelta(milliseconds=45))) +invisible.add_task(vafpy.Task(name="LivesInTexas", period=timedelta(milliseconds=111))) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/mockery.py b/VAF/tests/unit/cli_core/test_data/ftaf_467/mockery.py new file mode 100644 index 0000000..c2b5ff5 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/mockery.py @@ -0,0 +1,9 @@ +from datetime import timedelta + +from .imported_models import interfaces +from vaf import vafpy + +mockery = vafpy.ApplicationModule(name="Mockery", namespace="Snuggle") +mockery.add_consumed_interface(instance_name="McDonalds", interface=interfaces.Adas.Interfaces.object_detection_list_interface) +mockery.add_task(vafpy.Task(name="California", period=timedelta(milliseconds=121))) +mockery.add_task(vafpy.Task(name="Yorkies", period=timedelta(milliseconds=322))) diff --git a/VAF/tests/unit/cli_core/test_data/ftaf_467/model.py b/VAF/tests/unit/cli_core/test_data/ftaf_467/model.py new file mode 100644 index 0000000..09c39d7 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/ftaf_467/model.py @@ -0,0 +1,28 @@ +import os +from datetime import timedelta +from pathlib import Path + +from vaf.cli_core.common.utils import ProjectType + +os.environ["IMPORT_APPLICATION_MODULES"] = "import" + +from .application_modules import * +from vaf import * + +# TODO: Create executable instances (or configure existing ones from the platform configuration) +executable = Executable("Pulp-A-Tine", timedelta(milliseconds=10)) + +# TODO: Add application modules to executable instances +executable.add_application_module(Fake, [(Instances.Fake.Tasks.SweetHomeAlabama, timedelta(milliseconds=1), 0)]) +executable.add_application_module(Mockery, [(Instances.Mockery.Tasks.California, timedelta(milliseconds=1), 1)]) + +# TODO: Wire the internal application module instances +executable.connect_interfaces(Fake, Instances.Fake.ProvidedInterfaces.KentuckyFriedChicken, + Mockery, Instances.Mockery.ConsumedInterfaces.McDonalds) +def export_model(): + script_path = Path(__file__).resolve().parent + save_main_model(script_path / "model.json", project_type=ProjectType.INTEGRATION) + + +if __name__ == "__main__": + export_model() diff --git a/VAF/tests/unit/cli_core/test_data/minimal_vss.json b/VAF/tests/unit/cli_core/test_data/minimal_vss.json new file mode 100644 index 0000000..65636fe --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/minimal_vss.json @@ -0,0 +1,7 @@ +{ + "Vehicle": { + "children": { }, + "description": "High-level vehicle data.", + "type": "branch" + } +} diff --git a/VAF/tests/unit/cli_core/test_data/mock_prj/model/app/model.json b/VAF/tests/unit/cli_core/test_data/mock_prj/model/app/model.json new file mode 100644 index 0000000..8fff4ca --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/mock_prj/model/app/model.json @@ -0,0 +1,144 @@ +{ + "$schema": "../../../VafEntrySchema.json", + "DataTypeDefinitions": + { + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "data_types", + "TypeRef": "data_types::MyStruct" + } + ], + "Structs": [ + { + "Name": "MyStruct", + "Namespace": "data_types", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + } + ] + } + ], + "Arrays": [ + { + "Name": "MyArray", + "Namespace": "data_types", + "TypeRef": "data_types::MyVector", + "Size": 100 + } + ], + "Strings": [ + { + "Name": "MyString", + "Namespace": "data_types" + } + ], + "TypeRefs": [ + { + "Name": "MyTypeRef", + "Namespace": "data_types", + "TypeRef": "data_types::MyString" + } + ], + "Enums": [ + { + "Name": "MyEnum", + "Namespace": "data_types", + "Literals": [ + { + "Label": "A", + "Value": 0 + }, + { + "Label": "B", + "Value": 1 + } + ] + } + ], + "Maps": [ + { + "Name": "MyMap", + "Namespace": "data_types", + "MapKeyTypeRef": "data_types::MyTypeRef", + "MapValueTypeRef": "data_types::MyEnum" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "MyInterface", + "Namespace": "interfaces", + "DataElements": [ + { + "Name": "a", + "TypeRef": "data_types::MyVector" + }, + { + "Name": "b", + "TypeRef": "data_types::MyStruct" + }, + { + "Name": "c", + "TypeRef": "data_types::MyMap" + } + ], + "Operations": [ + { + "Name": "MyOperation", + "Parameters": [ + { + "Name": "in1", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "in2", + "TypeRef": "data_types::MyEnum", + "Direction": "IN" + }, + { + "Name": "out", + "TypeRef": "data_types::MyString", + "Direction": "OUT" + }, + { + "Name": "inout", + "TypeRef": "data_types::MyVector", + "Direction": "INOUT" + } + ] + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "app_modules", + "ProvidedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ConsumedInterfaces": [ ], + "Tasks": [ + { + "Name": "Step", + "Period": "10ms", + "PreferredOffset": 0 + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + } + ] +} diff --git a/VAF/tests/unit/cli_core/test_data/mock_prj/model/vaf/model.json b/VAF/tests/unit/cli_core/test_data/mock_prj/model/vaf/model.json new file mode 100644 index 0000000..46e6ea9 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_data/mock_prj/model/vaf/model.json @@ -0,0 +1,254 @@ +{ + "$schema": "../../../VafEntrySchema.json", + "DataTypeDefinitions": + { + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "data_types", + "TypeRef": "data_types::MyStruct" + } + ], + "Structs": [ + { + "Name": "MyStruct", + "Namespace": "data_types", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + } + ] + } + ], + "Arrays": [ + { + "Name": "MyArray", + "Namespace": "data_types", + "TypeRef": "data_types::MyVector", + "Size": 100 + } + ], + "Strings": [ + { + "Name": "MyString", + "Namespace": "data_types" + } + ], + "TypeRefs": [ + { + "Name": "MyTypeRef", + "Namespace": "data_types", + "TypeRef": "data_types::MyString" + } + ], + "Enums": [ + { + "Name": "MyEnum", + "Namespace": "data_types", + "Literals": [ + { + "Label": "A", + "Value": 0 + }, + { + "Label": "B", + "Value": 1 + } + ] + } + ], + "Maps": [ + { + "Name": "MyMap", + "Namespace": "data_types", + "MapKeyTypeRef": "data_types::MyTypeRef", + "MapValueTypeRef": "data_types::MyEnum" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "MyInterface", + "Namespace": "interfaces", + "DataElements": [ + { + "Name": "a", + "TypeRef": "data_types::MyVector" + }, + { + "Name": "b", + "TypeRef": "data_types::MyStruct" + }, + { + "Name": "c", + "TypeRef": "data_types::MyMap" + } + ], + "Operations": [ + { + "Name": "MyOperation", + "Parameters": [ + { + "Name": "in1", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "in2", + "TypeRef": "data_types::MyEnum", + "Direction": "IN" + }, + { + "Name": "out", + "TypeRef": "data_types::MyString", + "Direction": "OUT" + }, + { + "Name": "inout", + "TypeRef": "data_types::MyVector", + "Direction": "INOUT" + } + ] + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "app_modules", + "ProvidedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ConsumedInterfaces": [ ], + "Tasks": [ + { + "Name": "Step", + "Period": "10ms", + "PreferredOffset": 0 + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + }, + { + "Name": "AppModule2", + "Namespace": "app_modules", + "ProvidedInterfaces": [ ], + "ConsumedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "Tasks": [ + { + "Name": "Step", + "Period": "20ms" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + } + ], + "PlatformConsumerModules": [ + { + "Name": "ServiceConsumerSilkit", + "Namespace": "service_consumer_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_MyInterfaceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "ServiceProviderSilkit", + "Namespace": "service_provider_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_MyInterfaceProvider" + } + ], + "Executables": [ + { + "Name": "exe1", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "ServiceModuleVaf", + "Namespace": "service_modules", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "app_modules::AppModule1", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_provider_modules::ServiceProviderSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "app_modules::AppModule2", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_consumer_modules::ServiceConsumerSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms", + "Offset": 1 + } + ] + } + ] + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_MyInterfaceConsumer", + "ServiceInterfaceName": "Silkit_MyInterfaceConsumer", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_MyInterfaceProvider", + "ServiceInterfaceName": "Silkit_MyInterfaceProvider", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/cli_core/test_make_cmd.py b/VAF/tests/unit/cli_core/test_make_cmd.py new file mode 100644 index 0000000..485fad4 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_make_cmd.py @@ -0,0 +1,132 @@ +""" +example tests +""" + +# mypy: disable-error-code="no-untyped-def" + +import os +from contextlib import contextmanager +from pathlib import Path + +import pytest + +from vaf.cli_core.bootstrap import project_init_cmd as project_init +from vaf.cli_core.main import make_cmd as makecmd +from vaf.cli_core.main import project_cmd as project + + +@contextmanager +def change_dir(dir: Path): + current_dir = Path.cwd().as_posix() + os.chdir(dir) + try: + yield + finally: + os.chdir(current_dir) + + +@pytest.fixture(scope="session") +def shared_tmp_path(tmp_path_factory): + return tmp_path_factory.mktemp("test") + + +class TestMakeCmd: # pylint: disable=too-few-public-methods + """ + Class docstrings are also parsed + """ + + proj_name = "TestProject" + proj_parent_dir = Path(__file__).parent / "tmp" + build_dir = "build" + + @pytest.mark.dependency() + def test_make_preset_default(self, shared_tmp_path) -> None: + """ + .. test:: Tests the Preset command. + """ + pj_init = project_init.ProjectInitCmd() + pj_init.integration_project_init(str(self.proj_name), str(shared_tmp_path)) + proj_dir = shared_tmp_path / self.proj_name + assert Path(proj_dir).is_dir() # make sure we have a generated project + current_dir = Path.cwd().as_posix() + make = makecmd.MakeCmd() + make.preset(self.build_dir, "gcc12__x86_64-pc-linux-elf", "Release", "", str(current_dir / proj_dir)) + assert (proj_dir / self.build_dir).is_dir() # make sure we have a generated build folder + + # @pytest.mark.slow + @pytest.mark.dependency(depends=["TestMakeCmd::test_make_preset_default"]) + def test_make_application_modules_default(self, shared_tmp_path) -> None: + """ + .. test:: Tests the create_appmodule command. Depends on preset successful + """ + proj_dir = shared_tmp_path / self.proj_name + pj = project.ProjectCmd() + pj.create_appmodule( + name="AppModule1", + namespace="demo", + project_dir=proj_dir.as_posix(), + rel_pre_path=".", + model_dir="model/vaf", + ) + pj.create_appmodule( + name="AppModule2", + namespace="demo", + project_dir=proj_dir.as_posix(), + rel_pre_path="demo", + model_dir="model/vaf", + ) + pj = project.ProjectCmd() + test_dir = Path(__file__).parent + pj.generate_app_module( + input_file=str(test_dir / "test_data/ftaf_305/model/vaf/model_module1.json"), + project_dir=proj_dir.as_posix() + "/src/application_modules/app_module1", + ) + pj.generate_app_module( + input_file=str(test_dir / "test_data/ftaf_305/model/vaf/model_module2.json"), + project_dir=proj_dir.as_posix() + "/src/application_modules/demo/app_module2", + ) + + # @pytest.mark.slow + @pytest.mark.dependency(depends=["TestMakeCmd::test_make_application_modules_default"]) + def test_make_build_default(self, shared_tmp_path) -> None: + """ + .. test:: Tests the build command. Depends on create_appmodule successful + """ + proj_dir = shared_tmp_path / self.proj_name + pj = project.ProjectCmd() + test_dir = Path(__file__).parent + + pj.generate_integration( + input_file=str(test_dir / "test_data/ftaf_305/model/vaf/model.json"), + project_dir=proj_dir, + mode="PRJ", + ) + + make = makecmd.MakeCmd() + with change_dir(proj_dir): + make.build("conan-release") + assert ( + proj_dir / self.build_dir / "Release/bin/DemoExecutable/bin/DemoExecutable" + ).is_file() # make sure we have a built executable + + @pytest.mark.dependency(depends=["TestMakeCmd::test_make_build_default"]) + def test_make_install_default(self, shared_tmp_path) -> None: + """ + .. test:: Tests the install command. Depends on build successful + """ + proj_dir = shared_tmp_path / self.proj_name + make = makecmd.MakeCmd() + with change_dir(proj_dir): + make.install("conan-release") + assert (proj_dir / self.build_dir / "Release/install/opt/DemoExecutable/bin/DemoExecutable").is_file() + + @pytest.mark.dependency(depends=["TestMakeCmd::test_make_install_default"]) + def test_make_clean_default(self, shared_tmp_path) -> None: + """ + .. test:: Tests the build command. Depends on preset successful + """ + proj_dir = shared_tmp_path / self.proj_name + make = makecmd.MakeCmd() + with change_dir(proj_dir): + make.clean("conan-release") + assert not (proj_dir / self.build_dir / "Release/bin/DemoExecutable/bin/DemoExecutable").is_file() diff --git a/VAF/tests/unit/cli_core/test_model_cmd.py b/VAF/tests/unit/cli_core/test_model_cmd.py new file mode 100644 index 0000000..9e0a0ca --- /dev/null +++ b/VAF/tests/unit/cli_core/test_model_cmd.py @@ -0,0 +1,184 @@ +""" +example tests +""" + +import sys +from pathlib import Path +from shutil import copyfile +from types import ModuleType +from typing import Any, Dict, List + +import pytest +from test_project_cmd import import_by_file_name + +from vaf.cli_core.bootstrap import project_init_cmd +from vaf.cli_core.common.utils import ProjectType +from vaf.cli_core.main import model_cmd as uut +from vaf.cli_core.main import project_cmd +from vaf.vafmodel import load_json + +# mypy: disable-error-code="no-untyped-def" + + +# needed otherwise importlib error in CI +def mock_importlib_import_module(name: str) -> ModuleType: + """importlib.import_module somehow fails in pytest and can't find the modules""" + file_dir, file_name = name.split(".") + module: ModuleType = import_by_file_name(f"{sys.path[-1]}/{file_dir}/{file_name}.py") + + return module + + +class TestModelCmd: # pylint: disable=too-few-public-methods + """ + Class docstrings are also parsed + """ + + def assert_two_dictionary_identical(self, dict_1: Dict[str, Any], dict_2) -> None: + """Assert that two dictionaries are identical by checking contents and ignore orders""" + + def __sort_dictionary_by_key(dict_obj: Dict[str, Any]) -> Dict[str, Any]: + return {key: dict_obj[key] for key in sorted(list(dict_obj.keys()))} + + # first assert the keys + assert sorted(list(dict_1.keys())) == sorted(list(dict_2.keys())) + # assert values by ignoring orders + for key, values in dict_1.items(): + if isinstance(values, Dict): + assert __sort_dictionary_by_key(dict_1) == __sort_dictionary_by_key(dict_2) + elif isinstance(values, List): + assert sorted(values) == sorted(dict_2[key]) + + def test_import_vss(self, tmp_path) -> None: + """Test generate_vss function""" + model_cmd = uut.ModelCmd() + model_dir = tmp_path / "tmp_out" + model_dir.mkdir(exist_ok=True) + input_json = Path(__file__).parent / "test_data/minimal_vss.json" + model_cmd.import_vss(str(input_json), str(model_dir)) + assert (model_dir / "vss.py").is_file() + + # @mock.patch("importlib.import_module", side_effect=mock_importlib_import_module) + def test_ftaf_467( + self, + # mocked_importlib: mock.MagicMock, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + recwarn: pytest.WarningsRecorder, + ) -> None: + """FTAF-467: Handling of unconnected app-modules in integration project""" + test_data_dir = Path(__file__).parent / "test_data/ftaf_467" + + # create project + prj_setter = project_cmd.ProjectCmd() + model_cmd = uut.ModelCmd() + + prj_init_setter = project_init_cmd.ProjectInitCmd() + + # init interface project + prj_init_setter.interface_project_init("Interfaces", tmp_path.as_posix()) + # build interface project & appmodule pat + interface_prj_path = tmp_path / "Interfaces" + copyfile(test_data_dir / "interfaces.py", interface_prj_path / "interfaces.py") + model_cmd.generate(ProjectType.INTERFACE, str(interface_prj_path), "ALL") + + # init project + prj_init_setter.integration_project_init("SweetHomeAlabama", tmp_path.as_posix()) + prj_path = tmp_path / "SweetHomeAlabama" + + # initiates all app module projects + for app_module_name in ["Fake", "Mockery", "Invisible"]: + # add app-module + prj_setter.create_appmodule("Snuggle", app_module_name, str(prj_path), ".", "model/vaf") + + # copy app-module model + path_to_app_module_prj_model_dir = prj_path / "src/application_modules" / app_module_name.lower() / "model" + + model_cmd.import_model( + str(interface_prj_path / "export/Interfaces.json"), path_to_app_module_prj_model_dir.as_posix(), "copy" + ) + + for file_name in [f"{app_module_name.lower()}.py"]: + copyfile(test_data_dir / file_name, path_to_app_module_prj_model_dir / file_name) + + # add appmodule imported but not used + # init app-module and then import them to integration project + prj_init_setter.app_module_project_init("Snuggle", "BlueSparkle", str(tmp_path / "SesameStreet")) + prj_setter.import_appmodule(str(tmp_path / "SesameStreet/BlueSparkle"), str(prj_path), ".", "model/vaf") + + # copy model.py + copyfile(test_data_dir / "model.py", prj_path / "model/vaf/model.py") + + monkeypatch.chdir(prj_path) + + model_cmd.generate(ProjectType.INTEGRATION, "model/vaf", "ALL") + + # assert only connected app modules are used in model.json + goal_model = load_json(str(test_data_dir / "goal-model.json")) + generated_model = load_json(str(prj_path / "model/vaf/model.json")) + # assert set fields + assert goal_model.model_fields_set == generated_model.model_fields_set + for attr in goal_model.model_fields_set: + goal_attr_values = getattr(goal_model, attr) + generated_attr_values = getattr(generated_model, attr) + # Flaky DataTypeDefinitions: order doesn't matter + if attr == "DataTypeDefinitions": + for field in generated_attr_values.model_fields_set: + assert all( + generated_data in getattr(goal_attr_values, field) + for generated_data in getattr(generated_attr_values, field) + ), f"{field} is not identical!" + else: + assert len(goal_attr_values) == len(generated_attr_values), f"{attr} is not identical!" + for value in generated_attr_values: + assert value in goal_attr_values, f"{value} not in {goal_attr_values}" + + assert len(recwarn) == 1 + assert sorted(str(recwarn[0].message).split("\n")) == [ + f"App Module '{unconnected}' is defined, but not connected in any Executable" + for unconnected in ["Snuggle::BlueSparkle", "Snuggle::Invisible"] + ] + + def test_ftaf_460( + self, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + recwarn: pytest.WarningsRecorder, + ) -> None: + """FTAF-460: Provide datatypes as CaC in Interface Projects""" + test_data_dir = Path(__file__).parent / "test_data/ftaf_460" + + # create project + prj_init_setter = project_init_cmd.ProjectInitCmd() + model_cmd = uut.ModelCmd() + + # init interface project + prj_init_setter.interface_project_init("Interfaces", tmp_path.as_posix()) + # init app module project + prj_init_setter.app_module_project_init("Soft::Drinks::Aint::Beer", "SchocaCola", str(tmp_path)) + + # build interface project & appmodule pat + interface_prj_path = tmp_path / "Interfaces" + for filename in ["interfaces.py"]: + copyfile(test_data_dir / filename, interface_prj_path / filename) + model_cmd.generate(ProjectType.INTERFACE, str(interface_prj_path), "ALL") + + # build app_module project + app_module_path = tmp_path / "SchocaCola" + for filename in ["schoca_cola.py"]: + copyfile(test_data_dir / filename, app_module_path / "model" / filename) + model_cmd.import_model( + str(interface_prj_path / "export/Interfaces.json"), str(app_module_path / "model"), "copy" + ) + model_cmd.generate(ProjectType.APP_MODULE, str(app_module_path / "model"), "ALL") + + # DISABLED -> enable if the generated codes need to be assured + # run project generate app module + # dont forget to add pytest.mark.slow if enabled + # # monkeypatch.chdir(app_module_path) + # # prj_setter.generate_app_module("model/model.json", ".", "STD") + + # assert only connected app modules are used in model.json + goal_model = load_json(str(test_data_dir / "goal-model.json")) + generated_model = load_json(str(app_module_path / "model/model.json")) + assert goal_model == generated_model diff --git a/VAF/tests/unit/cli_core/test_project_cmd.py b/VAF/tests/unit/cli_core/test_project_cmd.py new file mode 100644 index 0000000..80cb1d2 --- /dev/null +++ b/VAF/tests/unit/cli_core/test_project_cmd.py @@ -0,0 +1,230 @@ +""" +example tests +""" + +import importlib +import inspect +import os +import sys +from pathlib import Path +from types import ModuleType +from unittest import mock + +import pytest + +from vaf.cli_core.bootstrap import project_init_cmd +from vaf.cli_core.main import project_cmd +from vaf.vafpy.elements import ApplicationModule + + +def import_by_file_name(file_path: str) -> ModuleType: + """importlib.import_module somehow fails in pytest and can't find the modules""" + file_name = file_path.rsplit("/")[1].rstrip(".py") + spec = importlib.util.spec_from_file_location(file_name, file_path) + if spec: + module = importlib.util.module_from_spec(spec) + if module and spec.loader: + sys.modules[file_name] = module + spec.loader.exec_module(module) + + if not module: + raise RuntimeError(f"Failed to import module in {file_path}") + + return module + + +def mock_importlib_import_module(name: str) -> ModuleType: + """importlib.import_module somehow fails in CI pytest and can't find the modules""" + module = None + if name in [ + f"application_modules.import_{mocked_module}" + for mocked_module in ["gerberit", "instances", "wakanda", "saufleisch"] + ]: + file_dir, file_name = name.split(".") + module = import_by_file_name(f"{sys.path[-1]}/{file_dir}/{file_name}.py") + if module is None: + module = importlib.import_module(name) + return module + + +class TestProjectCmd: # pylint: disable=too-few-public-methods + """ + Class docstrings are also parsed + """ + + def test_project_init_default(self, tmp_path: Path) -> None: + """ + .. test:: First unit test greet() + :id: TCASE-INTEG_001 + :links: CREQ-001 + + First unit test for greet() + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_init_cmd.ProjectInitCmd() + pj.integration_project_init("UutestProject", str(tmp_path)) + assert (tmp_path / "UutestProject").is_dir() + + def test_project_init_non_existing(self, tmp_path: Path) -> None: + """ + .. test:: Test the reporting of an error if the passed template is not + existing. + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_init_cmd.ProjectInitCmd() + with pytest.raises(Exception): + pj.integration_project_init("UutestProject", str(tmp_path), "not-existing") + + def test_missing_vafconfig(self, tmp_path: Path) -> None: + """ + Test verifying the existence of VAF_CFG_FILE + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_init_cmd.ProjectInitCmd() + + pwd = Path(__file__).resolve().parent + broken_template = pwd / "data" / "broken_templates" / "missing_vafconfig" + with pytest.raises(Exception): + pj.integration_project_init("UutestProject2", str(tmp_path), str(broken_template)) + + @pytest.mark.slow + def test_generate_integration(self, tmp_path: Path) -> None: + """FTAF-263: Identical Name of Application Modules are not allowed + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_cmd.ProjectCmd() + pj.generate_integration( + str(Path(__file__).parent / "test_data/mock_prj/model/vaf/model.json"), + str(tmp_path), + "PRJ", + ) + + @pytest.mark.slow + def test_generate_app_module(self, tmp_path: Path) -> None: + """FTAF-263: Identical Name of Application Modules are not allowed""" + pj = project_cmd.ProjectCmd() + pj.generate_app_module( + str(Path(__file__).parent / "test_data/mock_prj/model/app/model.json"), + str(tmp_path), + ) + + def test_generate_app_modules_identical_name(self, tmp_path: Path) -> None: + """FTAF-263: Identical Name of Application Modules are not allowed + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_cmd.ProjectCmd() + with pytest.raises(RuntimeError) as err: + pj.generate_integration( + str(Path(__file__).parent / "test_data/ftaf_263/model/vaf/model.json"), + str(tmp_path), + "PRJ", + ) + + assert ( + " ".join( + [ + "ERROR: There are 2 application modules", + "with name AppModuleTwin and install path ''.", + "Application Module must have a unique pair of name and install path!", + ] + ) + in err.value.args[0] + ) + + def test_add_import_appmodule(self, tmp_path: Path) -> None: + """ + Test to verify create_appmodule & import_appmodule + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_cmd.ProjectCmd() + pj_init = project_init_cmd.ProjectInitCmd() + + # init project + pj_init.integration_project_init("ExecuteOrder66", str(tmp_path)) + prj_path = tmp_path / "ExecuteOrder66" + + with mock.patch("importlib.import_module", side_effect=mock_importlib_import_module): + # add app-module + pj.create_appmodule("Kackhaus", "Gerberit", str(prj_path), ".", "model/vaf") + pj.create_appmodule("Forever", "Wakanda", str(prj_path), ".", "model/vaf") + + # init app-module and then import them to integration project + pj_init.app_module_project_init("Speck", "Saufleisch", str(tmp_path / "SesameStreet")) + pj.import_appmodule(str(tmp_path / "SesameStreet/Saufleisch"), str(prj_path), ".", "model/vaf") + + os.environ["IMPORT_APPLICATION_MODULES"] = "import" + # import __init__.py + init_module = import_by_file_name(str(prj_path / "model/vaf/application_modules/__init__.py")) + + # assert imported app modules + goal_app_modules = ["Gerberit", "Wakanda", "Saufleisch"] + imported_app_modules = [ + app_module_name + for app_module_name, _ in inspect.getmembers(init_module, lambda x: (isinstance(x, ApplicationModule))) + ] + assert sorted(imported_app_modules) == sorted(goal_app_modules) + + # assert imported python files + goal_py_modules = [f"import_{module_name.lower()}" for module_name in goal_app_modules + ["instances"]] + imported_py_modules = [ + app_module_name for app_module_name, _ in inspect.getmembers(init_module, inspect.ismodule) + ] + assert sorted(imported_py_modules) == sorted(goal_py_modules) + + def test_remove_appmodule(self, tmp_path: Path) -> None: + """ + Test to verify create_appmodule, import_appmodule & remove_appmodule + Args: + Path tmp_path: Temporary path provided by pytest + """ + pj = project_cmd.ProjectCmd() + pj_init = project_init_cmd.ProjectInitCmd() + + # init project + pj_init.integration_project_init("ExecuteOrder66", str(tmp_path)) + prj_path = tmp_path / "ExecuteOrder66" + + with mock.patch("importlib.import_module", side_effect=mock_importlib_import_module): + # add app-module + pj.create_appmodule("Kackhaus", "Gerberit", str(prj_path), ".", "model/vaf") + pj.create_appmodule("Forever", "Wakanda", str(prj_path), ".", "model/vaf") + + # init app-module and then import them to integration project + pj_init.app_module_project_init("Speck", "Saufleisch", str(tmp_path / "SesameStreet")) + pj.import_appmodule(str(tmp_path / "SesameStreet/Saufleisch"), str(prj_path), ".", "model/vaf") + + for removed in ["Gerberit", "Saufleisch"]: + # remove Gerberit and Saufleisch + pj.remove_appmodule( + prj_path, Path("model/vaf"), [str(prj_path / "src/application_modules" / removed.lower())] + ) + # assert app modules project and import_<app_module>.py removed + assert not Path(prj_path / "src/application_modules" / removed.lower()).is_dir() + assert not Path(prj_path / "model/vaf" / f"import_{removed.lower()}").is_file() + + os.environ["IMPORT_APPLICATION_MODULES"] = "import" + # import __init__.py + init_path = prj_path / "model/vaf/application_modules/__init__.py" + init_module = import_by_file_name(str(init_path)) + # assert imported app modules + goal_app_modules = ["Wakanda"] + imported_app_modules = [ + app_module_name + for app_module_name, _ in inspect.getmembers(init_module, lambda x: (isinstance(x, ApplicationModule))) + ] + assert sorted(imported_app_modules) == sorted(goal_app_modules) + + # assert imported python files + # use text assertion since using mechanism like in test_add_import_addmodule + # causes interference of the init_module value + goal_py_modules = [f"import_{module_name.lower()}" for module_name in goal_app_modules] + not_exist_py_modules = [f"import_{module_name.lower()}" for module_name in ["Gerberit", "Kackhaus"]] + init_path_content = init_path.read_text() + assert all(goal in init_path_content for goal in goal_py_modules) + assert not any(bad_apple in init_path_content for bad_apple in not_exist_py_modules) diff --git a/VAF/tests/unit/vafgeneration/__init__.py b/VAF/tests/unit/vafgeneration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/unit/vafgeneration/application_communication/CMakeLists.txt b/VAF/tests/unit/vafgeneration/application_communication/CMakeLists.txt new file mode 100644 index 0000000..2f09797 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_communication/CMakeLists.txt @@ -0,0 +1,35 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +set(TARGET vaf_my_service_module) + +add_library(${TARGET} STATIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include>) + +target_sources(${TARGET} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include/test/my_service_module.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/test/my_service_module.cpp + ) + +target_link_libraries(${TARGET} + PUBLIC + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_module_interfaces + ) diff --git a/VAF/tests/unit/vafgeneration/application_communication/my_service_module.cpp b/VAF/tests/unit/vafgeneration/application_communication/my_service_module.cpp new file mode 100644 index 0000000..8f12c0a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_communication/my_service_module.cpp @@ -0,0 +1,205 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_service_module.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "test/my_service_module.h" + +#include "vaf/internal/data_ptr_helper.h" +namespace test { + +MyServiceModule::MyServiceModule(vaf::Executor& executor, std::string name, std::vector<std::string> dependencies, vaf::ExecutableControllerInterface& executable_controller_interface) + : vaf::ControlInterface(std::move(name), std::move(dependencies), executable_controller_interface, executor), + executor_{vaf::ControlInterface::executor_} { +} + +vaf::Result<void> MyServiceModule::Init() noexcept { + return vaf::Result<void>{}; +} + +void MyServiceModule::Start() noexcept { + ReportOperational(); +} + +void MyServiceModule::Stop() noexcept { +} + +void MyServiceModule::DeInit() noexcept { +} + +void MyServiceModule::StartEventHandlerForModule(const std::string& module) { + for(auto& handler_container : my_data_element1_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + for(auto& handler_container : my_data_element2_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + + active_modules_.push_back(module); +} + +void MyServiceModule::StopEventHandlerForModule(const std::string& module) { + for(auto& handler_container : my_data_element1_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + for(auto& handler_container : my_data_element2_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + + static_cast<void>(std::remove(active_modules_.begin(), active_modules_.end(), module)); +} + + + +::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> MyServiceModule::GetAllocated_my_data_element1() { + return vaf::Result<vaf::ConstDataPtr<const std::uint64_t >>::FromValue( my_data_element1_sample_); +} + +std::uint64_t MyServiceModule::Get_my_data_element1() { return *my_data_element1_sample_; } + +void MyServiceModule::RegisterDataElementHandler_my_data_element1(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) { + my_data_element1_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + my_data_element1_handlers_.back().is_active_ = true; + } +} + +::vaf::Result<::vaf::DataPtr<std::uint64_t>> MyServiceModule::Allocate_my_data_element1() { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >()}; + return ::vaf::Result<vaf::DataPtr< std::uint64_t >>::FromValue(std::move(ptr)); +} + +::vaf::Result<void> MyServiceModule::SetAllocated_my_data_element1(::vaf::DataPtr<std::uint64_t>&& data) { + my_data_element1_sample_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(vaf::internal::DataPtrHelper<std::uint64_t>::getRawPtr(data))}; + + for(auto& handler_container : my_data_element1_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(my_data_element1_sample_); + } + } + + return vaf::Result<void>{}; +} + +::vaf::Result<void> MyServiceModule::Set_my_data_element1(const std::uint64_t& data) { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >(data)}; + my_data_element1_sample_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(ptr)}; + + for(auto& handler_container : my_data_element1_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(my_data_element1_sample_); + } + } + + return vaf::Result<void>{}; +} + + + +::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> MyServiceModule::GetAllocated_my_data_element2() { + return vaf::Result<vaf::ConstDataPtr<const std::uint64_t >>::FromValue( my_data_element2_sample_); +} + +std::uint64_t MyServiceModule::Get_my_data_element2() { return *my_data_element2_sample_; } + +void MyServiceModule::RegisterDataElementHandler_my_data_element2(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) { + my_data_element2_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + my_data_element2_handlers_.back().is_active_ = true; + } +} + +::vaf::Result<::vaf::DataPtr<std::uint64_t>> MyServiceModule::Allocate_my_data_element2() { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >()}; + return ::vaf::Result<vaf::DataPtr< std::uint64_t >>::FromValue(std::move(ptr)); +} + +::vaf::Result<void> MyServiceModule::SetAllocated_my_data_element2(::vaf::DataPtr<std::uint64_t>&& data) { + my_data_element2_sample_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(vaf::internal::DataPtrHelper<std::uint64_t>::getRawPtr(data))}; + + for(auto& handler_container : my_data_element2_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(my_data_element2_sample_); + } + } + + return vaf::Result<void>{}; +} + +::vaf::Result<void> MyServiceModule::Set_my_data_element2(const std::uint64_t& data) { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >(data)}; + my_data_element2_sample_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(ptr)}; + + for(auto& handler_container : my_data_element2_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(my_data_element2_sample_); + } + } + + return vaf::Result<void>{}; +} + + +void MyServiceModule::RegisterOperationHandler_MyVoidOperation(std::function<void(const std::uint64_t&)>&& f) { + MyVoidOperation_handler_ = std::move(f); +} + +::vaf::Future<void> MyServiceModule::MyVoidOperation(const std::uint64_t& in) { + ::vaf::Promise<void> p; + + if(MyVoidOperation_handler_) { + MyVoidOperation_handler_(in); + p.set_value(); + } else { + vaf::Error error_code{::vaf::ErrorCode::kNoOperationHandlerRegistered, "No operation handler registered for MyVoidOperation."}; + p.SetError(error_code); + } + + return p.get_future(); +} + +void MyServiceModule::RegisterOperationHandler_MyOperation(std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)>&& f) { + MyOperation_handler_ = std::move(f); +} + +::vaf::Future<test::MyOperation::Output> MyServiceModule::MyOperation(const std::uint64_t& in, const std::uint64_t& inout) { + ::vaf::Promise<test::MyOperation::Output> p; + + if(MyOperation_handler_) { + p.set_value(MyOperation_handler_(in, inout)); + } else { + vaf::Error error_code{::vaf::ErrorCode::kNoOperationHandlerRegistered, "No operation handler registered for MyOperation."}; + p.SetError(error_code); + } + + return p.get_future(); +} + + + +} // namespace test diff --git a/VAF/tests/unit/vafgeneration/application_communication/my_service_module.h b/VAF/tests/unit/vafgeneration/application_communication/my_service_module.h new file mode 100644 index 0000000..bf4cdc2 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_communication/my_service_module.h @@ -0,0 +1,93 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_service_module.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_SERVICE_MODULE_H +#define TEST_MY_SERVICE_MODULE_H + +#include <memory> +#include <string> +#include <vector> + +#include "vaf/receiver_handler_container.h" +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +#include "test/my_interface_consumer.h" +#include "test/my_interface_provider.h" + +namespace test { + + +class MyServiceModule + : public test::MyInterfaceConsumer, public test::MyInterfaceProvider, public vaf::ControlInterface { + public: + MyServiceModule(vaf::Executor& executor, std::string name, std::vector<std::string> dependencies, vaf::ExecutableControllerInterface& executable_controller_interface); + ~MyServiceModule() override = default; + + MyServiceModule(const MyServiceModule&) = delete; + MyServiceModule(MyServiceModule&&) = delete; + MyServiceModule& operator=(const MyServiceModule&) = delete; + MyServiceModule& operator=(MyServiceModule&&) = delete; + + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + void StartEventHandlerForModule(const std::string& module) override; + void StopEventHandlerForModule(const std::string& module) override; + + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_my_data_element1() override; + std::uint64_t Get_my_data_element1() override; + void RegisterDataElementHandler_my_data_element1(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) override; + + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_my_data_element1() override; + ::vaf::Result<void> SetAllocated_my_data_element1(::vaf::DataPtr<std::uint64_t>&& data) override; + ::vaf::Result<void> Set_my_data_element1(const std::uint64_t& data) override; + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_my_data_element2() override; + std::uint64_t Get_my_data_element2() override; + void RegisterDataElementHandler_my_data_element2(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) override; + + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_my_data_element2() override; + ::vaf::Result<void> SetAllocated_my_data_element2(::vaf::DataPtr<std::uint64_t>&& data) override; + ::vaf::Result<void> Set_my_data_element2(const std::uint64_t& data) override; + + ::vaf::Future<void> MyVoidOperation(const std::uint64_t& in) override; + void RegisterOperationHandler_MyVoidOperation(std::function<void(const std::uint64_t&)>&& f) override; + ::vaf::Future<test::MyOperation::Output> MyOperation(const std::uint64_t& in, const std::uint64_t& inout) override; + void RegisterOperationHandler_MyOperation(std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)>&& f) override; + + private: + vaf::ModuleExecutor& executor_; + std::vector<std::string> active_modules_; + + vaf::ConstDataPtr<const std::uint64_t> my_data_element1_sample_{std::make_unique<std::uint64_t>()}; + std::vector<vaf::ReceiverHandlerContainer<std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>>> my_data_element1_handlers_; + vaf::ConstDataPtr<const std::uint64_t> my_data_element2_sample_{std::make_unique<std::uint64_t>()}; + std::vector<vaf::ReceiverHandlerContainer<std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>>> my_data_element2_handlers_; + + std::function<void(const std::uint64_t&)> MyVoidOperation_handler_; + std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)> MyOperation_handler_; + +}; + + +} // namespace test + +#endif // TEST_MY_SERVICE_MODULE_H diff --git a/VAF/tests/unit/vafgeneration/application_module/app.cpp b/VAF/tests/unit/vafgeneration/application_module/app.cpp new file mode 100644 index 0000000..5281abd --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/app.cpp @@ -0,0 +1,75 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "apps/my_application_module.h" + +namespace apps { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - c_interface_instance_1 : test::MyInterfaceConsumer + - Data elements + - my_data_element : std::uint64_t + + + - c_interface_instance_2 : test::MyInterfaceConsumer + - Data elements + - my_data_element : std::uint64_t + + + Provider interfaces + =================== + - p_interface_instance_1 : test::MyInterfaceProvider + - Data elements + - my_data_element : std::uint64_t + + + - p_interface_instance_2 : test::MyInterfaceProvider + - Data elements + - my_data_element : std::uint64_t + + +*/ + +MyApplicationModule::MyApplicationModule(ConstructorToken&& token) + : MyApplicationModuleBase(std::move(token)) +{ +} + +void MyApplicationModule::task1() { +} + +void MyApplicationModule::task2() { +} + + +} // namespace apps diff --git a/VAF/tests/unit/vafgeneration/application_module/app.h b/VAF/tests/unit/vafgeneration/application_module/app.h new file mode 100644 index 0000000..f4a90f2 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/app.h @@ -0,0 +1,38 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef APPS_MY_APPLICATION_MODULE_H +#define APPS_MY_APPLICATION_MODULE_H + +#include "apps/my_application_module_base.h" + +namespace apps { + +class MyApplicationModule : public MyApplicationModuleBase { + public: + MyApplicationModule(ConstructorToken&& token); + + void task1() override; + void task2() override; + + private: +}; + +} // namespace apps + +#endif // APPS_MY_APPLICATION_MODULE_H diff --git a/VAF/tests/unit/vafgeneration/application_module/app_cmake.txt b/VAF/tests/unit/vafgeneration/application_module/app_cmake.txt new file mode 100644 index 0000000..2f36a1e --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/app_cmake.txt @@ -0,0 +1,66 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +cmake_minimum_required(VERSION 3.21) + +find_package(Threads) +find_package(GTest) + +set(TARGET my_application_module) + +add_library(${TARGET} STATIC "") + +target_compile_options(${TARGET} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${TARGET} PUBLIC cxx_std_14) + +target_compile_definitions(${TARGET} PUBLIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_sources(${TARGET} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include/apps/my_application_module.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/my_application_module.cpp + ) + +# cmake-format: off +target_link_libraries(${TARGET} + PUBLIC + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_module_interfaces + + vaf_my_application_module_base +) +# cmake-format: on diff --git a/VAF/tests/unit/vafgeneration/application_module/apps_cmake.txt b/VAF/tests/unit/vafgeneration/application_module/apps_cmake.txt new file mode 100644 index 0000000..da6ab86 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/apps_cmake.txt @@ -0,0 +1,43 @@ +option(VAF_STAND_ALONE_BUILD "Do you want to build the application module stand alone?" TRUE) +option(VAF_BUILD_TESTS "Enable unit and integration tests for this VAF project" ON) + +if(VAF_STAND_ALONE_BUILD) + +cmake_minimum_required(VERSION 3.25) + +project(myapplicationmodule) + +find_package(Threads) +find_package(vafcpp REQUIRED) + +find_program(CCACHE_PROGRAM ccache) +if(CCACHE_PROGRAM) + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") +endif() + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +set(CMAKE_INSTALL_PREFIX + "${CMAKE_BINARY_DIR}/install" + CACHE PATH "install prefix" FORCE) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_subdirectory(implementation) +add_subdirectory(src-gen) + +if(VAF_BUILD_TESTS) +add_subdirectory(test-gen) +endif() + +else() + +add_subdirectory(implementation) + +if(VAF_BUILD_TESTS) +add_subdirectory(test-gen) +endif() + +endif() diff --git a/VAF/tests/unit/vafgeneration/application_module/base.cpp b/VAF/tests/unit/vafgeneration/application_module/base.cpp new file mode 100644 index 0000000..03fc1ed --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/base.cpp @@ -0,0 +1,36 @@ + +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module_base.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "apps/my_application_module_base.h" + +namespace apps { + +MyApplicationModuleBase::MyApplicationModuleBase(ConstructorToken&& token) + : vaf::ControlInterface(token.name_, std::move(token.dependencies_), token.executable_controller_interface_, token.executor_), + executor_{vaf::ControlInterface::executor_}, + c_interface_instance_1_{std::move(token.c_interface_instance_1_)}, + c_interface_instance_2_{std::move(token.c_interface_instance_2_)}, + p_interface_instance_1_{std::move(token.p_interface_instance_1_)}, + p_interface_instance_2_{std::move(token.p_interface_instance_2_)} + { + executor_.RunPeriodic("task1", std::chrono::milliseconds{ 10 }, [this]() { task1(); }, {}, token.task_offset_task1_, token.task_budget_task1_); + executor_.RunPeriodic("task2", std::chrono::milliseconds{ 20 }, [this]() { task2(); }, {"task1"}, token.task_offset_task2_, token.task_budget_task2_); +} + +} // namespace apps diff --git a/VAF/tests/unit/vafgeneration/application_module/base.h b/VAF/tests/unit/vafgeneration/application_module/base.h new file mode 100644 index 0000000..bee16db --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/base.h @@ -0,0 +1,73 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef APPS_MY_APPLICATION_MODULE_BASE_H +#define APPS_MY_APPLICATION_MODULE_BASE_H + +#include <memory> + +#include "vaf/executor.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/controller_interface.h" + +#include "test/my_interface_consumer.h" +#include "test/my_interface_provider.h" + +namespace apps { + +class MyApplicationModuleBase : public vaf::ControlInterface { + public: + struct ConstructorToken { + std::string name_; + std::vector<std::string> dependencies_; + vaf::ExecutableControllerInterface& executable_controller_interface_; + vaf::Executor& executor_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_1_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_2_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_1_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_2_; + uint64_t task_offset_task1_; + std::chrono::nanoseconds task_budget_task1_; + uint64_t task_offset_task2_; + std::chrono::nanoseconds task_budget_task2_; + }; + + MyApplicationModuleBase(ConstructorToken&& token); + virtual ~MyApplicationModuleBase() = default; + + virtual vaf::Result<void> Init() noexcept { return vaf::Result<void>{}; } + virtual void Start() noexcept { ReportOperational(); } + virtual void Stop() noexcept {} + virtual void DeInit() noexcept {} + + virtual void OnError(const vaf::Error& error) override { static_cast<void>(error); } + + virtual void task1() = 0; + virtual void task2() = 0; + + protected: + vaf::ModuleExecutor& executor_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_1_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_2_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_1_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_2_; +}; + +} // namespace apps + +#endif // APPS_MY_APPLICATION_MODULE_BASE_H diff --git a/VAF/tests/unit/vafgeneration/application_module/base_cmake.txt b/VAF/tests/unit/vafgeneration/application_module/base_cmake.txt new file mode 100644 index 0000000..458defb --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/base_cmake.txt @@ -0,0 +1,35 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +set(TARGET vaf_my_application_module_base) + +add_library(${TARGET} STATIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include>) + +target_sources(${TARGET} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include/apps/my_application_module_base.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/apps/my_application_module_base.cpp + ) + +target_link_libraries(${TARGET} + PUBLIC + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_module_interfaces + ) diff --git a/VAF/tests/unit/vafgeneration/application_module/main.cpp b/VAF/tests/unit/vafgeneration/application_module/main.cpp new file mode 100644 index 0000000..94ec10a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/main.cpp @@ -0,0 +1,33 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file main.cpp + * \brief + * + *********************************************************************************************************************/ +#include "gtest/gtest.h" +#include <iostream> +#include <fstream> + +int main(int argc, char **argv) { + int gtest_ret{0}; + ::testing::InitGoogleTest(&argc, argv); + + // Set death tests to threadsafe globally because logging uses a separate thread. + //::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + // Execute tests via gtest + gtest_ret = RUN_ALL_TESTS(); + + return gtest_ret; +} diff --git a/VAF/tests/unit/vafgeneration/application_module/test_base.cpp b/VAF/tests/unit/vafgeneration/application_module/test_base.cpp new file mode 100644 index 0000000..a909bae --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/test_base.cpp @@ -0,0 +1,30 @@ + +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module_base.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "apps/my_application_module_base.h" + +namespace apps { + +MyApplicationModuleBase::MyApplicationModuleBase(ConstructorToken&& token): + c_interface_instance_1_{std::move(token.c_interface_instance_1_)}, + c_interface_instance_2_{std::move(token.c_interface_instance_2_)}, + p_interface_instance_1_{std::move(token.p_interface_instance_1_)}, + p_interface_instance_2_{std::move(token.p_interface_instance_2_)} {} + +} // namespace apps diff --git a/VAF/tests/unit/vafgeneration/application_module/test_base.h b/VAF/tests/unit/vafgeneration/application_module/test_base.h new file mode 100644 index 0000000..dedac08 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/test_base.h @@ -0,0 +1,58 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_application_module_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef APPS_MY_APPLICATION_MODULE_BASE_H +#define APPS_MY_APPLICATION_MODULE_BASE_H + +#include <memory> +#include "vaf/controller_interface.h" + +#include "test/my_interface_consumer.h" +#include "test/my_interface_provider.h" + +namespace apps { + +class MyApplicationModuleBase { + public: + struct ConstructorToken { + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_1_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_2_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_1_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_2_; + }; + + MyApplicationModuleBase(ConstructorToken&& token); + virtual ~MyApplicationModuleBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + + virtual void task1() = 0; + virtual void task2() = 0; + + protected: + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_1_; + std::shared_ptr<test::MyInterfaceConsumer> c_interface_instance_2_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_1_; + std::shared_ptr<test::MyInterfaceProvider> p_interface_instance_2_; +}; + +} // namespace apps + +#endif // APPS_MY_APPLICATION_MODULE_BASE_H diff --git a/VAF/tests/unit/vafgeneration/application_module/test_cmake.txt b/VAF/tests/unit/vafgeneration/application_module/test_cmake.txt new file mode 100644 index 0000000..40edc6e --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/test_cmake.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.21) +project(my_application_module_unittest) + +find_package(Threads) +find_package(GTest REQUIRED) +if (NOT GTest_FOUND) + message(FATAL_ERROR "Cannot find Google Test Framework!") +endif() + +include(GoogleTest) + +add_executable(${PROJECT_NAME}) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) + +target_compile_definitions(${PROJECT_NAME} PUBLIC) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src +) + +target_sources( + ${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/apps/my_application_module.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/my_application_module.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/apps/my_application_module_base.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/apps/my_application_module_base.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tests.cpp +) + +# cmake-format: off +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + gmock + gtest::gtest + $<TARGET_NAME_IF_EXISTS:vaf_data_types> + $<TARGET_NAME_IF_EXISTS:vaf_module_interfaces> + $<TARGET_NAME_IF_EXISTS:vaf_module_interface_mocks> +) +# cmake-format: on + +gtest_discover_tests(${PROJECT_NAME}) diff --git a/VAF/tests/unit/vafgeneration/application_module/tests.cpp b/VAF/tests/unit/vafgeneration/application_module/tests.cpp new file mode 100644 index 0000000..2751c34 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/application_module/tests.cpp @@ -0,0 +1,85 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file tests.cpp + * \brief + * + *********************************************************************************************************************/ +#include <cstddef> +#include <cstdint> +#include <csignal> +#include <iostream> +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "test/my_interface_consumer_mock.h" +#include "test/my_interface_provider_mock.h" +#include "apps/my_application_module.h" + +// Put inside test to skip +//GTEST_SKIP() << "Skipping single test"; +using ::testing::Return; +using ::testing::_; + +namespace vaf { + /*! + * \brief Initializes the signal handling. + * \return void. + */ + void InitializeSignalHandling() noexcept { + bool success{true}; + sigset_t signals; + + /* Block all signals except the SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV signals because blocking them will lead to + * undefined behavior. Their default handling shall not be changed (dependent on underlying POSIX environment, usually + * process is killed and a dump file is written). Signal mask will be inherited by subsequent threads. */ + + success = success && (0 == sigfillset(&signals)); + success = success && (0 == sigdelset(&signals, SIGABRT)); + success = success && (0 == sigdelset(&signals, SIGBUS)); + success = success && (0 == sigdelset(&signals, SIGFPE)); + success = success && (0 == sigdelset(&signals, SIGILL)); + success = success && (0 == sigdelset(&signals, SIGSEGV)); + success = success && (0 == pthread_sigmask(SIG_SETMASK, &signals, nullptr)); + + if (!success) { + // Exit + } + } + + class MyApplicationModuleUnitTest : public ::testing::Test { + protected: + MyApplicationModuleUnitTest() {} + + virtual ~MyApplicationModuleUnitTest() {} + + virtual void SetUp() { + InitializeSignalHandling(); + } + + virtual void TearDown() { + } + }; + + TEST_F(MyApplicationModuleUnitTest, Test_1) { + auto c_interface_instance_1Mock = std::make_shared<test::MyInterfaceConsumerMock>(); + auto c_interface_instance_2Mock = std::make_shared<test::MyInterfaceConsumerMock>(); + auto p_interface_instance_1Mock = std::make_shared<test::MyInterfaceProviderMock>(); + auto p_interface_instance_2Mock = std::make_shared<test::MyInterfaceProviderMock>(); + + auto MyApplicationModule = std::make_shared<apps::MyApplicationModule>(apps::MyApplicationModule ::ConstructorToken{ + c_interface_instance_1Mock, + c_interface_instance_2Mock, + p_interface_instance_1Mock, + p_interface_instance_2Mock}); + } +} // namespace vaf diff --git a/VAF/tests/unit/vafgeneration/cac_support/silkit.py.example b/VAF/tests/unit/vafgeneration/cac_support/silkit.py.example new file mode 100644 index 0000000..7157fd9 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cac_support/silkit.py.example @@ -0,0 +1,30 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_datatype, + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "derived-model.json")) + +class Nsexec: + class Nstest: + # Platform Consumer Modules + my_consumer_module = get_platform_consumer_module( + "MyConsumerModule", "nsexec::nstest" + ) + # Platform Provider Modules + my_provider_module = get_platform_provider_module( + "MyProviderModule", "nsexec::nstest" + ) +class Test: + # Module Interfaces + my_interface = get_module_interface( + "MyInterface", "test" + ) diff --git a/VAF/tests/unit/vafgeneration/cmake_common/cmake.txt b/VAF/tests/unit/vafgeneration/cmake_common/cmake.txt new file mode 100644 index 0000000..ffb076f --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cmake_common/cmake.txt @@ -0,0 +1,17 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +add_subdirectory(libs) +add_subdirectory(executables) diff --git a/VAF/tests/unit/vafgeneration/cmake_common/exe_cmake.txt b/VAF/tests/unit/vafgeneration/cmake_common/exe_cmake.txt new file mode 100644 index 0000000..df03672 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cmake_common/exe_cmake.txt @@ -0,0 +1,18 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +add_subdirectory(already_existing_executable1) +add_subdirectory(already_existing_executable2) +add_subdirectory(my_executable) diff --git a/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake.txt b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake.txt new file mode 100644 index 0000000..6afa0c0 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake.txt @@ -0,0 +1,20 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +add_subdirectory(interfaces) +add_subdirectory(protobuf_serdes) +add_subdirectory(application_modules_base) +add_subdirectory(platform_vaf) +add_subdirectory(platform_silkit) diff --git a/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append.txt b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append.txt new file mode 100644 index 0000000..6afa0c0 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append.txt @@ -0,0 +1,20 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +add_subdirectory(interfaces) +add_subdirectory(protobuf_serdes) +add_subdirectory(application_modules_base) +add_subdirectory(platform_vaf) +add_subdirectory(platform_silkit) diff --git a/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append2.txt b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append2.txt new file mode 100644 index 0000000..6afa0c0 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/cmake_common/libs_cmake_append2.txt @@ -0,0 +1,20 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +add_subdirectory(interfaces) +add_subdirectory(protobuf_serdes) +add_subdirectory(application_modules_base) +add_subdirectory(platform_vaf) +add_subdirectory(platform_silkit) diff --git a/VAF/tests/unit/vafgeneration/controller/CMakeLists.txt b/VAF/tests/unit/vafgeneration/controller/CMakeLists.txt new file mode 100644 index 0000000..1094bd1 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.21) +project(MyExecutable) + +find_package(Threads) + +add_executable(${PROJECT_NAME}) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) + +target_compile_definitions(${PROJECT_NAME} PUBLIC) + +set(target ${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${PROJECT_NAME}/bin) + +target_include_directories(${PROJECT_NAME} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_sources( + ${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include/executable_controller/executable_controller.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/executable_controller/executable_controller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp +) + +# cmake-format: off +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_my_module3 + vaf_my_module4 + vaf_my_module1 + vaf_my_module2 + my_app + vaf_MyExecutable_user_controller +) +# cmake-format: on + +# Define files to be installed +install(TARGETS ${PROJECT_NAME} DESTINATION "opt/${PROJECT_NAME}/bin") + +install(PROGRAMS "/usr/local/bin/sil-kit-registry" DESTINATION "opt/silkit/bin") diff --git a/VAF/tests/unit/vafgeneration/controller/controller.cpp b/VAF/tests/unit/vafgeneration/controller/controller.cpp new file mode 100644 index 0000000..63114c1 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/controller.cpp @@ -0,0 +1,102 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file executable_controller.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "executable_controller/executable_controller.h" + +#include "test/my_module1.h" +#include "test/my_module2.h" +#include "test/my_module3.h" +#include "test/my_module4.h" +#include "test/my_app.h" + + +#include "vaf/result.h" + +namespace executable_controller { + +ExecutableController::ExecutableController() + : ExecutableControllerBase(), + executor_{} { +} + +void ExecutableController::DoInitialize() { + executor_ = std::make_unique<vaf::Executor>(std::chrono::milliseconds{ 10 }); + + + auto MyModule3 = std::make_shared<test::MyModule3>( + *executor_, + "MyModule3", + *this); + + auto MyModule4 = std::make_shared<test::MyModule4>( + *executor_, + "MyModule4", + *this); + + auto MyModule2 = std::make_shared<test::MyModule2>( + *executor_, + "MyModule2", + *this); + + auto MyModule1 = std::make_shared<test::MyModule1>( + *executor_, + "MyModule1", + std::vector<std::string>{}, + *this); + + auto MyApp = std::make_shared<test::MyApp>( test::MyApp::ConstructorToken{ + "MyApp", + std::vector<std::string>{ + {"MyModule2"}, + {"MyModule3"} + }, + *this, + *executor_, + MyModule3, + MyModule4, + MyModule1, + MyModule2 +, 0, + std::chrono::nanoseconds{ 10000000 }, + 1, + std::chrono::nanoseconds{ 0 } + }); + + RegisterModule(MyModule3); + + RegisterModule(MyModule4); + + RegisterModule(MyModule1); + + RegisterModule(MyModule2); + + RegisterModule(MyApp); + + ExecutableControllerBase::DoInitialize(); +} + +void ExecutableController::DoStart() { + ExecutableControllerBase::DoStart(); +} + +void ExecutableController::DoShutdown() { + ExecutableControllerBase::DoShutdown(); +} + + +} // namespace executable_controller diff --git a/VAF/tests/unit/vafgeneration/controller/controller.h b/VAF/tests/unit/vafgeneration/controller/controller.h new file mode 100644 index 0000000..4048a8b --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/controller.h @@ -0,0 +1,45 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file executable_controller.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef EXECUTABLE_CONTROLLER_EXECUTABLE_CONTROLLER_H +#define EXECUTABLE_CONTROLLER_EXECUTABLE_CONTROLLER_H + +#include <memory> + +#include "vaf/executable_controller_base.h" +#include "vaf/executor.h" + +namespace executable_controller { + +class ExecutableController final : public vaf::ExecutableControllerBase { + public: + ExecutableController(); + ~ExecutableController() override = default; + + protected: + void DoInitialize() override; + void DoStart() override; + void DoShutdown() override; + + private: + std::unique_ptr<vaf::Executor> executor_; +}; + +} // namespace executable_controller + +#endif // EXECUTABLE_CONTROLLER_EXECUTABLE_CONTROLLER_H diff --git a/VAF/tests/unit/vafgeneration/controller/main.cpp b/VAF/tests/unit/vafgeneration/controller/main.cpp new file mode 100644 index 0000000..a1d11b9 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/main.cpp @@ -0,0 +1,25 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file main.cpp + * \brief + * + *********************************************************************************************************************/ +#include "executable_controller/executable_controller.h" + +int main() { + executable_controller::ExecutableController executable_controller; + executable_controller.Run(false); + + return 0; +} diff --git a/VAF/tests/unit/vafgeneration/controller/user_controller.cpp b/VAF/tests/unit/vafgeneration/controller/user_controller.cpp new file mode 100644 index 0000000..6b545a1 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/user_controller.cpp @@ -0,0 +1,57 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file user_controller.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "user_controller.h" + +#include <iostream> + +std::unique_ptr<vaf::UserControllerInterface> CreateUserController() { + return std::make_unique<UserController>(); +} + +void UserController::PreInitialize() { + std::cout << "UserController::PreInitialize\n"; +} + +void UserController::PostInitialize() { + std::cout << "UserController::PostInitialize\n"; +} + +void UserController::PreStart() { + std::cout << "UserController::PreStart\n"; +} + +void UserController::PostStart() { + std::cout << "UserController::PostStart\n"; +} + +void UserController::PreShutdown() { + std::cout << "UserController::PreShutdown\n"; +} + +void UserController::PostShutdown() { + std::cout << "UserController::PostShutdown\n"; +} + +void UserController::OnError(vaf::Error error, std::string name, bool critical) { + std::cout << "UserController::OnError: name: " << name << ", Message: " << error.Message() << ", critical: " << critical << "\n"; + if(critical){ + std::cout << "UserController::OnError: Critical call, aborting execution!" << std::endl; + std::abort(); + } +} diff --git a/VAF/tests/unit/vafgeneration/controller/user_controller.h b/VAF/tests/unit/vafgeneration/controller/user_controller.h new file mode 100644 index 0000000..bdbd7de --- /dev/null +++ b/VAF/tests/unit/vafgeneration/controller/user_controller.h @@ -0,0 +1,40 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file user_controller.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef USER_CONTROLLER_H +#define USER_CONTROLLER_H + +#include "vaf/user_controller_interface.h" + + +class UserController : public vaf::UserControllerInterface { +public: + void PreInitialize() override; + void PostInitialize() override; + void PreStart() override; + void PostStart() override; + void PreShutdown() override; + void PostShutdown() override; + + void OnError(vaf::Error error, std::string name, bool critical) override; + +private: +}; + + +#endif // USER_CONTROLLER_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/model_changed_complex.json b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/model_changed_complex.json new file mode 100644 index 0000000..ed0aa87 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/model_changed_complex.json @@ -0,0 +1,445 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "G", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "B", + "TypeRef": "datatypes::MyVector" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "Order66", + "Period": "332ms", + "PreferredOffset": 12 + }, + { + "Name": "Leaf", + "Period": "112ms", + "PreferredOffset": 5, + "RunAfter": [ + "Order66" + ] + }, + { + "Name": "Methanol", + "Period": "233ms", + "PreferredOffset": 3, + "RunAfter": [ + "Order66" + ] + }, + { + "Name": "Trumpeltier", + "Period": "152ms", + "PreferredOffset": 0, + "RunAfter": [ + "Leaf", + "Methanol" + ] + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "RPort_ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1" + }, + { + "Name": "RPort_ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2" + }, + { + "Name": "RPort_VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService" + }, + { + "Name": "RPort_SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService" + }, + { + "Name": "RPort_BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService" + } + ], + "PlatformProviderModules": [ + { + "Name": "PPort_BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService" + }, + { + "Name": "PPort_SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService" + }, + { + "Name": "PPort_ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1" + }, + { + "Name": "PPort_VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService" + }, + { + "Name": "PPort_ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_base_test_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_base_test_goal.h new file mode 100644 index 0000000..154989c --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_base_test_goal.h @@ -0,0 +1,81 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + bool GetStatus() {return _mock_status}; + std::string GetMockId() {return _mock_id}; + +<<<<<<< {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h + virtual void Step1() = 0; + void TestHelper(std::string& mock_str, bool mock_status); + virtual void Step2() = 0; + virtual void Step3() = 0; + int GetTestNumber(std::string& test_name); + virtual void Step4() = 0; +======= + virtual void Order66() = 0; + virtual void Leaf() = 0; + virtual void Methanol() = 0; + virtual void Trumpeltier() = 0; +>>>>>>> {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h.new~ + + private: + bool _mock_status{false}; + std::string _mock_id{"mecorino"}; + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.cpp new file mode 100644 index 0000000..abe5a28 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.cpp @@ -0,0 +1,132 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" +#include <iostream> + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - ImageServiceConsumer1 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - ImageServiceConsumer2 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - SteeringAngleServiceConsumer : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + + + - VelocityServiceConsumer : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + + Provider interfaces + =================== + - ObjectDetectionListModule : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + +*/ + +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + std::string marker{"MARK-2"}; + bool constructed_{true}; + std::cout << marker << ": Construction of SensorFusion is " << constructed_ << std::endl; +} + +<<<<<<< {TMP_PATH}/SensorFusion/implementation/src/sensor_fusion.cpp +void SensorFusion::Step1() { + std::cout << "Step1 is performed: Clapton likes to clap" << std::endl; +} + +void SensorFusion::Step2() { + std::cout << "Step2 is performed: Mayo is naise" << std::endl; +} + +void SensorFusion::Step3() { + std::cout << "Step3 is performed: Penultimate is not Penaldo" << std::endl; + _status = true; +} + +void SensorFusion::Step4() { + std::cout << "Sensor Fusion successfully run all periodic tasks!" << std::endl; + nada = "Pico-Bello"; +======= +/********************************************************************************************************************** + 4 periodic task(s) +**********************************************************************************************************************/ +// Task with name Order66 and a period of 332ms. +void SensorFusion::Order66() { + // Insert your code for periodic execution here... +} + +// Task with name Leaf and a period of 112ms. +void SensorFusion::Leaf() { + // Insert your code for periodic execution here... +} + +// Task with name Methanol and a period of 233ms. +void SensorFusion::Methanol() { + // Insert your code for periodic execution here... +} + +// Task with name Trumpeltier and a period of 152ms. +void SensorFusion::Trumpeltier() { + // Insert your code for periodic execution here... +>>>>>>> {TMP_PATH}/SensorFusion/implementation/src/sensor_fusion.cpp.new~ +} + + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.h new file mode 100644 index 0000000..0db59dc --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/complex_changes/sensor_fusion_goal.h @@ -0,0 +1,47 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include <iostream> +#include "easylogging++.h" +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" +#include "mock.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + void Order66() override; + void Leaf() override; + void Methanol() override; + void Trumpeltier() override; + + private: + bool _status{false}; + std::string nada{"Gellow"}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/CMakeLists.txt b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/CMakeLists.txt new file mode 100644 index 0000000..a42801d --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/CMakeLists.txt @@ -0,0 +1,71 @@ +#[=======================================================================[ + COPYRIGHT + ------------------------------------------------------------------------------------------------------------------- + + Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + + This software is copyright protected and proprietary to Vector Informatik GmbH. + Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + All other rights remain with Vector Informatik GmbH. + + ------------------------------------------------------------------------------------------------------------------- + FILE DESCRIPTION + ------------------------------------------------------------------------------------------------------------------- + \file CMakeLists.txt +#]=======================================================================] +cmake_minimum_required(VERSION 3.21) + +find_package(Threads) +find_package(GTest) + +set(TARGET sensor_fusion) + +add_library(${TARGET} STATIC "") + +target_compile_options(${TARGET} + PRIVATE + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wall> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wextra> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wshadow> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wnon-virtual-dtor> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wold-style-cast> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wcast-align> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wunused> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Woverloaded-virtual> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-pedantic> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wconversion> + $<$<AND:$<PLATFORM_ID:Linux>,$<C_COMPILER_ID:GNU>>:-Wsign-conversion>) + +target_compile_features(${TARGET} PUBLIC cxx_std_14) + +target_compile_definitions(${TARGET} PUBLIC) + +target_include_directories(${TARGET} + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + $<INSTALL_INTERFACE:include> + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_sources(${TARGET} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include/nsapplicationunit/nssensorfusion/sensor_fusion.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/sensor_fusion.cpp + ) + +# cmake-format: off +target_link_libraries(${TARGET} + PUBLIC + Threads::Threads + $<IF:$<TARGET_EXISTS:vafcpp::vaf_core>,vafcpp::vaf_core,vaf_core> + vaf_module_interfaces + + vaf_new_target_1 + vaf_new_target_2 +) +# cmake-format: on + +if(VAF_BUILD_TESTS) +add_subdirectory(test) +endif() diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_base_test_edited.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_base_test_edited.h new file mode 100644 index 0000000..f48acc8 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_base_test_edited.h @@ -0,0 +1,74 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + bool GetStatus() {return _mock_status}; + std::string GetMockId() {return _mock_id}; + + virtual void Step1() = 0; + void TestHelper(std::string& mock_str, bool mock_status); + virtual void Step2() = 0; + virtual void Step3() = 0; + int GetTestNumber(std::string& test_name); + virtual void Step4() = 0; + + private: + bool _mock_status{false}; + std::string _mock_id{"mecorino"}; + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.cpp new file mode 100644 index 0000000..0e7c833 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.cpp @@ -0,0 +1,108 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" +#include <iostream> + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - ImageServiceConsumer1 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - ImageServiceConsumer2 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - SteeringAngleServiceConsumer : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + + + - VelocityServiceConsumer : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + + Provider interfaces + =================== + - ObjectDetectionListModule : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + +*/ + +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + std::string marker{"MARK-2"}; + bool constructed_{true}; + std::cout << marker << ": Construction of SensorFusion is " << constructed_ << std::endl; +} + +void SensorFusion::Step1() { + std::cout << "Step1 is performed: Clapton likes to clap" << std::endl; +} + +void SensorFusion::Step2() { + std::cout << "Step2 is performed: Mayo is naise" << std::endl; +} + +void SensorFusion::Step3() { + std::cout << "Step3 is performed: Penultimate is not Penaldo" << std::endl; + _status = true; +} + +void SensorFusion::Step4() { + std::cout << "Sensor Fusion successfully run all periodic tasks!" << std::endl; + nada = "Pico-Bello"; +} + + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.h new file mode 100644 index 0000000..beb003c --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/first_cycle_editing/sensor_fusion_edited.h @@ -0,0 +1,47 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include <iostream> +#include "easylogging++.h" +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" +#include "mock.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + void Step1() override; + void Step2() override; + void Step3() override; + void Step4() override; + + private: + bool _status{false}; + std::string nada{"Gellow"}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/model_base.json b/VAF/tests/unit/vafgeneration/data/merge_strategy/model_base.json new file mode 100644 index 0000000..6073946 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/model_base.json @@ -0,0 +1,445 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "G", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "B", + "TypeRef": "datatypes::MyVector" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "Step1", + "Period": "200ms", + "PreferredOffset": 0 + }, + { + "Name": "Step2", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step1" + ] + }, + { + "Name": "Step3", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step1", + "Step2" + ] + }, + { + "Name": "Step4", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step3" + ] + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "RPort_ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1" + }, + { + "Name": "RPort_ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2" + }, + { + "Name": "RPort_VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService" + }, + { + "Name": "RPort_SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService" + }, + { + "Name": "RPort_BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService" + } + ], + "PlatformProviderModules": [ + { + "Name": "PPort_BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService" + }, + { + "Name": "PPort_SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService" + }, + { + "Name": "PPort_ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1" + }, + { + "Name": "PPort_VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService" + }, + { + "Name": "PPort_ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/model_changed.json b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/model_changed.json new file mode 100644 index 0000000..f58edc9 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/model_changed.json @@ -0,0 +1,413 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "G", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "B", + "TypeRef": "datatypes::MyVector" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + } + } + ], + "PlatformConsumerModules": [ + { + "Name": "RPort_ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1" + }, + { + "Name": "RPort_ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2" + }, + { + "Name": "RPort_VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService" + }, + { + "Name": "RPort_SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService" + }, + { + "Name": "RPort_BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService" + } + ], + "PlatformProviderModules": [ + { + "Name": "PPort_BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService" + }, + { + "Name": "PPort_SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService" + }, + { + "Name": "PPort_ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1" + }, + { + "Name": "PPort_VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService" + }, + { + "Name": "PPort_ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_base_test_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_base_test_goal.h new file mode 100644 index 0000000..70a62f3 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_base_test_goal.h @@ -0,0 +1,62 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.cpp new file mode 100644 index 0000000..2e77195 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.cpp @@ -0,0 +1,84 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Generated based on configuration in ../../model/sensor_fusion.py + + Consumer interfaces + =================== + Data element API example for camera_image of type datatypes::Image + - ::vaf::Result<::vaf::ConstDataPtr<const datatypes::Image>> GetAllocated_camera_image() + - datatypes::Image Get_camera_image() + - void RegisterDataElementHandler_camera_image(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const datatypes::Image>)>&& f) + + - ImageServiceConsumer1_ : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + - ImageServiceConsumer2_ : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + - SteeringAngleServiceConsumer_ : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + - VelocityServiceConsumer_ : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + Provider interfaces + =================== + Data element API example for object_detection_list of type adas::interfaces::ObjectDetectionList + - ::vaf::Result<::vaf::DataPtr<adas::interfaces::ObjectDetectionList>> Allocate_object_detection_list() + - ::vaf::Result<void> SetAllocated_object_detection_list(::vaf::DataPtr<adas::interfaces::ObjectDetectionList>&& data) + - ::vaf::Result<void> Set_object_detection_list(const adas::interfaces::ObjectDetectionList& data) + + - ObjectDetectionListModule_ : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList +*/ + +/********************************************************************************************************************** + Constructor +**********************************************************************************************************************/ +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + // Insert your code here... +} + +/********************************************************************************************************************** + 0 periodic task(s) +**********************************************************************************************************************/ + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.h new file mode 100644 index 0000000..4bd478a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/removal/sensor_fusion_goal.h @@ -0,0 +1,38 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + + private: +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_base_test_edited.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_base_test_edited.h new file mode 100644 index 0000000..12ff81a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_base_test_edited.h @@ -0,0 +1,78 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <iostream> +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/new_nada.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" +#include "sleep.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + bool GetStatus() {return _mock_status}; + std::string GetMockId() {return _mock_id}; + + virtual void Step1() = 0; + void TestHelper(std::string& mock_str, bool mock_status); + virtual void Step2() = 0; + virtual void Step2a() = 0; + int GetTestNumber(std::string& test_name); + virtual void Step2b() = 0; + + private: + bool _mock_status{false}; + int _mock_sensor_id{22}; + std::string _mock_id{"mecorino"}; + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.cpp new file mode 100644 index 0000000..dc0cdcd --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.cpp @@ -0,0 +1,111 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" +#include <iostream> + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - ImageServiceConsumer1 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - ImageServiceConsumer2 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - SteeringAngleServiceConsumer : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + + + - VelocityServiceConsumer : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + + Provider interfaces + =================== + - ObjectDetectionListModule : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + +*/ + +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + std::string marker{"MARK-2"}; + bool constructed_{true}; + std::cout << marker << ": Construction of SensorFusion is " << constructed_ << std::endl; + // Init sensor id & current task id + sensor_id = 2; + current_task_id = 007; +} + +void SensorFusion::Step1() { + std::cout << "Step1 is performed: Clapton likes to clap" << std::endl; +} + +void SensorFusion::Step2() { + std::cout << "Step2 is performed: Mayo is naise" << std::endl; +} + +void SensorFusion::Step2a() { + std::cout << "Step2a is performed: Penultimate is not Penaldo" << std::endl; + _status = true; +} + +void SensorFusion::Step2b() { + std::cout << "Step2b is performed -> Done!" << std::endl; + nada = "Pico-Bello"; +} + + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.h new file mode 100644 index 0000000..9b330cf --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/second_cycle_editing/sensor_fusion_edited.h @@ -0,0 +1,52 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include <iostream> +#include "easylogging++.h" +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" +#include "mock.h" +#include "sleep.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + void Step1() override; + void RepeatSomething(std::string& repeat_id, const int& task_id); + void Step2() override; + void Step2a() override; + int GetTaskId(); + void Step2b() override; + + private: + bool _status{false}; + int sensor_id; + int current_task_id; + std::string nada{"Gellow"}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/model_changed.json b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/model_changed.json new file mode 100644 index 0000000..421df34 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/model_changed.json @@ -0,0 +1,446 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "G", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "B", + "TypeRef": "datatypes::MyVector" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "Step1", + "Period": "300ms", + "PreferredOffset": 0 + }, + { + "Name": "Step2", + "Period": "150ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step1" + ] + }, + { + "Name": "Step2a", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step1", + "Step2" + ] + }, + { + "Name": "Step2b", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Step1", + "Step2a" + ] + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "RPort_ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1" + }, + { + "Name": "RPort_ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2" + }, + { + "Name": "RPort_VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService" + }, + { + "Name": "RPort_SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService" + }, + { + "Name": "RPort_BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService" + } + ], + "PlatformProviderModules": [ + { + "Name": "PPort_BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService" + }, + { + "Name": "PPort_SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService" + }, + { + "Name": "PPort_ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1" + }, + { + "Name": "PPort_VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService" + }, + { + "Name": "PPort_ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_base_test_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_base_test_goal.h new file mode 100644 index 0000000..7f1030e --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_base_test_goal.h @@ -0,0 +1,79 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + bool GetStatus() {return _mock_status}; + std::string GetMockId() {return _mock_id}; + + virtual void Step1() = 0; + void TestHelper(std::string& mock_str, bool mock_status); + virtual void Step2() = 0; +<<<<<<< {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h + virtual void Step3() = 0; + int GetTestNumber(std::string& test_name); + virtual void Step4() = 0; +======= + virtual void Step2a() = 0; + virtual void Step2b() = 0; +>>>>>>> {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h.new~ + + private: + bool _mock_status{false}; + std::string _mock_id{"mecorino"}; + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.cpp new file mode 100644 index 0000000..0e7c833 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.cpp @@ -0,0 +1,108 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" +#include <iostream> + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - ImageServiceConsumer1 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - ImageServiceConsumer2 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - SteeringAngleServiceConsumer : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + + + - VelocityServiceConsumer : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + + Provider interfaces + =================== + - ObjectDetectionListModule : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + +*/ + +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + std::string marker{"MARK-2"}; + bool constructed_{true}; + std::cout << marker << ": Construction of SensorFusion is " << constructed_ << std::endl; +} + +void SensorFusion::Step1() { + std::cout << "Step1 is performed: Clapton likes to clap" << std::endl; +} + +void SensorFusion::Step2() { + std::cout << "Step2 is performed: Mayo is naise" << std::endl; +} + +void SensorFusion::Step3() { + std::cout << "Step3 is performed: Penultimate is not Penaldo" << std::endl; + _status = true; +} + +void SensorFusion::Step4() { + std::cout << "Sensor Fusion successfully run all periodic tasks!" << std::endl; + nada = "Pico-Bello"; +} + + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.h new file mode 100644 index 0000000..70a415b --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes/sensor_fusion_goal.h @@ -0,0 +1,47 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include <iostream> +#include "easylogging++.h" +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" +#include "mock.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + + void Step1() override; + void Step2() override; + void Step2a() override; + void Step2b() override; + + private: + bool _status{false}; + std::string nada{"Gellow"}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/model_changed.json b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/model_changed.json new file mode 100644 index 0000000..64713f6 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/model_changed.json @@ -0,0 +1,446 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "G", + "TypeRef": "datatypes::MyVector" + }, + { + "Name": "B", + "TypeRef": "datatypes::MyVector" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "Steppe", + "Period": "300ms", + "PreferredOffset": 0 + }, + { + "Name": "Estepo", + "Period": "150ms", + "PreferredOffset": 0, + "RunAfter": [ + "Steppe" + ] + }, + { + "Name": "Staipo", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Steppe", + "Estepo" + ] + }, + { + "Name": "Finales", + "Period": "200ms", + "PreferredOffset": 0, + "RunAfter": [ + "Steppe", + "Staipo" + ] + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "RPort_ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1" + }, + { + "Name": "RPort_ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2" + }, + { + "Name": "RPort_VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService" + }, + { + "Name": "RPort_SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService" + }, + { + "Name": "RPort_BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService" + } + ], + "PlatformProviderModules": [ + { + "Name": "PPort_BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService" + }, + { + "Name": "PPort_SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService" + }, + { + "Name": "PPort_ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1" + }, + { + "Name": "PPort_VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService" + }, + { + "Name": "PPort_ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPoint_adas_demo_app_ProviderModules_PPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_app_ConsumerModules_RPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_SteeringAngleService", + "ServiceInterfaceName": "SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService1", + "ServiceInterfaceName": "ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_VelocityService", + "ServiceInterfaceName": "VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ProviderModules_PPort_ImageService2", + "ServiceInterfaceName": "ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPoint_adas_demo_test_app_ConsumerModules_RPort_BrakeService", + "ServiceInterfaceName": "BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_base_test_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_base_test_goal.h new file mode 100644 index 0000000..914260a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_base_test_goal.h @@ -0,0 +1,85 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion_base.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H + +#include <iostream> +#include <memory> +#include "vaf/controller_interface.h" + +#include "af/adas_demo_app/services/image_service_consumer.h" +#include "af/adas_demo_app/services/steering_angle_service_consumer.h" +#include "af/adas_demo_app/services/new_nada.h" +#include "af/adas_demo_app/services/velocity_service_consumer.h" +#include "nsapplicationunit/nsmoduleinterface/nsobjectdetectionlist/object_detection_list_interface_provider.h" +#include "sleep.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusionBase { + public: + struct ConstructorToken { + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; + }; + + SensorFusionBase(ConstructorToken&& token); + virtual ~SensorFusionBase() = default; + + void ReportError(vaf::ErrorCode, std::string, bool) {} + virtual void OnError(const vaf::Error&) {} + std::string GetName() { return ""; } + bool GetStatus() {return _mock_status}; + std::string GetMockId() {return _mock_id}; + +<<<<<<< {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h + virtual void Step1() = 0; + void TestHelper(std::string& mock_str, bool mock_status); + virtual void Step2() = 0; + virtual void Step2a() = 0; + int GetTestNumber(std::string& test_name); + virtual void Step2b() = 0; +======= + virtual void Steppe() = 0; + virtual void Estepo() = 0; + virtual void Staipo() = 0; + virtual void Finales() = 0; +>>>>>>> {TMP_PATH}/SensorFusion/implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h.new~ + + private: + bool _mock_status{false}; + int _mock_sensor_id{22}; + std::string _mock_id{"mecorino"}; + + protected: + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer1_; + std::shared_ptr<af::adas_demo_app::services::ImageServiceConsumer> ImageServiceConsumer2_; + std::shared_ptr<af::adas_demo_app::services::SteeringAngleServiceConsumer> SteeringAngleServiceConsumer_; + std::shared_ptr<af::adas_demo_app::services::VelocityServiceConsumer> VelocityServiceConsumer_; + std::shared_ptr<nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider> ObjectDetectionListModule_; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_BASE_H diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.cpp b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.cpp new file mode 100644 index 0000000..3a6c18c --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.cpp @@ -0,0 +1,135 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "nsapplicationunit/nssensorfusion/sensor_fusion.h" +#include <iostream> + +namespace NsApplicationUnit { +namespace NsSensorFusion { + + +/* + Data element API example for MyDataElement of type std::uint64_t + ================================================================ + - Provider + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_MyDataElement() + ::vaf::Result<void> SetAllocated_MyDataElement(::vaf::DataPtr<std::uint64_t>&& data) + ::vaf::Result<void> Set_MyDataElement(const std::uint64_t& data) + - Consumer + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_MyDataElement() + std::uint64_t Get_MyDataElement() + std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)> + void RegisterDataElementHandler_MyDataElement(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) + + Consumer interfaces + =================== + - ImageServiceConsumer1 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - ImageServiceConsumer2 : af::adas_demo_app::services::ImageServiceConsumer + - Data elements + - camera_image : datatypes::Image + - image_scaling_factor_FieldNotifier : std::uint64_t + + - Operations + - ::vaf::Future<af::adas_demo_app::services::internal::methods::GetImageSize::Output> GetImageSize() + - ::vaf::Future<af::adas_demo_app::services::internal::methods::image_scaling_factor_FieldGetter::Output> image_scaling_factor_FieldGetter() + - ::vaf::Future<void> image_scaling_factor_FieldSetter(const std::uint64_t& data) + + - SteeringAngleServiceConsumer : af::adas_demo_app::services::SteeringAngleServiceConsumer + - Data elements + - steering_angle : datatypes::SteeringAngle + + + - VelocityServiceConsumer : af::adas_demo_app::services::VelocityServiceConsumer + - Data elements + - car_velocity : datatypes::Velocity + + + Provider interfaces + =================== + - ObjectDetectionListModule : nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider + - Data elements + - object_detection_list : adas::interfaces::ObjectDetectionList + + +*/ + +SensorFusion::SensorFusion(ConstructorToken&& token) + : SensorFusionBase(std::move(token)) +{ + std::string marker{"MARK-2"}; + bool constructed_{true}; + std::cout << marker << ": Construction of SensorFusion is " << constructed_ << std::endl; + // Init sensor id & current task id + sensor_id = 2; + current_task_id = 007; +} + +<<<<<<< {TMP_PATH}/SensorFusion/implementation/src/sensor_fusion.cpp +void SensorFusion::Step1() { + std::cout << "Step1 is performed: Clapton likes to clap" << std::endl; +} + +void SensorFusion::Step2() { + std::cout << "Step2 is performed: Mayo is naise" << std::endl; +} + +void SensorFusion::Step2a() { + std::cout << "Step2a is performed: Penultimate is not Penaldo" << std::endl; + _status = true; +} + +void SensorFusion::Step2b() { + std::cout << "Step2b is performed -> Done!" << std::endl; + nada = "Pico-Bello"; +======= +/********************************************************************************************************************** + 4 periodic task(s) +**********************************************************************************************************************/ +// Task with name Steppe and a period of 300ms. +void SensorFusion::Steppe() { + // Insert your code for periodic execution here... +} + +// Task with name Estepo and a period of 150ms. +void SensorFusion::Estepo() { + // Insert your code for periodic execution here... +} + +// Task with name Staipo and a period of 200ms. +void SensorFusion::Staipo() { + // Insert your code for periodic execution here... +} + +// Task with name Finales and a period of 200ms. +void SensorFusion::Finales() { + // Insert your code for periodic execution here... +>>>>>>> {TMP_PATH}/SensorFusion/implementation/src/sensor_fusion.cpp.new~ +} + + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit diff --git a/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.h b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.h new file mode 100644 index 0000000..1869b62 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/data/merge_strategy/simple_changes_second_cycle/sensor_fusion_goal.h @@ -0,0 +1,59 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file sensor_fusion.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H +#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H + +#include <iostream> +#include "easylogging++.h" +#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h" +#include "mock.h" +#include "sleep.h" + +namespace NsApplicationUnit { +namespace NsSensorFusion { + +class SensorFusion : public SensorFusionBase { + public: + SensorFusion(ConstructorToken&& token); + +<<<<<<< {TMP_PATH}/SensorFusion/implementation/include/nsapplicationunit/nssensorfusion/sensor_fusion.h + void Step1() override; + void RepeatSomething(std::string& repeat_id, const int& task_id); + void Step2() override; + void Step2a() override; + int GetTaskId(); + void Step2b() override; +======= + void Steppe() override; + void Estepo() override; + void Staipo() override; + void Finales() override; +>>>>>>> {TMP_PATH}/SensorFusion/implementation/include/nsapplicationunit/nssensorfusion/sensor_fusion.h.new~ + + private: + bool _status{false}; + int sensor_id; + int current_task_id; + std::string nada{"Gellow"}; +}; + +} // namespace NsSensorFusion +} // namespace NsApplicationUnit + +#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H diff --git a/VAF/tests/unit/vafgeneration/input_model_examples/silkit.json b/VAF/tests/unit/vafgeneration/input_model_examples/silkit.json new file mode 100644 index 0000000..ed03647 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/input_model_examples/silkit.json @@ -0,0 +1,66 @@ +{ + "$schema": "../../../MetaModel/VafEntrySchema.json", + "DataTypeDefinitions": { + + }, + "ModuleInterfaces": [ + { + "Name": "ServiceY", + "Namespace": "nsmiddleware::nsmoduleinterface::nsservicey", + "DataElements": [ + { + "Name": "EventY", + "TypeRef": "uint32_t" + } + ], + "Operations": [ + + ] + }, + { + "Name": "ServiceX", + "Namespace": "nsmiddleware::nsmoduleinterface::nsservicex", + "DataElements": [ + { + "Name": "EventX", + "TypeRef": "uint32_t" + } + ], + "Operations": [ + + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "ServiceXConsumer", + "Namespace": "nsserviceconsumer::nsservicexconsumer", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsservicex::ServiceX", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPointServiceXConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "ServiceYProvider", + "Namespace": "nsserviceprovider::nsserviceyprovider", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsservicey::ServiceY", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "CPointServiceYProvider" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "CPointServiceXConsumer", + "ServiceInterfaceName": "ServiceX", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "CPointServiceYProvider", + "ServiceInterfaceName": "ServiceY", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafgeneration/interface/test1_consumer_expected.h b/VAF/tests/unit/vafgeneration/interface/test1_consumer_expected.h new file mode 100644 index 0000000..674758e --- /dev/null +++ b/VAF/tests/unit/vafgeneration/interface/test1_consumer_expected.h @@ -0,0 +1,48 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_interface_consumer.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_INTERFACE_CONSUMER_H +#define TEST_MY_INTERFACE_CONSUMER_H + +#include <string> +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" + +#include "test/my_function.h" +#include <cstdint> + +namespace test { + +class MyInterfaceConsumer { +public: + virtual ~MyInterfaceConsumer() = default; + + virtual ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_my_data_element() = 0; + virtual std::uint64_t Get_my_data_element() = 0; + virtual void RegisterDataElementHandler_my_data_element(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) = 0; + + virtual ::vaf::Future<test::my_function::Output> my_function(const std::uint64_t& in, const std::uint64_t& inout) = 0; + virtual ::vaf::Future<void> my_function_void(const std::uint64_t& in) = 0; +}; + +} // namespace test + +#endif // TEST_MY_INTERFACE_CONSUMER_H diff --git a/VAF/tests/unit/vafgeneration/interface/test1_consumer_mock_expected.h b/VAF/tests/unit/vafgeneration/interface/test1_consumer_mock_expected.h new file mode 100644 index 0000000..8e8ec20 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/interface/test1_consumer_mock_expected.h @@ -0,0 +1,48 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_interface_consumer_mock.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_INTERFACE_CONSUMER_MOCK_H +#define TEST_MY_INTERFACE_CONSUMER_MOCK_H + +#include <string> +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" +#include "gmock/gmock.h" + +#include "test/my_function.h" +#include "test/my_interface_consumer.h" +#include <cstdint> + +namespace test { + +class MyInterfaceConsumerMock : public MyInterfaceConsumer{ +public: + MOCK_METHOD(::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>>, GetAllocated_my_data_element, (), (override)); + MOCK_METHOD(std::uint64_t, Get_my_data_element, (), (override)); + MOCK_METHOD(void, RegisterDataElementHandler_my_data_element, (std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f), (override)); + + MOCK_METHOD(::vaf::Future<test::my_function::Output>, my_function, (const std::uint64_t& in, const std::uint64_t& inout), (override)); + MOCK_METHOD(::vaf::Future<void>, my_function_void, (const std::uint64_t& in), (override)); +}; + +} // namespace test + +#endif // TEST_MY_INTERFACE_CONSUMER_MOCK_H diff --git a/VAF/tests/unit/vafgeneration/interface/test1_provider_expected.h b/VAF/tests/unit/vafgeneration/interface/test1_provider_expected.h new file mode 100644 index 0000000..cf902de --- /dev/null +++ b/VAF/tests/unit/vafgeneration/interface/test1_provider_expected.h @@ -0,0 +1,47 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_interface_provider.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_INTERFACE_PROVIDER_H +#define TEST_MY_INTERFACE_PROVIDER_H + +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" + +#include "test/my_function.h" +#include <cstdint> + +namespace test { + +class MyInterfaceProvider { +public: + virtual ~MyInterfaceProvider() = default; + + virtual ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_my_data_element() = 0; + virtual ::vaf::Result<void> SetAllocated_my_data_element(::vaf::DataPtr<std::uint64_t>&& data) = 0; + virtual ::vaf::Result<void> Set_my_data_element(const std::uint64_t& data) = 0; + + virtual void RegisterOperationHandler_my_function(std::function<test::my_function::Output(const std::uint64_t&, const std::uint64_t&)>&& f) = 0; + virtual void RegisterOperationHandler_my_function_void(std::function<void(const std::uint64_t&)>&& f) = 0; +}; + +} // namespace test + +#endif // TEST_MY_INTERFACE_PROVIDER_H diff --git a/VAF/tests/unit/vafgeneration/interface/test1_provider_mock_expected.h b/VAF/tests/unit/vafgeneration/interface/test1_provider_mock_expected.h new file mode 100644 index 0000000..5632e17 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/interface/test1_provider_mock_expected.h @@ -0,0 +1,47 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_interface_provider_mock.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_INTERFACE_PROVIDER_MOCK_H +#define TEST_MY_INTERFACE_PROVIDER_MOCK_H + +#include <functional> + +#include "vaf/future.h" +#include "vaf/result.h" +#include "vaf/data_ptr.h" +#include "gmock/gmock.h" + +#include "test/my_function.h" +#include "test/my_interface_provider.h" +#include <cstdint> + +namespace test { + +class MyInterfaceProviderMock : public MyInterfaceProvider{ +public: + MOCK_METHOD(::vaf::Result<::vaf::DataPtr<std::uint64_t>>, Allocate_my_data_element, (), (override)); + MOCK_METHOD(::vaf::Result<void>, SetAllocated_my_data_element, (::vaf::DataPtr<std::uint64_t>&& data), (override)); + MOCK_METHOD(::vaf::Result<void>, Set_my_data_element, (const std::uint64_t& data), (override)); + + MOCK_METHOD(void, RegisterOperationHandler_my_function, (std::function<test::my_function::Output(const std::uint64_t&, const std::uint64_t&)>&& f), (override)); + MOCK_METHOD(void, RegisterOperationHandler_my_function_void, (std::function<void(const std::uint64_t&)>&& f), (override)); +}; + +} // namespace test + +#endif // TEST_MY_INTERFACE_PROVIDER_MOCK_H diff --git a/VAF/tests/unit/vafgeneration/protobuf/protobuf_test.proto b/VAF/tests/unit/vafgeneration/protobuf/protobuf_test.proto new file mode 100644 index 0000000..54c9297 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/protobuf/protobuf_test.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +import "protobuf_test2.proto"; + +package protobuf.test; + +message MyArray { + repeated uint64 vaf_value_internal = 1; +} +message MyVector { + repeated uint32 vaf_value_internal = 1; +} +message MyMapEntry { + uint64 vaf_key_internal = 1; + protobuf.test.MyString vaf_value_internal = 2; +} +message MyMap { + repeated MyMapEntry vaf_entry_internal = 1; +} +message MyString { + string vaf_value_internal = 1; +} +message MyEnum { + uint32 vaf_value_internal = 1; +} +message MyStruct { + protobuf.test2.MyStruct MySub1 = 1; + protobuf.test.MyVector MySub2 = 2; +} +message MyTypeRef { + uint64 vaf_value_internal = 1; +} diff --git a/VAF/tests/unit/vafgeneration/protobuf/protobuf_test2.proto b/VAF/tests/unit/vafgeneration/protobuf/protobuf_test2.proto new file mode 100644 index 0000000..353afd0 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/protobuf/protobuf_test2.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + + +package protobuf.test2; + +message MyArray { + repeated uint64 vaf_value_internal = 1; +} +message MyVector { + repeated uint32 vaf_value_internal = 1; +} +message MyStruct { + protobuf.test2.MyStruct MySub1 = 1; + protobuf.test2.MyVector MySub2 = 2; +} diff --git a/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.cpp b/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.cpp new file mode 100644 index 0000000..30363e5 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.cpp @@ -0,0 +1,346 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_consumer_module.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "test/my_consumer_module.h" + +#include <chrono> + +#include "vaf/error_domain.h" +#include "protobuf/interface/test/myinterface/protobuf_transformer.h" +namespace test { + +MyConsumerModule::MyConsumerModule(::vaf::Executor& executor, std::string name, ::vaf::ExecutableControllerInterface& executable_controller_interface) + : ::vaf::ControlInterface(std::move(name), {}, executable_controller_interface, executor), + executor_{ControlInterface::executor_} { +} + +::vaf::Result<void> MyConsumerModule::Init() noexcept { + return ::vaf::Result<void>{}; +} + +void MyConsumerModule::Start() noexcept { + const auto registry_uri = "silkit://localhost:8500"; + const std::string participant_config_text = R"( + Description: My participant configuration + Logging: + Sinks: + - Type: Stdout + Level: Info + )"; + auto config = SilKit::Config::ParticipantConfigurationFromString(participant_config_text); + participant_ = SilKit::CreateParticipant(config, "test_MyConsumerModule", registry_uri); + + SilKit::Services::PubSub::PubSubSpec pubsubspec_test_my_data_element1{"MyInterface_my_data_element1", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_test_my_data_element1.AddLabel("Instance", "MyInterface_my_data_element1", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto receptionHandler_test_my_data_element1 = [&](auto* subscriber, const auto& dataMessageEvent) { + const std::lock_guard<std::mutex> lock(cached_test_my_data_element1_mutex_); + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(dataMessageEvent.data)); + std::vector<std::uint8_t> eventData = deserializer.Deserialize<std::vector<uint8_t>>(); + + std::unique_ptr< std::uint64_t > ptr; + protobuf::interface::test::MyInterface::my_data_element1 deserialized; + deserialized.ParseFromArray( eventData.data(), eventData.size() ); + ptr = std::make_unique< std::uint64_t >(); + ::protobuf::interface::test::MyInterface::my_data_element1ProtoToVaf(deserialized,*ptr); + this->cached_test_my_data_element1_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(ptr)}; + + for(auto& handler_container : registered_test_my_data_element1_event_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(cached_test_my_data_element1_); + } + } + }; + subscriber_test_my_data_element1_= participant_->CreateDataSubscriber("Subscriber_test_my_data_element1", pubsubspec_test_my_data_element1, receptionHandler_test_my_data_element1); + + SilKit::Services::PubSub::PubSubSpec pubsubspec_test_my_data_element2{"MyInterface_my_data_element2", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_test_my_data_element2.AddLabel("Instance", "MyInterface_my_data_element2", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto receptionHandler_test_my_data_element2 = [&](auto* subscriber, const auto& dataMessageEvent) { + const std::lock_guard<std::mutex> lock(cached_test_my_data_element2_mutex_); + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(dataMessageEvent.data)); + std::vector<std::uint8_t> eventData = deserializer.Deserialize<std::vector<uint8_t>>(); + + std::unique_ptr< std::uint64_t > ptr; + protobuf::interface::test::MyInterface::my_data_element2 deserialized; + deserialized.ParseFromArray( eventData.data(), eventData.size() ); + ptr = std::make_unique< std::uint64_t >(); + ::protobuf::interface::test::MyInterface::my_data_element2ProtoToVaf(deserialized,*ptr); + this->cached_test_my_data_element2_ = vaf::ConstDataPtr<const std::uint64_t>{std::move(ptr)}; + + for(auto& handler_container : registered_test_my_data_element2_event_handlers_) { + if(handler_container.is_active_) { + handler_container.handler_(cached_test_my_data_element2_); + } + } + }; + subscriber_test_my_data_element2_= participant_->CreateDataSubscriber("Subscriber_test_my_data_element2", pubsubspec_test_my_data_element2, receptionHandler_test_my_data_element2); + + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyVoidOperation{"MyInterface_MyVoidOperation", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyVoidOperation.AddLabel("Instance", "MyInterface_MyVoidOperation", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto ReturnFunc_test_MyVoidOperation = [&](auto* /*client*/, const auto& event) { + ::vaf::Promise<void>* + promise_pointer = static_cast< + ::vaf::Promise<void>*>( + event.userContext); + if (event.callStatus == SilKit::Services::Rpc::RpcCallStatus::Success) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.resultData)); + std::vector<std::uint8_t> result_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + promise_pointer->set_value(); + } else { + vaf::Error error_code{::vaf::ErrorCode::kDefaultErrorCode, "Rpc call failed"}; + promise_pointer->SetError(error_code); + } + delete promise_pointer; + }; + rpc_client_test_MyVoidOperation_= participant_->CreateRpcClient("test_MyVoidOperation", rpcspec_test_MyVoidOperation, ReturnFunc_test_MyVoidOperation); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyOperation{"MyInterface_MyOperation", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyOperation.AddLabel("Instance", "MyInterface_MyOperation", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto ReturnFunc_test_MyOperation = [&](auto* /*client*/, const auto& event) { + ::vaf::Promise<test::MyOperation::Output>* + promise_pointer = static_cast< + ::vaf::Promise<test::MyOperation::Output>*>( + event.userContext); + if (event.callStatus == SilKit::Services::Rpc::RpcCallStatus::Success) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.resultData)); + std::vector<std::uint8_t> result_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + test::MyOperation::Output output; + protobuf::interface::test::MyInterface::MyOperation_out deserialized; + deserialized.ParseFromArray( result_vector.data(), result_vector.size() ); + ::protobuf::interface::test::MyInterface::MyOperationOutProtoToVaf(deserialized, output); + promise_pointer->set_value(output); + } else { + vaf::Error error_code{::vaf::ErrorCode::kDefaultErrorCode, "Rpc call failed"}; + promise_pointer->SetError(error_code); + } + delete promise_pointer; + }; + rpc_client_test_MyOperation_= participant_->CreateRpcClient("test_MyOperation", rpcspec_test_MyOperation, ReturnFunc_test_MyOperation); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyGetter{"MyInterface_MyGetter", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyGetter.AddLabel("Instance", "MyInterface_MyGetter", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto ReturnFunc_test_MyGetter = [&](auto* /*client*/, const auto& event) { + ::vaf::Promise<test::MyGetter::Output>* + promise_pointer = static_cast< + ::vaf::Promise<test::MyGetter::Output>*>( + event.userContext); + if (event.callStatus == SilKit::Services::Rpc::RpcCallStatus::Success) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.resultData)); + std::vector<std::uint8_t> result_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + test::MyGetter::Output output; + protobuf::interface::test::MyInterface::MyGetter_out deserialized; + deserialized.ParseFromArray( result_vector.data(), result_vector.size() ); + ::protobuf::interface::test::MyInterface::MyGetterOutProtoToVaf(deserialized, output); + promise_pointer->set_value(output); + } else { + vaf::Error error_code{::vaf::ErrorCode::kDefaultErrorCode, "Rpc call failed"}; + promise_pointer->SetError(error_code); + } + delete promise_pointer; + }; + rpc_client_test_MyGetter_= participant_->CreateRpcClient("test_MyGetter", rpcspec_test_MyGetter, ReturnFunc_test_MyGetter); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MySetter{"MyInterface_MySetter", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MySetter.AddLabel("Instance", "MyInterface_MySetter", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto ReturnFunc_test_MySetter = [&](auto* /*client*/, const auto& event) { + ::vaf::Promise<void>* + promise_pointer = static_cast< + ::vaf::Promise<void>*>( + event.userContext); + if (event.callStatus == SilKit::Services::Rpc::RpcCallStatus::Success) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.resultData)); + std::vector<std::uint8_t> result_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + promise_pointer->set_value(); + } else { + vaf::Error error_code{::vaf::ErrorCode::kDefaultErrorCode, "Rpc call failed"}; + promise_pointer->SetError(error_code); + } + delete promise_pointer; + }; + rpc_client_test_MySetter_= participant_->CreateRpcClient("test_MySetter", rpcspec_test_MySetter, ReturnFunc_test_MySetter); + + ReportOperational(); +} + +void MyConsumerModule::Stop() noexcept { +} + +void MyConsumerModule::DeInit() noexcept { +} + +void MyConsumerModule::StartEventHandlerForModule(const std::string& module) { + for(auto& handler_container : registered_test_my_data_element1_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + for(auto& handler_container : registered_test_my_data_element2_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = true; + } + } + active_modules_.push_back(module); +} + +void MyConsumerModule::StopEventHandlerForModule(const std::string& module) { + for(auto& handler_container : registered_test_my_data_element1_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + for(auto& handler_container : registered_test_my_data_element2_event_handlers_) { + if(handler_container.owner_ == module) { + handler_container.is_active_ = false; + } + } + static_cast<void>(std::remove(active_modules_.begin(), active_modules_.end(), module)); +} + + +::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> MyConsumerModule::GetAllocated_my_data_element1() { + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> result_value{ + ::vaf::Error{::vaf::ErrorCode::kNoSampleAvailable, "No sample available"}}; + const std::lock_guard<std::mutex> lock(cached_test_my_data_element1_mutex_); + if (cached_test_my_data_element1_) { + result_value = ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>>{cached_test_my_data_element1_}; + } + return result_value; +} + +std::uint64_t MyConsumerModule::Get_my_data_element1() { + std::uint64_t return_value{}; + const std::lock_guard<std::mutex> lock(cached_test_my_data_element1_mutex_); + if (cached_test_my_data_element1_) { + return_value = *cached_test_my_data_element1_; + } + return return_value; +} + +void MyConsumerModule::RegisterDataElementHandler_my_data_element1(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) { + registered_test_my_data_element1_event_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + registered_test_my_data_element1_event_handlers_.back().is_active_ = true; + } +} + + +::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> MyConsumerModule::GetAllocated_my_data_element2() { + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> result_value{ + ::vaf::Error{::vaf::ErrorCode::kNoSampleAvailable, "No sample available"}}; + const std::lock_guard<std::mutex> lock(cached_test_my_data_element2_mutex_); + if (cached_test_my_data_element2_) { + result_value = ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>>{cached_test_my_data_element2_}; + } + return result_value; +} + +std::uint64_t MyConsumerModule::Get_my_data_element2() { + std::uint64_t return_value{}; + const std::lock_guard<std::mutex> lock(cached_test_my_data_element2_mutex_); + if (cached_test_my_data_element2_) { + return_value = *cached_test_my_data_element2_; + } + return return_value; +} + +void MyConsumerModule::RegisterDataElementHandler_my_data_element2(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) { + registered_test_my_data_element2_event_handlers_.emplace_back(owner, std::move(f)); + if(std::find(active_modules_.begin(), active_modules_.end(), owner) != active_modules_.end()) { + registered_test_my_data_element2_event_handlers_.back().is_active_ = true; + } +} + + + +::vaf::Future<void> MyConsumerModule::MyVoidOperation(const std::uint64_t& in) { + ::vaf::Future<void> return_value; + ::vaf::Promise<void>* promise_pointer = + new ::vaf::Promise<void>(); + return_value = promise_pointer->get_future(); + protobuf::interface::test::MyInterface::MyVoidOperation_in request; + protobuf::interface::test::MyInterface::MyVoidOperationInVafToProto(in, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + + rpc_client_test_MyVoidOperation_->Call(serializer.ReleaseBuffer(), promise_pointer); + + return return_value; +} +::vaf::Future<test::MyOperation::Output> MyConsumerModule::MyOperation(const std::uint64_t& in, const std::uint64_t& inout) { + ::vaf::Future<test::MyOperation::Output> return_value; + ::vaf::Promise<test::MyOperation::Output>* promise_pointer = + new ::vaf::Promise<test::MyOperation::Output>(); + return_value = promise_pointer->get_future(); + protobuf::interface::test::MyInterface::MyOperation_in request; + protobuf::interface::test::MyInterface::MyOperationInVafToProto(in, inout, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + + rpc_client_test_MyOperation_->Call(serializer.ReleaseBuffer(), promise_pointer); + + return return_value; +} +::vaf::Future<test::MyGetter::Output> MyConsumerModule::MyGetter() { + ::vaf::Future<test::MyGetter::Output> return_value; + ::vaf::Promise<test::MyGetter::Output>* promise_pointer = + new ::vaf::Promise<test::MyGetter::Output>(); + return_value = promise_pointer->get_future(); + protobuf::interface::test::MyInterface::MyGetter_in request; + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + + rpc_client_test_MyGetter_->Call(serializer.ReleaseBuffer(), promise_pointer); + + return return_value; +} +::vaf::Future<void> MyConsumerModule::MySetter(const std::uint64_t& a) { + ::vaf::Future<void> return_value; + ::vaf::Promise<void>* promise_pointer = + new ::vaf::Promise<void>(); + return_value = promise_pointer->get_future(); + protobuf::interface::test::MyInterface::MySetter_in request; + protobuf::interface::test::MyInterface::MySetterInVafToProto(a, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + + rpc_client_test_MySetter_->Call(serializer.ReleaseBuffer(), promise_pointer); + + return return_value; +} + +} // namespace test diff --git a/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.h b/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.h new file mode 100644 index 0000000..64aff48 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/silkit/my_consumer_module.h @@ -0,0 +1,97 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_consumer_module.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_CONSUMER_MODULE_H +#define TEST_MY_CONSUMER_MODULE_H + +#include <atomic> +#include <mutex> +#include <memory> +#include <string> +#include <vector> + +#include "vaf/receiver_handler_container.h" +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +#include "silkit/SilKit.hpp" +#include "silkit/services/all.hpp" +#include "silkit/services/orchestration/string_utils.hpp" +#include "silkit/util/serdes/Serialization.hpp" +#include "protobuf_interface_test_MyInterface.pb.h" + +#include "test/my_interface_consumer.h" + + +namespace test { + +class MyConsumerModule final : public test::MyInterfaceConsumer, public vaf::ControlInterface { + public: + MyConsumerModule(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface); + ~MyConsumerModule() override = default; + + MyConsumerModule(const MyConsumerModule&) = delete; + MyConsumerModule(MyConsumerModule&&) = delete; + MyConsumerModule& operator=(const MyConsumerModule&) = delete; + MyConsumerModule& operator=(MyConsumerModule&&) = delete; + + // Management related operations + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + void StartEventHandlerForModule(const std::string& module) override; + void StopEventHandlerForModule(const std::string& module) override; + + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_my_data_element1() override; + std::uint64_t Get_my_data_element1() override; + void RegisterDataElementHandler_my_data_element1(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) override; + ::vaf::Result<::vaf::ConstDataPtr<const std::uint64_t>> GetAllocated_my_data_element2() override; + std::uint64_t Get_my_data_element2() override; + void RegisterDataElementHandler_my_data_element2(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>&& f) override; + + ::vaf::Future<void> MyVoidOperation(const std::uint64_t& in) override; + ::vaf::Future<test::MyOperation::Output> MyOperation(const std::uint64_t& in, const std::uint64_t& inout) override; + ::vaf::Future<test::MyGetter::Output> MyGetter() override; + ::vaf::Future<void> MySetter(const std::uint64_t& a) override; + + private: + vaf::ModuleExecutor& executor_; + std::vector<std::string> active_modules_; + std::unique_ptr<SilKit::IParticipant> participant_; + + ::vaf::ConstDataPtr<const std::uint64_t> cached_test_my_data_element1_{}; + std::vector<::vaf::ReceiverHandlerContainer<std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>>> registered_test_my_data_element1_event_handlers_{}; + std::mutex cached_test_my_data_element1_mutex_; + SilKit::Services::PubSub::IDataSubscriber* subscriber_test_my_data_element1_; + ::vaf::ConstDataPtr<const std::uint64_t> cached_test_my_data_element2_{std::make_unique<const std::uint64_t>(std::uint64_t{64})}; + std::vector<::vaf::ReceiverHandlerContainer<std::function<void(const ::vaf::ConstDataPtr<const std::uint64_t>)>>> registered_test_my_data_element2_event_handlers_{}; + std::mutex cached_test_my_data_element2_mutex_; + SilKit::Services::PubSub::IDataSubscriber* subscriber_test_my_data_element2_; + SilKit::Services::Rpc::IRpcClient* rpc_client_test_MyVoidOperation_; + SilKit::Services::Rpc::IRpcClient* rpc_client_test_MyOperation_; + SilKit::Services::Rpc::IRpcClient* rpc_client_test_MyGetter_; + SilKit::Services::Rpc::IRpcClient* rpc_client_test_MySetter_; +}; + + +} // namespace test + +#endif // TEST_MY_CONSUMER_MODULE_H diff --git a/VAF/tests/unit/vafgeneration/silkit/my_provider_module.cpp b/VAF/tests/unit/vafgeneration/silkit/my_provider_module.cpp new file mode 100644 index 0000000..f7d04a0 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/silkit/my_provider_module.cpp @@ -0,0 +1,259 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_provider_module.cpp + * \brief + * + *********************************************************************************************************************/ + +#include "test/my_provider_module.h" + +#include <memory> + +#include "vaf/internal/data_ptr_helper.h" +#include "vaf/result.h" +#include "vaf/controller_interface.h" +#include "vaf/error_domain.h" +#include "protobuf/interface/test/myinterface/protobuf_transformer.h" +namespace test { + +MyProviderModule::MyProviderModule(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface) + : vaf::ControlInterface(std::move(name), {}, executable_controller_interface, executor) { +} + +vaf::Result<void> MyProviderModule::Init() noexcept { + return vaf::Result<void>{}; +} + +void MyProviderModule::Start() noexcept { + const auto registry_uri = "silkit://localhost:8500"; + const std::string participant_config_text = R"( + Description: My participant configuration + Logging: + Sinks: + - Type: Stdout + Level: Info + )"; + auto config = SilKit::Config::ParticipantConfigurationFromString(participant_config_text); + participant_ = SilKit::CreateParticipant(config, "test_MyProviderModule", registry_uri); + + SilKit::Services::PubSub::PubSubSpec pubsubspec_test_my_data_element1{"MyInterface_my_data_element1", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_test_my_data_element1.AddLabel("Instance", "MyInterface_my_data_element1", SilKit::Services::MatchingLabel::Kind::Mandatory); + publisher_test_my_data_element1_= participant_->CreateDataPublisher("Publisher_test_my_data_element1", pubsubspec_test_my_data_element1); + + SilKit::Services::PubSub::PubSubSpec pubsubspec_test_my_data_element2{"MyInterface_my_data_element2", SilKit::Util::SerDes::MediaTypeData()}; + pubsubspec_test_my_data_element2.AddLabel("Instance", "MyInterface_my_data_element2", SilKit::Services::MatchingLabel::Kind::Mandatory); + publisher_test_my_data_element2_= participant_->CreateDataPublisher("Publisher_test_my_data_element2", pubsubspec_test_my_data_element2); + + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyVoidOperation{"MyInterface_MyVoidOperation", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyVoidOperation.AddLabel("Instance", "MyInterface_MyVoidOperation", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto RemoteFunc_test_MyVoidOperation = [&](auto* server, const auto& event) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.argumentData)); + std::vector<std::uint8_t> argument_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + + protobuf::interface::test::MyInterface::MyVoidOperation_in deserialized; + deserialized.ParseFromArray( argument_vector.data(), argument_vector.size() ); + std::uint64_t in{}; + protobuf::interface::test::MyInterface::MyVoidOperationInProtoToVaf(deserialized, in); + if (CbkFunction_test_MyVoidOperation_) { + CbkFunction_test_MyVoidOperation_(in); + } + protobuf::interface::test::MyInterface::MyVoidOperation_out request; + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + server->SubmitResult(event.callHandle, serializer.ReleaseBuffer()); + }; + server_test_MyVoidOperation_= participant_->CreateRpcServer("test::MyVoidOperation", rpcspec_test_MyVoidOperation, RemoteFunc_test_MyVoidOperation); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyOperation{"MyInterface_MyOperation", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyOperation.AddLabel("Instance", "MyInterface_MyOperation", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto RemoteFunc_test_MyOperation = [&](auto* server, const auto& event) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.argumentData)); + std::vector<std::uint8_t> argument_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + + protobuf::interface::test::MyInterface::MyOperation_in deserialized; + deserialized.ParseFromArray( argument_vector.data(), argument_vector.size() ); + std::uint64_t in{}; + std::uint64_t inout{}; + protobuf::interface::test::MyInterface::MyOperationInProtoToVaf(deserialized, in, inout); + test::MyOperation::Output result; + if (CbkFunction_test_MyOperation_) { + result = CbkFunction_test_MyOperation_(in, inout); + } + protobuf::interface::test::MyInterface::MyOperation_out request; + protobuf::interface::test::MyInterface::MyOperationOutVafToProto(result, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + server->SubmitResult(event.callHandle, serializer.ReleaseBuffer()); + }; + server_test_MyOperation_= participant_->CreateRpcServer("test::MyOperation", rpcspec_test_MyOperation, RemoteFunc_test_MyOperation); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MyGetter{"MyInterface_MyGetter", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MyGetter.AddLabel("Instance", "MyInterface_MyGetter", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto RemoteFunc_test_MyGetter = [&](auto* server, const auto& event) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.argumentData)); + std::vector<std::uint8_t> argument_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + + protobuf::interface::test::MyInterface::MyGetter_in deserialized; + deserialized.ParseFromArray( argument_vector.data(), argument_vector.size() ); + test::MyGetter::Output result; + if (CbkFunction_test_MyGetter_) { + result = CbkFunction_test_MyGetter_(); + } + protobuf::interface::test::MyInterface::MyGetter_out request; + protobuf::interface::test::MyInterface::MyGetterOutVafToProto(result, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + server->SubmitResult(event.callHandle, serializer.ReleaseBuffer()); + }; + server_test_MyGetter_= participant_->CreateRpcServer("test::MyGetter", rpcspec_test_MyGetter, RemoteFunc_test_MyGetter); + + SilKit::Services::Rpc::RpcSpec rpcspec_test_MySetter{"MyInterface_MySetter", SilKit::Util::SerDes::MediaTypeRpc()}; + rpcspec_test_MySetter.AddLabel("Instance", "MyInterface_MySetter", SilKit::Services::MatchingLabel::Kind::Mandatory); + auto RemoteFunc_test_MySetter = [&](auto* server, const auto& event) { + SilKit::Util::SerDes::Deserializer deserializer(SilKit::Util::ToStdVector(event.argumentData)); + std::vector<std::uint8_t> argument_vector = deserializer.Deserialize<std::vector<uint8_t>>(); + + protobuf::interface::test::MyInterface::MySetter_in deserialized; + deserialized.ParseFromArray( argument_vector.data(), argument_vector.size() ); + std::uint64_t a{}; + protobuf::interface::test::MyInterface::MySetterInProtoToVaf(deserialized, a); + if (CbkFunction_test_MySetter_) { + CbkFunction_test_MySetter_(a); + } + protobuf::interface::test::MyInterface::MySetter_out request; + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + server->SubmitResult(event.callHandle, serializer.ReleaseBuffer()); + }; + server_test_MySetter_= participant_->CreateRpcServer("test::MySetter", rpcspec_test_MySetter, RemoteFunc_test_MySetter); + + ReportOperational(); +} + +void MyProviderModule::Stop() noexcept { +} + +void MyProviderModule::DeInit() noexcept { +} + +::vaf::Result<::vaf::DataPtr<std::uint64_t>> MyProviderModule::Allocate_my_data_element1() { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >()}; + return ::vaf::Result<vaf::DataPtr< std::uint64_t >>::FromValue(std::move(ptr)); +} + +::vaf::Result<void> MyProviderModule::SetAllocated_my_data_element1(::vaf::DataPtr<std::uint64_t>&& data) { + protobuf::interface::test::MyInterface::my_data_element1 request; + protobuf::interface::test::MyInterface::my_data_element1VafToProto(*vaf::internal::DataPtrHelper<std::uint64_t>::getRawPtr(data), request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_test_my_data_element1_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} + +::vaf::Result<void> MyProviderModule::Set_my_data_element1(const std::uint64_t& data) { + protobuf::interface::test::MyInterface::my_data_element1 request; + protobuf::interface::test::MyInterface::my_data_element1VafToProto(data, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_test_my_data_element1_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} +::vaf::Result<::vaf::DataPtr<std::uint64_t>> MyProviderModule::Allocate_my_data_element2() { + std::unique_ptr< std::uint64_t > ptr{ + std::make_unique< std::uint64_t >()}; + return ::vaf::Result<vaf::DataPtr< std::uint64_t >>::FromValue(std::move(ptr)); +} + +::vaf::Result<void> MyProviderModule::SetAllocated_my_data_element2(::vaf::DataPtr<std::uint64_t>&& data) { + protobuf::interface::test::MyInterface::my_data_element2 request; + protobuf::interface::test::MyInterface::my_data_element2VafToProto(*vaf::internal::DataPtrHelper<std::uint64_t>::getRawPtr(data), request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_test_my_data_element2_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} + +::vaf::Result<void> MyProviderModule::Set_my_data_element2(const std::uint64_t& data) { + protobuf::interface::test::MyInterface::my_data_element2 request; + protobuf::interface::test::MyInterface::my_data_element2VafToProto(data, request); + size_t nbytes = request.ByteSizeLong(); + std::vector<std::uint8_t> serialized(nbytes); + if (nbytes) { + request.SerializeToArray(serialized.data(), nbytes); + } + SilKit::Util::SerDes::Serializer serializer; + serializer.Serialize(serialized); + publisher_test_my_data_element2_->Publish(serializer.ReleaseBuffer()); + + return ::vaf::Result<void>{}; +} + +void MyProviderModule::RegisterOperationHandler_MyVoidOperation(std::function<void(const std::uint64_t&)>&& f) { + CbkFunction_test_MyVoidOperation_ = std::move(f); +} + +void MyProviderModule::RegisterOperationHandler_MyOperation(std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)>&& f) { + CbkFunction_test_MyOperation_ = std::move(f); +} + +void MyProviderModule::RegisterOperationHandler_MyGetter(std::function<test::MyGetter::Output()>&& f) { + CbkFunction_test_MyGetter_ = std::move(f); +} + +void MyProviderModule::RegisterOperationHandler_MySetter(std::function<void(const std::uint64_t&)>&& f) { + CbkFunction_test_MySetter_ = std::move(f); +} + + +} // namespace test diff --git a/VAF/tests/unit/vafgeneration/silkit/my_provider_module.h b/VAF/tests/unit/vafgeneration/silkit/my_provider_module.h new file mode 100644 index 0000000..ea89c6a --- /dev/null +++ b/VAF/tests/unit/vafgeneration/silkit/my_provider_module.h @@ -0,0 +1,80 @@ +/*!******************************************************************************************************************** + * COPYRIGHT + * ------------------------------------------------------------------------------------------------------------------- + * \verbatim + * Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved. + * + * This software is copyright protected and proprietary to Vector Informatik GmbH. + * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. + * All other rights remain with Vector Informatik GmbH. + * \endverbatim + * ------------------------------------------------------------------------------------------------------------------- + * FILE DESCRIPTION + * -----------------------------------------------------------------------------------------------------------------*/ +/*! \file my_provider_module.h + * \brief + * + *********************************************************************************************************************/ + +#ifndef TEST_MY_PROVIDER_MODULE_H +#define TEST_MY_PROVIDER_MODULE_H + +#include <memory> +#include <string> +#include <vector> + +#include "vaf/controller_interface.h" +#include "vaf/data_ptr.h" +#include "vaf/executable_controller_interface.h" +#include "vaf/result.h" + +#include "silkit/SilKit.hpp" +#include "silkit/services/all.hpp" +#include "silkit/services/orchestration/string_utils.hpp" +#include "silkit/util/serdes/Serialization.hpp" +#include "protobuf_interface_test_MyInterface.pb.h" + +#include "test/my_interface_provider.h" + +namespace test { + +class MyProviderModule final : public test::MyInterfaceProvider, public vaf::ControlInterface { + public: + explicit MyProviderModule(vaf::Executor& executor, std::string name, vaf::ExecutableControllerInterface& executable_controller_interface); + ~MyProviderModule() override = default; + + vaf::Result<void> Init() noexcept override; + void Start() noexcept override; + void Stop() noexcept override; + void DeInit() noexcept override; + + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_my_data_element1() override; + ::vaf::Result<void> SetAllocated_my_data_element1(::vaf::DataPtr<std::uint64_t>&& data) override; + ::vaf::Result<void> Set_my_data_element1(const std::uint64_t& data) override; + ::vaf::Result<::vaf::DataPtr<std::uint64_t>> Allocate_my_data_element2() override; + ::vaf::Result<void> SetAllocated_my_data_element2(::vaf::DataPtr<std::uint64_t>&& data) override; + ::vaf::Result<void> Set_my_data_element2(const std::uint64_t& data) override; + + void RegisterOperationHandler_MyVoidOperation(std::function<void(const std::uint64_t&)>&& f) override; + void RegisterOperationHandler_MyOperation(std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)>&& f) override; + void RegisterOperationHandler_MyGetter(std::function<test::MyGetter::Output()>&& f) override; + void RegisterOperationHandler_MySetter(std::function<void(const std::uint64_t&)>&& f) override; + + private: + std::unique_ptr<SilKit::IParticipant> participant_; + SilKit::Services::PubSub::IDataPublisher* publisher_test_my_data_element1_; + SilKit::Services::PubSub::IDataPublisher* publisher_test_my_data_element2_; + + std::function<void(const std::uint64_t&)> CbkFunction_test_MyVoidOperation_{}; + SilKit::Services::Rpc::IRpcServer* server_test_MyVoidOperation_; + std::function<test::MyOperation::Output(const std::uint64_t&, const std::uint64_t&)> CbkFunction_test_MyOperation_{}; + SilKit::Services::Rpc::IRpcServer* server_test_MyOperation_; + std::function<test::MyGetter::Output()> CbkFunction_test_MyGetter_{}; + SilKit::Services::Rpc::IRpcServer* server_test_MyGetter_; + std::function<void(const std::uint64_t&)> CbkFunction_test_MySetter_{}; + SilKit::Services::Rpc::IRpcServer* server_test_MySetter_; +}; + +} // namespace test + +#endif // TEST_MY_PROVIDER_MODULE_H diff --git a/VAF/tests/unit/vafgeneration/test_application_communication.py b/VAF/tests/unit/vafgeneration/test_application_communication.py new file mode 100644 index 0000000..5efbd0b --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_application_communication.py @@ -0,0 +1,105 @@ +""" +Application communication generator test +""" + +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=too-few-public-methods +# mypy: disable-error-code="no-untyped-def" +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_application_communication + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for application communication generation""" + m = vafmodel.MainModel() + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element1", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + parameters: list[vafmodel.Parameter] = [] + parameters.append( + vafmodel.Parameter( + Name="in", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + operations.append(vafmodel.Operation(Name="MyVoidOperation", Parameters=parameters)) + + parameters.append( + vafmodel.Parameter( + Name="out", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ) + parameters.append( + vafmodel.Parameter( + Name="inout", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + operations.append(vafmodel.Operation(Name="MyOperation", Parameters=parameters)) + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + + m.Executables.append( + vafmodel.Executable( + Name="my_executable", + ExecutorPeriod="10ms", + InternalCommunicationModules=[ + vafmodel.PlatformModule( + Name="MyServiceModule", Namespace="test", ModuleInterfaceRef=m.ModuleInterfaces[0] + ) + ], + ApplicationModules=[], + ) + ) + + vaf_application_communication.generate(m, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + assert filecmp.cmp( + tmp_path / "src-gen/libs/platform_vaf/my_service_module/include/test/my_service_module.h", + script_dir / "application_communication/my_service_module.h", + ) + assert filecmp.cmp( + tmp_path / "src-gen/libs/platform_vaf/my_service_module/src/test/my_service_module.cpp", + script_dir / "application_communication/my_service_module.cpp", + ) + assert filecmp.cmp( + tmp_path / "src-gen/libs/platform_vaf/my_service_module/CMakeLists.txt", + script_dir / "application_communication/CMakeLists.txt", + ) diff --git a/VAF/tests/unit/vafgeneration/test_application_module.py b/VAF/tests/unit/vafgeneration/test_application_module.py new file mode 100644 index 0000000..ed7a7c9 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_application_module.py @@ -0,0 +1,200 @@ +""" +Application module generator +""" + +import filecmp +import os + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" +from pathlib import Path +from typing import List, Tuple +from unittest import mock + +import pytest + +from vaf import vafmodel +from vaf.vafgeneration import vaf_application_module + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for interface generation""" + m = vafmodel.MainModel() + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + + consumed_interfaces: list[vafmodel.ApplicationModuleConsumedInterface] = [] + provided_interfaces: list[vafmodel.ApplicationModuleProvidedInterface] = [] + tasks: list[vafmodel.ApplicationModuleTasks] = [] + + consumed_interfaces.append( + vafmodel.ApplicationModuleConsumedInterface( + InstanceName="c_interface_instance_1", ModuleInterfaceRef=m.ModuleInterfaces[0] + ) + ) + consumed_interfaces.append( + vafmodel.ApplicationModuleConsumedInterface( + InstanceName="c_interface_instance_2", ModuleInterfaceRef=m.ModuleInterfaces[0] + ) + ) + provided_interfaces.append( + vafmodel.ApplicationModuleProvidedInterface( + InstanceName="p_interface_instance_1", ModuleInterfaceRef=m.ModuleInterfaces[0] + ) + ) + provided_interfaces.append( + vafmodel.ApplicationModuleProvidedInterface( + InstanceName="p_interface_instance_2", ModuleInterfaceRef=m.ModuleInterfaces[0] + ) + ) + + tasks.append(vafmodel.ApplicationModuleTasks(Name="task1", Period="10ms")) + tasks.append( + vafmodel.ApplicationModuleTasks(Name="task2", Period="20ms", PreferredOffset=0, RunAfter=["task1"]) + ) + + app_module = vafmodel.ApplicationModule( + Name="MyApplicationModule", + Namespace="apps", + ConsumedInterfaces=consumed_interfaces, + ProvidedInterfaces=provided_interfaces, + Tasks=tasks, + ) + + vaf_application_module.generate_app_module_project_files(app_module, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "src-gen/libs/application_modules_base/my_application_module/include/apps/my_application_module_base.h", + script_dir / "application_module/base.h", + ) + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "src-gen/libs/application_modules_base/my_application_module/src/apps/my_application_module_base.cpp", + script_dir / "application_module/base.cpp", + ) + assert filecmp.cmp( + tmp_path / "src-gen/libs/application_modules_base/my_application_module/CMakeLists.txt", + script_dir / "application_module/base_cmake.txt", + ) + assert filecmp.cmp( + tmp_path / "src-gen/libs/application_modules_base/my_application_module/CMakeLists.txt", + script_dir / "application_module/base_cmake.txt", + ) + + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "implementation/test/unittest/include/apps/my_application_module_base.h", + script_dir / "application_module/test_base.h", + ) + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "implementation//test/unittest/src/apps/my_application_module_base.cpp", + script_dir / "application_module/test_base.cpp", + ) + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "implementation//test/unittest/src/tests.cpp", + script_dir / "application_module/tests.cpp", + ) + assert filecmp.cmp( + tmp_path + # pylint: disable-next=line-too-long + / "implementation//test/unittest/src/main.cpp", + script_dir / "application_module/main.cpp", + ) + assert filecmp.cmp( + tmp_path / "implementation//test/unittest/CMakeLists.txt", + script_dir / "application_module/test_cmake.txt", + ) + + def __mock_app_modules_data( + self, mocked_model: mock.MagicMock, mocked_app_modules_data: List[Tuple[str, str]] + ) -> mock.MagicMock: + mocked_app_modules = [] + for mocked_data in mocked_app_modules_data: + tmp_app_module = mock.MagicMock() + type(tmp_app_module).Name = mocked_data[0] + type(tmp_app_module).ImplementationProperties = mock.PropertyMock() + type(tmp_app_module).ImplementationProperties.InstallationPath = mocked_data[1] + mocked_app_modules.append(tmp_app_module) + type(mocked_model).ApplicationModules = mocked_app_modules + + return mocked_model + + @mock.patch.object(vafmodel, "MainModel") + def test_validate_names_success(self, mocked_model) -> None: + """Test validate_names() that ends with success""" + mocked_app_modules_data = [ + ("Amari", "one"), + ("Amari", "two"), + ("Amarilo", "one"), + ("Countach", "one"), + ("Countacht", "one"), + ("Countacht", "two"), + ] + + mocked_model = self.__mock_app_modules_data(mocked_model, mocked_app_modules_data) + + vaf_application_module.validate_model_app_modules(mocked_model) + + @mock.patch.object(vafmodel, "MainModel") + def test_validate_names_failed(self, mocked_model) -> None: + """Test validate_names() that ends with success""" + mocked_app_modules_data = [ + ("Ver", "one"), + ("Mero", "one"), + ("Countr", "one"), + ("Berk", "one"), + ("Mero", "one"), + ("Loct", "one"), + ("Countr", "one"), + ("Mero", "one"), + ("Herald", "one"), + ] + mocked_model = self.__mock_app_modules_data(mocked_model, mocked_app_modules_data) + + with pytest.raises(RuntimeError) as err: + vaf_application_module.validate_model_app_modules(mocked_model) + + for app_name in [("Mero", "one"), ("Countr", "one")]: + assert ( + " ".join( + [ + f"ERROR: There are {mocked_app_modules_data.count(app_name)} application modules", + f"with name {app_name[0]} and install path '{app_name[1]}'.", + "Application Module must have a unique pair of name and install path!", + ] + ) + in err.value.args[0] + ) diff --git a/VAF/tests/unit/vafgeneration/test_cac_support.py b/VAF/tests/unit/vafgeneration/test_cac_support.py new file mode 100644 index 0000000..fd3d723 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_cac_support.py @@ -0,0 +1,383 @@ +""" +CaC support tests +""" + +import copy +import filecmp +import importlib +import sys +from pathlib import Path +from types import ModuleType +from typing import List + +from vaf import vafmodel, vafpy +from vaf.vafgeneration import vaf_cac_support + + +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=missing-function-docstring +# pylint: disable=duplicate-code +# mypy: disable-error-code="no-untyped-def" +class Brahma: # pylint: disable=dangerous-default-value + """ + Here comes the God of Creation + """ + + @staticmethod + def create_dummy_data_element( + name: str = "dummy_element", namespace: str = "", data_type: str = "uint64_t" + ) -> vafmodel.DataElement: + return vafmodel.DataElement( + Name=name, + TypeRef=vafmodel.DataType(Name=data_type, Namespace=namespace), + ) + + @staticmethod + def create_dummy_parameter( + name: str = "dummy_parameter", + namespace: str = "", + data_type: str = "uint64_t", + direction: vafmodel.ParameterDirection = vafmodel.ParameterDirection.OUT, + ) -> vafmodel.Parameter: + return vafmodel.Parameter( + Name=name, + TypeRef=vafmodel.DataType(Name=data_type, Namespace=namespace), + Direction=direction, + ) + + @staticmethod + def create_dummy_operation( + name: str = "DummyOp", + parameters: List[vafmodel.Parameter] = [create_dummy_parameter()], + ) -> vafmodel.Operation: + return vafmodel.Operation(Name=name, Parameters=parameters) + + @staticmethod + def create_dummy_module_interface( + name: str = "DummyInterface", + namespace: str = "nada", + data_elements: List[vafmodel.DataElement] = [create_dummy_data_element()], + operations: List[vafmodel.Operation] = [create_dummy_operation()], + ) -> vafmodel.ModuleInterface: + return vafmodel.ModuleInterface( + Name=name, Namespace=namespace, DataElements=data_elements, Operations=operations + ) + + +class TestIntegration: # pylint: disable=too-few-public-methods + """ + Class docstrings are also parsed + """ + + @staticmethod + def __process_cac( + model: vafmodel.MainModel, path: Path, file_name: str = "model.json", generate_type: str = "silkit" + ) -> None: + with open(path / file_name, "w", encoding="utf-8") as json_file: + json_file.write(model.model_dump_json(indent=2, by_alias=True)) + ## generate silkit.py + vaf_cac_support.generate(path, file_name, generate_type, path) + + def test_basic_generation(self, tmp_path) -> None: + """ + .. test:: First unit test greet() + :id: TCASE-INTEG_001 + :links: CREQ-001 + + First unit test for greet() + """ + + m = vafmodel.MainModel( + SILKITAdditionalConfiguration=vafmodel.SILKITAdditionalConfigurationType(ConnectionPoints=[]) + ) + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element1", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + InitialValue="{64}", + ) + ) + + parameters: list[vafmodel.Parameter] = [] + parameters.append( + vafmodel.Parameter( + Name="in", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + operations.append(vafmodel.Operation(Name="MyVoidOperation", Parameters=parameters)) + + parameters.append( + vafmodel.Parameter( + Name="out", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ) + parameters.append( + vafmodel.Parameter( + Name="inout", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + operations.append(vafmodel.Operation(Name="MyOperation", Parameters=parameters)) + + operations.append( + vafmodel.Operation( + Name="MyGetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ], + ) + ) + + operations.append( + vafmodel.Operation( + Name="MySetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ], + ) + ) + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + + m.PlatformProviderModules.append( + vafmodel.PlatformModule( + Name="MyProviderModule", + Namespace="nsexec::nstest", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="CPoint", ServiceInterfaceName="ServiceName", RegistryUri="silkit://localhost:8500" + ), + ) + ) + + connection_point = m.PlatformProviderModules[0].ConnectionPointRef + assert isinstance(connection_point, vafmodel.SILKITConnectionPoint) + m.SILKITAdditionalConfiguration = vafmodel.SILKITAdditionalConfigurationType( + ConnectionPoints=[connection_point] + ) + + m.PlatformConsumerModules.append(copy.deepcopy(m.PlatformProviderModules[0])) + m.PlatformConsumerModules[0].Name = "MyConsumerModule" + + with open(tmp_path / "derived-model.json", "w+", encoding="utf-8") as json_file: + json_str = m.model_dump_json(indent=2, by_alias=True) + json_file.write(json_str) + + vaf_cac_support.generate(tmp_path, "derived-model.json", "silkit", tmp_path) + + test_dir = Path(__file__).parent + + assert filecmp.cmp( + tmp_path / "silkit.py", + test_dir / "cac_support/silkit.py.example", + ) + + def test_create_unique_module_interface(self, tmp_path: Path) -> None: + """Resolve FTAF-376: Make module interface in CaC unique + Args: + tmp_path: pytest tmp_path fixture + """ + + def __import_by_file_name(file_path: str) -> ModuleType: + file_name = file_path.rsplit("/")[1].rstrip(".py") + spec = importlib.util.spec_from_file_location(file_name, file_path) + if spec: + module = importlib.util.module_from_spec(spec) + if module and spec.loader: + sys.modules[file_name] = module + spec.loader.exec_module(module) + + if not module: + raise RuntimeError(f"Failed to import module in {file_path}") + + return module + + def __assert_cac_result(list_interfaces: List[vafpy.ModuleInterface], goal: List[str]) -> None: + for idx, interface in enumerate(list_interfaces): + assert "::".join([interface.Namespace, interface.Name]) == goal[idx] + + ## CASE 1: Easiest -> Unique Name + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Yeah", namespace="uno::dos::tres::cuatro"), + Brahma.create_dummy_module_interface(name="Yuhu", namespace="uno::dos::tres::cuatro"), + Brahma.create_dummy_module_interface(name="Entre", namespace="uno::dos::tres::cuatro"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case1.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + __assert_cac_result( + [ + result_module.Uno.Dos.Tres.Cuatro.yeah, + result_module.Uno.Dos.Tres.Cuatro.yuhu, + result_module.Uno.Dos.Tres.Cuatro.entre, + ], + [ + "uno::dos::tres::cuatro::Yeah", + "uno::dos::tres::cuatro::Yuhu", + "uno::dos::tres::cuatro::Entre", + ], + ) + + ## CASE 2: Medium -> Identical Name, but last namespace unique + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::dos::tres::dos"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::dos::tres::tres"), + Brahma.create_dummy_module_interface(name="Weird", namespace="uno::dos::tres::uno"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case2.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + __assert_cac_result( + [ + result_module.Uno.Dos.Tres.Dos.triplet, + result_module.Uno.Dos.Tres.Tres.triplet, + result_module.Uno.Dos.Tres.Uno.triplet, + result_module.Uno.Dos.Tres.Uno.weird, + ], + [ + "uno::dos::tres::dos::Triplet", + "uno::dos::tres::tres::Triplet", + "uno::dos::tres::uno::Triplet", + "uno::dos::tres::uno::Weird", + ], + ) + + ## CASE 3: Hard -> Identical Name and first & last namespace, but + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::tres::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::dos::tres::tres"), + Brahma.create_dummy_module_interface(name="Weird", namespace="uno::dos::tres::uno"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case3.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + __assert_cac_result( + [ + result_module.Uno.Dos.Tres.Tres.triplet, + result_module.Uno.Dos.Tres.Uno.triplet, + result_module.Uno.Dos.Tres.Uno.weird, + result_module.Uno.Tres.Tres.Uno.triplet, + ], + [ + "uno::dos::tres::tres::Triplet", + "uno::dos::tres::uno::Triplet", + "uno::dos::tres::uno::Weird", + "uno::tres::tres::uno::Triplet", + ], + ) + + ## CASE 4: Extra Hard -> Longer Namespaces -> Extra Long + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::mono::teamo::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="tambien::mono::teamo::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="trabajo::mono::teamo::dos::tres::uno"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case4.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + interfaces = [ + result_module.Uno.Mono.Teamo.Dos.Tres.Uno.triplet, + result_module.Tambien.Mono.Teamo.Dos.Tres.Uno.triplet, + result_module.Trabajo.Mono.Teamo.Dos.Tres.Uno.triplet, + ] + unique_ns = ["uno", "tambien", "trabajo"] + for idx, interface in enumerate(interfaces): + assert isinstance(interface, vafpy.ModuleInterface) + assert ( + "::".join([interface.Namespace, interface.Name]) + == f"{unique_ns[idx]}::mono::teamo::dos::tres::uno::Triplet" + ) + + ## CASE 5: Extreme Hard -> Different Namespace lengths + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Weird", namespace="uno::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="uno"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case5.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + interfaces = [ + result_module.Uno.weird, + result_module.Tres.Uno.weird, + result_module.Dos.Tres.Uno.weird, + result_module.Uno.Dos.Tres.Uno.weird, + ] + unique_ns = ["", "tres::", "dos::tres::", "uno::dos::tres::"] + for idx, interface in enumerate(interfaces): + assert isinstance(interface, vafpy.ModuleInterface) + assert "::".join([interface.Namespace, interface.Name]) == f"{unique_ns[idx]}uno::Weird" + + ## CASE 6: Supreme Hard -> Long Namespaces + Different Namespaces + mock_model = vafmodel.MainModel( + ModuleInterfaces=[ + Brahma.create_dummy_module_interface(name="Triplet", namespace="uno::mono::teamo::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="tambien::mono::teamo::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Triplet", namespace="trabajo::mono::teamo::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="uno::dos::tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="tres::uno"), + Brahma.create_dummy_module_interface(name="Weird", namespace="uno"), + ] + ) + self.__process_cac(mock_model, tmp_path, "case6.json") + result_module = __import_by_file_name(str(tmp_path / "silkit.py")) + interfaces = [ + result_module.Uno.Mono.Teamo.Dos.Tres.Uno.triplet, + result_module.Tambien.Mono.Teamo.Dos.Tres.Uno.triplet, + result_module.Trabajo.Mono.Teamo.Dos.Tres.Uno.triplet, + result_module.Uno.Dos.Tres.Uno.weird, + result_module.Tres.Uno.weird, + result_module.Uno.weird, + ] + unique_ns = [ + "uno::mono::teamo::dos::tres::", + "tambien::mono::teamo::dos::tres::", + "trabajo::mono::teamo::dos::tres::", + "uno::dos::tres::", + "tres::", + "", + ] + for idx, interface in enumerate(interfaces): + assert isinstance(interface, vafpy.ModuleInterface) + assert "::".join([interface.Namespace, interface.Name]) == f"{unique_ns[idx]}uno::{interface.Name}" diff --git a/VAF/tests/unit/vafgeneration/test_cmake_common.py b/VAF/tests/unit/vafgeneration/test_cmake_common.py new file mode 100644 index 0000000..19d3603 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_cmake_common.py @@ -0,0 +1,109 @@ +""" +Tests for cmake common +""" + +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_cmake_common + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=line-too-long +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for cmake common generation""" + + m = vafmodel.MainModel() + m.ModuleInterfaces.append(vafmodel.ModuleInterface(Name="MyInterface", Namespace="test")) + m.ApplicationModules.append( + vafmodel.ApplicationModule(Name="MyApp", Namespace="test", ConsumedInterfaces=[], ProvidedInterfaces=[]) + ) + + vaf_module = vafmodel.PlatformModule( + Name="MyModule", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="MyConnectionPoint1", ServiceInterfaceName="ServiceName", RegistryUri="silkit://localhost:8500" + ), + ) + + m.PlatformProviderModules.append(vaf_module) + + mapping = vafmodel.ExecutableApplicationModuleMapping( + ApplicationModuleRef=m.ApplicationModules[0], + InterfaceInstanceToModuleMappings=[ + vafmodel.InterfaceInstanceToModuleMapping(InstanceName="instance1", ModuleRef=vaf_module) + ], + TaskMapping=[], + ) + + m.Executables.append( + vafmodel.Executable( + Name="MyExecutable", + ExecutorPeriod="10ms", + InternalCommunicationModules=[vaf_module], + ApplicationModules=[mapping], + ) + ) + + (tmp_path / "src-gen/executables/already_existing_executable1").mkdir(parents=True, exist_ok=True) + (tmp_path / "src-gen/executables/already_existing_executable2").mkdir(parents=True, exist_ok=True) + + vaf_cmake_common.generate(m, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + assert filecmp.cmp( + tmp_path / "src-gen/CMakeLists.txt", + script_dir / "cmake_common/cmake.txt", + ) + + assert filecmp.cmp( + tmp_path / "src-gen/executables/CMakeLists.txt", + script_dir / "cmake_common/exe_cmake.txt", + ) + + assert filecmp.cmp( + tmp_path / "src-gen/libs/CMakeLists.txt", + script_dir / "cmake_common/libs_cmake.txt", + ) + + vaf_cmake_common.generate(m, tmp_path) + + assert filecmp.cmp( + tmp_path / "src-gen/libs/CMakeLists.txt", + script_dir / "cmake_common/libs_cmake_append.txt", + ) + + m.PlatformProviderModules.append( + vafmodel.PlatformModule( + Name="MyProviderModule", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="CPoint", + ServiceInterfaceName="MyInterface", + RegistryUri="silkit://localhost:8500", + ), + ) + ) + + vaf_cmake_common.generate(m, tmp_path) + + assert filecmp.cmp( + tmp_path / "src-gen/libs/CMakeLists.txt", + script_dir / "cmake_common/libs_cmake_append2.txt", + ) diff --git a/VAF/tests/unit/vafgeneration/test_controller.py b/VAF/tests/unit/vafgeneration/test_controller.py new file mode 100644 index 0000000..0e97ddd --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_controller.py @@ -0,0 +1,149 @@ +""" +Tests for controller generator +""" + +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_controller + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=line-too-long +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for controller generation""" + + m = vafmodel.MainModel() + m.ModuleInterfaces.append(vafmodel.ModuleInterface(Name="MyInterface", Namespace="test")) + m.ApplicationModules.append( + vafmodel.ApplicationModule( + Name="MyApp", + Namespace="test", + ConsumedInterfaces=[ + vafmodel.ApplicationModuleConsumedInterface( + InstanceName="instance3", ModuleInterfaceRef=m.ModuleInterfaces[0] + ), + vafmodel.ApplicationModuleConsumedInterface( + InstanceName="instance4", ModuleInterfaceRef=m.ModuleInterfaces[0], IsOptional=True + ), + ], + ProvidedInterfaces=[ + vafmodel.ApplicationModuleProvidedInterface( + InstanceName="instance1", ModuleInterfaceRef=m.ModuleInterfaces[0] + ), + vafmodel.ApplicationModuleProvidedInterface( + InstanceName="instance2", ModuleInterfaceRef=m.ModuleInterfaces[0] + ), + ], + Tasks=[ + vafmodel.ApplicationModuleTasks(Name="R1", Period="10ms"), + vafmodel.ApplicationModuleTasks(Name="R2", Period="20ms", PreferredOffset=1), + ], + ) + ) + + vaf_module = vafmodel.PlatformModule( + Name="MyModule1", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + ) + + vaf_module2 = vafmodel.PlatformModule( + Name="MyModule4", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + ) + + m.PlatformProviderModules.append( + vafmodel.PlatformModule( + Name="MyModule2", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="MyConnectionPoint1", ServiceInterfaceName="MyInterface", RegistryUri="silkit://localhost:8500" + ), + ) + ) + m.PlatformConsumerModules.append( + vafmodel.PlatformModule( + Name="MyModule3", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="MyConnectionPoint1", ServiceInterfaceName="MyInterface", RegistryUri="silkit://localhost:8500" + ), + ) + ) + + mapping = vafmodel.ExecutableApplicationModuleMapping( + ApplicationModuleRef=m.ApplicationModules[0], + InterfaceInstanceToModuleMappings=[ + vafmodel.InterfaceInstanceToModuleMapping(InstanceName="instance1", ModuleRef=vaf_module), + vafmodel.InterfaceInstanceToModuleMapping( + InstanceName="instance2", ModuleRef=m.PlatformProviderModules[0] + ), + vafmodel.InterfaceInstanceToModuleMapping( + InstanceName="instance3", ModuleRef=m.PlatformConsumerModules[0] + ), + vafmodel.InterfaceInstanceToModuleMapping(InstanceName="instance4", ModuleRef=vaf_module2), + ], + TaskMapping=[ + vafmodel.ExecutableTaskMapping(TaskName="R1", Offset=0, Budget="10ms"), + vafmodel.ExecutableTaskMapping(TaskName="R2"), + ], + ) + + m.Executables.append( + vafmodel.Executable( + Name="MyExecutable", + ExecutorPeriod="10ms", + ApplicationModules=[mapping], + InternalCommunicationModules=[vaf_module], + ) + ) + + vaf_controller.generate(m, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + assert filecmp.cmp( + tmp_path / "src-gen/executables/my_executable/include/executable_controller/executable_controller.h", + script_dir / "controller/controller.h", + ) + + assert filecmp.cmp( + tmp_path / "src-gen/executables/my_executable/src/executable_controller/executable_controller.cpp", + script_dir / "controller/controller.cpp", + ) + + assert filecmp.cmp( + tmp_path / "src/executables/my_executable/include/user_controller.h", + script_dir / "controller/user_controller.h", + ) + + assert filecmp.cmp( + tmp_path / "src/executables/my_executable/src/user_controller.cpp", + script_dir / "controller/user_controller.cpp", + ) + + assert filecmp.cmp( + tmp_path / "src-gen/executables/my_executable/src/main.cpp", + script_dir / "controller/main.cpp", + ) + + assert filecmp.cmp( + tmp_path / "src-gen/executables/my_executable/CMakeLists.txt", + script_dir / "controller/CMakeLists.txt", + ) diff --git a/VAF/tests/unit/vafgeneration/test_generation.py b/VAF/tests/unit/vafgeneration/test_generation.py new file mode 100644 index 0000000..bd254d8 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_generation.py @@ -0,0 +1,213 @@ +"""Test of generation.py""" + +from pathlib import Path + +from vaf import vafmodel +from vaf.cli_core.common.utils import to_camel_case, to_snake_case +from vaf.vafgeneration.generation import ( + FileHelper, + data_type_to_str, + get_data_type_include, + has_operation_out_or_inout_parameter, + is_data_type_base_type, + is_data_type_cstdint_type, + is_out_parameter, + split_full_type, +) + + +def test_to_camel_case() -> None: + """Test to camel case conversion""" + assert to_camel_case("HelloWorld") == "HelloWorld" + assert to_camel_case("Hello World") == "HelloWorld" + assert to_camel_case("Hello_world") == "HelloWorld" + assert to_camel_case("hello_world") == "HelloWorld" + assert to_camel_case("Hello World") == "HelloWorld" + assert to_camel_case("hello") == "Hello" + assert to_camel_case("Hello") == "Hello" + + +def test_to_snake_case() -> None: + """Test to snake case conversion""" + assert to_snake_case("Hello World") == "hello_world" + assert to_snake_case("Hello_world") == "hello_world" + assert to_snake_case("hello_world") == "hello_world" + assert to_snake_case("Hello World") == "hello_world" + assert to_snake_case("hello") == "hello" + assert to_snake_case("Hello") == "hello" + assert to_snake_case("HelloWorld") == "hello_world" + assert to_snake_case("HelloWorldPPortVHato") == "hello_world_p_port_v_hato" + assert to_snake_case("HelloWorld_PPortVHato") == "hello_world_p_port_v_hato" + + +def test_data_type_to_str() -> None: + """Test data type to string conversion""" + # fmt: off + assert data_type_to_str(vafmodel.DataType(Name="uint64_t", Namespace="")) == "std::uint64_t" + assert data_type_to_str(vafmodel.DataType(Name="uint32_t", Namespace="")) == "std::uint32_t" + assert data_type_to_str(vafmodel.DataType(Name="uint16_t", Namespace="")) == "std::uint16_t" + assert data_type_to_str(vafmodel.DataType(Name="uint8_t", Namespace="")) == "std::uint8_t" + assert data_type_to_str(vafmodel.DataType(Name="int64_t", Namespace="")) == "std::int64_t" + assert data_type_to_str(vafmodel.DataType(Name="int32_t", Namespace="")) == "std::int32_t" + assert data_type_to_str(vafmodel.DataType(Name="int16_t", Namespace="")) == "std::int16_t" + assert data_type_to_str(vafmodel.DataType(Name="int8_t", Namespace="")) == "std::int8_t" + assert data_type_to_str(vafmodel.DataType(Name="uint64_t", Namespace="std")) == "std::uint64_t" + assert data_type_to_str(vafmodel.DataType(Name="uint8_t", Namespace="std")) == "std::uint8_t" + assert data_type_to_str(vafmodel.DataType(Name="uint8_t", Namespace="not_std")) == "not_std::uint8_t" + assert data_type_to_str(vafmodel.DataType(Name="double", Namespace="")) == "double" + assert data_type_to_str(vafmodel.DataType(Name="float", Namespace="")) == "float" + assert data_type_to_str(vafmodel.DataType(Name="bool", Namespace="")) == "bool" + assert data_type_to_str(vafmodel.DataType(Name="ABC", Namespace="")) == "ABC" + assert data_type_to_str(vafmodel.DataType(Name="ABC", Namespace="test")) == "test::ABC" + assert data_type_to_str(vafmodel.DataType(Name="ABC", Namespace="test::1")) == "test::1::ABC" + # fmt: on + + +def test_file_helper() -> None: + """Test of file helper class""" + f = FileHelper("file", "abc::dfg") + + assert f.get_file_path(Path.cwd(), ".h") == Path.cwd() / "include/abc/dfg/file.h" + assert f.get_guard() == "ABC_DFG_FILE_H" + assert f.get_include() == '#include "abc/dfg/file.h"' + assert f.get_name() == "file" + assert f.get_namespace_start() == "namespace abc {\nnamespace dfg {\n" + + f2 = FileHelper("file", "MyNamespace") + assert f2.get_file_path(Path.cwd(), ".cpp") == Path.cwd() / "src/mynamespace/file.cpp" + + f3 = FileHelper("file", "MyNamespace") + assert f3.get_file_path(Path.cwd(), ".txt") == Path.cwd() / "mynamespace/file.txt" + assert f3.get_namespace_start() == "namespace MyNamespace {\n" + + +def test_get_data_type_include() -> None: + """Test function get_data_type_include""" + assert get_data_type_include("T", "ABC") == '#include "abc/impl_type_t.h"' + assert get_data_type_include("T", "ABC::dfg") == '#include "abc/dfg/impl_type_t.h"' + + assert get_data_type_include("uint8_t", "") == "#include <cstdint>" + assert get_data_type_include("uint16_t", "") == "#include <cstdint>" + assert get_data_type_include("uint32_t", "") == "#include <cstdint>" + assert get_data_type_include("uint64_t", "") == "#include <cstdint>" + assert get_data_type_include("int8_t", "") == "#include <cstdint>" + assert get_data_type_include("int16_t", "") == "#include <cstdint>" + assert get_data_type_include("int32_t", "") == "#include <cstdint>" + assert get_data_type_include("int64_t", "") == "#include <cstdint>" + assert get_data_type_include("int64_t", "std") == "#include <cstdint>" + + assert get_data_type_include("int64_t", "not_std") == '#include "not_std/impl_type_int64_t.h"' + + assert get_data_type_include("double", "") == "" + assert get_data_type_include("float", "") == "" + assert get_data_type_include("bool", "") == "" + + assert get_data_type_include("bool", "std") == "" + + +def test_has_operation_out_or_inout_parameter() -> None: + """Tests function has_operation_out_or_inout_parameter""" + parameters: list[vafmodel.Parameter] = [] + parameters.append( + vafmodel.Parameter( + Name="dummy", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + + assert has_operation_out_or_inout_parameter(vafmodel.Operation(Name="dummy", Parameters=parameters)) is False # pylint: disable=line-too-long + + parameters.append( + vafmodel.Parameter( + Name="dummy", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + + assert has_operation_out_or_inout_parameter(vafmodel.Operation(Name="dummy", Parameters=parameters)) is True # pylint: disable=line-too-long + + +def test_is_out_parameter() -> None: + """Tests function is_out_parameter""" + assert ( + is_out_parameter( + vafmodel.Parameter( + Name="dummy", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + is False + ) + assert ( + is_out_parameter( + vafmodel.Parameter( + Name="dummy", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + is False + ) + assert ( + is_out_parameter( + vafmodel.Parameter( + Name="dummy", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ) + is True + ) + + +def test_split_full_type() -> None: + """Test for split_full_type""" + assert split_full_type("test::Test") == ("Test", "test") + assert split_full_type("Test") == ("Test", "") + assert split_full_type("test1::test2::Test") == ("Test", "test1::test2") + + +def test_is_data_type_base_type() -> None: + """Test for is_data_type_base_type""" + assert is_data_type_base_type("float", "") + assert is_data_type_base_type("double", "") + assert is_data_type_base_type("bool", "") + assert is_data_type_base_type("float", "std") + assert is_data_type_base_type("double", "std") + assert is_data_type_base_type("bool", "std") + + assert not is_data_type_base_type("float", "test") + assert not is_data_type_base_type("double", "std1") + assert not is_data_type_base_type("bool", "sstd") + assert not is_data_type_base_type("uint8_t", "std") + assert not is_data_type_base_type("dummy", "test") + assert not is_data_type_base_type("uint8_t", "") + + +def test_is_data_type_cstdint_type() -> None: + """Test for is_data_type_cstdint_type""" + assert is_data_type_cstdint_type("uint8_t", "") + assert is_data_type_cstdint_type("uint16_t", "") + assert is_data_type_cstdint_type("uint32_t", "") + assert is_data_type_cstdint_type("uint64_t", "") + assert is_data_type_cstdint_type("int8_t", "") + assert is_data_type_cstdint_type("int16_t", "") + assert is_data_type_cstdint_type("int32_t", "") + assert is_data_type_cstdint_type("int64_t", "") + + assert is_data_type_cstdint_type("uint8_t", "std") + assert is_data_type_cstdint_type("uint16_t", "std") + assert is_data_type_cstdint_type("uint32_t", "std") + assert is_data_type_cstdint_type("uint64_t", "std") + assert is_data_type_cstdint_type("int8_t", "std") + assert is_data_type_cstdint_type("int16_t", "std") + assert is_data_type_cstdint_type("int32_t", "std") + assert is_data_type_cstdint_type("int64_t", "std") + + assert not is_data_type_cstdint_type("int64_t2", "") + assert not is_data_type_cstdint_type("test", "test") + assert not is_data_type_cstdint_type("test", "") + assert not is_data_type_cstdint_type("int64_t", "test") diff --git a/VAF/tests/unit/vafgeneration/test_merge_after_regeneration.py b/VAF/tests/unit/vafgeneration/test_merge_after_regeneration.py new file mode 100644 index 0000000..3d832bb --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_merge_after_regeneration.py @@ -0,0 +1,332 @@ +""" +Application module generator +""" + +import filecmp + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=line-too-long +# pylint: disable=missing-function-docstring +# mypy: disable-error-code="no-untyped-def, no-untyped-call" +from pathlib import Path +from shutil import copyfile +from typing import Dict + +from vaf.cli_core.bootstrap import project_init_cmd +from vaf.cli_core.common.utils import concat_str_to_path +from vaf.cli_core.main import project_cmd +from vaf.vafgeneration.vaf_generate_application_module import generate_application_module +from vaf.vafgeneration.vaf_generate_common import ( + __file_has_conflict, + __get_ancestor_file_rel_path, + __get_newly_generated_file_path, + suffix_old_source, +) + + +def get_newly_generated_file_path(*args, **kwargs): + return __get_newly_generated_file_path(*args, **kwargs) + + +def file_has_conflict(*args, **kwargs): + return __file_has_conflict(*args, **kwargs) + + +def get_ancestor_file_rel_path(*args, **kwargs): + return __get_ancestor_file_rel_path(*args, **kwargs) + + +class TestRegenerationMerge: + """Testing regeneration in app module project""" + + ut_mock_data_path = Path(__file__).parent / "data/merge_strategy" + model_rel_out_path = "model/model.json" + cpp_rel_path = "implementation/src/sensor_fusion.cpp" + h_rel_path = "implementation/include/nsapplicationunit/nssensorfusion/sensor_fusion.h" + ut_h_rel_path = "implementation/test/unittest/include/nsapplicationunit/nssensorfusion/sensor_fusion_base.h" + cmake_rel_path = "implementation/CMakeLists.txt" + prj_cmd = project_cmd.ProjectCmd() + prj_init_cmd = project_init_cmd.ProjectInitCmd() + int_to_ordinal_dict: Dict[int, str] = {1: "first", 2: "second"} + + def _update_model_json(self, path_new_json: Path, path_old_json: Path) -> None: + # simulate regeneration: current model.json -> model.json~ + copyfile( + path_old_json, + concat_str_to_path(path_old_json, "~"), + ) + # copy new model + copyfile( + path_new_json, + path_old_json, + ) + + def _compare_file_with_conflict(self, gen_file_path: Path, goal_file_path: Path, workspace_path: Path) -> bool: + with open(gen_file_path, "r", encoding="utf-8") as gen_file: + with open(goal_file_path, "r", encoding="utf-8") as goal_file: + assert gen_file.read() == goal_file.read().replace("{TMP_PATH}", str(workspace_path)) + return True + + def _generate(self, out_path: Path, disable_auto_merge: bool = False) -> None: + generate_application_module( + str(out_path / "SensorFusion" / self.model_rel_out_path), + str(out_path / "SensorFusion"), + execute_merge=not disable_auto_merge, + ) + + def _prerun_test_merge_regeneration(self, out_path: Path, cycle: int, edited_source: bool = True) -> None: + # init stuffs only needed in first cycle: + if cycle == 1: + # create app module project + self.prj_init_cmd.app_module_project_init( + "NsApplicationUnit::NsSensorFusion", "SensorFusion", str(out_path) + ) + + # copy model_base.json + copyfile(self.ut_mock_data_path / "model_base.json", out_path / "SensorFusion" / self.model_rel_out_path) + + # vaf project generate model base + self._generate(out_path) + + if edited_source: + # simulate user editing cpp & h implementations & ut + copyfile( + self.ut_mock_data_path + / f"{self.int_to_ordinal_dict[cycle]}_cycle_editing" + / "sensor_fusion_edited.cpp", + out_path / "SensorFusion" / self.cpp_rel_path, + ) + copyfile( + self.ut_mock_data_path / f"{self.int_to_ordinal_dict[cycle]}_cycle_editing" / "sensor_fusion_edited.h", + out_path / "SensorFusion" / self.h_rel_path, + ) + copyfile( + self.ut_mock_data_path + / f"{self.int_to_ordinal_dict[cycle]}_cycle_editing" + / "sensor_fusion_base_test_edited.h", + out_path / "SensorFusion" / self.ut_h_rel_path, + ) + if ( + self.ut_mock_data_path / f"{self.int_to_ordinal_dict[cycle]}_cycle_editing" / "CMakeLists.txt" + ).is_file(): + copyfile( + self.ut_mock_data_path / f"{self.int_to_ordinal_dict[cycle]}_cycle_editing" / "CMakeLists.txt", + out_path / "SensorFusion" / self.cmake_rel_path, + ) + + def test_simple_merge_regeneration(self, tmp_path) -> None: + """FTAF-262: Test merging files after regeneration in app module with simple model changes""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + copyfile( + tmp_path / "SensorFusion" / self.model_rel_out_path, + concat_str_to_path(tmp_path / "SensorFusion" / self.model_rel_out_path, "~"), + ) + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # assert conflicts exist in cpp + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.cpp_rel_path, + goal_file_path=self.ut_mock_data_path / "simple_changes/sensor_fusion_goal.cpp", + workspace_path=tmp_path, + ) + # assert no conflicts in h + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.h_rel_path, + self.ut_mock_data_path / "simple_changes/sensor_fusion_goal.h", + ) + # assert conflicts exist ut h + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.ut_h_rel_path, + goal_file_path=self.ut_mock_data_path / "simple_changes/sensor_fusion_base_test_goal.h", + workspace_path=tmp_path, + ) + # assert CMakeLists + assert (tmp_path / "SensorFusion" / (self.cmake_rel_path + suffix_old_source)).is_file() + assert not (tmp_path / "SensorFusion" / get_newly_generated_file_path(self.cmake_rel_path)).is_file() + + def test_complex_merge_regeneration(self, tmp_path) -> None: + """FTAF-262: Test merging files after regeneration in app module with complex model changes""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + # update model + self._update_model_json( + self.ut_mock_data_path / "complex_changes/model_changed_complex.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # assert conflicts exist in cpp + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.cpp_rel_path, + goal_file_path=self.ut_mock_data_path / "complex_changes/sensor_fusion_goal.cpp", + workspace_path=tmp_path, + ) + # assert no conflicts in h + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.h_rel_path, + self.ut_mock_data_path / "complex_changes/sensor_fusion_goal.h", + ) + # assert conflicts exist ut h + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.ut_h_rel_path, + goal_file_path=self.ut_mock_data_path / "complex_changes/sensor_fusion_base_test_goal.h", + workspace_path=tmp_path, + ) + + def test_merge_regeneration_without_model_change(self, tmp_path) -> None: + """FTAF-262: Test merging files after regeneration in app module without any model changes""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + # regenerate + self._generate(tmp_path) + + # assert user changes are kept and not overwritten + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.cpp_rel_path, + self.ut_mock_data_path / "first_cycle_editing/sensor_fusion_edited.cpp", + ) + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.h_rel_path, + self.ut_mock_data_path / "first_cycle_editing/sensor_fusion_edited.h", + ) + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.ut_h_rel_path, + self.ut_mock_data_path / "first_cycle_editing/sensor_fusion_base_test_edited.h", + ) + + def test_two_cycle_merge_regeneration(self, tmp_path) -> None: + """FTAF-262: Test merging files after regeneration in app module in two cycles""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + self._prerun_test_merge_regeneration(tmp_path, cycle=2) + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes_second_cycle/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # assert conflicts exist in cpp + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.cpp_rel_path, + goal_file_path=self.ut_mock_data_path / "simple_changes_second_cycle/sensor_fusion_goal.cpp", + workspace_path=tmp_path, + ) + # assert conflicts exist in h + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.h_rel_path, + goal_file_path=self.ut_mock_data_path / "simple_changes_second_cycle/sensor_fusion_goal.h", + workspace_path=tmp_path, + ) + # assert conflicts exist ut h + assert self._compare_file_with_conflict( + gen_file_path=tmp_path / "SensorFusion" / self.ut_h_rel_path, + goal_file_path=self.ut_mock_data_path / "simple_changes_second_cycle/sensor_fusion_base_test_goal.h", + workspace_path=tmp_path, + ) + + def test_old_way(self, tmp_path) -> None: + """Test old way of regeneration""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + copyfile( + tmp_path / "SensorFusion" / self.model_rel_out_path, + concat_str_to_path(tmp_path / "SensorFusion" / self.model_rel_out_path, "~"), + ) + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path, disable_auto_merge=True) + + # assert ~new is generated and no ancestor + assert (tmp_path / "SensorFusion" / get_newly_generated_file_path(self.cpp_rel_path)).is_file() + assert not (tmp_path / "SensorFusion" / get_ancestor_file_rel_path(self.cpp_rel_path)).is_file() + assert (tmp_path / "SensorFusion" / get_newly_generated_file_path(self.h_rel_path)).is_file() + assert not (tmp_path / "SensorFusion" / get_ancestor_file_rel_path(self.h_rel_path)).is_file() + assert (tmp_path / "SensorFusion" / get_newly_generated_file_path(self.ut_h_rel_path)).is_file() + assert not (tmp_path / "SensorFusion" / get_ancestor_file_rel_path(self.ut_h_rel_path)).is_file() + + def test_not_overwrite_conflicted_file(self, tmp_path) -> None: + """FTAF-431: Test source files with conflict won't be overwritten""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1) + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # update model + self._update_model_json( + self.ut_mock_data_path / "simple_changes_second_cycle/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # assert no conflicts in backup files + assert not file_has_conflict( + concat_str_to_path(tmp_path / "SensorFusion" / self.cpp_rel_path, suffix_old_source) + ) + assert not file_has_conflict(concat_str_to_path(tmp_path / "SensorFusion" / self.h_rel_path, suffix_old_source)) + assert not file_has_conflict( + concat_str_to_path(tmp_path / "SensorFusion" / self.ut_h_rel_path, suffix_old_source) + ) + + def test_merge_removal(self, tmp_path) -> None: + """FTAF-453: Test merging files after regeneration in app module with removal in models""" + self._prerun_test_merge_regeneration(tmp_path, cycle=1, edited_source=False) + copyfile( + tmp_path / "SensorFusion" / self.model_rel_out_path, + concat_str_to_path(tmp_path / "SensorFusion" / self.model_rel_out_path, "~"), + ) + # update model + self._update_model_json( + self.ut_mock_data_path / "removal/model_changed.json", + tmp_path / "SensorFusion" / self.model_rel_out_path, + ) + + # regenerate + self._generate(tmp_path) + + # assert no conflicts in cpp + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.cpp_rel_path, + self.ut_mock_data_path / "removal/sensor_fusion_goal.cpp", + ) + # assert no conflicts in h + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.h_rel_path, + self.ut_mock_data_path / "removal/sensor_fusion_goal.h", + ) + # assert no conflicts in h + assert filecmp.cmp( + tmp_path / "SensorFusion" / self.ut_h_rel_path, + self.ut_mock_data_path / "removal/sensor_fusion_base_test_goal.h", + ) diff --git a/VAF/tests/unit/vafgeneration/test_protobuf.py b/VAF/tests/unit/vafgeneration/test_protobuf.py new file mode 100644 index 0000000..fb146ca --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_protobuf.py @@ -0,0 +1,258 @@ +""" +protobuf generator test +""" + +# pylint: disable=duplicate-code +import copy +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_protobuf_serdes +from vaf.vafpy import import_model +from vaf.vafpy.model_runtime import model_runtime + + +# pylint: disable=too-many-statements +# pylint: disable=missing-any-param-doc +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=too-few-public-methods +# mypy: disable-error-code="no-untyped-def" +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for silkit generation""" + m = vafmodel.MainModel() + + m.DataTypeDefinitions = vafmodel.DataTypeDefinition() + m.DataTypeDefinitions.Arrays.append( + vafmodel.Array( + Name="MyArray", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Size=1, + ) + ) + m.DataTypeDefinitions.Vectors.append( + vafmodel.Vector( + Name="MyVector", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + ) + ) + sub1 = vafmodel.SubElement( + Name="MySub1", + TypeRef=vafmodel.DataType(Name="MyStruct", Namespace="test2"), + ) + sub2 = vafmodel.SubElement( + Name="MySub2", + TypeRef=vafmodel.DataType(Name="MyVector", Namespace="test"), + ) + m.DataTypeDefinitions.Structs.append( + vafmodel.Struct( + Name="MyStruct", + Namespace="test", + SubElements=[sub1, sub2], + ) + ) + m.DataTypeDefinitions.Strings.append( + vafmodel.String( + Name="MyString", + Namespace="test", + ) + ) + literals = [ + vafmodel.EnumLiteral( + Label="MyLit1", + Value=0, + ), + vafmodel.EnumLiteral( + Label="MyLit2", + Value=1, + ), + vafmodel.EnumLiteral( + Label="MyLit3", + Value=4, + ), + ] + m.DataTypeDefinitions.Enums.append( + vafmodel.VafEnum( + Name="MyEnum", + Namespace="test", + Literals=literals, + ) + ) + m.DataTypeDefinitions.Maps.append( + vafmodel.Map( + Name="MyMap", + Namespace="test", + MapKeyTypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + MapValueTypeRef=vafmodel.DataType(Name="MyString", Namespace="test"), + ) + ) + m.DataTypeDefinitions.TypeRefs.append( + vafmodel.TypeRef( + Name="MyTypeRef", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + m.DataTypeDefinitions.Arrays.append( + vafmodel.Array( + Name="MyArray", + Namespace="test2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Size=1, + ) + ) + m.DataTypeDefinitions.Vectors.append( + vafmodel.Vector( + Name="MyVector", + Namespace="test2", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + ) + ) + sub1 = vafmodel.SubElement( + Name="MySub1", + TypeRef=vafmodel.DataType(Name="MyStruct", Namespace="test2"), + ) + sub2 = vafmodel.SubElement( + Name="MySub2", + TypeRef=vafmodel.DataType(Name="MyVector", Namespace="test2"), + ) + m.DataTypeDefinitions.Structs.append( + vafmodel.Struct( + Name="MyStruct", + Namespace="test2", + SubElements=[sub1, sub2], + ) + ) + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element1", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + InitialValue="{64}", + ) + ) + + parameters: list[vafmodel.Parameter] = [] + parameters.append( + vafmodel.Parameter( + Name="in", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + operations.append(vafmodel.Operation(Name="MyVoidOperation", Parameters=parameters)) + + parameters.append( + vafmodel.Parameter( + Name="out", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ) + parameters.append( + vafmodel.Parameter( + Name="inout", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + operations.append(vafmodel.Operation(Name="MyOperation", Parameters=parameters)) + + operations.append( + vafmodel.Operation( + Name="MyGetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ], + ) + ) + + operations.append( + vafmodel.Operation( + Name="MySetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ], + ) + ) + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + + silkit_connection_point = vafmodel.SILKITConnectionPoint( + Name="CPoint", + ServiceInterfaceName="MyInterface", + RegistryUri="silkit://localhost:8500", + ) + + m.PlatformProviderModules.append( + vafmodel.PlatformModule( + Name="MyProviderModule", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=silkit_connection_point, + ) + ) + + m.PlatformConsumerModules.append(copy.deepcopy(m.PlatformProviderModules[0])) + m.PlatformConsumerModules[0].Name = "MyConsumerModule" + + m.SILKITAdditionalConfiguration = vafmodel.SILKITAdditionalConfigurationType( + ConnectionPoints=[silkit_connection_point], + ) + + tmp_file = tmp_path / "tmp.json" + with open(tmp_file, "w", encoding="utf-8") as f: + f.write(m.model_dump_json(indent=2, exclude_none=True, exclude_defaults=True, by_alias=True)) + + import_model(str(tmp_file)) + + vaf_protobuf_serdes.generate(model_runtime, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + pm_path = tmp_path / "src-gen/libs/protobuf_serdes/proto" + assert filecmp.cmp( + pm_path / "protobuf_test.proto", + script_dir / "protobuf/protobuf_test.proto", + ) + assert filecmp.cmp( + pm_path / "protobuf_test2.proto", + script_dir / "protobuf/protobuf_test2.proto", + ) + + +# pylint: enable=too-many-statements diff --git a/VAF/tests/unit/vafgeneration/test_silkit.py b/VAF/tests/unit/vafgeneration/test_silkit.py new file mode 100644 index 0000000..19a2d28 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_silkit.py @@ -0,0 +1,255 @@ +""" +silkit generator test +""" + +# pylint: disable=duplicate-code +import copy +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_silkit + + +# pylint: disable=too-many-statements +# pylint: disable=missing-any-param-doc +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=too-few-public-methods +# mypy: disable-error-code="no-untyped-def" +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for silkit generation""" + m = vafmodel.MainModel() + + m.DataTypeDefinitions = vafmodel.DataTypeDefinition() + m.DataTypeDefinitions.Arrays.append( + vafmodel.Array( + Name="MyArray", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Size=1, + ) + ) + m.DataTypeDefinitions.Vectors.append( + vafmodel.Vector( + Name="MyVector", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + ) + ) + sub1 = vafmodel.SubElement( + Name="MySub1", + TypeRef=vafmodel.DataType(Name="MyStruct", Namespace="test2"), + ) + sub2 = vafmodel.SubElement( + Name="MySub2", + TypeRef=vafmodel.DataType(Name="MyVector", Namespace="test"), + ) + m.DataTypeDefinitions.Structs.append( + vafmodel.Struct( + Name="MyStruct", + Namespace="test", + SubElements=[sub1, sub2], + ) + ) + m.DataTypeDefinitions.Strings.append( + vafmodel.String( + Name="MyString", + Namespace="test", + ) + ) + lit1 = vafmodel.EnumLiteral( + Label="MyLit1", + Value=0, + ) + lit2 = vafmodel.EnumLiteral( + Label="MyLit2", + Value=1, + ) + lit3 = vafmodel.EnumLiteral( + Label="MyLit3", + Value=4, + ) + m.DataTypeDefinitions.Enums.append( + vafmodel.VafEnum( + Name="MyEnum", + Namespace="test", + Literals=[lit1, lit2, lit3], + ) + ) + m.DataTypeDefinitions.Maps.append( + vafmodel.Map( + Name="MyMap", + Namespace="test", + MapKeyTypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + MapValueTypeRef=vafmodel.DataType(Name="MyString", Namespace="test"), + ) + ) + m.DataTypeDefinitions.TypeRefs.append( + vafmodel.TypeRef( + Name="MyTypeRef", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + m.DataTypeDefinitions.Arrays.append( + vafmodel.Array( + Name="MyArray", + Namespace="test2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Size=1, + ) + ) + m.DataTypeDefinitions.Vectors.append( + vafmodel.Vector( + Name="MyVector", + Namespace="test2", + TypeRef=vafmodel.DataType(Name="uint8_t", Namespace=""), + ) + ) + sub1 = vafmodel.SubElement( + Name="MySub1", + TypeRef=vafmodel.DataType(Name="MyStruct", Namespace="test2"), + ) + sub2 = vafmodel.SubElement( + Name="MySub2", + TypeRef=vafmodel.DataType(Name="MyVector", Namespace="test2"), + ) + m.DataTypeDefinitions.Structs.append( + vafmodel.Struct( + Name="MyStruct", + Namespace="test2", + SubElements=[sub1, sub2], + ) + ) + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element1", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element2", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + InitialValue="{64}", + ) + ) + + parameters: list[vafmodel.Parameter] = [] + parameters.append( + vafmodel.Parameter( + Name="in", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ) + operations.append(vafmodel.Operation(Name="MyVoidOperation", Parameters=parameters)) + + parameters.append( + vafmodel.Parameter( + Name="out", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ) + parameters.append( + vafmodel.Parameter( + Name="inout", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ) + ) + operations.append(vafmodel.Operation(Name="MyOperation", Parameters=parameters)) + + operations.append( + vafmodel.Operation( + Name="MyGetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ) + ], + ) + ) + + operations.append( + vafmodel.Operation( + Name="MySetter", + Parameters=[ + vafmodel.Parameter( + Name="a", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ) + ], + ) + ) + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + + m.PlatformProviderModules.append( + vafmodel.PlatformModule( + Name="MyProviderModule", + Namespace="test", + ModuleInterfaceRef=m.ModuleInterfaces[0], + OriginalEcoSystem=vafmodel.OriginalEcoSystemEnum.SILKIT, + ConnectionPointRef=vafmodel.SILKITConnectionPoint( + Name="CPoint", + ServiceInterfaceName="MyInterface", + RegistryUri="silkit://localhost:8500", + ), + ) + ) + + m.PlatformConsumerModules.append(copy.deepcopy(m.PlatformProviderModules[0])) + m.PlatformConsumerModules[0].Name = "MyConsumerModule" + + vaf_silkit.generate(m, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + + assert filecmp.cmp( + tmp_path + / "src-gen/libs/platform_silkit/platform_consumer_modules/my_consumer_module/include/test/my_consumer_module.h", # pylint: disable=line-too-long + script_dir / "silkit/my_consumer_module.h", + ) + + assert filecmp.cmp( + tmp_path + / "src-gen/libs/platform_silkit/platform_consumer_modules/my_consumer_module/src/test/my_consumer_module.cpp", # pylint: disable=line-too-long + script_dir / "silkit/my_consumer_module.cpp", + ) + + pm_path = tmp_path / "src-gen/libs/platform_silkit/platform_provider_modules/my_provider_module" + assert filecmp.cmp( + pm_path / "include/test/my_provider_module.h", + script_dir / "silkit/my_provider_module.h", + ) + + assert filecmp.cmp( + pm_path / "src/test/my_provider_module.cpp", + script_dir / "silkit/my_provider_module.cpp", + ) + + +# pylint: enable=too-many-statements diff --git a/VAF/tests/unit/vafgeneration/test_vafinterface.py b/VAF/tests/unit/vafgeneration/test_vafinterface.py new file mode 100644 index 0000000..8b6b265 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_vafinterface.py @@ -0,0 +1,82 @@ +""" +example tests +""" + +import filecmp +import os +from pathlib import Path + +from vaf import vafmodel +from vaf.vafgeneration import vaf_interface + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for interface generation""" + + m = vafmodel.MainModel() + + data_elements: list[vafmodel.DataElement] = [] + operations: list[vafmodel.Operation] = [] + + data_elements.append( + vafmodel.DataElement( + Name="my_data_element", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + ) + ) + parameters = [ + vafmodel.Parameter( + Name="in", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.IN, + ), + vafmodel.Parameter( + Name="inout", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.INOUT, + ), + vafmodel.Parameter( + Name="out", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Direction=vafmodel.ParameterDirection.OUT, + ), + ] + operations.append(vafmodel.Operation(Name="my_function", Parameters=parameters)) + operations.append(vafmodel.Operation(Name="my_function_void", Parameters=parameters[:1])) # pylint: disable=line-too-long + + m.ModuleInterfaces.append( + vafmodel.ModuleInterface( + Name="MyInterface", + Namespace="test", + DataElements=data_elements, + Operations=operations, + ) + ) + vaf_interface.generate_module_interfaces(m, tmp_path) + + script_dir = Path(os.path.realpath(__file__)).parent + assert filecmp.cmp( + tmp_path / "src-gen/libs/interfaces/include/test/my_interface_consumer.h", + script_dir / "interface/test1_consumer_expected.h", + ) + assert filecmp.cmp( + tmp_path / "src-gen/libs/interfaces/include/test/my_interface_provider.h", + script_dir / "interface/test1_provider_expected.h", + ) + assert filecmp.cmp( + tmp_path / "test-gen/mocks/interfaces/include/test/my_interface_consumer_mock.h", + script_dir / "interface/test1_consumer_mock_expected.h", + ) + assert filecmp.cmp( + tmp_path / "test-gen/mocks/interfaces/include/test/my_interface_provider_mock.h", + script_dir / "interface/test1_provider_mock_expected.h", + ) diff --git a/VAF/tests/unit/vafgeneration/test_vafproject.py b/VAF/tests/unit/vafgeneration/test_vafproject.py new file mode 100644 index 0000000..1aa4a36 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_vafproject.py @@ -0,0 +1,61 @@ +""" +example tests +""" + +from pathlib import Path + +import pytest + +from vaf import vafmodel +from vaf.vafgeneration import vaf_generate_project + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" + + +class TestIntegration: + """Basic generation test class""" + + def test_get_ecosystems(self) -> None: + """Basic test for get_ecosystems function""" + project_path = str(Path(__file__).parent.parent.parent.parent.parent) + + test_dict = {"SILKIT": "VAF/tests/unit/vafgeneration/input_model_examples/silkit.json"} + + for ecosystem_name, ecosystem_mock_data in test_dict.items(): + main_model = vafmodel.load_json(f"{project_path}/{ecosystem_mock_data}") + assert [ecosystem_name] == vaf_generate_project.get_ecosystems(main_model) + + @pytest.mark.slow + def test_basic_generation(self, tmp_path) -> None: + """Basic test for interface generation + + Raises: + FileNotFoundError: Raised if conanfile not present + ValueError: Raised if package not found + + """ + + project_path = str(Path(__file__).parent.parent.parent.parent.parent) + + test_dict = { + "SILKIT": { + "mock_data": "VAF/tests/unit/vafgeneration/input_model_examples/silkit.json", + "not_exist_list": [ + "vaf", + ], # platform_vaf should also not generated due to empty app modules + }, + } + + for ecosystem_test_data in test_dict.values(): + vaf_generate_project.generate_integration_project( + f"{project_path}/{ecosystem_test_data['mock_data']}", str(tmp_path) + ) + + for i_must_not_exist in ecosystem_test_data["not_exist_list"]: + assert not Path(f"{tmp_path}/src-gen/libs/platform_{i_must_not_exist}").is_dir(), ( + f"{tmp_path}/src-gen/libs/platform_{i_must_not_exist}" + ) diff --git a/VAF/tests/unit/vafgeneration/test_vss.py b/VAF/tests/unit/vafgeneration/test_vss.py new file mode 100644 index 0000000..38050c1 --- /dev/null +++ b/VAF/tests/unit/vafgeneration/test_vss.py @@ -0,0 +1,43 @@ +""" +VSS generator test +""" + +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# pylint: disable=too-few-public-methods +# mypy: disable-error-code="no-untyped-def" +import importlib +import inspect +import sys +from pathlib import Path + +from vaf.vafgeneration import vaf_cac_support +from vaf.vafpy import ModuleInterface +from vaf.vafvssimport import vss_import + + +class TestIntegration: + """Basic generation test class""" + + def test_basic_generation(self, tmp_path) -> None: + """Basic test for VSS generation""" + vss_input = Path(__file__).parent / "vss/seat_vss.json" + vss_import.run_import(str(tmp_path), str(vss_input)) + vaf_cac_support.generate(tmp_path, "vss-derived-model.json", "vss", Path(tmp_path)) + + # try to import the vss + spec = importlib.util.spec_from_file_location("vss", tmp_path / "vss.py") + module = importlib.util.module_from_spec(spec) # type: ignore[arg-type] + sys.modules["vss"] = module + spec.loader.exec_module(module) # type: ignore[union-attr] + + assert inspect.isclass(module.Vss) + assert inspect.isclass(module.Vss.Vehicle) + assert isinstance(module.Vss.vehicle_if, ModuleInterface) + assert inspect.isclass(module.Vss.Vehicle.Cabin.Seat.Row1.Driverside) + assert isinstance(module.Vss.Vehicle.Cabin.Seat.Row1.driver_side_if, ModuleInterface) + assert inspect.isclass(module.Vss.Vehicle.Cabin.Seat.Row1.Driverside.Backrest) + assert inspect.isclass(module.Vss.Vehicle.Cabin.Seat.Row2.Driverside.Backrest) + assert isinstance(module.Vss.Vehicle.Cabin.Seat.Row1.Driverside.Backrest.lumbar_if, ModuleInterface) + assert isinstance(module.Vss.Vehicle.Cabin.Seat.Row2.Driverside.Backrest.lumbar_if, ModuleInterface) diff --git a/VAF/tests/unit/vafgeneration/vss/seat_vss.json b/VAF/tests/unit/vafgeneration/vss/seat_vss.json new file mode 100644 index 0000000..ba2253d --- /dev/null +++ b/VAF/tests/unit/vafgeneration/vss/seat_vss.json @@ -0,0 +1,2114 @@ +{ + "Vehicle": { + "children": { + "Cabin": { + "children": { + "Seat": { + "children": { + "Row1": { + "children": { + "DriverSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Middle": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Row2": { + "children": { + "DriverSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "Middle": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + }, + "PassengerSide": { + "children": { + "Airbag": { + "children": { + "IsDeployed": { + "datatype": "boolean", + "description": "Airbag deployment status. True = Airbag deployed. False = Airbag not deployed.", + "type": "sensor" + } + }, + "description": "Airbag signals.", + "type": "branch" + }, + "Backrest": { + "children": { + "Lumbar": { + "children": { + "Height": { + "datatype": "uint8", + "description": "Height of lumbar support. Position is relative within available movable range of the lumbar support. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "Support": { + "datatype": "float", + "description": "Lumbar support (in/out position). 0 = Innermost position. 100 = Outermost position.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Adjustable lumbar support mechanisms in seats allow the user to change the seat back shape.", + "type": "branch" + }, + "Recline": { + "comment": "Seat z-axis depends on seat tilt. This means that movement of backrest due to seat tilting will not affect Backrest.Recline as long as the angle between Seating and Backrest are constant. Absolute recline relative to vehicle z-axis can be calculated as Tilt + Backrest.Recline.", + "datatype": "float", + "description": "Backrest recline compared to seat z-axis (seat vertical axis). 0 degrees = Upright/Vertical backrest. Negative degrees for forward recline. Positive degrees for backward recline.", + "type": "actuator", + "unit": "degrees" + }, + "SideBolster": { + "children": { + "Support": { + "datatype": "float", + "description": "Side bolster support. 0 = Minimum support (widest side bolster setting). 100 = Maximum support.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + } + }, + "description": "Backrest side bolster (lumbar side support) settings.", + "type": "branch" + } + }, + "description": "Describes signals related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "Angle": { + "datatype": "float", + "description": "Headrest angle, relative to backrest, 0 degrees if parallel to backrest, Positive degrees = tilted forward.", + "type": "actuator", + "unit": "degrees" + }, + "Height": { + "datatype": "uint8", + "description": "Position of headrest relative to movable range of the head rest. 0 = Bottommost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "description": "Headrest settings.", + "type": "branch" + }, + "Heating": { + "datatype": "int8", + "deprecation": "v4.1 replaced with HeatingCooling", + "description": "Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "HeatingCooling": { + "datatype": "int8", + "description": "Heating or Cooling requsted for the Item. -100 = Maximum cooling, 0 = Heating/cooling deactivated, 100 = Maximum heating.", + "max": 100, + "min": -100, + "type": "actuator", + "unit": "percent" + }, + "Height": { + "datatype": "uint16", + "description": "Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "IsBelted": { + "datatype": "boolean", + "description": "Is the belt engaged.", + "type": "sensor" + }, + "IsOccupied": { + "datatype": "boolean", + "description": "Does the seat have a passenger in it.", + "type": "sensor" + }, + "Massage": { + "datatype": "uint8", + "description": "Seat massage level. 0 = off. 100 = max massage.", + "max": 100, + "min": 0, + "type": "actuator", + "unit": "percent" + }, + "Occupant": { + "children": { + "Identifier": { + "children": { + "Issuer": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Unique Issuer for the authentication of the occupant e.g. https://accounts.funcorp.com.", + "type": "sensor" + }, + "Subject": { + "datatype": "string", + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Subject for the authentication of the occupant e.g. UserID 7331677.", + "type": "sensor" + } + }, + "deprecation": "v5.0 - use data from Vehicle.Occupant.*.*.Identifier.", + "description": "Identifier attributes based on OAuth 2.0.", + "type": "branch" + } + }, + "description": "Occupant data.", + "type": "branch" + }, + "Position": { + "datatype": "uint16", + "description": "Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.", + "min": 0, + "type": "actuator", + "unit": "mm" + }, + "SeatBeltHeight": { + "datatype": "uint16", + "description": "Seat belt position on vehicle z-axis. Position is relative within available movable range of the seat belt. 0 = Lowermost position supported.", + "type": "actuator", + "unit": "mm" + }, + "Seating": { + "children": { + "Length": { + "datatype": "uint16", + "description": "Length adjustment of seating. 0 = Adjustable part of seating in rearmost position (Shortest length of seating).", + "min": 0, + "type": "actuator", + "unit": "mm" + } + }, + "comment": "Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.", + "description": "Describes signals related to the seat bottom of the seat.", + "type": "branch" + }, + "Switch": { + "children": { + "Backrest": { + "children": { + "IsReclineBackwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline backward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "IsReclineForwardEngaged": { + "datatype": "boolean", + "description": "Backrest recline forward switch engaged (SingleSeat.Backrest.Recline).", + "type": "actuator" + }, + "Lumbar": { + "children": { + "IsDownEngaged": { + "datatype": "boolean", + "description": "Lumbar down switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more lumbar support engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Lumbar up switch engaged (SingleSeat.Backrest.Lumbar.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.Lumbar.", + "type": "branch" + }, + "SideBolster": { + "children": { + "IsLessSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for less side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + }, + "IsMoreSupportEngaged": { + "datatype": "boolean", + "description": "Is switch for more side bolster support engaged (SingleSeat.Backrest.SideBolster.Support).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Backrest.SideBolster.", + "type": "branch" + } + }, + "description": "Describes switches related to the backrest of the seat.", + "type": "branch" + }, + "Headrest": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Head rest backward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Head rest down switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Head rest forward switch engaged (SingleSeat.Headrest.Angle).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Head rest up switch engaged (SingleSeat.Headrest.Height).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Headrest.", + "type": "branch" + }, + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Seat backward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsCoolerEngaged": { + "datatype": "boolean", + "description": "Cooler switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "IsDownEngaged": { + "datatype": "boolean", + "description": "Seat down switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Seat forward switch engaged (SingleSeat.Position).", + "type": "actuator" + }, + "IsTiltBackwardEngaged": { + "datatype": "boolean", + "description": "Tilt backward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsTiltForwardEngaged": { + "datatype": "boolean", + "description": "Tilt forward switch engaged (SingleSeat.Tilt).", + "type": "actuator" + }, + "IsUpEngaged": { + "datatype": "boolean", + "description": "Seat up switch engaged (SingleSeat.Height).", + "type": "actuator" + }, + "IsWarmerEngaged": { + "datatype": "boolean", + "description": "Warmer switch for Seat heater (SingleSeat.Heating).", + "type": "actuator" + }, + "Massage": { + "children": { + "IsDecreaseEngaged": { + "datatype": "boolean", + "description": "Decrease massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + }, + "IsIncreaseEngaged": { + "datatype": "boolean", + "description": "Increase massage level switch engaged (SingleSeat.Massage).", + "type": "actuator" + } + }, + "description": "Switches for SingleSeat.Massage.", + "type": "branch" + }, + "Seating": { + "children": { + "IsBackwardEngaged": { + "datatype": "boolean", + "description": "Is switch to decrease seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + }, + "IsForwardEngaged": { + "datatype": "boolean", + "description": "Is switch to increase seating length engaged (SingleSeat.Seating.Length).", + "type": "actuator" + } + }, + "description": "Describes switches related to the seating of the seat.", + "type": "branch" + } + }, + "description": "Seat switch signals", + "type": "branch" + }, + "Tilt": { + "comment": "In VSS it is assumed that tilting a seat affects both seating (seat bottom) and backrest, i.e. the angle between seating and backrest will not be affected when changing Tilt.", + "datatype": "float", + "description": "Tilting of seat (seating and backrest) relative to vehicle x-axis. 0 = seat bottom is flat, seat bottom and vehicle x-axis are parallel. Positive degrees = seat tilted backwards, seat x-axis tilted upward, seat z-axis is tilted backward.", + "type": "actuator", + "unit": "degrees" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All seats.", + "type": "branch" + } + }, + "description": "All in-cabin components, including doors.", + "type": "branch" + } + }, + "description": "High-level vehicle data.", + "type": "branch" + } +} diff --git a/VAF/tests/unit/vafmodel/__init__.py b/VAF/tests/unit/vafmodel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/unit/vafmodel/test_example.py b/VAF/tests/unit/vafmodel/test_example.py new file mode 100644 index 0000000..3246569 --- /dev/null +++ b/VAF/tests/unit/vafmodel/test_example.py @@ -0,0 +1,61 @@ +""" +Test +""" + +# pylint: disable=missing-class-docstring +# pylint: disable=too-few-public-methods +# pylint: disable=unused-variable + +# from unittest import mock + +import json +import os +from pathlib import Path + +from vaf import vafmodel + + +class TestMain: + """ + TestMain class + """ + + def test_schema_export(self) -> None: + """test schema export""" + vafmodel.generate_json_schema("./schema.json") + Path.unlink(Path("./schema.json")) + + def test_import(self) -> None: + """Test importing a model""" + script_dir = Path(os.path.realpath(__file__)).parent + model_file = script_dir / "test_model.json" + m = vafmodel.load_json(model_file) + with open("./export_model.json", "w", encoding="utf-8") as f: + f.write(m.model_dump_json(indent=2)) + Path.unlink(Path("./export_model.json")) + + def test_import2(self) -> None: + """Test importing a model""" + script_dir = Path(os.path.realpath(__file__)).parent + model_file = script_dir / "test_model2.json" + m = vafmodel.load_json(model_file) + with open("./export_model.json", "w", encoding="utf-8") as f: + f.write(m.model_dump_json(indent=2)) + Path.unlink(Path("./export_model.json")) + + def test_manual_usage(self) -> None: + """Test for direct usage of the classes""" + m = vafmodel.MainModel() + m.DataTypeDefinitions = vafmodel.DataTypeDefinition() + m.DataTypeDefinitions.Arrays.append( + vafmodel.Array( + Name="MyArray", + Namespace="test", + TypeRef=vafmodel.DataType(Name="uint64_t", Namespace=""), + Size=1, + ) + ) + j = json.loads(m.model_dump_json()) + assert j["DataTypeDefinitions"]["Arrays"][0]["Name"] == "MyArray" + assert j["DataTypeDefinitions"]["Arrays"][0]["TypeRef"] == "uint64_t" + assert j["DataTypeDefinitions"]["Arrays"][0]["Size"] == 1 diff --git a/VAF/tests/unit/vafmodel/test_model.json b/VAF/tests/unit/vafmodel/test_model.json new file mode 100644 index 0000000..d4b1b37 --- /dev/null +++ b/VAF/tests/unit/vafmodel/test_model.json @@ -0,0 +1,400 @@ +{ + "$schema": "../../../VafEntrySchema.json", + "DataTypeDefinitions": + { + "Vectors": [ + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + }, + { + "Name": "UInt8Vector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + } + ], + "Structs": [ + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + }, + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::UInt8Vector" + }, + { + "Name": "G", + "TypeRef": "datatypes::UInt8Vector" + }, + { + "Name": "B", + "TypeRef": "datatypes::UInt8Vector" + } + ] + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "nsmiddleware::nsmoduleinterface::nsbrakservice", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "nsmiddleware::nsmoduleinterface::nsimageservice", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsmiddleware::nsmoduleinterface::nssteeringangleservice", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "nsmiddleware::nsmoduleinterface::nsvelocityservice", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "SensorFusion", + "Namespace": "NsApplicationUnit::NsSensorFusion", + "ConsumedInterfaces": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsimageservice::ImageService" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsimageservice::ImageService" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nssteeringangleservice::SteeringAngleService" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsvelocityservice::VelocityService" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "Tasks": [ + { + "Name": "Step", + "Period": "200ms", + "PreferredOffset": 0 + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + }, + { + "Name": "CollisionDetection", + "Namespace": "NsApplicationUnit::NsCollisionDetection", + "ConsumedInterfaces": [ + { + "InstanceName": "ObjectDetectionListModule", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "BrakeServiceProvider", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsbrakservice::BrakeService" + } + ], + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + } + ], + "PlatformConsumerModules": [ + { + "Name": "ImageServiceConsumer1", + "Namespace": "NsServiceConsumer::NsImageServiceConsumer1", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsimageservice::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer1" + }, + { + "Name": "ImageServiceConsumer2", + "Namespace": "NsServiceConsumer::NsImageServiceConsumer2", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsimageservice::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer2" + }, + { + "Name": "SteeringAngleServiceConsumer", + "Namespace": "NsServiceConsumer::NsSteeringAngleServiceConsumer", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nssteeringangleservice::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_SteeringAngleServiceConsumer" + }, + { + "Name": "VelocityServiceConsumer", + "Namespace": "NsServiceConsumer::NsVelocityServiceConsumer", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsvelocityservice::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_VelocityServiceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "BrakeServiceProvider", + "Namespace": "NsServiceProvider::NsBrakeServiceProvider", + "ModuleInterfaceRef": "nsmiddleware::nsmoduleinterface::nsbrakservice::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_BrakeServiceProvider" + } + ], + "Executables": [ + { + "Name": "adas_demo_app", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "ObjectDetectionListModule", + "Namespace": "NsAppCom::NsObjectDetectionList", + "ModuleInterfaceRef": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "NsApplicationUnit::NsSensorFusion::SensorFusion", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "ImageServiceConsumer1", + "ModuleRef": "NsServiceConsumer::NsImageServiceConsumer1::ImageServiceConsumer1" + }, + { + "InstanceName": "ImageServiceConsumer2", + "ModuleRef": "NsServiceConsumer::NsImageServiceConsumer2::ImageServiceConsumer2" + }, + { + "InstanceName": "SteeringAngleServiceConsumer", + "ModuleRef": "NsServiceConsumer::NsSteeringAngleServiceConsumer::SteeringAngleServiceConsumer" + }, + { + "InstanceName": "VelocityServiceConsumer", + "ModuleRef": "NsServiceConsumer::NsVelocityServiceConsumer::VelocityServiceConsumer" + }, + { + "InstanceName": "ObjectDetectionListModule", + "ModuleRef": "NsAppCom::NsObjectDetectionList::ObjectDetectionListModule" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "NsApplicationUnit::NsCollisionDetection::CollisionDetection", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "BrakeServiceProvider", + "ModuleRef": "NsServiceProvider::NsBrakeServiceProvider::BrakeServiceProvider" + }, + { + "InstanceName": "ObjectDetectionListModule", + "ModuleRef": "NsAppCom::NsObjectDetectionList::ObjectDetectionListModule" + } + ], + "TaskMapping": [ + { + "TaskName": "PeriodicTask", + "Budget": "1ms", + "Offset": 1 + } + ] + } + ] + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer1", + "ServiceInterfaceName": "Silkit_ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer2", + "ServiceInterfaceName": "Silkit_ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_SteeringAngleServiceConsumer", + "ServiceInterfaceName": "Silkit_SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_VelocityServiceConsumer", + "ServiceInterfaceName": "Silkit_VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_BrakeServiceProvider", + "ServiceInterfaceName": "Silkit_BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafmodel/test_model2.json b/VAF/tests/unit/vafmodel/test_model2.json new file mode 100644 index 0000000..c991a62 --- /dev/null +++ b/VAF/tests/unit/vafmodel/test_model2.json @@ -0,0 +1,254 @@ +{ + "$schema": "../../../VafEntrySchema.json", + "DataTypeDefinitions": + { + "Vectors": [ + { + "Name": "MyVector", + "Namespace": "data_types", + "TypeRef": "data_types::MyStruct" + } + ], + "Structs": [ + { + "Name": "MyStruct", + "Namespace": "data_types", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + } + ] + } + ], + "Arrays": [ + { + "Name": "MyArray", + "Namespace": "data_types", + "TypeRef": "data_types::MyVector", + "Size": 100 + } + ], + "Strings": [ + { + "Name": "MyString", + "Namespace": "data_types" + } + ], + "TypeRefs": [ + { + "Name": "MyTypeRef", + "Namespace": "data_types", + "TypeRef": "data_types::MyString" + } + ], + "Enums": [ + { + "Name": "MyEnum", + "Namespace": "data_types", + "Literals": [ + { + "Label": "A", + "Value": 0 + }, + { + "Label": "B", + "Value": 1 + } + ] + } + ], + "Maps": [ + { + "Name": "MyMap", + "Namespace": "data_types", + "MapKeyTypeRef": "data_types::MyTypeRef", + "MapValueTypeRef": "data_types::MyEnum" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "MyInterface", + "Namespace": "interfaces", + "DataElements": [ + { + "Name": "a", + "TypeRef": "data_types::MyVector" + }, + { + "Name": "b", + "TypeRef": "data_types::MyStruct" + }, + { + "Name": "c", + "TypeRef": "data_types::MyMap" + } + ], + "Operations": [ + { + "Name": "MyOperation", + "Parameters": [ + { + "Name": "in1", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "in2", + "TypeRef": "data_types::MyEnum", + "Direction": "IN" + }, + { + "Name": "out", + "TypeRef": "data_types::MyString", + "Direction": "OUT" + }, + { + "Name": "inout", + "TypeRef": "data_types::MyVector", + "Direction": "INOUT" + } + ] + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "app_modules", + "ProvidedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ConsumedInterfaces": [ ], + "Tasks": [ + { + "Name": "Step", + "Period": "10ms", + "PreferredOffset": 0 + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + }, + { + "Name": "AppModule2", + "Namespace": "app_modules", + "ProvidedInterfaces": [ ], + "ConsumedInterfaces": [ + { + "InstanceName": "Instance1", + "ModuleInterfaceRef": "interfaces::MyInterface" + }, + { + "InstanceName": "Instance2", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "Tasks": [ + { + "Name": "Step", + "Period": "20ms" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": false + } + } + ], + "PlatformConsumerModules": [ + { + "Name": "ServiceConsumerSilkit", + "Namespace": "service_consumer_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_MyInterfaceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "ServiceProviderSilkit", + "Namespace": "service_provider_modules", + "ModuleInterfaceRef": "interfaces::MyInterface", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_MyInterfaceProvider" + } + ], + "Executables": [ + { + "Name": "exe1", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "ServiceModuleVaf", + "Namespace": "service_modules", + "ModuleInterfaceRef": "interfaces::MyInterface" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "app_modules::AppModule1", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_provider_modules::ServiceProviderSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "app_modules::AppModule2", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "Instance1", + "ModuleRef": "service_consumer_modules::ServiceConsumerSilkit" + }, + { + "InstanceName": "Instance2", + "ModuleRef": "service_modules::ServiceModuleVaf" + } + ], + "TaskMapping": [ + { + "TaskName": "Step", + "Budget": "1ms", + "Offset": 1 + } + ] + } + ] + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_MyInterfaceConsumer", + "ServiceInterfaceName": "Silkit_MyInterfaceConsumer", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_MyInterfaceProvider", + "ServiceInterfaceName": "Silkit_MyInterfaceProvider", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafpy/__init__.py b/VAF/tests/unit/vafpy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/unit/vafpy/test_cac.py b/VAF/tests/unit/vafpy/test_cac.py new file mode 100644 index 0000000..cd95c6a --- /dev/null +++ b/VAF/tests/unit/vafpy/test_cac.py @@ -0,0 +1,541 @@ +""" +Test CaC with vafpy +""" + +# pylint: disable=missing-param-doc +# pylint: disable=missing-any-param-doc +# pylint: disable=anomalous-backslash-in-string +# pylint: disable=missing-raises-doc +# pylint: disable=line-too-long +# pylint: disable=too-few-public-methods +# pylint: disable=unused-variable +# pylint: disable=missing-class-docstring +# pylint: disable=too-many-locals +# mypy: disable-error-code="no-untyped-def,union-attr" + + +# Ruff: ignore unused variables +# ruff: noqa: F841 + +import importlib +import json +import os +import re +import sys +from pathlib import Path +from shutil import copyfile, copytree +from types import ModuleType +from unittest import mock + +import pytest + +from vaf import save_main_model, save_part_of_main_model, vafmodel, vafpy +from vaf.cli_core.common.utils import ProjectType, create_name_namespace_full_name +from vaf.vafpy.model_runtime import model_runtime + +### IMPORT MOCKING ### +# Store original __import__ +orig_import = __import__ +mock_import: dict[str, ModuleType] = {} + + +def import_mock(name: str, *args) -> ModuleType: + """Function to mock import calls from CaC python files""" + return mock_import[name] if name in mock_import else orig_import(name, *args) + + +def import_by_file_name(path_to_file: Path | str, file_name: str) -> ModuleType: + """importlib.import_module somehow fails in pytest and can't find the modules""" + spec = importlib.util.spec_from_file_location(file_name, f"{path_to_file}/{file_name}.py") + if spec: + module = importlib.util.module_from_spec(spec) + if module and spec.loader: + sys.modules[file_name] = module + spec.loader.exec_module(module) + + if not module: + raise RuntimeError(f"Failed to import module in {path_to_file}/{file_name}.py") + + return module + + +def mock_vafpy(path_to_model: str | Path, imports_list: list[str]) -> None: + """Mock vafpy call using __import__ + Args: + path_to_model: path to the output dir that contains the CaC models + imports_list: all modules to be imported + """ + with mock.patch("builtins.__import__", side_effect=import_mock): + mock_import["vafpy"] = importlib.import_module("vaf.vafpy") + for import_name in imports_list: + if "/" in import_name: + import_file_data = import_name.split("/") + mock_import[".".join(import_file_data)] = import_by_file_name( + f"{path_to_model}/{''.join(import_file_data[:-1])}", import_file_data[-1] + ) + else: + mock_import[import_name] = import_by_file_name(path_to_model, import_name) + import_by_file_name(path_to_model, "model") + + +def __get_type_ref_string(typeref: vafmodel.TypeRef | vafmodel.DataType) -> str: + return create_name_namespace_full_name(typeref.Name, typeref.Namespace) + + +UT_PATH = Path(__file__).parent + + +### UNIT TESTS ### +def test_generate_vss_model(tmp_path) -> None: + """FTAF-260: Test Generation of VSS Artifacts based on CaC""" + path_out = tmp_path / "ftaf_260" + + copytree(UT_PATH / "test_data/common", path_out) + copyfile(UT_PATH / "test_data/ftaf_260/model.py", path_out / "model.py") + + mock_vafpy(path_out, ["vss"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.INTEGRATION) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_260/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + + +def test_bug_ftaf_260_app_module(tmp_path) -> None: + """FTAF-260: Bug with Application Modules""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_260_bug" + copytree(UT_PATH / "test_data/common", path_out) + copyfile(UT_PATH / "test_data/ftaf_260_bug/model.py", path_out / "model.py") + # assert that unused Vectors, Maps, TypeRefs, Arrays, Enums are removed + copyfile(UT_PATH / "test_data/ftaf_260_bug/silkit-model.json", path_out / "silkit-model.json") + os.chdir(path_out) + + try: + mock_vafpy(path_out, ["silkit"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.INTEGRATION) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_260_bug/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + finally: + os.chdir(original_working_dir) + + +def test_error_duplicate_executables(tmp_path) -> None: + """FTAF-339: Error in case of duplicate executables""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_339" + + copytree(UT_PATH / "test_data/common", path_out) + copyfile( + UT_PATH / "test_data/ftaf_339/model.py", + path_out / "model.py", + ) + os.chdir(path_out) + try: + mock_vafpy(path_out, ["silkit"]) + + with pytest.raises(vafpy.core.ModelError) as error_msg: + save_main_model(path_out / "model.json", project_type=ProjectType.INTEGRATION) + assert error_msg.value.args[0] == "Executable adas_demo_app is defined multiple times!" + finally: + os.chdir(original_working_dir) + + +def test_validation_unconnected_interfaces(tmp_path, recwarn) -> None: + """FTAF-258: Warn user of unconnected interfaces""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_258" + + copytree(UT_PATH / "test_data/common", path_out) + copyfile( + UT_PATH / "test_data/ftaf_258/model.py", + path_out / "model.py", + ) + os.chdir(path_out) + + try: + mock_vafpy(path_out, ["silkit"]) + + save_main_model(path_out / "model.json", project_type=ProjectType.INTEGRATION) + + relevant_warnings = [ + wrn.message.args[0] for wrn in recwarn if wrn.message.args[0].startswith("Following interfaces") + ] + assert len(relevant_warnings) == 1 + + goal_unconnected_interfaces = [ + "NsApplicationUnit::NsCollisionDetection::CollisionDetection - BrakeServiceProvider", + "NsApplicationUnit::NsCollisionDetection::CollisionDetection - ImageServiceProvider1", + "NsApplicationUnit::NsSensorFusion::SensorFusion - ImageServiceConsumer1", + "NsApplicationUnit::NsSensorFusion::SensorFusion - ImageServiceConsumer2", + "NsApplicationUnit::NsSensorFusion::SensorFusion - SteeringAngleServiceConsumer", + "NsApplicationUnit::NsSensorFusion::SensorFusion - VelocityServiceConsumer", + ] + + result_unconnected_interfaces = re.findall( + r"Following interfaces are defined but not connected: \[(.+?)\]", relevant_warnings[0] + ) + assert result_unconnected_interfaces, f"Incorrect Warning returned: {relevant_warnings[0]}" + result_unconnected_interfaces = [ + unconnected_interface.replace("'", "").replace('"', "") + for unconnected_interface in result_unconnected_interfaces[0].split(", '") + ] + assert set(goal_unconnected_interfaces) == set(result_unconnected_interfaces) + finally: + os.chdir(original_working_dir) + + +def test_invalid_exec_periodic_tasks(tmp_path, recwarn) -> None: + """FTAF-421: Error if Exec's periodic task > its tasks' Periodic tasks""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_421" + + copytree(UT_PATH / "test_data/common", path_out) + copyfile( + UT_PATH / "test_data/ftaf_421/model.py", + path_out / "model.py", + ) + copyfile( + UT_PATH / "test_data/ftaf_421/silkit.py", + path_out / "silkit.py", + ) + os.chdir(path_out) + + try: + mock_vafpy(path_out, ["silkit"]) + + with pytest.raises(vafpy.core.ModelError) as error_msg: + save_main_model(path_out / "model.json", project_type=ProjectType.INTEGRATION) + + # ensure validator errors + goal_errors = [ + "Invalid ExecutorPeriod of Executable adas_demo_app: 23ms!", + "Executor Period 23ms is longer than its Task(s)' period:", + " AppModule: NsApplicationUnit::NsSensorFusion::SensorFusion - Task: Step2 with period 5ms", + " AppModule: NsApplicationUnit::NsSensorFusion::SensorFusion - Task: Step3 with period 22ms", + ] + errors = error_msg.value.args[0].split("\n") + assert len(recwarn) == 0 + assert sorted(errors) == sorted(goal_errors) + finally: + os.chdir(original_working_dir) + + +def test_validation_empty_interfaces(tmp_path, recwarn) -> None: + """FTAF-457: Detect and warn about empty interface definition in vafpy""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_457" + copytree(UT_PATH / "test_data/common", path_out) + copyfile( + UT_PATH / "test_data/ftaf_457/model.py", + path_out / "model.py", + ) + os.chdir(path_out) + + try: + mock_vafpy(path_out, []) + + save_part_of_main_model( + Path("model.json"), ["DataTypeDefinitions", "ModuleInterfaces"], project_type=ProjectType.INTEGRATION + ) + + relevant_warnings = [ + wrn.message.args[0] for wrn in recwarn if wrn.message.args[0].startswith("Following interfaces") + ] + assert len(relevant_warnings) == 1 + + goal_epmty_interfaces = [ + "demo::EmptyInterface", + ] + + result_epmty_interfaces = re.findall( + r"Following interfaces are defined without data elements and operations: \[(.+?)\]", relevant_warnings[0] + ) + assert result_epmty_interfaces, f"Incorrect Warning returned: {relevant_warnings[0]}" + result_epmty_interfaces = [ + epmty_interface.replace("'", "").replace('"', "") + for epmty_interface in result_epmty_interfaces[0].split(", '") + ] + assert set(goal_epmty_interfaces) == set(result_epmty_interfaces) + finally: + os.chdir(original_working_dir) + + +def test_validation_duplicate_datatype_interface(tmp_path) -> None: + """FTAF-354: Warning for duplicates datatypes & interfaces""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf-354" + copytree(UT_PATH / "test_data/common", path_out) + copyfile( + UT_PATH / "test_data/ftaf_354/model.py", + path_out / "model.py", + ) + os.chdir(path_out) + + try: + with pytest.raises(vafpy.core.ModelError) as error_msg: + mock_vafpy(path_out, ["silkit"]) + + # ensure validator errors + goal_errors = [ + "Failed to add a duplicate for DataTypeDefinition with Type Struct: datatypes::SteeringAngle", + ] + errors = error_msg.value.args[0].split("\n") + assert sorted(errors) == sorted(goal_errors) + finally: + os.chdir(original_working_dir) + + +def test_bug_remove_unused_artifacts(tmp_path) -> None: + """FTAF-386: Bug in __remove_unused_artifacts""" + path_out = tmp_path / "ftaf_386" + + copytree(UT_PATH / "test_data/ftaf_386", path_out) + + mock_vafpy(path_out, ["imported_models/interface_project", "app_module1"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.INTEGRATION) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_386/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + + +def test_bug2_remove_unused_artifacts(tmp_path) -> None: + """FTAF-394: 2nd Bug in __remove_unused_artifacts""" + path_out = tmp_path / "ftaf_394" + + copytree(UT_PATH / "test_data/ftaf_394", path_out) + + mock_vafpy(path_out, ["silkit", "app_module1"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.INTEGRATION) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_394/goal-model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + + +def test_consolidation_fixed_size_array_vector() -> None: + """FTAF-382: Consolidation of Fixed Size Arrays & Vectors + Update FTAF-474: Feature reverted! + """ + + ma_struct = vafpy.datatypes.Struct(name="MaStruct", namespace="test") + ma_struct.add_subelement(name="x", datatype=vafpy.BaseTypes.DOUBLE) + + vafpy.datatypes.Vector(name="MaVector", namespace="test", datatype=ma_struct) + + vafpy.datatypes.Vector(name="MyVectorFixed", namespace="test", datatype=ma_struct) + vafpy.datatypes.Vector(name="MyVectorFixedAgain", namespace="test", datatype=ma_struct) + + vafpy.datatypes.Vector(name="MockVector1", namespace="test", datatype=vafpy.BaseTypes.UINT16_T) + vafpy.datatypes.Vector(name="MockVector2", namespace="test", datatype=vafpy.BaseTypes.UINT16_T) + vafpy.datatypes.Vector(name="MockVector3", namespace="test", datatype=vafpy.BaseTypes.UINT16_T) + vafpy.datatypes.Vector(name="MockVector4", namespace="test", datatype=vafpy.BaseTypes.FLOAT) + vafpy.datatypes.Vector(name="MockVector5", namespace="test", datatype=vafpy.BaseTypes.BOOL) + + vafpy.datatypes.Array(name="MyFixedArray", namespace="test", datatype=ma_struct, size=2) + vafpy.datatypes.Array(name="MyFixedArray2", namespace="test", datatype=ma_struct, size=2) + + vafpy.datatypes.Array(name="MockArray1", namespace="test", datatype=vafpy.BaseTypes.UINT16_T, size=2) + vafpy.datatypes.Array(name="MockArray2", namespace="test", datatype=vafpy.BaseTypes.UINT16_T, size=2) + vafpy.datatypes.Array(name="MockArray3", namespace="test", datatype=vafpy.BaseTypes.FLOAT, size=2) + vafpy.datatypes.Array(name="MockArray4", namespace="test", datatype=vafpy.BaseTypes.BOOL, size=2) + + assert len(model_runtime.main_model.DataTypeDefinitions.Vectors) == 8 + for idx, name in enumerate( + [ + "MaVector", + "MyVectorFixed", + "MyVectorFixedAgain", + "MockVector1", + "MockVector2", + "MockVector3", + "MockVector4", + "MockVector5", + ] + ): + assert model_runtime.main_model.DataTypeDefinitions.Vectors[idx].Name == name + + assert len(model_runtime.main_model.DataTypeDefinitions.Arrays) == 6 + for idx, name in enumerate( + ["MyFixedArray", "MyFixedArray2", "MockArray1", "MockArray2", "MockArray3", "MockArray4"] + ): + assert model_runtime.main_model.DataTypeDefinitions.Arrays[idx].Name == name + + +def test_consolidation_fixed_size_array_vector_reference() -> None: + """Assert References of Consolidated Fixed Size Arrays & Vectors""" + + ma_struct = vafpy.datatypes.Struct(name="MaStruct", namespace="test") + ma_struct.add_subelement(name="x", datatype=vafpy.BaseTypes.DOUBLE) + + vafpy.datatypes.Vector(name="MaVector", namespace="test", datatype=ma_struct) + + my_vector_fix = vafpy.datatypes.Vector(name="MyVectorFixed", namespace="test", datatype=ma_struct) + + mock_vector2 = vafpy.datatypes.Vector(name="MockVector2", namespace="test", datatype=vafpy.BaseTypes.FLOAT) + mock_vector3 = vafpy.datatypes.Vector(name="MockVector3", namespace="test", datatype=vafpy.BaseTypes.FLOAT) + mock_vector4 = vafpy.datatypes.Vector(name="MockVector4", namespace="test", datatype=vafpy.BaseTypes.FLOAT) + + mock_array1 = vafpy.datatypes.Array(name="MockArray1", namespace="test", datatype=vafpy.BaseTypes.UINT16_T, size=2) + mock_array2 = vafpy.datatypes.Array(name="MockArray2", namespace="test", datatype=vafpy.BaseTypes.UINT16_T, size=2) + mock_array3 = vafpy.datatypes.Array(name="MockArray3", namespace="test", datatype=vafpy.BaseTypes.FLOAT, size=2) + + mock_struct = vafpy.datatypes.Struct(name="MockStruct", namespace="test") + mock_struct.add_subelement(name="W", datatype=mock_vector3) + mock_struct.add_subelement(name="H", datatype=mock_vector2) + mock_struct.add_subelement(name="Y", datatype=mock_array3) + mock_struct.add_subelement(name="M", datatype=mock_array1) + mock_struct.add_subelement(name="C", datatype=mock_array2) + mock_struct.add_subelement(name="A", datatype=mock_vector4) + + vafpy.datatypes.TypeRef(name="MockTypeRef", namespace="test", datatype=mock_array3) + + vafpy.datatypes.Map(name="MockMap", namespace="test", key_type=mock_array2, value_type=mock_array3) + vafpy.datatypes.Map(name="MockMap1", namespace="test", key_type=mock_struct, value_type=my_vector_fix) + + vafpy.datatypes.Vector(name="RefVector", namespace="test", datatype=mock_array2) + + vafpy.datatypes.Array(name="RefArray", namespace="test", datatype=mock_vector4, size=2) + + mock_interface = vafpy.ModuleInterface(name="MockInterface", namespace="test") + mock_interface.add_data_element(name="struct", datatype=mock_struct) + mock_interface.add_data_element(name="array", datatype=mock_array2) + mock_interface.add_data_element(name="vector", datatype=mock_vector4) + + mock_interface_func = vafpy.ModuleInterface(name="MockInterfaceFWraps", namespace="interfaces1") + mock_interface_func.add_operation( + name="func1", + in_parameter={"in1": mock_array2, "in2": mock_vector4}, + out_parameter={"out1": mock_array3, "out2": mock_vector4}, + inout_parameter={"inout1": mock_array1, "inout2": mock_array2}, + ) + + mock_mod = vafpy.ApplicationModule(name="temp", namespace="test") + mock_mod.add_provided_interface(instance_name="MockIf1", interface=mock_interface) + mock_mod.add_provided_interface(instance_name="MockIf2", interface=mock_interface_func) + + # assert reference in struct + mock_struct_goal = { + "W": "test::MockVector3", + "H": "test::MockVector2", + "Y": "test::MockArray3", + "M": "test::MockArray1", + "C": "test::MockArray2", + "A": "test::MockVector4", + } + for subelement in model_runtime.main_model.DataTypeDefinitions.Structs[-1].SubElements: + assert __get_type_ref_string(subelement.TypeRef) == mock_struct_goal[subelement.Name] + # assert corresponding typerefs + mock_typeref_goal = { + "MockTypeRef": "test::MockArray3", + } + assert len(model_runtime.main_model.DataTypeDefinitions.TypeRefs) == len(mock_typeref_goal) + for typeref in model_runtime.main_model.DataTypeDefinitions.TypeRefs: + assert __get_type_ref_string(typeref.TypeRef) == mock_typeref_goal[typeref.Name] + + # assert reference in maps + assert ( + __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Maps[-2].MapKeyTypeRef) == "test::MockArray2" + ) + assert ( + __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Maps[-2].MapValueTypeRef) + == "test::MockArray3" + ) + assert ( + __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Maps[-1].MapKeyTypeRef) == "test::MockStruct" + ) + assert ( + __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Maps[-1].MapValueTypeRef) + == "test::MyVectorFixed" + ) + + # assert reference in vectors + assert __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Vectors[-1].TypeRef) == "test::MockArray2" + # assert reference in arrays + assert __get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Arrays[-1].TypeRef) == "test::MockVector4" + + # assert reference in module interface + mock_interface_goal = { + "struct": "test::MockStruct", + "array": "test::MockArray2", + "vector": "test::MockVector4", + } + for data_element in model_runtime.main_model.ModuleInterfaces[0].DataElements: + assert __get_type_ref_string(data_element.TypeRef) == mock_interface_goal[data_element.Name] + + mock_interface_fwrap_goal = { + "in1": "test::MockArray2", + "in2": "test::MockVector4", + "out1": "test::MockArray3", + "out2": "test::MockVector4", + "inout1": "test::MockArray1", + "inout2": "test::MockArray2", + } + for param in model_runtime.main_model.ModuleInterfaces[1].Operations[0].Parameters: + assert __get_type_ref_string(param.TypeRef) == mock_interface_fwrap_goal[param.Name] + + +def test_bug_cleanup_vss_model(tmp_path) -> None: + """FTAF-399: Test Bug on Cleanup of VSS Model""" + path_out = tmp_path / "ftaf_399" + + copytree(UT_PATH / "test_data/ftaf_399", path_out) + + mock_vafpy(path_out, ["vss", "app_module1"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.APP_MODULE) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_399/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + + +def test_bug_cleanup_ftaf_422(tmp_path) -> None: + """FTAF-422: Test vafpy cleanup fails with source node ::uint32_t not in graph""" + path_out = tmp_path / "ftaf_422" + + copytree(UT_PATH / "test_data/ftaf_422", path_out) + + mock_vafpy(path_out, ["imported_models/interface", "app_module1"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.APP_MODULE) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_422/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) + + +def test_bug_ftaf_553(tmp_path) -> None: + """FTAF-553: Custom datatype as operation parameter is removed from model""" + path_out = tmp_path / "ftaf_553" + + copytree(UT_PATH / "test_data/ftaf_553", path_out) + + mock_vafpy(path_out, ["imported_models/interfaces", "app_module1"]) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.APP_MODULE) + + vafmodel.load_json(path_out / "model.json") + + +def test_ftaf_576_string_base_type(tmp_path) -> None: + """FTAF-576: Add string to basetypes""" + original_working_dir = Path.cwd() + path_out = tmp_path / "ftaf_576_string_base_type" + path_out.mkdir(parents=True, exist_ok=True) + copyfile(UT_PATH / "test_data/ftaf_576/model.py", path_out / "model.py") + + mock_vafpy(path_out, []) + + save_main_model(path_out / "model.json", cleanup=True, project_type=ProjectType.INTEGRATION) + + with open(path_out / "model.json", "r", encoding="utf-8") as generated: + with open(UT_PATH / "test_data/ftaf_576/model.json", "r", encoding="utf-8") as goal: + assert json.loads(generated.read()) == json.loads(goal.read()) diff --git a/VAF/tests/unit/vafpy/test_data/common/.vafconfig.json b/VAF/tests/unit/vafpy/test_data/common/.vafconfig.json new file mode 100644 index 0000000..ad8ab96 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/common/.vafconfig.json @@ -0,0 +1,8 @@ +{ + "version": "0.1.0", + "vaf-artifacts": { + "vaf-output": ".", + "vaf-init-model": "model/vaf" + }, + "project-type": "integration-project" +} diff --git a/VAF/tests/unit/vafpy/test_data/common/silkit-model.json b/VAF/tests/unit/vafpy/test_data/common/silkit-model.json new file mode 100644 index 0000000..a1d9b42 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/common/silkit-model.json @@ -0,0 +1,347 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "G", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "B", + "TypeRef": "datatypes::Vector1" + } + ] + } + ], + "Vectors": [ + { + "Name": "Vector1", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer1" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer2" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_VelocityServiceConsumer" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_SteeringAngleServiceConsumer" + }, + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_BrakeServiceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_BrakeServiceProvider" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_SteeringAngleServiceProvider" + }, + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider1" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_VelocityServiceProvider" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer1", + "ServiceInterfaceName": "Silkit_ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer2", + "ServiceInterfaceName": "Silkit_ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_SteeringAngleServiceConsumer", + "ServiceInterfaceName": "Silkit_SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_VelocityServiceConsumer", + "ServiceInterfaceName": "Silkit_VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_BrakeServiceConsumer", + "ServiceInterfaceName": "Silkit_BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_ImageServiceProvider1", + "ServiceInterfaceName": "Silkit_ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_ImageServiceProvider2", + "ServiceInterfaceName": "Silkit_ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_SteeringAngleServiceProvider", + "ServiceInterfaceName": "Silkit_SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_VelocityServiceProvider", + "ServiceInterfaceName": "Silkit_VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_BrakeServiceProvider", + "ServiceInterfaceName": "Silkit_BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafpy/test_data/common/silkit.py b/VAF/tests/unit/vafpy/test_data/common/silkit.py new file mode 100644 index 0000000..713a7da --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/common/silkit.py @@ -0,0 +1,63 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "silkit-model.json")) + +# Adapted to work with SIL Kit + + +# Service interfaces +class Af: + class Adas_Demo_App: + class Services: + # Module Interfaces + brake_service = get_module_interface("BrakeService", "af::adas_demo_app::services") + image_service = get_module_interface("ImageService", "af::adas_demo_app::services") + steering_angle_service = get_module_interface("SteeringAngleService", "af::adas_demo_app::services") + velocity_service = get_module_interface("VelocityService", "af::adas_demo_app::services") + + +# Executables and their ports +class AdasDemoApp: + # Executable + executable = Executable("adas_demo_app") + + # Required Ports + class ConsumerModules: + image_service1 = get_platform_consumer_module("ImageService1", "nsadas_demo_app::nsconsumermodules") + image_service2 = get_platform_consumer_module("ImageService2", "nsadas_demo_app::nsconsumermodules") + velocity_service = get_platform_consumer_module("VelocityService", "nsadas_demo_app::nsconsumermodules") + steering_angle_service = get_platform_consumer_module( + "SteeringAngleService", "nsadas_demo_app::nsconsumermodules" + ) + + # Provided Ports + class ProviderModules: + brake_service = get_platform_provider_module("BrakeService", "nsadas_demo_app::nsprovidermodules") + + +class AdasDemoTestApp: + # Executable + executable = Executable("adas_demo_test_app") + + # Required Ports + class ConsumerModules: + brake_service = get_platform_consumer_module("BrakeService", "nsadas_demo_test_app::nsconsumermodules") + + # Provided Ports + class ProviderModules: + steering_angle_service = get_platform_provider_module( + "SteeringAngleService", "nsadas_demo_test_app::nsprovidermodules" + ) + image_service1 = get_platform_provider_module("ImageService1", "nsadas_demo_test_app::nsprovidermodules") + velocity_service = get_platform_provider_module("VelocityService", "nsadas_demo_test_app::nsprovidermodules") + image_service2 = get_platform_provider_module("ImageService2", "nsadas_demo_test_app::nsprovidermodules") diff --git a/VAF/tests/unit/vafpy/test_data/common/vss-derived-model.json b/VAF/tests/unit/vafpy/test_data/common/vss-derived-model.json new file mode 100644 index 0000000..8b5454d --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/common/vss-derived-model.json @@ -0,0 +1,17474 @@ +{ + "DataTypeDefinitions": { + "Strings": [ + { + "Name": "string", + "Namespace": "vaf" + } + ], + "Enums": [ + { + "Name": "LowVoltageSystemState", + "Namespace": "vss::vehicle", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNDEFINED", + "Value": 1 + }, + { + "Label": "LOCK", + "Value": 2 + }, + { + "Label": "OFF", + "Value": 3 + }, + { + "Label": "ACC", + "Value": 4 + }, + { + "Label": "ON", + "Value": 5 + }, + { + "Label": "START", + "Value": 6 + } + ] + }, + { + "Name": "SupportedAutonomyLevel", + "Namespace": "vss::vehicle::adas", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "SAE_0", + "Value": 1 + }, + { + "Label": "SAE_1", + "Value": 2 + }, + { + "Label": "SAE_2", + "Value": 3 + }, + { + "Label": "SAE_3", + "Value": 4 + }, + { + "Label": "SAE_4", + "Value": 5 + }, + { + "Label": "SAE_5", + "Value": 6 + } + ] + }, + { + "Name": "ActiveAutonomyLevel", + "Namespace": "vss::vehicle::adas", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "SAE_0", + "Value": 1 + }, + { + "Label": "SAE_1", + "Value": 2 + }, + { + "Label": "SAE_2_DISENGAGING", + "Value": 3 + }, + { + "Label": "SAE_2", + "Value": 4 + }, + { + "Label": "SAE_3_DISENGAGING", + "Value": 5 + }, + { + "Label": "SAE_3", + "Value": 6 + }, + { + "Label": "SAE_4_DISENGAGING", + "Value": 7 + }, + { + "Label": "SAE_4", + "Value": 8 + }, + { + "Label": "SAE_5", + "Value": 9 + } + ] + }, + { + "Name": "RefuelPosition", + "Namespace": "vss::vehicle::body", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "FRONT_LEFT", + "Value": 1 + }, + { + "Label": "FRONT_RIGHT", + "Value": 2 + }, + { + "Label": "MIDDLE_LEFT", + "Value": 3 + }, + { + "Label": "MIDDLE_RIGHT", + "Value": 4 + }, + { + "Label": "REAR_LEFT", + "Value": 5 + }, + { + "Label": "REAR_RIGHT", + "Value": 6 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::body::hood", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "LightSwitch", + "Namespace": "vss::vehicle::body::lights", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "OFF", + "Value": 1 + }, + { + "Label": "POSITION", + "Value": 2 + }, + { + "Label": "DAYTIME_RUNNING_LIGHTS", + "Value": 3 + }, + { + "Label": "AUTO", + "Value": 4 + }, + { + "Label": "BEAM", + "Value": 5 + } + ] + }, + { + "Name": "IsActive", + "Namespace": "vss::vehicle::body::lights::brake", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "ACTIVE", + "Value": 2 + }, + { + "Label": "ADAPTIVE", + "Value": 3 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::body::trunk::front", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::body::trunk::rear", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::body::windshield::front::wiping", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "OFF", + "Value": 1 + }, + { + "Label": "SLOW", + "Value": 2 + }, + { + "Label": "MEDIUM", + "Value": 3 + }, + { + "Label": "FAST", + "Value": 4 + }, + { + "Label": "INTERVAL", + "Value": 5 + }, + { + "Label": "RAIN_SENSOR", + "Value": 6 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::body::windshield::front::wiping::system", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "STOP_HOLD", + "Value": 1 + }, + { + "Label": "WIPE", + "Value": 2 + }, + { + "Label": "PLANT_MODE", + "Value": 3 + }, + { + "Label": "EMERGENCY_STOP", + "Value": 4 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::body::windshield::rear::wiping", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "OFF", + "Value": 1 + }, + { + "Label": "SLOW", + "Value": 2 + }, + { + "Label": "MEDIUM", + "Value": 3 + }, + { + "Label": "FAST", + "Value": 4 + }, + { + "Label": "INTERVAL", + "Value": 5 + }, + { + "Label": "RAIN_SENSOR", + "Value": 6 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::body::windshield::rear::wiping::system", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "STOP_HOLD", + "Value": 1 + }, + { + "Label": "WIPE", + "Value": 2 + }, + { + "Label": "PLANT_MODE", + "Value": 3 + }, + { + "Label": "EMERGENCY_STOP", + "Value": 4 + } + ] + }, + { + "Name": "DriverPosition", + "Namespace": "vss::vehicle::cabin", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "LEFT", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "RIGHT", + "Value": 3 + } + ] + }, + { + "Name": "Status", + "Namespace": "vss::vehicle::cabin::convertible", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNDEFINED", + "Value": 1 + }, + { + "Label": "CLOSED", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "CLOSING", + "Value": 4 + }, + { + "Label": "OPENING", + "Value": 5 + }, + { + "Label": "STALLED", + "Value": 6 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::driverside", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::driverside::shade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::driverside::window", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside::shade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside::window", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::driverside", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::driverside::shade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::driverside::window", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside::shade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside::window", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row1::driver", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row1::passenger", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row2::driver", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row2::passenger", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row3::driver", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row3::passenger", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row4::driver", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "AirDistribution", + "Namespace": "vss::vehicle::cabin::hvac::station::row4::passenger", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UP", + "Value": 1 + }, + { + "Label": "MIDDLE", + "Value": 2 + }, + { + "Label": "DOWN", + "Value": 3 + } + ] + }, + { + "Name": "EVEconomyUnits", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "MILES_PER_KILOWATT_HOUR", + "Value": 1 + }, + { + "Label": "KILOMETERS_PER_KILOWATT_HOUR", + "Value": 2 + }, + { + "Label": "KILOWATT_HOURS_PER_100_MILES", + "Value": 3 + }, + { + "Label": "KILOWATT_HOURS_PER_100_KILOMETERS", + "Value": 4 + }, + { + "Label": "WATT_HOURS_PER_MILE", + "Value": 5 + }, + { + "Label": "WATT_HOURS_PER_KILOMETER", + "Value": 6 + } + ] + }, + { + "Name": "EVEnergyUnits", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "WATT_HOURS", + "Value": 1 + }, + { + "Label": "AMPERE_HOURS", + "Value": 2 + }, + { + "Label": "KILOWATT_HOURS", + "Value": 3 + } + ] + }, + { + "Name": "DateFormat", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "YYYY_MM_DD", + "Value": 1 + }, + { + "Label": "DD_MM_YYYY", + "Value": 2 + }, + { + "Label": "MM_DD_YYYY", + "Value": 3 + }, + { + "Label": "YY_MM_DD", + "Value": 4 + }, + { + "Label": "DD_MM_YY", + "Value": 5 + }, + { + "Label": "MM_DD_YY", + "Value": 6 + } + ] + }, + { + "Name": "SpeedUnit", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "METERS_PER_SECOND", + "Value": 1 + }, + { + "Label": "MILES_PER_HOUR", + "Value": 2 + }, + { + "Label": "KILOMETERS_PER_HOUR", + "Value": 3 + } + ] + }, + { + "Name": "FontSize", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "STANDARD", + "Value": 1 + }, + { + "Label": "LARGE", + "Value": 2 + }, + { + "Label": "EXTRA_LARGE", + "Value": 3 + } + ] + }, + { + "Name": "DayNightMode", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "DAY", + "Value": 1 + }, + { + "Label": "NIGHT", + "Value": 2 + } + ] + }, + { + "Name": "TemperatureUnit", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "C", + "Value": 1 + }, + { + "Label": "F", + "Value": 2 + } + ] + }, + { + "Name": "FuelEconomyUnits", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "MPG_UK", + "Value": 1 + }, + { + "Label": "MPG_US", + "Value": 2 + }, + { + "Label": "MILES_PER_LITER", + "Value": 3 + }, + { + "Label": "KILOMETERS_PER_LITER", + "Value": 4 + }, + { + "Label": "LITERS_PER_100_KILOMETERS", + "Value": 5 + } + ] + }, + { + "Name": "TimeFormat", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "HR_12", + "Value": 1 + }, + { + "Label": "HR_24", + "Value": 2 + } + ] + }, + { + "Name": "DistanceUnit", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "MILES", + "Value": 1 + }, + { + "Label": "KILOMETERS", + "Value": 2 + } + ] + }, + { + "Name": "FuelVolumeUnit", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "LITER", + "Value": 1 + }, + { + "Label": "GALLON_US", + "Value": 2 + }, + { + "Label": "GALLON_UK", + "Value": 3 + } + ] + }, + { + "Name": "TirePressureUnit", + "Namespace": "vss::vehicle::cabin::infotainment::hmi", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "PSI", + "Value": 1 + }, + { + "Label": "KPA", + "Value": 2 + }, + { + "Label": "BAR", + "Value": 3 + } + ] + }, + { + "Name": "Action", + "Namespace": "vss::vehicle::cabin::infotainment::media", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "STOP", + "Value": 2 + }, + { + "Label": "PLAY", + "Value": 3 + }, + { + "Label": "FAST_FORWARD", + "Value": 4 + }, + { + "Label": "FAST_BACKWARD", + "Value": 5 + }, + { + "Label": "SKIP_FORWARD", + "Value": 6 + }, + { + "Label": "SKIP_BACKWARD", + "Value": 7 + } + ] + }, + { + "Name": "Source", + "Namespace": "vss::vehicle::cabin::infotainment::media::played", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "SIRIUS_XM", + "Value": 2 + }, + { + "Label": "AM", + "Value": 3 + }, + { + "Label": "FM", + "Value": 4 + }, + { + "Label": "DAB", + "Value": 5 + }, + { + "Label": "TV", + "Value": 6 + }, + { + "Label": "CD", + "Value": 7 + }, + { + "Label": "DVD", + "Value": 8 + }, + { + "Label": "AUX", + "Value": 9 + }, + { + "Label": "USB", + "Value": 10 + }, + { + "Label": "DISK", + "Value": 11 + }, + { + "Label": "BLUETOOTH", + "Value": 12 + }, + { + "Label": "INTERNET", + "Value": 13 + }, + { + "Label": "VOICE", + "Value": 14 + }, + { + "Label": "BEEP", + "Value": 15 + } + ] + }, + { + "Name": "GuidanceVoice", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "STANDARD_MALE", + "Value": 1 + }, + { + "Label": "STANDARD_FEMALE", + "Value": 2 + }, + { + "Label": "ETC", + "Value": 3 + } + ] + }, + { + "Name": "Mute", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "MUTED", + "Value": 1 + }, + { + "Label": "ALERT_ONLY", + "Value": 2 + }, + { + "Label": "UNMUTED", + "Value": 3 + } + ] + }, + { + "Name": "Source", + "Namespace": "vss::vehicle::cabin::infotainment::smartphoneprojection", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "USB", + "Value": 1 + }, + { + "Label": "BLUETOOTH", + "Value": 2 + }, + { + "Label": "WIFI", + "Value": 3 + } + ] + }, + { + "Name": "Active", + "Namespace": "vss::vehicle::cabin::infotainment::smartphoneprojection", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "NONE", + "Value": 1 + }, + { + "Label": "ACTIVE", + "Value": 2 + }, + { + "Label": "INACTIVE", + "Value": 3 + } + ] + }, + { + "Name": "Source", + "Namespace": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "USB", + "Value": 1 + }, + { + "Label": "BLUETOOTH", + "Value": 2 + }, + { + "Label": "WIFI", + "Value": 3 + } + ] + }, + { + "Name": "Active", + "Namespace": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "NONE", + "Value": 1 + }, + { + "Label": "ACTIVE", + "Value": 2 + }, + { + "Label": "INACTIVE", + "Value": 3 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::rearshade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::sunroof", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + }, + { + "Label": "TILT_UP", + "Value": 6 + }, + { + "Label": "TILT_DOWN", + "Value": 7 + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::sunroof::shade", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "CLOSE", + "Value": 2 + }, + { + "Label": "OPEN", + "Value": 3 + }, + { + "Label": "ONE_SHOT_CLOSE", + "Value": 4 + }, + { + "Label": "ONE_SHOT_OPEN", + "Value": 5 + } + ] + }, + { + "Name": "FixType", + "Namespace": "vss::vehicle::currentlocation::gnssreceiver", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "NONE", + "Value": 1 + }, + { + "Label": "TWO_D", + "Value": 2 + }, + { + "Label": "TWO_D_SATELLITE_BASED_AUGMENTATION", + "Value": 3 + }, + { + "Label": "TWO_D_GROUND_BASED_AUGMENTATION", + "Value": 4 + }, + { + "Label": "TWO_D_SATELLITE_AND_GROUND_BASED_AUGMENTATION", + "Value": 5 + }, + { + "Label": "THREE_D", + "Value": 6 + }, + { + "Label": "THREE_D_SATELLITE_BASED_AUGMENTATION", + "Value": 7 + }, + { + "Label": "THREE_D_GROUND_BASED_AUGMENTATION", + "Value": 8 + }, + { + "Label": "THREE_D_SATELLITE_AND_GROUND_BASED_AUGMENTATION", + "Value": 9 + } + ] + }, + { + "Name": "IgnitionType", + "Namespace": "vss::vehicle::obd::drivecyclestatus", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "SPARK", + "Value": 1 + }, + { + "Label": "COMPRESSION", + "Value": 2 + } + ] + }, + { + "Name": "IgnitionType", + "Namespace": "vss::vehicle::obd::status", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "SPARK", + "Value": 1 + }, + { + "Label": "COMPRESSION", + "Value": 2 + } + ] + }, + { + "Name": "Type", + "Namespace": "vss::vehicle::powertrain", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "COMBUSTION", + "Value": 1 + }, + { + "Label": "HYBRID", + "Value": 2 + }, + { + "Label": "ELECTRIC", + "Value": 3 + } + ] + }, + { + "Name": "Configuration", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "STRAIGHT", + "Value": 2 + }, + { + "Label": "V", + "Value": 3 + }, + { + "Label": "BOXER", + "Value": 4 + }, + { + "Label": "W", + "Value": 5 + }, + { + "Label": "ROTARY", + "Value": 6 + }, + { + "Label": "RADIAL", + "Value": 7 + }, + { + "Label": "SQUARE", + "Value": 8 + }, + { + "Label": "H", + "Value": 9 + }, + { + "Label": "U", + "Value": 10 + }, + { + "Label": "OPPOSED", + "Value": 11 + }, + { + "Label": "X", + "Value": 12 + } + ] + }, + { + "Name": "EngineOilLevel", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "CRITICALLY_LOW", + "Value": 1 + }, + { + "Label": "LOW", + "Value": 2 + }, + { + "Label": "NORMAL", + "Value": 3 + }, + { + "Label": "HIGH", + "Value": 4 + }, + { + "Label": "CRITICALLY_HIGH", + "Value": 5 + } + ] + }, + { + "Name": "AspirationType", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "NATURAL", + "Value": 2 + }, + { + "Label": "SUPERCHARGER", + "Value": 3 + }, + { + "Label": "TURBOCHARGER", + "Value": 4 + } + ] + }, + { + "Name": "Level", + "Namespace": "vss::vehicle::powertrain::combustionengine::enginecoolant", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "CRITICALLY_LOW", + "Value": 1 + }, + { + "Label": "LOW", + "Value": 2 + }, + { + "Label": "NORMAL", + "Value": 3 + } + ] + }, + { + "Name": "Level", + "Namespace": "vss::vehicle::powertrain::combustionengine::engineoil", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "CRITICALLY_LOW", + "Value": 1 + }, + { + "Label": "LOW", + "Value": 2 + }, + { + "Label": "NORMAL", + "Value": 3 + }, + { + "Label": "HIGH", + "Value": 4 + }, + { + "Label": "CRITICALLY_HIGH", + "Value": 5 + } + ] + }, + { + "Name": "Level", + "Namespace": "vss::vehicle::powertrain::electricmotor::enginecoolant", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "CRITICALLY_LOW", + "Value": 1 + }, + { + "Label": "LOW", + "Value": 2 + }, + { + "Label": "NORMAL", + "Value": 3 + } + ] + }, + { + "Name": "HybridType", + "Namespace": "vss::vehicle::powertrain::fuelsystem", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "NOT_APPLICABLE", + "Value": 2 + }, + { + "Label": "STOP_START", + "Value": 3 + }, + { + "Label": "BELT_ISG", + "Value": 4 + }, + { + "Label": "CIMG", + "Value": 5 + }, + { + "Label": "PHEV", + "Value": 6 + } + ] + }, + { + "Name": "RequestedMode", + "Namespace": "vss::vehicle::powertrain::tractionbattery::batteryconditioning", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "FAST_CHARGING_PREPARATION", + "Value": 2 + }, + { + "Label": "DRIVING_PREPARATION", + "Value": 3 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "DEACTIVATED", + "Value": 1 + }, + { + "Label": "AUTOMATIC", + "Value": 2 + }, + { + "Label": "TRIGGERED", + "Value": 3 + }, + { + "Label": "TIMER", + "Value": 4 + }, + { + "Label": "PROFILE", + "Value": 5 + }, + { + "Label": "EXTERNAL_ENTITY", + "Value": 6 + }, + { + "Label": "MANUAL", + "Value": 7 + }, + { + "Label": "GRID", + "Value": 8 + } + ] + }, + { + "Name": "StartStopCharging", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "START", + "Value": 1 + }, + { + "Label": "STOP", + "Value": 2 + } + ] + }, + { + "Name": "ChargePortFlap", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "OPEN", + "Value": 1 + }, + { + "Label": "CLOSED", + "Value": 2 + } + ] + }, + { + "Name": "Mode", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging::timer", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "INACTIVE", + "Value": 1 + }, + { + "Label": "START_TIME", + "Value": 2 + }, + { + "Label": "END_TIME", + "Value": 3 + } + ] + }, + { + "Name": "PerformanceMode", + "Namespace": "vss::vehicle::powertrain::transmission", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "NORMAL", + "Value": 1 + }, + { + "Label": "SPORT", + "Value": 2 + }, + { + "Label": "ECONOMY", + "Value": 3 + }, + { + "Label": "SNOW", + "Value": 4 + }, + { + "Label": "RAIN", + "Value": 5 + } + ] + }, + { + "Name": "DriveType", + "Namespace": "vss::vehicle::powertrain::transmission", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "FORWARD_WHEEL_DRIVE", + "Value": 2 + }, + { + "Label": "REAR_WHEEL_DRIVE", + "Value": 3 + }, + { + "Label": "ALL_WHEEL_DRIVE", + "Value": 4 + } + ] + }, + { + "Name": "GearChangeMode", + "Namespace": "vss::vehicle::powertrain::transmission", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "MANUAL", + "Value": 1 + }, + { + "Label": "AUTOMATIC", + "Value": 2 + } + ] + }, + { + "Name": "Type", + "Namespace": "vss::vehicle::powertrain::transmission", + "BaseType": "uint8_t", + "Literals": [ + { + "Label": "UNKNOWN", + "Value": 1 + }, + { + "Label": "SEQUENTIAL", + "Value": 2 + }, + { + "Label": "H", + "Value": 3 + }, + { + "Label": "AUTOMATIC", + "Value": 4 + }, + { + "Label": "DSG", + "Value": 5 + }, + { + "Label": "CVT", + "Value": 6 + } + ] + } + ], + "Structs": [ + { + "Name": "VersionVSS", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Label", + "TypeRef": "vaf::string" + }, + { + "Name": "Major", + "TypeRef": "uint32_t" + }, + { + "Name": "Minor", + "TypeRef": "uint32_t" + }, + { + "Name": "Patch", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "Acceleration", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Lateral", + "TypeRef": "float" + }, + { + "Name": "Longitudinal", + "TypeRef": "float" + }, + { + "Name": "Vertical", + "TypeRef": "float" + } + ] + }, + { + "Name": "AngularVelocity", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float" + }, + { + "Name": "Roll", + "TypeRef": "float" + }, + { + "Name": "Yaw", + "TypeRef": "float" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Exterior", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AirTemperature", + "TypeRef": "float" + }, + { + "Name": "Humidity", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "LightIntensity", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Powertrain", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AccumulatedBrakingEnergy", + "TypeRef": "float" + }, + { + "Name": "CombustionEngine", + "TypeRef": "vss::vehicle::powertrain::CombustionEngine" + }, + { + "Name": "ElectricMotor", + "TypeRef": "vss::vehicle::powertrain::ElectricMotor" + }, + { + "Name": "FuelSystem", + "TypeRef": "vss::vehicle::powertrain::FuelSystem" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + }, + { + "Name": "TractionBattery", + "TypeRef": "vss::vehicle::powertrain::TractionBattery" + }, + { + "Name": "Transmission", + "TypeRef": "vss::vehicle::powertrain::Transmission" + }, + { + "Name": "Type", + "TypeRef": "vss::vehicle::powertrain::Type" + } + ] + }, + { + "Name": "Body", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "BodyType", + "TypeRef": "vaf::string" + }, + { + "Name": "Hood", + "TypeRef": "vss::vehicle::body::Hood" + }, + { + "Name": "Horn", + "TypeRef": "vss::vehicle::body::Horn" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "Lights", + "TypeRef": "vss::vehicle::body::Lights" + }, + { + "Name": "Mirrors", + "TypeRef": "vss::vehicle::body::Mirrors" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Raindetection", + "TypeRef": "vss::vehicle::body::Raindetection" + }, + { + "Name": "RearMainSpoilerPosition", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "RefuelPosition", + "TypeRef": "vss::vehicle::body::RefuelPosition" + }, + { + "Name": "Trunk", + "TypeRef": "vss::vehicle::body::Trunk" + }, + { + "Name": "Windshield", + "TypeRef": "vss::vehicle::body::Windshield" + } + ] + }, + { + "Name": "Connectivity", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "IsConnectivityAvailable", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Service", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "DistanceToService", + "TypeRef": "float" + }, + { + "Name": "IsServiceDue", + "TypeRef": "bool" + }, + { + "Name": "TimeToService", + "TypeRef": "int32_t" + } + ] + }, + { + "Name": "Diagnostics", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "DTCList", + "TypeRef": "vss::stringVector" + } + ] + }, + { + "Name": "LowVoltageBattery", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "CurrentCurrent", + "TypeRef": "float" + }, + { + "Name": "CurrentVoltage", + "TypeRef": "float" + }, + { + "Name": "NominalCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "NominalVoltage", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "CurrentLocation", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Altitude", + "TypeRef": "double" + }, + { + "Name": "GNSSReceiver", + "TypeRef": "vss::vehicle::currentlocation::GNSSReceiver" + }, + { + "Name": "Heading", + "TypeRef": "double", + "Min": 0.0, + "Max": 360.0 + }, + { + "Name": "HorizontalAccuracy", + "TypeRef": "double" + }, + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Timestamp", + "TypeRef": "vaf::string" + }, + { + "Name": "VerticalAccuracy", + "TypeRef": "double" + } + ] + }, + { + "Name": "Cabin", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Convertible", + "TypeRef": "vss::vehicle::cabin::Convertible" + }, + { + "Name": "Door", + "TypeRef": "vss::vehicle::cabin::Door" + }, + { + "Name": "DoorCount", + "TypeRef": "uint8_t" + }, + { + "Name": "DriverPosition", + "TypeRef": "vss::vehicle::cabin::DriverPosition" + }, + { + "Name": "HVAC", + "TypeRef": "vss::vehicle::cabin::HVAC" + }, + { + "Name": "Infotainment", + "TypeRef": "vss::vehicle::cabin::Infotainment" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "IsWindowChildLockEngaged", + "TypeRef": "bool" + }, + { + "Name": "Light", + "TypeRef": "vss::vehicle::cabin::Light" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "RearShade", + "TypeRef": "vss::vehicle::cabin::RearShade" + }, + { + "Name": "RearviewMirror", + "TypeRef": "vss::vehicle::cabin::RearviewMirror" + }, + { + "Name": "Seat", + "TypeRef": "vss::vehicle::cabin::Seat" + }, + { + "Name": "SeatPosCount", + "TypeRef": "vss::uint8Vector" + }, + { + "Name": "SeatRowCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Sunroof", + "TypeRef": "vss::vehicle::cabin::Sunroof" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AttentiveProbability", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DistractionLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "FatigueLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeartRate", + "TypeRef": "uint16_t" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::driver::Identifier" + }, + { + "Name": "IsEyesOnRoad", + "TypeRef": "bool" + }, + { + "Name": "IsHandsOnWheel", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Trailer", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "IsConnected", + "TypeRef": "bool" + } + ] + }, + { + "Name": "ADAS", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "ABS", + "TypeRef": "vss::vehicle::adas::ABS" + }, + { + "Name": "ActiveAutonomyLevel", + "TypeRef": "vss::vehicle::adas::ActiveAutonomyLevel" + }, + { + "Name": "CruiseControl", + "TypeRef": "vss::vehicle::adas::CruiseControl" + }, + { + "Name": "DMS", + "TypeRef": "vss::vehicle::adas::DMS" + }, + { + "Name": "EBA", + "TypeRef": "vss::vehicle::adas::EBA" + }, + { + "Name": "EBD", + "TypeRef": "vss::vehicle::adas::EBD" + }, + { + "Name": "ESC", + "TypeRef": "vss::vehicle::adas::ESC" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "LaneDepartureDetection", + "TypeRef": "vss::vehicle::adas::LaneDepartureDetection" + }, + { + "Name": "ObstacleDetection", + "TypeRef": "vss::vehicle::adas::ObstacleDetection" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "SupportedAutonomyLevel", + "TypeRef": "vss::vehicle::adas::SupportedAutonomyLevel" + }, + { + "Name": "TCS", + "TypeRef": "vss::vehicle::adas::TCS" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::occupant::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::occupant::Row2" + } + ] + }, + { + "Name": "VehicleIdentification", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AcrissCode", + "TypeRef": "vaf::string" + }, + { + "Name": "BodyType", + "TypeRef": "vaf::string" + }, + { + "Name": "Brand", + "TypeRef": "vaf::string" + }, + { + "Name": "DateVehicleFirstRegistered", + "TypeRef": "vaf::string" + }, + { + "Name": "KnownVehicleDamages", + "TypeRef": "vaf::string" + }, + { + "Name": "LicensePlate", + "TypeRef": "vaf::string" + }, + { + "Name": "MeetsEmissionStandard", + "TypeRef": "vaf::string" + }, + { + "Name": "Model", + "TypeRef": "vaf::string" + }, + { + "Name": "OptionalExtras", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ProductionDate", + "TypeRef": "vaf::string" + }, + { + "Name": "PurchaseDate", + "TypeRef": "vaf::string" + }, + { + "Name": "VIN", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleConfiguration", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleExteriorColor", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleInteriorColor", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleInteriorType", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleModelDate", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleSeatingCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "VehicleSpecialUsage", + "TypeRef": "vaf::string" + }, + { + "Name": "WMI", + "TypeRef": "vaf::string" + }, + { + "Name": "Year", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "OBD", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AbsoluteLoad", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionD", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionE", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionF", + "TypeRef": "float" + }, + { + "Name": "AirStatus", + "TypeRef": "vaf::string" + }, + { + "Name": "AmbientAirTemperature", + "TypeRef": "float" + }, + { + "Name": "BarometricPressure", + "TypeRef": "float" + }, + { + "Name": "Catalyst", + "TypeRef": "vss::vehicle::obd::Catalyst" + }, + { + "Name": "CommandedEGR", + "TypeRef": "float" + }, + { + "Name": "CommandedEVAP", + "TypeRef": "float" + }, + { + "Name": "CommandedEquivalenceRatio", + "TypeRef": "float" + }, + { + "Name": "ControlModuleVoltage", + "TypeRef": "float" + }, + { + "Name": "CoolantTemperature", + "TypeRef": "float" + }, + { + "Name": "DTCList", + "TypeRef": "vss::stringVector" + }, + { + "Name": "DistanceSinceDTCClear", + "TypeRef": "float" + }, + { + "Name": "DistanceWithMIL", + "TypeRef": "float" + }, + { + "Name": "DriveCycleStatus", + "TypeRef": "vss::vehicle::obd::DriveCycleStatus" + }, + { + "Name": "EGRError", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressure", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressureAbsolute", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressureAlternate", + "TypeRef": "float" + }, + { + "Name": "EngineLoad", + "TypeRef": "float" + }, + { + "Name": "EngineSpeed", + "TypeRef": "float" + }, + { + "Name": "EthanolPercent", + "TypeRef": "float" + }, + { + "Name": "FreezeDTC", + "TypeRef": "vaf::string" + }, + { + "Name": "FuelInjectionTiming", + "TypeRef": "float" + }, + { + "Name": "FuelLevel", + "TypeRef": "float" + }, + { + "Name": "FuelPressure", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureAbsolute", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureDirect", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureVac", + "TypeRef": "float" + }, + { + "Name": "FuelRate", + "TypeRef": "float" + }, + { + "Name": "FuelStatus", + "TypeRef": "vaf::string" + }, + { + "Name": "FuelType", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 23.0 + }, + { + "Name": "HybridBatteryRemaining", + "TypeRef": "float" + }, + { + "Name": "IntakeTemp", + "TypeRef": "float" + }, + { + "Name": "IsPTOActive", + "TypeRef": "bool" + }, + { + "Name": "LongTermFuelTrim1", + "TypeRef": "float" + }, + { + "Name": "LongTermFuelTrim2", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim1", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim2", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim3", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim4", + "TypeRef": "float" + }, + { + "Name": "MAF", + "TypeRef": "float" + }, + { + "Name": "MAP", + "TypeRef": "float" + }, + { + "Name": "MaxMAF", + "TypeRef": "float" + }, + { + "Name": "O2", + "TypeRef": "vss::vehicle::obd::O2" + }, + { + "Name": "O2WR", + "TypeRef": "vss::vehicle::obd::O2WR" + }, + { + "Name": "OBDStandards", + "TypeRef": "uint8_t" + }, + { + "Name": "OilTemperature", + "TypeRef": "float" + }, + { + "Name": "OxygenSensorsIn2Banks", + "TypeRef": "uint8_t" + }, + { + "Name": "OxygenSensorsIn4Banks", + "TypeRef": "uint8_t" + }, + { + "Name": "PidsA", + "TypeRef": "vss::stringVector" + }, + { + "Name": "PidsB", + "TypeRef": "vss::stringVector" + }, + { + "Name": "PidsC", + "TypeRef": "vss::stringVector" + }, + { + "Name": "RelativeAcceleratorPosition", + "TypeRef": "float" + }, + { + "Name": "RelativeThrottlePosition", + "TypeRef": "float" + }, + { + "Name": "RunTime", + "TypeRef": "float" + }, + { + "Name": "RunTimeMIL", + "TypeRef": "float" + }, + { + "Name": "ShortTermFuelTrim1", + "TypeRef": "float" + }, + { + "Name": "ShortTermFuelTrim2", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim1", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim2", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim3", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim4", + "TypeRef": "float" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Status", + "TypeRef": "vss::vehicle::obd::Status" + }, + { + "Name": "ThrottleActuator", + "TypeRef": "float" + }, + { + "Name": "ThrottlePosition", + "TypeRef": "float" + }, + { + "Name": "ThrottlePositionB", + "TypeRef": "float" + }, + { + "Name": "ThrottlePositionC", + "TypeRef": "float" + }, + { + "Name": "TimeSinceDTCCleared", + "TypeRef": "float" + }, + { + "Name": "TimingAdvance", + "TypeRef": "float" + }, + { + "Name": "WarmupsSinceDTCClear", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Vehicle", + "Namespace": "vss", + "SubElements": [ + { + "Name": "ADAS", + "TypeRef": "vss::vehicle::ADAS" + }, + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "AngularVelocity", + "TypeRef": "vss::vehicle::AngularVelocity" + }, + { + "Name": "AverageSpeed", + "TypeRef": "float" + }, + { + "Name": "Body", + "TypeRef": "vss::vehicle::Body" + }, + { + "Name": "Cabin", + "TypeRef": "vss::vehicle::Cabin" + }, + { + "Name": "CargoVolume", + "TypeRef": "float", + "Min": 0.0 + }, + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + }, + { + "Name": "Connectivity", + "TypeRef": "vss::vehicle::Connectivity" + }, + { + "Name": "CurbWeight", + "TypeRef": "uint16_t" + }, + { + "Name": "CurrentLocation", + "TypeRef": "vss::vehicle::CurrentLocation" + }, + { + "Name": "CurrentOverallWeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Diagnostics", + "TypeRef": "vss::vehicle::Diagnostics" + }, + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + }, + { + "Name": "EmissionsCO2", + "TypeRef": "int16_t" + }, + { + "Name": "Exterior", + "TypeRef": "vss::vehicle::Exterior" + }, + { + "Name": "GrossWeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Height", + "TypeRef": "uint16_t" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "IsBrokenDown", + "TypeRef": "bool" + }, + { + "Name": "IsMoving", + "TypeRef": "bool" + }, + { + "Name": "Length", + "TypeRef": "uint16_t" + }, + { + "Name": "LowVoltageBattery", + "TypeRef": "vss::vehicle::LowVoltageBattery" + }, + { + "Name": "LowVoltageSystemState", + "TypeRef": "vss::vehicle::LowVoltageSystemState" + }, + { + "Name": "MaxTowBallWeight", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxTowWeight", + "TypeRef": "uint16_t" + }, + { + "Name": "OBD", + "TypeRef": "vss::vehicle::OBD" + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::Occupant" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Powertrain", + "TypeRef": "vss::vehicle::Powertrain" + }, + { + "Name": "RoofLoad", + "TypeRef": "int16_t" + }, + { + "Name": "Service", + "TypeRef": "vss::vehicle::Service" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "StartTime", + "TypeRef": "vaf::string" + }, + { + "Name": "Trailer", + "TypeRef": "vss::vehicle::Trailer" + }, + { + "Name": "TraveledDistance", + "TypeRef": "float" + }, + { + "Name": "TraveledDistanceSinceStart", + "TypeRef": "float" + }, + { + "Name": "TripDuration", + "TypeRef": "float" + }, + { + "Name": "TripMeterReading", + "TypeRef": "float" + }, + { + "Name": "TurningDiameter", + "TypeRef": "uint16_t" + }, + { + "Name": "VehicleIdentification", + "TypeRef": "vss::vehicle::VehicleIdentification" + }, + { + "Name": "VersionVSS", + "TypeRef": "vss::vehicle::VersionVSS" + }, + { + "Name": "Width", + "TypeRef": "uint16_t" + }, + { + "Name": "WidthExcludingMirrors", + "TypeRef": "uint16_t" + }, + { + "Name": "WidthFoldedMirrors", + "TypeRef": "uint16_t" + }, + { + "Name": "WidthIncludingMirrors", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "ESC", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsStrongCrossWindDetected", + "TypeRef": "bool" + }, + { + "Name": "RoadFriction", + "TypeRef": "vss::vehicle::adas::esc::RoadFriction" + } + ] + }, + { + "Name": "CruiseControl", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + }, + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "SpeedSet", + "TypeRef": "float" + } + ] + }, + { + "Name": "EBD", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "ABS", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "EBA", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DMS", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "TCS", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "ObstacleDetection", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "LaneDepartureDetection", + "Namespace": "vss::vehicle::adas", + "SubElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "RoadFriction", + "Namespace": "vss::vehicle::adas::esc", + "SubElements": [ + { + "Name": "LowerBound", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "MostProbable", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "UpperBound", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Lights", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "Backup", + "TypeRef": "vss::vehicle::body::lights::Backup" + }, + { + "Name": "Beam", + "TypeRef": "vss::vehicle::body::lights::Beam" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::body::lights::Brake" + }, + { + "Name": "DirectionIndicator", + "TypeRef": "vss::vehicle::body::lights::DirectionIndicator" + }, + { + "Name": "Fog", + "TypeRef": "vss::vehicle::body::lights::Fog" + }, + { + "Name": "Hazard", + "TypeRef": "vss::vehicle::body::lights::Hazard" + }, + { + "Name": "IsHighBeamSwitchOn", + "TypeRef": "bool" + }, + { + "Name": "LicensePlate", + "TypeRef": "vss::vehicle::body::lights::LicensePlate" + }, + { + "Name": "LightSwitch", + "TypeRef": "vss::vehicle::body::lights::LightSwitch" + }, + { + "Name": "Parking", + "TypeRef": "vss::vehicle::body::lights::Parking" + }, + { + "Name": "Running", + "TypeRef": "vss::vehicle::body::lights::Running" + } + ] + }, + { + "Name": "Windshield", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::windshield::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::windshield::Rear" + } + ] + }, + { + "Name": "Raindetection", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Horn", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Hood", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::hood::Switch" + } + ] + }, + { + "Name": "Trunk", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::trunk::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::trunk::Rear" + } + ] + }, + { + "Name": "Mirrors", + "Namespace": "vss::vehicle::body", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::body::mirrors::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::body::mirrors::PassengerSide" + } + ] + }, + { + "Name": "Running", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Hazard", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Beam", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "High", + "TypeRef": "vss::vehicle::body::lights::beam::High" + }, + { + "Name": "Low", + "TypeRef": "vss::vehicle::body::lights::beam::Low" + } + ] + }, + { + "Name": "DirectionIndicator", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::body::lights::directionindicator::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::body::lights::directionindicator::Right" + } + ] + }, + { + "Name": "Parking", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsActive", + "TypeRef": "vss::vehicle::body::lights::brake::IsActive" + }, + { + "Name": "IsDefect", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backup", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Fog", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::lights::fog::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::lights::fog::Rear" + } + ] + }, + { + "Name": "LicensePlate", + "Namespace": "vss::vehicle::body::lights", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Low", + "Namespace": "vss::vehicle::body::lights::beam", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "High", + "Namespace": "vss::vehicle::body::lights::beam", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::body::lights::directionindicator", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::body::lights::directionindicator", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Rear", + "Namespace": "vss::vehicle::body::lights::fog", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Front", + "Namespace": "vss::vehicle::body::lights::fog", + "SubElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::body::mirrors", + "SubElements": [ + { + "Name": "IsFolded", + "TypeRef": "bool" + }, + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "Pan", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::body::mirrors", + "SubElements": [ + { + "Name": "IsFolded", + "TypeRef": "bool" + }, + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "Pan", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Front", + "Namespace": "vss::vehicle::body::trunk", + "SubElements": [ + { + "Name": "IsLightOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::trunk::front::Switch" + } + ] + }, + { + "Name": "Rear", + "Namespace": "vss::vehicle::body::trunk", + "SubElements": [ + { + "Name": "IsLightOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::trunk::rear::Switch" + } + ] + }, + { + "Name": "Rear", + "Namespace": "vss::vehicle::body::windshield", + "SubElements": [ + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "WasherFluid", + "TypeRef": "vss::vehicle::body::windshield::rear::WasherFluid" + }, + { + "Name": "Wiping", + "TypeRef": "vss::vehicle::body::windshield::rear::Wiping" + } + ] + }, + { + "Name": "Front", + "Namespace": "vss::vehicle::body::windshield", + "SubElements": [ + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "WasherFluid", + "TypeRef": "vss::vehicle::body::windshield::front::WasherFluid" + }, + { + "Name": "Wiping", + "TypeRef": "vss::vehicle::body::windshield::front::Wiping" + } + ] + }, + { + "Name": "WasherFluid", + "Namespace": "vss::vehicle::body::windshield::front", + "SubElements": [ + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Wiping", + "Namespace": "vss::vehicle::body::windshield::front", + "SubElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t" + }, + { + "Name": "IsWipersWorn", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::Mode" + }, + { + "Name": "System", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::System" + }, + { + "Name": "WiperWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "System", + "Namespace": "vss::vehicle::body::windshield::front::wiping", + "SubElements": [ + { + "Name": "ActualPosition", + "TypeRef": "float" + }, + { + "Name": "DriveCurrent", + "TypeRef": "float" + }, + { + "Name": "Frequency", + "TypeRef": "uint8_t" + }, + { + "Name": "IsBlocked", + "TypeRef": "bool" + }, + { + "Name": "IsEndingWipeCycle", + "TypeRef": "bool" + }, + { + "Name": "IsOverheated", + "TypeRef": "bool" + }, + { + "Name": "IsPositionReached", + "TypeRef": "bool" + }, + { + "Name": "IsWiperError", + "TypeRef": "bool" + }, + { + "Name": "IsWiping", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::system::Mode" + }, + { + "Name": "TargetPosition", + "TypeRef": "float" + } + ] + }, + { + "Name": "WasherFluid", + "Namespace": "vss::vehicle::body::windshield::rear", + "SubElements": [ + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Wiping", + "Namespace": "vss::vehicle::body::windshield::rear", + "SubElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t" + }, + { + "Name": "IsWipersWorn", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::Mode" + }, + { + "Name": "System", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::System" + }, + { + "Name": "WiperWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "System", + "Namespace": "vss::vehicle::body::windshield::rear::wiping", + "SubElements": [ + { + "Name": "ActualPosition", + "TypeRef": "float" + }, + { + "Name": "DriveCurrent", + "TypeRef": "float" + }, + { + "Name": "Frequency", + "TypeRef": "uint8_t" + }, + { + "Name": "IsBlocked", + "TypeRef": "bool" + }, + { + "Name": "IsEndingWipeCycle", + "TypeRef": "bool" + }, + { + "Name": "IsOverheated", + "TypeRef": "bool" + }, + { + "Name": "IsPositionReached", + "TypeRef": "bool" + }, + { + "Name": "IsWiperError", + "TypeRef": "bool" + }, + { + "Name": "IsWiping", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::system::Mode" + }, + { + "Name": "TargetPosition", + "TypeRef": "float" + } + ] + }, + { + "Name": "Infotainment", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "HMI", + "TypeRef": "vss::vehicle::cabin::infotainment::HMI" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "Media", + "TypeRef": "vss::vehicle::cabin::infotainment::Media" + }, + { + "Name": "Navigation", + "TypeRef": "vss::vehicle::cabin::infotainment::Navigation" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "SmartphoneProjection", + "TypeRef": "vss::vehicle::cabin::infotainment::SmartphoneProjection" + }, + { + "Name": "SmartphoneScreenMirroring", + "TypeRef": "vss::vehicle::cabin::infotainment::SmartphoneScreenMirroring" + } + ] + }, + { + "Name": "Seat", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::seat::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::seat::Row2" + } + ] + }, + { + "Name": "Convertible", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "Status", + "TypeRef": "vss::vehicle::cabin::convertible::Status" + } + ] + }, + { + "Name": "HVAC", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "AmbientAirTemperature", + "TypeRef": "float" + }, + { + "Name": "IsAirConditioningActive", + "TypeRef": "bool" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "IsFrontDefrosterActive", + "TypeRef": "bool" + }, + { + "Name": "IsRearDefrosterActive", + "TypeRef": "bool" + }, + { + "Name": "IsRecirculationActive", + "TypeRef": "bool" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Station", + "TypeRef": "vss::vehicle::cabin::hvac::Station" + } + ] + }, + { + "Name": "Light", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "AmbientLight", + "TypeRef": "vss::vehicle::cabin::light::AmbientLight" + }, + { + "Name": "InteractiveLightBar", + "TypeRef": "vss::vehicle::cabin::light::InteractiveLightBar" + }, + { + "Name": "IsDomeOn", + "TypeRef": "bool" + }, + { + "Name": "IsGloveBoxOn", + "TypeRef": "bool" + }, + { + "Name": "PerceivedAmbientLight", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Spotlight", + "TypeRef": "vss::vehicle::cabin::light::Spotlight" + } + ] + }, + { + "Name": "Sunroof", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "Position", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::sunroof::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::sunroof::Switch" + } + ] + }, + { + "Name": "RearviewMirror", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "DimmingLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "RearShade", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::rearshade::Switch" + } + ] + }, + { + "Name": "Door", + "Namespace": "vss::vehicle::cabin", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::door::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::door::Row2" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::cabin::door", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::door::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::door::row2::PassengerSide" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::cabin::door", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::door::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::door::row1::PassengerSide" + } + ] + }, + { + "Name": "Shade", + "Namespace": "vss::vehicle::cabin::door::row1::driverside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::shade::Switch" + } + ] + }, + { + "Name": "Window", + "Namespace": "vss::vehicle::cabin::door::row1::driverside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::window::Switch" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::door::row1", + "SubElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Window" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::door::row1", + "SubElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Window" + } + ] + }, + { + "Name": "Window", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::window::Switch" + } + ] + }, + { + "Name": "Shade", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::shade::Switch" + } + ] + }, + { + "Name": "Shade", + "Namespace": "vss::vehicle::cabin::door::row2::driverside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::shade::Switch" + } + ] + }, + { + "Name": "Window", + "Namespace": "vss::vehicle::cabin::door::row2::driverside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::window::Switch" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::door::row2", + "SubElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Window" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::door::row2", + "SubElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Window" + } + ] + }, + { + "Name": "Shade", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::shade::Switch" + } + ] + }, + { + "Name": "Window", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::window::Switch" + } + ] + }, + { + "Name": "Station", + "Namespace": "vss::vehicle::cabin::hvac", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row2" + }, + { + "Name": "Row3", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row3" + }, + { + "Name": "Row4", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row4" + } + ] + }, + { + "Name": "Row4", + "Namespace": "vss::vehicle::cabin::hvac::station", + "SubElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::Passenger" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::cabin::hvac::station", + "SubElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::Passenger" + } + ] + }, + { + "Name": "Row3", + "Namespace": "vss::vehicle::cabin::hvac::station", + "SubElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::Passenger" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::cabin::hvac::station", + "SubElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::Passenger" + } + ] + }, + { + "Name": "Passenger", + "Namespace": "vss::vehicle::cabin::hvac::station::row1", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle::cabin::hvac::station::row1", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger", + "Namespace": "vss::vehicle::cabin::hvac::station::row2", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle::cabin::hvac::station::row2", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger", + "Namespace": "vss::vehicle::cabin::hvac::station::row3", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle::cabin::hvac::station::row3", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger", + "Namespace": "vss::vehicle::cabin::hvac::station::row4", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle::cabin::hvac::station::row4", + "SubElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Navigation", + "Namespace": "vss::vehicle::cabin::infotainment", + "SubElements": [ + { + "Name": "DestinationSet", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::DestinationSet" + }, + { + "Name": "GuidanceVoice", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::GuidanceVoice" + }, + { + "Name": "Map", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::Map" + }, + { + "Name": "Mute", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::Mute" + }, + { + "Name": "Volume", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Media", + "Namespace": "vss::vehicle::cabin::infotainment", + "SubElements": [ + { + "Name": "Action", + "TypeRef": "vss::vehicle::cabin::infotainment::media::Action" + }, + { + "Name": "DeclinedURI", + "TypeRef": "vaf::string" + }, + { + "Name": "Played", + "TypeRef": "vss::vehicle::cabin::infotainment::media::Played" + }, + { + "Name": "SelectedURI", + "TypeRef": "vaf::string" + }, + { + "Name": "Volume", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SmartphoneProjection", + "Namespace": "vss::vehicle::cabin::infotainment", + "SubElements": [ + { + "Name": "Active", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphoneprojection::Active" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphoneprojection::Source" + }, + { + "Name": "SupportedMode", + "TypeRef": "vss::stringVector" + } + ] + }, + { + "Name": "SmartphoneScreenMirroring", + "Namespace": "vss::vehicle::cabin::infotainment", + "SubElements": [ + { + "Name": "Active", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring::Active" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring::Source" + } + ] + }, + { + "Name": "HMI", + "Namespace": "vss::vehicle::cabin::infotainment", + "SubElements": [ + { + "Name": "Brightness", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "CurrentLanguage", + "TypeRef": "vaf::string" + }, + { + "Name": "DateFormat", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DateFormat" + }, + { + "Name": "DayNightMode", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DayNightMode" + }, + { + "Name": "DisplayOffDuration", + "TypeRef": "uint16_t" + }, + { + "Name": "DistanceUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DistanceUnit" + }, + { + "Name": "EVEconomyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::EVEconomyUnits" + }, + { + "Name": "EVEnergyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::EVEnergyUnits" + }, + { + "Name": "FontSize", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FontSize" + }, + { + "Name": "FuelEconomyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FuelEconomyUnits" + }, + { + "Name": "FuelVolumeUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FuelVolumeUnit" + }, + { + "Name": "IsScreenAlwaysOn", + "TypeRef": "bool" + }, + { + "Name": "LastActionTime", + "TypeRef": "vaf::string" + }, + { + "Name": "SpeedUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::SpeedUnit" + }, + { + "Name": "TemperatureUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TemperatureUnit" + }, + { + "Name": "TimeFormat", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TimeFormat" + }, + { + "Name": "TirePressureUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TirePressureUnit" + } + ] + }, + { + "Name": "Played", + "Namespace": "vss::vehicle::cabin::infotainment::media", + "SubElements": [ + { + "Name": "Album", + "TypeRef": "vaf::string" + }, + { + "Name": "Artist", + "TypeRef": "vaf::string" + }, + { + "Name": "PlaybackRate", + "TypeRef": "float" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::media::played::Source" + }, + { + "Name": "Track", + "TypeRef": "vaf::string" + }, + { + "Name": "URI", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Map", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "SubElements": [ + { + "Name": "IsAutoScaleModeUsed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DestinationSet", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "SubElements": [ + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + } + ] + }, + { + "Name": "Spotlight", + "Namespace": "vss::vehicle::cabin::light", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row2" + }, + { + "Name": "Row3", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row3" + }, + { + "Name": "Row4", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row4" + } + ] + }, + { + "Name": "InteractiveLightBar", + "Namespace": "vss::vehicle::cabin::light", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Effect", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "AmbientLight", + "Namespace": "vss::vehicle::cabin::light", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::Row2" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::cabin::light::ambientlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row2::PassengerSide" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::cabin::light::ambientlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row1::PassengerSide" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row1", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row1", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row2", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row2", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row1::PassengerSide" + } + ] + }, + { + "Name": "Row3", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row3::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row3::PassengerSide" + } + ] + }, + { + "Name": "Row4", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row4::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row4::PassengerSide" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row2::PassengerSide" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row1", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row1", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row2", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row2", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row3", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row3", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row4", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::light::spotlight::row4", + "SubElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::cabin::seat", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::seat::row1::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::cabin::seat::row1::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::seat::row1::PassengerSide" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::cabin::seat", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::seat::row2::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::cabin::seat::row2::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::seat::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::seat::row1", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Middle", + "Namespace": "vss::vehicle::cabin::seat::row1", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::seat::row1", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::occupant::Identifier" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Seating" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::backrest::SideBolster" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::occupant::Identifier" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Seating" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::backrest::SideBolster" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Seating" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::backrest::SideBolster" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::occupant::Identifier" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::cabin::seat::row2", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::cabin::seat::row2", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Middle", + "Namespace": "vss::vehicle::cabin::seat::row2", + "SubElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Seating" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::backrest::SideBolster" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::occupant::Identifier" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Seating" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::occupant::Identifier" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::backrest::SideBolster" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Switch", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Seating" + } + ] + }, + { + "Name": "Occupant", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::occupant::Identifier" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::backrest::SideBolster" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Airbag", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "SubElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::backrest", + "SubElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::backrest", + "SubElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::occupant", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "SubElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "SubElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "SubElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest", + "SubElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest", + "SubElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Shade", + "Namespace": "vss::vehicle::cabin::sunroof", + "SubElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::sunroof::shade::Switch" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "MountingPosition", + "Namespace": "vss::vehicle::currentlocation::gnssreceiver", + "SubElements": [ + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "GNSSReceiver", + "Namespace": "vss::vehicle::currentlocation", + "SubElements": [ + { + "Name": "FixType", + "TypeRef": "vss::vehicle::currentlocation::gnssreceiver::FixType" + }, + { + "Name": "MountingPosition", + "TypeRef": "vss::vehicle::currentlocation::gnssreceiver::MountingPosition" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::driver", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Catalyst", + "Namespace": "vss::vehicle::obd", + "SubElements": [ + { + "Name": "Bank1", + "TypeRef": "vss::vehicle::obd::catalyst::Bank1" + }, + { + "Name": "Bank2", + "TypeRef": "vss::vehicle::obd::catalyst::Bank2" + } + ] + }, + { + "Name": "O2WR", + "Namespace": "vss::vehicle::obd", + "SubElements": [ + { + "Name": "Sensor1", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor1" + }, + { + "Name": "Sensor2", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor2" + }, + { + "Name": "Sensor3", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor3" + }, + { + "Name": "Sensor4", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor4" + }, + { + "Name": "Sensor5", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor5" + }, + { + "Name": "Sensor6", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor6" + }, + { + "Name": "Sensor7", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor7" + }, + { + "Name": "Sensor8", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor8" + } + ] + }, + { + "Name": "O2", + "Namespace": "vss::vehicle::obd", + "SubElements": [ + { + "Name": "Sensor1", + "TypeRef": "vss::vehicle::obd::o2::Sensor1" + }, + { + "Name": "Sensor2", + "TypeRef": "vss::vehicle::obd::o2::Sensor2" + }, + { + "Name": "Sensor3", + "TypeRef": "vss::vehicle::obd::o2::Sensor3" + }, + { + "Name": "Sensor4", + "TypeRef": "vss::vehicle::obd::o2::Sensor4" + }, + { + "Name": "Sensor5", + "TypeRef": "vss::vehicle::obd::o2::Sensor5" + }, + { + "Name": "Sensor6", + "TypeRef": "vss::vehicle::obd::o2::Sensor6" + }, + { + "Name": "Sensor7", + "TypeRef": "vss::vehicle::obd::o2::Sensor7" + }, + { + "Name": "Sensor8", + "TypeRef": "vss::vehicle::obd::o2::Sensor8" + } + ] + }, + { + "Name": "DriveCycleStatus", + "Namespace": "vss::vehicle::obd", + "SubElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "IgnitionType", + "TypeRef": "vss::vehicle::obd::drivecyclestatus::IgnitionType" + }, + { + "Name": "IsMILOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Status", + "Namespace": "vss::vehicle::obd", + "SubElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "IgnitionType", + "TypeRef": "vss::vehicle::obd::status::IgnitionType" + }, + { + "Name": "IsMILOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Bank1", + "Namespace": "vss::vehicle::obd::catalyst", + "SubElements": [ + { + "Name": "Temperature1", + "TypeRef": "float" + }, + { + "Name": "Temperature2", + "TypeRef": "float" + } + ] + }, + { + "Name": "Bank2", + "Namespace": "vss::vehicle::obd::catalyst", + "SubElements": [ + { + "Name": "Temperature1", + "TypeRef": "float" + }, + { + "Name": "Temperature2", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor1", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor5", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor4", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor8", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor3", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor7", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor2", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor6", + "Namespace": "vss::vehicle::obd::o2", + "SubElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor1", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor8", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor7", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor6", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor5", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor4", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor3", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor2", + "Namespace": "vss::vehicle::obd::o2wr", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::occupant", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::occupant::row2::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::occupant::row2::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::occupant::row2::PassengerSide" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::occupant", + "SubElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::occupant::row1::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::occupant::row1::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::occupant::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::occupant::row1", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::driverside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::driverside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::driverside::MidEyeGaze" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::occupant::row1", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::MidEyeGaze" + } + ] + }, + { + "Name": "Middle", + "Namespace": "vss::vehicle::occupant::row1", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::middle::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::middle::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::middle::MidEyeGaze" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row1::middle", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row1::middle", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row1::middle", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "DriverSide", + "Namespace": "vss::vehicle::occupant::row2", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::driverside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::driverside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::driverside::MidEyeGaze" + } + ] + }, + { + "Name": "PassengerSide", + "Namespace": "vss::vehicle::occupant::row2", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::MidEyeGaze" + } + ] + }, + { + "Name": "Middle", + "Namespace": "vss::vehicle::occupant::row2", + "SubElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::middle::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::middle::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::middle::MidEyeGaze" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row2::middle", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row2::middle", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row2::middle", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "HeadPosition", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "SubElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "SubElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "CombustionEngine", + "Namespace": "vss::vehicle::powertrain", + "SubElements": [ + { + "Name": "AspirationType", + "TypeRef": "vss::vehicle::powertrain::combustionengine::AspirationType" + }, + { + "Name": "Bore", + "TypeRef": "float" + }, + { + "Name": "CompressionRatio", + "TypeRef": "vaf::string" + }, + { + "Name": "Configuration", + "TypeRef": "vss::vehicle::powertrain::combustionengine::Configuration" + }, + { + "Name": "DieselExhaustFluid", + "TypeRef": "vss::vehicle::powertrain::combustionengine::DieselExhaustFluid" + }, + { + "Name": "DieselParticulateFilter", + "TypeRef": "vss::vehicle::powertrain::combustionengine::DieselParticulateFilter" + }, + { + "Name": "Displacement", + "TypeRef": "uint16_t" + }, + { + "Name": "ECT", + "TypeRef": "int16_t" + }, + { + "Name": "EOP", + "TypeRef": "uint16_t" + }, + { + "Name": "EOT", + "TypeRef": "int16_t" + }, + { + "Name": "EngineCode", + "TypeRef": "vaf::string" + }, + { + "Name": "EngineCoolant", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineCoolant" + }, + { + "Name": "EngineCoolantCapacity", + "TypeRef": "float" + }, + { + "Name": "EngineHours", + "TypeRef": "float" + }, + { + "Name": "EngineOil", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineOil" + }, + { + "Name": "EngineOilCapacity", + "TypeRef": "float" + }, + { + "Name": "EngineOilLevel", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineOilLevel" + }, + { + "Name": "IdleHours", + "TypeRef": "float" + }, + { + "Name": "IsRunning", + "TypeRef": "bool" + }, + { + "Name": "MAF", + "TypeRef": "uint16_t" + }, + { + "Name": "MAP", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "NumberOfCylinders", + "TypeRef": "uint16_t" + }, + { + "Name": "NumberOfValvesPerCylinder", + "TypeRef": "uint16_t" + }, + { + "Name": "OilLifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Power", + "TypeRef": "uint16_t" + }, + { + "Name": "Speed", + "TypeRef": "uint16_t" + }, + { + "Name": "StrokeLength", + "TypeRef": "float" + }, + { + "Name": "TPS", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "Torque", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "FuelSystem", + "Namespace": "vss::vehicle::powertrain", + "SubElements": [ + { + "Name": "AbsoluteLevel", + "TypeRef": "float" + }, + { + "Name": "AverageConsumption", + "TypeRef": "float", + "Min": 0.0 + }, + { + "Name": "ConsumptionSinceStart", + "TypeRef": "float" + }, + { + "Name": "HybridType", + "TypeRef": "vss::vehicle::powertrain::fuelsystem::HybridType" + }, + { + "Name": "InstantConsumption", + "TypeRef": "float", + "Min": 0.0 + }, + { + "Name": "IsEngineStopStartEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsFuelLevelLow", + "TypeRef": "bool" + }, + { + "Name": "IsFuelPortFlapOpen", + "TypeRef": "bool" + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "RefuelPortPosition", + "TypeRef": "vss::stringVector" + }, + { + "Name": "RelativeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "SupportedFuel", + "TypeRef": "vss::stringVector" + }, + { + "Name": "SupportedFuelTypes", + "TypeRef": "vss::stringVector" + }, + { + "Name": "TankCapacity", + "TypeRef": "float" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "Transmission", + "Namespace": "vss::vehicle::powertrain", + "SubElements": [ + { + "Name": "ClutchEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "ClutchWear", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "CurrentGear", + "TypeRef": "int8_t" + }, + { + "Name": "DiffLockFrontEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DiffLockRearEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DriveType", + "TypeRef": "vss::vehicle::powertrain::transmission::DriveType" + }, + { + "Name": "GearChangeMode", + "TypeRef": "vss::vehicle::powertrain::transmission::GearChangeMode" + }, + { + "Name": "GearCount", + "TypeRef": "int8_t" + }, + { + "Name": "IsElectricalPowertrainEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLowRangeEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsParkLockEngaged", + "TypeRef": "bool" + }, + { + "Name": "PerformanceMode", + "TypeRef": "vss::vehicle::powertrain::transmission::PerformanceMode" + }, + { + "Name": "SelectedGear", + "TypeRef": "int8_t" + }, + { + "Name": "Temperature", + "TypeRef": "int16_t" + }, + { + "Name": "TorqueDistribution", + "TypeRef": "float", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "TravelledDistance", + "TypeRef": "float" + }, + { + "Name": "Type", + "TypeRef": "vss::vehicle::powertrain::transmission::Type" + } + ] + }, + { + "Name": "TractionBattery", + "Namespace": "vss::vehicle::powertrain", + "SubElements": [ + { + "Name": "AccumulatedChargedEnergy", + "TypeRef": "float" + }, + { + "Name": "AccumulatedChargedThroughput", + "TypeRef": "float" + }, + { + "Name": "AccumulatedConsumedEnergy", + "TypeRef": "float" + }, + { + "Name": "AccumulatedConsumedThroughput", + "TypeRef": "float" + }, + { + "Name": "BatteryConditioning", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::BatteryConditioning" + }, + { + "Name": "CellVoltage", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::CellVoltage" + }, + { + "Name": "Charging", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::Charging" + }, + { + "Name": "CurrentCurrent", + "TypeRef": "float" + }, + { + "Name": "CurrentPower", + "TypeRef": "float" + }, + { + "Name": "CurrentVoltage", + "TypeRef": "float" + }, + { + "Name": "DCDC", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::DCDC" + }, + { + "Name": "ErrorCodes", + "TypeRef": "vss::stringVector" + }, + { + "Name": "GrossCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "Id", + "TypeRef": "vaf::string" + }, + { + "Name": "IsGroundConnected", + "TypeRef": "bool" + }, + { + "Name": "IsPowerConnected", + "TypeRef": "bool" + }, + { + "Name": "MaxVoltage", + "TypeRef": "uint16_t" + }, + { + "Name": "NetCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "NominalVoltage", + "TypeRef": "uint16_t" + }, + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "ProductionDate", + "TypeRef": "vaf::string" + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "StateOfCharge", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::StateOfCharge" + }, + { + "Name": "StateOfHealth", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::Temperature" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "ElectricMotor", + "Namespace": "vss::vehicle::powertrain", + "SubElements": [ + { + "Name": "CoolantTemperature", + "TypeRef": "int16_t" + }, + { + "Name": "EngineCode", + "TypeRef": "vaf::string" + }, + { + "Name": "EngineCoolant", + "TypeRef": "vss::vehicle::powertrain::electricmotor::EngineCoolant" + }, + { + "Name": "MaxPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxRegenPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxRegenTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "Power", + "TypeRef": "int16_t" + }, + { + "Name": "Speed", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "int16_t" + }, + { + "Name": "TimeInUse", + "TypeRef": "float" + }, + { + "Name": "Torque", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "DieselExhaustFluid", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "SubElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "EngineCoolant", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "SubElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::combustionengine::enginecoolant::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "DieselParticulateFilter", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "SubElements": [ + { + "Name": "DeltaPressure", + "TypeRef": "float" + }, + { + "Name": "InletTemperature", + "TypeRef": "float" + }, + { + "Name": "OutletTemperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "EngineOil", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "SubElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::combustionengine::engineoil::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "EngineCoolant", + "Namespace": "vss::vehicle::powertrain::electricmotor", + "SubElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::electricmotor::enginecoolant::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "BatteryConditioning", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + }, + { + "Name": "IsOngoing", + "TypeRef": "bool" + }, + { + "Name": "RequestedMode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::batteryconditioning::RequestedMode" + }, + { + "Name": "StartTime", + "TypeRef": "vaf::string" + }, + { + "Name": "TargetTemperature", + "TypeRef": "float" + }, + { + "Name": "TargetTime", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "CellVoltage", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "CellVoltages", + "TypeRef": "vss::floatVector" + }, + { + "Name": "IdMax", + "TypeRef": "uint16_t" + }, + { + "Name": "IdMin", + "TypeRef": "uint16_t" + }, + { + "Name": "Max", + "TypeRef": "float" + }, + { + "Name": "Min", + "TypeRef": "float" + } + ] + }, + { + "Name": "Temperature", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "Average", + "TypeRef": "float" + }, + { + "Name": "CellTemperature", + "TypeRef": "vss::floatVector" + }, + { + "Name": "Max", + "TypeRef": "float" + }, + { + "Name": "Min", + "TypeRef": "float" + } + ] + }, + { + "Name": "StateOfCharge", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "Current", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "CurrentEnergy", + "TypeRef": "float" + }, + { + "Name": "Displayed", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "DCDC", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Charging", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "SubElements": [ + { + "Name": "AveragePower", + "TypeRef": "float" + }, + { + "Name": "ChargeCurrent", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargeCurrent" + }, + { + "Name": "ChargeLimit", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "ChargePlugType", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargePortFlap", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargePortFlap" + }, + { + "Name": "ChargePortPosition", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargePortType", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargeRate", + "TypeRef": "float" + }, + { + "Name": "ChargeVoltage", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargeVoltage" + }, + { + "Name": "EvseId", + "TypeRef": "vaf::string" + }, + { + "Name": "IsChargePortFlapOpen", + "TypeRef": "bool" + }, + { + "Name": "IsCharging", + "TypeRef": "bool" + }, + { + "Name": "IsChargingCableConnected", + "TypeRef": "bool" + }, + { + "Name": "IsChargingCableLocked", + "TypeRef": "bool" + }, + { + "Name": "IsDischarging", + "TypeRef": "bool" + }, + { + "Name": "Location", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Location" + }, + { + "Name": "MaxPower", + "TypeRef": "float" + }, + { + "Name": "MaximumChargingCurrent", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::MaximumChargingCurrent" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Mode" + }, + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "StartStopCharging", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::StartStopCharging" + }, + { + "Name": "Temperature", + "TypeRef": "float" + }, + { + "Name": "TimeToComplete", + "TypeRef": "uint32_t" + }, + { + "Name": "Timer", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Timer" + } + ] + }, + { + "Name": "Location", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "SubElements": [ + { + "Name": "Altitude", + "TypeRef": "double" + }, + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + } + ] + }, + { + "Name": "Timer", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "SubElements": [ + { + "Name": "Mode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::timer::Mode" + }, + { + "Name": "Time", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "ChargeCurrent", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "SubElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + }, + { + "Name": "ChargeVoltage", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "SubElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + }, + { + "Name": "MaximumChargingCurrent", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "SubElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + } + ], + "Vectors": [ + { + "Name": "stringVector", + "Namespace": "vss", + "TypeRef": "vaf::string" + }, + { + "Name": "uint8Vector", + "Namespace": "vss", + "TypeRef": "uint8_t" + }, + { + "Name": "floatVector", + "Namespace": "vss", + "TypeRef": "float" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Vehicle_If", + "Namespace": "vss", + "DataElements": [ + { + "Name": "Vehicle", + "TypeRef": "vss::Vehicle" + }, + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + } + ] + }, + { + "Name": "ADAS_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "ABS", + "TypeRef": "vss::vehicle::adas::ABS" + }, + { + "Name": "ActiveAutonomyLevel", + "TypeRef": "vss::vehicle::adas::ActiveAutonomyLevel" + }, + { + "Name": "CruiseControl", + "TypeRef": "vss::vehicle::adas::CruiseControl" + }, + { + "Name": "DMS", + "TypeRef": "vss::vehicle::adas::DMS" + }, + { + "Name": "EBA", + "TypeRef": "vss::vehicle::adas::EBA" + }, + { + "Name": "EBD", + "TypeRef": "vss::vehicle::adas::EBD" + }, + { + "Name": "ESC", + "TypeRef": "vss::vehicle::adas::ESC" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "LaneDepartureDetection", + "TypeRef": "vss::vehicle::adas::LaneDepartureDetection" + }, + { + "Name": "ObstacleDetection", + "TypeRef": "vss::vehicle::adas::ObstacleDetection" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "SupportedAutonomyLevel", + "TypeRef": "vss::vehicle::adas::SupportedAutonomyLevel" + }, + { + "Name": "TCS", + "TypeRef": "vss::vehicle::adas::TCS" + } + ] + }, + { + "Name": "ABS_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "CruiseControl_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + }, + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "SpeedSet", + "TypeRef": "float" + } + ] + }, + { + "Name": "DMS_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "EBA_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "EBD_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "ESC_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsStrongCrossWindDetected", + "TypeRef": "bool" + }, + { + "Name": "RoadFriction", + "TypeRef": "vss::vehicle::adas::esc::RoadFriction" + } + ] + }, + { + "Name": "RoadFriction_If", + "Namespace": "vss::vehicle::adas::esc", + "DataElements": [ + { + "Name": "LowerBound", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "MostProbable", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "UpperBound", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "LaneDepartureDetection_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "ObstacleDetection_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + }, + { + "Name": "IsWarning", + "TypeRef": "bool" + } + ] + }, + { + "Name": "TCS_If", + "Namespace": "vss::vehicle::adas", + "DataElements": [ + { + "Name": "IsEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsError", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Acceleration_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "Lateral", + "TypeRef": "float" + }, + { + "Name": "Longitudinal", + "TypeRef": "float" + }, + { + "Name": "Vertical", + "TypeRef": "float" + } + ] + }, + { + "Name": "AngularVelocity_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float" + }, + { + "Name": "Roll", + "TypeRef": "float" + }, + { + "Name": "Yaw", + "TypeRef": "float" + } + ] + }, + { + "Name": "Body_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "BodyType", + "TypeRef": "vaf::string" + }, + { + "Name": "Hood", + "TypeRef": "vss::vehicle::body::Hood" + }, + { + "Name": "Horn", + "TypeRef": "vss::vehicle::body::Horn" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "Lights", + "TypeRef": "vss::vehicle::body::Lights" + }, + { + "Name": "Mirrors", + "TypeRef": "vss::vehicle::body::Mirrors" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Raindetection", + "TypeRef": "vss::vehicle::body::Raindetection" + }, + { + "Name": "RearMainSpoilerPosition", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "RefuelPosition", + "TypeRef": "vss::vehicle::body::RefuelPosition" + }, + { + "Name": "Trunk", + "TypeRef": "vss::vehicle::body::Trunk" + }, + { + "Name": "Windshield", + "TypeRef": "vss::vehicle::body::Windshield" + } + ] + }, + { + "Name": "Hood_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::hood::Switch" + } + ] + }, + { + "Name": "Horn_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Lights_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "Backup", + "TypeRef": "vss::vehicle::body::lights::Backup" + }, + { + "Name": "Beam", + "TypeRef": "vss::vehicle::body::lights::Beam" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::body::lights::Brake" + }, + { + "Name": "DirectionIndicator", + "TypeRef": "vss::vehicle::body::lights::DirectionIndicator" + }, + { + "Name": "Fog", + "TypeRef": "vss::vehicle::body::lights::Fog" + }, + { + "Name": "Hazard", + "TypeRef": "vss::vehicle::body::lights::Hazard" + }, + { + "Name": "IsHighBeamSwitchOn", + "TypeRef": "bool" + }, + { + "Name": "LicensePlate", + "TypeRef": "vss::vehicle::body::lights::LicensePlate" + }, + { + "Name": "LightSwitch", + "TypeRef": "vss::vehicle::body::lights::LightSwitch" + }, + { + "Name": "Parking", + "TypeRef": "vss::vehicle::body::lights::Parking" + }, + { + "Name": "Running", + "TypeRef": "vss::vehicle::body::lights::Running" + } + ] + }, + { + "Name": "Backup_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Beam_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "High", + "TypeRef": "vss::vehicle::body::lights::beam::High" + }, + { + "Name": "Low", + "TypeRef": "vss::vehicle::body::lights::beam::Low" + } + ] + }, + { + "Name": "High_If", + "Namespace": "vss::vehicle::body::lights::beam", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Low_If", + "Namespace": "vss::vehicle::body::lights::beam", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsActive", + "TypeRef": "vss::vehicle::body::lights::brake::IsActive" + }, + { + "Name": "IsDefect", + "TypeRef": "bool" + } + ] + }, + { + "Name": "DirectionIndicator_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::body::lights::directionindicator::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::body::lights::directionindicator::Right" + } + ] + }, + { + "Name": "Left_If", + "Namespace": "vss::vehicle::body::lights::directionindicator", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Right_If", + "Namespace": "vss::vehicle::body::lights::directionindicator", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Fog_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::lights::fog::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::lights::fog::Rear" + } + ] + }, + { + "Name": "Front_If", + "Namespace": "vss::vehicle::body::lights::fog", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Rear_If", + "Namespace": "vss::vehicle::body::lights::fog", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Hazard_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsSignaling", + "TypeRef": "bool" + } + ] + }, + { + "Name": "LicensePlate_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Parking_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Running_If", + "Namespace": "vss::vehicle::body::lights", + "DataElements": [ + { + "Name": "IsDefect", + "TypeRef": "bool" + }, + { + "Name": "IsOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Mirrors_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::body::mirrors::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::body::mirrors::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::body::mirrors", + "DataElements": [ + { + "Name": "IsFolded", + "TypeRef": "bool" + }, + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "Pan", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::body::mirrors", + "DataElements": [ + { + "Name": "IsFolded", + "TypeRef": "bool" + }, + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "Pan", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Raindetection_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Trunk_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::trunk::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::trunk::Rear" + } + ] + }, + { + "Name": "Front_If", + "Namespace": "vss::vehicle::body::trunk", + "DataElements": [ + { + "Name": "IsLightOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::trunk::front::Switch" + } + ] + }, + { + "Name": "Rear_If", + "Namespace": "vss::vehicle::body::trunk", + "DataElements": [ + { + "Name": "IsLightOn", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::body::trunk::rear::Switch" + } + ] + }, + { + "Name": "Windshield_If", + "Namespace": "vss::vehicle::body", + "DataElements": [ + { + "Name": "Front", + "TypeRef": "vss::vehicle::body::windshield::Front" + }, + { + "Name": "Rear", + "TypeRef": "vss::vehicle::body::windshield::Rear" + } + ] + }, + { + "Name": "Front_If", + "Namespace": "vss::vehicle::body::windshield", + "DataElements": [ + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "WasherFluid", + "TypeRef": "vss::vehicle::body::windshield::front::WasherFluid" + }, + { + "Name": "Wiping", + "TypeRef": "vss::vehicle::body::windshield::front::Wiping" + } + ] + }, + { + "Name": "WasherFluid_If", + "Namespace": "vss::vehicle::body::windshield::front", + "DataElements": [ + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Wiping_If", + "Namespace": "vss::vehicle::body::windshield::front", + "DataElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t" + }, + { + "Name": "IsWipersWorn", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::Mode" + }, + { + "Name": "System", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::System" + }, + { + "Name": "WiperWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "System_If", + "Namespace": "vss::vehicle::body::windshield::front::wiping", + "DataElements": [ + { + "Name": "ActualPosition", + "TypeRef": "float" + }, + { + "Name": "DriveCurrent", + "TypeRef": "float" + }, + { + "Name": "Frequency", + "TypeRef": "uint8_t" + }, + { + "Name": "IsBlocked", + "TypeRef": "bool" + }, + { + "Name": "IsEndingWipeCycle", + "TypeRef": "bool" + }, + { + "Name": "IsOverheated", + "TypeRef": "bool" + }, + { + "Name": "IsPositionReached", + "TypeRef": "bool" + }, + { + "Name": "IsWiperError", + "TypeRef": "bool" + }, + { + "Name": "IsWiping", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::front::wiping::system::Mode" + }, + { + "Name": "TargetPosition", + "TypeRef": "float" + } + ] + }, + { + "Name": "Rear_If", + "Namespace": "vss::vehicle::body::windshield", + "DataElements": [ + { + "Name": "IsHeatingOn", + "TypeRef": "bool" + }, + { + "Name": "WasherFluid", + "TypeRef": "vss::vehicle::body::windshield::rear::WasherFluid" + }, + { + "Name": "Wiping", + "TypeRef": "vss::vehicle::body::windshield::rear::Wiping" + } + ] + }, + { + "Name": "WasherFluid_If", + "Namespace": "vss::vehicle::body::windshield::rear", + "DataElements": [ + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Wiping_If", + "Namespace": "vss::vehicle::body::windshield::rear", + "DataElements": [ + { + "Name": "Intensity", + "TypeRef": "uint8_t" + }, + { + "Name": "IsWipersWorn", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::Mode" + }, + { + "Name": "System", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::System" + }, + { + "Name": "WiperWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "System_If", + "Namespace": "vss::vehicle::body::windshield::rear::wiping", + "DataElements": [ + { + "Name": "ActualPosition", + "TypeRef": "float" + }, + { + "Name": "DriveCurrent", + "TypeRef": "float" + }, + { + "Name": "Frequency", + "TypeRef": "uint8_t" + }, + { + "Name": "IsBlocked", + "TypeRef": "bool" + }, + { + "Name": "IsEndingWipeCycle", + "TypeRef": "bool" + }, + { + "Name": "IsOverheated", + "TypeRef": "bool" + }, + { + "Name": "IsPositionReached", + "TypeRef": "bool" + }, + { + "Name": "IsWiperError", + "TypeRef": "bool" + }, + { + "Name": "IsWiping", + "TypeRef": "bool" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::body::windshield::rear::wiping::system::Mode" + }, + { + "Name": "TargetPosition", + "TypeRef": "float" + } + ] + }, + { + "Name": "Cabin_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Convertible", + "TypeRef": "vss::vehicle::cabin::Convertible" + }, + { + "Name": "Door", + "TypeRef": "vss::vehicle::cabin::Door" + }, + { + "Name": "DoorCount", + "TypeRef": "uint8_t" + }, + { + "Name": "DriverPosition", + "TypeRef": "vss::vehicle::cabin::DriverPosition" + }, + { + "Name": "HVAC", + "TypeRef": "vss::vehicle::cabin::HVAC" + }, + { + "Name": "Infotainment", + "TypeRef": "vss::vehicle::cabin::Infotainment" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "IsWindowChildLockEngaged", + "TypeRef": "bool" + }, + { + "Name": "Light", + "TypeRef": "vss::vehicle::cabin::Light" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "RearShade", + "TypeRef": "vss::vehicle::cabin::RearShade" + }, + { + "Name": "RearviewMirror", + "TypeRef": "vss::vehicle::cabin::RearviewMirror" + }, + { + "Name": "Seat", + "TypeRef": "vss::vehicle::cabin::Seat" + }, + { + "Name": "SeatPosCount", + "TypeRef": "vss::uint8Vector" + }, + { + "Name": "SeatRowCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Sunroof", + "TypeRef": "vss::vehicle::cabin::Sunroof" + } + ] + }, + { + "Name": "Convertible_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "Status", + "TypeRef": "vss::vehicle::cabin::convertible::Status" + } + ] + }, + { + "Name": "Door_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::door::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::door::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::cabin::door", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::door::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::door::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::door::row1", + "DataElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::Window" + } + ] + }, + { + "Name": "Shade_If", + "Namespace": "vss::vehicle::cabin::door::row1::driverside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::shade::Switch" + } + ] + }, + { + "Name": "Window_If", + "Namespace": "vss::vehicle::cabin::door::row1::driverside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::driverside::window::Switch" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::door::row1", + "DataElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::Window" + } + ] + }, + { + "Name": "Shade_If", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::shade::Switch" + } + ] + }, + { + "Name": "Window_If", + "Namespace": "vss::vehicle::cabin::door::row1::passengerside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row1::passengerside::window::Switch" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::cabin::door", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::door::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::door::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::door::row2", + "DataElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::Window" + } + ] + }, + { + "Name": "Shade_If", + "Namespace": "vss::vehicle::cabin::door::row2::driverside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::shade::Switch" + } + ] + }, + { + "Name": "Window_If", + "Namespace": "vss::vehicle::cabin::door::row2::driverside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::driverside::window::Switch" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::door::row2", + "DataElements": [ + { + "Name": "IsChildLockActive", + "TypeRef": "bool" + }, + { + "Name": "IsLocked", + "TypeRef": "bool" + }, + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Switch" + }, + { + "Name": "Window", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::Window" + } + ] + }, + { + "Name": "Shade_If", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::shade::Switch" + } + ] + }, + { + "Name": "Window_If", + "Namespace": "vss::vehicle::cabin::door::row2::passengerside", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::door::row2::passengerside::window::Switch" + } + ] + }, + { + "Name": "HVAC_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "AmbientAirTemperature", + "TypeRef": "float" + }, + { + "Name": "IsAirConditioningActive", + "TypeRef": "bool" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "IsFrontDefrosterActive", + "TypeRef": "bool" + }, + { + "Name": "IsRearDefrosterActive", + "TypeRef": "bool" + }, + { + "Name": "IsRecirculationActive", + "TypeRef": "bool" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Station", + "TypeRef": "vss::vehicle::cabin::hvac::Station" + } + ] + }, + { + "Name": "Station_If", + "Namespace": "vss::vehicle::cabin::hvac", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row2" + }, + { + "Name": "Row3", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row3" + }, + { + "Name": "Row4", + "TypeRef": "vss::vehicle::cabin::hvac::station::Row4" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::cabin::hvac::station", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::Passenger" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row1", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row1", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row1::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::cabin::hvac::station", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::Passenger" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row2", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row2", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row2::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Row3_If", + "Namespace": "vss::vehicle::cabin::hvac::station", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::Passenger" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row3", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row3", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row3::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Row4_If", + "Namespace": "vss::vehicle::cabin::hvac::station", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::Driver" + }, + { + "Name": "Passenger", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::Passenger" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row4", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::driver::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Passenger_If", + "Namespace": "vss::vehicle::cabin::hvac::station::row4", + "DataElements": [ + { + "Name": "AirDistribution", + "TypeRef": "vss::vehicle::cabin::hvac::station::row4::passenger::AirDistribution" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "int8_t" + } + ] + }, + { + "Name": "Infotainment_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "HMI", + "TypeRef": "vss::vehicle::cabin::infotainment::HMI" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "Media", + "TypeRef": "vss::vehicle::cabin::infotainment::Media" + }, + { + "Name": "Navigation", + "TypeRef": "vss::vehicle::cabin::infotainment::Navigation" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "SmartphoneProjection", + "TypeRef": "vss::vehicle::cabin::infotainment::SmartphoneProjection" + }, + { + "Name": "SmartphoneScreenMirroring", + "TypeRef": "vss::vehicle::cabin::infotainment::SmartphoneScreenMirroring" + } + ] + }, + { + "Name": "HMI_If", + "Namespace": "vss::vehicle::cabin::infotainment", + "DataElements": [ + { + "Name": "Brightness", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "CurrentLanguage", + "TypeRef": "vaf::string" + }, + { + "Name": "DateFormat", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DateFormat" + }, + { + "Name": "DayNightMode", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DayNightMode" + }, + { + "Name": "DisplayOffDuration", + "TypeRef": "uint16_t" + }, + { + "Name": "DistanceUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::DistanceUnit" + }, + { + "Name": "EVEconomyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::EVEconomyUnits" + }, + { + "Name": "EVEnergyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::EVEnergyUnits" + }, + { + "Name": "FontSize", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FontSize" + }, + { + "Name": "FuelEconomyUnits", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FuelEconomyUnits" + }, + { + "Name": "FuelVolumeUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::FuelVolumeUnit" + }, + { + "Name": "IsScreenAlwaysOn", + "TypeRef": "bool" + }, + { + "Name": "LastActionTime", + "TypeRef": "vaf::string" + }, + { + "Name": "SpeedUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::SpeedUnit" + }, + { + "Name": "TemperatureUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TemperatureUnit" + }, + { + "Name": "TimeFormat", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TimeFormat" + }, + { + "Name": "TirePressureUnit", + "TypeRef": "vss::vehicle::cabin::infotainment::hmi::TirePressureUnit" + } + ] + }, + { + "Name": "Media_If", + "Namespace": "vss::vehicle::cabin::infotainment", + "DataElements": [ + { + "Name": "Action", + "TypeRef": "vss::vehicle::cabin::infotainment::media::Action" + }, + { + "Name": "DeclinedURI", + "TypeRef": "vaf::string" + }, + { + "Name": "Played", + "TypeRef": "vss::vehicle::cabin::infotainment::media::Played" + }, + { + "Name": "SelectedURI", + "TypeRef": "vaf::string" + }, + { + "Name": "Volume", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Played_If", + "Namespace": "vss::vehicle::cabin::infotainment::media", + "DataElements": [ + { + "Name": "Album", + "TypeRef": "vaf::string" + }, + { + "Name": "Artist", + "TypeRef": "vaf::string" + }, + { + "Name": "PlaybackRate", + "TypeRef": "float" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::media::played::Source" + }, + { + "Name": "Track", + "TypeRef": "vaf::string" + }, + { + "Name": "URI", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Navigation_If", + "Namespace": "vss::vehicle::cabin::infotainment", + "DataElements": [ + { + "Name": "DestinationSet", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::DestinationSet" + }, + { + "Name": "GuidanceVoice", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::GuidanceVoice" + }, + { + "Name": "Map", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::Map" + }, + { + "Name": "Mute", + "TypeRef": "vss::vehicle::cabin::infotainment::navigation::Mute" + }, + { + "Name": "Volume", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "DestinationSet_If", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "DataElements": [ + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + } + ] + }, + { + "Name": "Map_If", + "Namespace": "vss::vehicle::cabin::infotainment::navigation", + "DataElements": [ + { + "Name": "IsAutoScaleModeUsed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SmartphoneProjection_If", + "Namespace": "vss::vehicle::cabin::infotainment", + "DataElements": [ + { + "Name": "Active", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphoneprojection::Active" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphoneprojection::Source" + }, + { + "Name": "SupportedMode", + "TypeRef": "vss::stringVector" + } + ] + }, + { + "Name": "SmartphoneScreenMirroring_If", + "Namespace": "vss::vehicle::cabin::infotainment", + "DataElements": [ + { + "Name": "Active", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring::Active" + }, + { + "Name": "Source", + "TypeRef": "vss::vehicle::cabin::infotainment::smartphonescreenmirroring::Source" + } + ] + }, + { + "Name": "Light_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "AmbientLight", + "TypeRef": "vss::vehicle::cabin::light::AmbientLight" + }, + { + "Name": "InteractiveLightBar", + "TypeRef": "vss::vehicle::cabin::light::InteractiveLightBar" + }, + { + "Name": "IsDomeOn", + "TypeRef": "bool" + }, + { + "Name": "IsGloveBoxOn", + "TypeRef": "bool" + }, + { + "Name": "PerceivedAmbientLight", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Spotlight", + "TypeRef": "vss::vehicle::cabin::light::Spotlight" + } + ] + }, + { + "Name": "AmbientLight_If", + "Namespace": "vss::vehicle::cabin::light", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row1", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row1", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::ambientlight::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row2", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::ambientlight::row2", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "InteractiveLightBar_If", + "Namespace": "vss::vehicle::cabin::light", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Effect", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Spotlight_If", + "Namespace": "vss::vehicle::cabin::light", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row2" + }, + { + "Name": "Row3", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row3" + }, + { + "Name": "Row4", + "TypeRef": "vss::vehicle::cabin::light::spotlight::Row4" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row1::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row1", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row1", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row2::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row2", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row2", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row3_If", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row3::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row3::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row3", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row3", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row4_If", + "Namespace": "vss::vehicle::cabin::light::spotlight", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row4::DriverSide" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::light::spotlight::row4::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row4", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::light::spotlight::row4", + "DataElements": [ + { + "Name": "Color", + "TypeRef": "vaf::string" + }, + { + "Name": "Intensity", + "TypeRef": "uint8_t", + "Min": 1.0, + "Max": 100.0 + }, + { + "Name": "IsLightOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "RearShade_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::rearshade::Switch" + } + ] + }, + { + "Name": "RearviewMirror_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "DimmingLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Seat_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::cabin::seat::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::cabin::seat::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::cabin::seat", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::seat::row1::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::cabin::seat::row1::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::seat::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::seat::row1", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::driverside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Middle_If", + "Namespace": "vss::vehicle::cabin::seat::row1", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::middle::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::middle::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::seat::row1", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row1::passengerside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::cabin::seat", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::cabin::seat::row2::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::cabin::seat::row2::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::cabin::seat::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::cabin::seat::row2", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::driverside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Middle_If", + "Namespace": "vss::vehicle::cabin::seat::row2", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::middle::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::middle::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::cabin::seat::row2", + "DataElements": [ + { + "Name": "Airbag", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Airbag" + }, + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Headrest" + }, + { + "Name": "Heating", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Height", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "IsBelted", + "TypeRef": "bool" + }, + { + "Name": "IsOccupied", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Occupant", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Occupant" + }, + { + "Name": "Position", + "TypeRef": "uint16_t", + "Min": 0.0 + }, + { + "Name": "SeatBeltHeight", + "TypeRef": "uint16_t" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Seating" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::Switch" + }, + { + "Name": "Tilt", + "TypeRef": "float" + } + ] + }, + { + "Name": "Airbag_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "IsDeployed", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::backrest::Lumbar" + }, + { + "Name": "Recline", + "TypeRef": "float" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::backrest", + "DataElements": [ + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + }, + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::backrest", + "DataElements": [ + { + "Name": "Support", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "float" + }, + { + "Name": "Height", + "TypeRef": "uint8_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::occupant::Identifier" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::occupant", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "Length", + "TypeRef": "uint16_t", + "Min": 0.0 + } + ] + }, + { + "Name": "Switch_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside", + "DataElements": [ + { + "Name": "Backrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Backrest" + }, + { + "Name": "Headrest", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Headrest" + }, + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsCoolerEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsTiltForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsWarmerEngaged", + "TypeRef": "bool" + }, + { + "Name": "Massage", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Massage" + }, + { + "Name": "Seating", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::Seating" + } + ] + }, + { + "Name": "Backrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "DataElements": [ + { + "Name": "IsReclineBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsReclineForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "Lumbar", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest::Lumbar" + }, + { + "Name": "SideBolster", + "TypeRef": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest::SideBolster" + } + ] + }, + { + "Name": "Lumbar_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest", + "DataElements": [ + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SideBolster_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest", + "DataElements": [ + { + "Name": "IsLessSupportEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsMoreSupportEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Headrest_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsDownEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsUpEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Massage_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "DataElements": [ + { + "Name": "IsDecreaseEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsIncreaseEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Seating_If", + "Namespace": "vss::vehicle::cabin::seat::row2::passengerside::switch", + "DataElements": [ + { + "Name": "IsBackwardEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsForwardEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Sunroof_If", + "Namespace": "vss::vehicle::cabin", + "DataElements": [ + { + "Name": "Position", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Shade", + "TypeRef": "vss::vehicle::cabin::sunroof::Shade" + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::sunroof::Switch" + } + ] + }, + { + "Name": "Shade_If", + "Namespace": "vss::vehicle::cabin::sunroof", + "DataElements": [ + { + "Name": "IsOpen", + "TypeRef": "bool" + }, + { + "Name": "Position", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Switch", + "TypeRef": "vss::vehicle::cabin::sunroof::shade::Switch" + } + ] + }, + { + "Name": "Chassis_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel_If", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel_If", + "Namespace": "vss::vehicle::chassis::axle::row2", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SteeringWheel_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Connectivity_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "IsConnectivityAvailable", + "TypeRef": "bool" + } + ] + }, + { + "Name": "CurrentLocation_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Altitude", + "TypeRef": "double" + }, + { + "Name": "GNSSReceiver", + "TypeRef": "vss::vehicle::currentlocation::GNSSReceiver" + }, + { + "Name": "Heading", + "TypeRef": "double", + "Min": 0.0, + "Max": 360.0 + }, + { + "Name": "HorizontalAccuracy", + "TypeRef": "double" + }, + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Timestamp", + "TypeRef": "vaf::string" + }, + { + "Name": "VerticalAccuracy", + "TypeRef": "double" + } + ] + }, + { + "Name": "GNSSReceiver_If", + "Namespace": "vss::vehicle::currentlocation", + "DataElements": [ + { + "Name": "FixType", + "TypeRef": "vss::vehicle::currentlocation::gnssreceiver::FixType" + }, + { + "Name": "MountingPosition", + "TypeRef": "vss::vehicle::currentlocation::gnssreceiver::MountingPosition" + } + ] + }, + { + "Name": "MountingPosition_If", + "Namespace": "vss::vehicle::currentlocation::gnssreceiver", + "DataElements": [ + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Diagnostics_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "DTCList", + "TypeRef": "vss::stringVector" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + }, + { + "Name": "AttentiveProbability", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DistractionLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "FatigueLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeartRate", + "TypeRef": "uint16_t" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::driver::Identifier" + }, + { + "Name": "IsEyesOnRoad", + "TypeRef": "bool" + }, + { + "Name": "IsHandsOnWheel", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::driver", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "Exterior_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "AirTemperature", + "TypeRef": "float" + }, + { + "Name": "Humidity", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "LightIntensity", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "LowVoltageBattery_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "CurrentCurrent", + "TypeRef": "float" + }, + { + "Name": "CurrentVoltage", + "TypeRef": "float" + }, + { + "Name": "NominalCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "NominalVoltage", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "OBD_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "AbsoluteLoad", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionD", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionE", + "TypeRef": "float" + }, + { + "Name": "AcceleratorPositionF", + "TypeRef": "float" + }, + { + "Name": "AirStatus", + "TypeRef": "vaf::string" + }, + { + "Name": "AmbientAirTemperature", + "TypeRef": "float" + }, + { + "Name": "BarometricPressure", + "TypeRef": "float" + }, + { + "Name": "Catalyst", + "TypeRef": "vss::vehicle::obd::Catalyst" + }, + { + "Name": "CommandedEGR", + "TypeRef": "float" + }, + { + "Name": "CommandedEVAP", + "TypeRef": "float" + }, + { + "Name": "CommandedEquivalenceRatio", + "TypeRef": "float" + }, + { + "Name": "ControlModuleVoltage", + "TypeRef": "float" + }, + { + "Name": "CoolantTemperature", + "TypeRef": "float" + }, + { + "Name": "DTCList", + "TypeRef": "vss::stringVector" + }, + { + "Name": "DistanceSinceDTCClear", + "TypeRef": "float" + }, + { + "Name": "DistanceWithMIL", + "TypeRef": "float" + }, + { + "Name": "DriveCycleStatus", + "TypeRef": "vss::vehicle::obd::DriveCycleStatus" + }, + { + "Name": "EGRError", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressure", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressureAbsolute", + "TypeRef": "float" + }, + { + "Name": "EVAPVaporPressureAlternate", + "TypeRef": "float" + }, + { + "Name": "EngineLoad", + "TypeRef": "float" + }, + { + "Name": "EngineSpeed", + "TypeRef": "float" + }, + { + "Name": "EthanolPercent", + "TypeRef": "float" + }, + { + "Name": "FreezeDTC", + "TypeRef": "vaf::string" + }, + { + "Name": "FuelInjectionTiming", + "TypeRef": "float" + }, + { + "Name": "FuelLevel", + "TypeRef": "float" + }, + { + "Name": "FuelPressure", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureAbsolute", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureDirect", + "TypeRef": "float" + }, + { + "Name": "FuelRailPressureVac", + "TypeRef": "float" + }, + { + "Name": "FuelRate", + "TypeRef": "float" + }, + { + "Name": "FuelStatus", + "TypeRef": "vaf::string" + }, + { + "Name": "FuelType", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 23.0 + }, + { + "Name": "HybridBatteryRemaining", + "TypeRef": "float" + }, + { + "Name": "IntakeTemp", + "TypeRef": "float" + }, + { + "Name": "IsPTOActive", + "TypeRef": "bool" + }, + { + "Name": "LongTermFuelTrim1", + "TypeRef": "float" + }, + { + "Name": "LongTermFuelTrim2", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim1", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim2", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim3", + "TypeRef": "float" + }, + { + "Name": "LongTermO2Trim4", + "TypeRef": "float" + }, + { + "Name": "MAF", + "TypeRef": "float" + }, + { + "Name": "MAP", + "TypeRef": "float" + }, + { + "Name": "MaxMAF", + "TypeRef": "float" + }, + { + "Name": "O2", + "TypeRef": "vss::vehicle::obd::O2" + }, + { + "Name": "O2WR", + "TypeRef": "vss::vehicle::obd::O2WR" + }, + { + "Name": "OBDStandards", + "TypeRef": "uint8_t" + }, + { + "Name": "OilTemperature", + "TypeRef": "float" + }, + { + "Name": "OxygenSensorsIn2Banks", + "TypeRef": "uint8_t" + }, + { + "Name": "OxygenSensorsIn4Banks", + "TypeRef": "uint8_t" + }, + { + "Name": "PidsA", + "TypeRef": "vss::stringVector" + }, + { + "Name": "PidsB", + "TypeRef": "vss::stringVector" + }, + { + "Name": "PidsC", + "TypeRef": "vss::stringVector" + }, + { + "Name": "RelativeAcceleratorPosition", + "TypeRef": "float" + }, + { + "Name": "RelativeThrottlePosition", + "TypeRef": "float" + }, + { + "Name": "RunTime", + "TypeRef": "float" + }, + { + "Name": "RunTimeMIL", + "TypeRef": "float" + }, + { + "Name": "ShortTermFuelTrim1", + "TypeRef": "float" + }, + { + "Name": "ShortTermFuelTrim2", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim1", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim2", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim3", + "TypeRef": "float" + }, + { + "Name": "ShortTermO2Trim4", + "TypeRef": "float" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Status", + "TypeRef": "vss::vehicle::obd::Status" + }, + { + "Name": "ThrottleActuator", + "TypeRef": "float" + }, + { + "Name": "ThrottlePosition", + "TypeRef": "float" + }, + { + "Name": "ThrottlePositionB", + "TypeRef": "float" + }, + { + "Name": "ThrottlePositionC", + "TypeRef": "float" + }, + { + "Name": "TimeSinceDTCCleared", + "TypeRef": "float" + }, + { + "Name": "TimingAdvance", + "TypeRef": "float" + }, + { + "Name": "WarmupsSinceDTCClear", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Catalyst_If", + "Namespace": "vss::vehicle::obd", + "DataElements": [ + { + "Name": "Bank1", + "TypeRef": "vss::vehicle::obd::catalyst::Bank1" + }, + { + "Name": "Bank2", + "TypeRef": "vss::vehicle::obd::catalyst::Bank2" + } + ] + }, + { + "Name": "Bank1_If", + "Namespace": "vss::vehicle::obd::catalyst", + "DataElements": [ + { + "Name": "Temperature1", + "TypeRef": "float" + }, + { + "Name": "Temperature2", + "TypeRef": "float" + } + ] + }, + { + "Name": "Bank2_If", + "Namespace": "vss::vehicle::obd::catalyst", + "DataElements": [ + { + "Name": "Temperature1", + "TypeRef": "float" + }, + { + "Name": "Temperature2", + "TypeRef": "float" + } + ] + }, + { + "Name": "DriveCycleStatus_If", + "Namespace": "vss::vehicle::obd", + "DataElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "IgnitionType", + "TypeRef": "vss::vehicle::obd::drivecyclestatus::IgnitionType" + }, + { + "Name": "IsMILOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "O2_If", + "Namespace": "vss::vehicle::obd", + "DataElements": [ + { + "Name": "Sensor1", + "TypeRef": "vss::vehicle::obd::o2::Sensor1" + }, + { + "Name": "Sensor2", + "TypeRef": "vss::vehicle::obd::o2::Sensor2" + }, + { + "Name": "Sensor3", + "TypeRef": "vss::vehicle::obd::o2::Sensor3" + }, + { + "Name": "Sensor4", + "TypeRef": "vss::vehicle::obd::o2::Sensor4" + }, + { + "Name": "Sensor5", + "TypeRef": "vss::vehicle::obd::o2::Sensor5" + }, + { + "Name": "Sensor6", + "TypeRef": "vss::vehicle::obd::o2::Sensor6" + }, + { + "Name": "Sensor7", + "TypeRef": "vss::vehicle::obd::o2::Sensor7" + }, + { + "Name": "Sensor8", + "TypeRef": "vss::vehicle::obd::o2::Sensor8" + } + ] + }, + { + "Name": "Sensor1_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor2_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor3_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor4_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor5_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor6_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor7_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor8_If", + "Namespace": "vss::vehicle::obd::o2", + "DataElements": [ + { + "Name": "ShortTermFuelTrim", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "O2WR_If", + "Namespace": "vss::vehicle::obd", + "DataElements": [ + { + "Name": "Sensor1", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor1" + }, + { + "Name": "Sensor2", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor2" + }, + { + "Name": "Sensor3", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor3" + }, + { + "Name": "Sensor4", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor4" + }, + { + "Name": "Sensor5", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor5" + }, + { + "Name": "Sensor6", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor6" + }, + { + "Name": "Sensor7", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor7" + }, + { + "Name": "Sensor8", + "TypeRef": "vss::vehicle::obd::o2wr::Sensor8" + } + ] + }, + { + "Name": "Sensor1_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor2_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor3_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor4_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor5_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor6_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor7_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Sensor8_If", + "Namespace": "vss::vehicle::obd::o2wr", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float" + }, + { + "Name": "Lambda", + "TypeRef": "float" + }, + { + "Name": "Voltage", + "TypeRef": "float" + } + ] + }, + { + "Name": "Status_If", + "Namespace": "vss::vehicle::obd", + "DataElements": [ + { + "Name": "DTCCount", + "TypeRef": "uint8_t" + }, + { + "Name": "IgnitionType", + "TypeRef": "vss::vehicle::obd::status::IgnitionType" + }, + { + "Name": "IsMILOn", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Occupant_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::occupant::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::occupant::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::occupant", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::occupant::row1::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::occupant::row1::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::occupant::row1::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::occupant::row1", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::driverside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::driverside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::driverside::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row1::driverside", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "Middle_If", + "Namespace": "vss::vehicle::occupant::row1", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::middle::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::middle::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::middle::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row1::middle", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row1::middle", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row1::middle", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::occupant::row1", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row1::passengerside::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row1::passengerside", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::occupant", + "DataElements": [ + { + "Name": "DriverSide", + "TypeRef": "vss::vehicle::occupant::row2::DriverSide" + }, + { + "Name": "Middle", + "TypeRef": "vss::vehicle::occupant::row2::Middle" + }, + { + "Name": "PassengerSide", + "TypeRef": "vss::vehicle::occupant::row2::PassengerSide" + } + ] + }, + { + "Name": "DriverSide_If", + "Namespace": "vss::vehicle::occupant::row2", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::driverside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::driverside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::driverside::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row2::driverside", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "Middle_If", + "Namespace": "vss::vehicle::occupant::row2", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::middle::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::middle::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::middle::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row2::middle", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row2::middle", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row2::middle", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "PassengerSide_If", + "Namespace": "vss::vehicle::occupant::row2", + "DataElements": [ + { + "Name": "HeadPosition", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::HeadPosition" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::Identifier" + }, + { + "Name": "MidEyeGaze", + "TypeRef": "vss::vehicle::occupant::row2::passengerside::MidEyeGaze" + } + ] + }, + { + "Name": "HeadPosition_If", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "DataElements": [ + { + "Name": "Pitch", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Roll", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "X", + "TypeRef": "int16_t" + }, + { + "Name": "Y", + "TypeRef": "int16_t" + }, + { + "Name": "Yaw", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Z", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "Identifier_If", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "DataElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "MidEyeGaze_If", + "Namespace": "vss::vehicle::occupant::row2::passengerside", + "DataElements": [ + { + "Name": "Azimuth", + "TypeRef": "float", + "Min": -180.0, + "Max": 180.0 + }, + { + "Name": "Elevation", + "TypeRef": "float", + "Min": -90.0, + "Max": 90.0 + } + ] + }, + { + "Name": "Powertrain_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "AccumulatedBrakingEnergy", + "TypeRef": "float" + }, + { + "Name": "CombustionEngine", + "TypeRef": "vss::vehicle::powertrain::CombustionEngine" + }, + { + "Name": "ElectricMotor", + "TypeRef": "vss::vehicle::powertrain::ElectricMotor" + }, + { + "Name": "FuelSystem", + "TypeRef": "vss::vehicle::powertrain::FuelSystem" + }, + { + "Name": "IsAutoPowerOptimize", + "TypeRef": "bool" + }, + { + "Name": "PowerOptimizeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 10.0 + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + }, + { + "Name": "TractionBattery", + "TypeRef": "vss::vehicle::powertrain::TractionBattery" + }, + { + "Name": "Transmission", + "TypeRef": "vss::vehicle::powertrain::Transmission" + }, + { + "Name": "Type", + "TypeRef": "vss::vehicle::powertrain::Type" + } + ] + }, + { + "Name": "CombustionEngine_If", + "Namespace": "vss::vehicle::powertrain", + "DataElements": [ + { + "Name": "AspirationType", + "TypeRef": "vss::vehicle::powertrain::combustionengine::AspirationType" + }, + { + "Name": "Bore", + "TypeRef": "float" + }, + { + "Name": "CompressionRatio", + "TypeRef": "vaf::string" + }, + { + "Name": "Configuration", + "TypeRef": "vss::vehicle::powertrain::combustionengine::Configuration" + }, + { + "Name": "DieselExhaustFluid", + "TypeRef": "vss::vehicle::powertrain::combustionengine::DieselExhaustFluid" + }, + { + "Name": "DieselParticulateFilter", + "TypeRef": "vss::vehicle::powertrain::combustionengine::DieselParticulateFilter" + }, + { + "Name": "Displacement", + "TypeRef": "uint16_t" + }, + { + "Name": "ECT", + "TypeRef": "int16_t" + }, + { + "Name": "EOP", + "TypeRef": "uint16_t" + }, + { + "Name": "EOT", + "TypeRef": "int16_t" + }, + { + "Name": "EngineCode", + "TypeRef": "vaf::string" + }, + { + "Name": "EngineCoolant", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineCoolant" + }, + { + "Name": "EngineCoolantCapacity", + "TypeRef": "float" + }, + { + "Name": "EngineHours", + "TypeRef": "float" + }, + { + "Name": "EngineOil", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineOil" + }, + { + "Name": "EngineOilCapacity", + "TypeRef": "float" + }, + { + "Name": "EngineOilLevel", + "TypeRef": "vss::vehicle::powertrain::combustionengine::EngineOilLevel" + }, + { + "Name": "IdleHours", + "TypeRef": "float" + }, + { + "Name": "IsRunning", + "TypeRef": "bool" + }, + { + "Name": "MAF", + "TypeRef": "uint16_t" + }, + { + "Name": "MAP", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "NumberOfCylinders", + "TypeRef": "uint16_t" + }, + { + "Name": "NumberOfValvesPerCylinder", + "TypeRef": "uint16_t" + }, + { + "Name": "OilLifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Power", + "TypeRef": "uint16_t" + }, + { + "Name": "Speed", + "TypeRef": "uint16_t" + }, + { + "Name": "StrokeLength", + "TypeRef": "float" + }, + { + "Name": "TPS", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "Torque", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "DieselExhaustFluid_If", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "DataElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "IsLevelLow", + "TypeRef": "bool" + }, + { + "Name": "Level", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "DieselParticulateFilter_If", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "DataElements": [ + { + "Name": "DeltaPressure", + "TypeRef": "float" + }, + { + "Name": "InletTemperature", + "TypeRef": "float" + }, + { + "Name": "OutletTemperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "EngineCoolant_If", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "DataElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::combustionengine::enginecoolant::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "EngineOil_If", + "Namespace": "vss::vehicle::powertrain::combustionengine", + "DataElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::combustionengine::engineoil::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "ElectricMotor_If", + "Namespace": "vss::vehicle::powertrain", + "DataElements": [ + { + "Name": "CoolantTemperature", + "TypeRef": "int16_t" + }, + { + "Name": "EngineCode", + "TypeRef": "vaf::string" + }, + { + "Name": "EngineCoolant", + "TypeRef": "vss::vehicle::powertrain::electricmotor::EngineCoolant" + }, + { + "Name": "MaxPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxRegenPower", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxRegenTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "MaxTorque", + "TypeRef": "uint16_t" + }, + { + "Name": "Power", + "TypeRef": "int16_t" + }, + { + "Name": "Speed", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "int16_t" + }, + { + "Name": "TimeInUse", + "TypeRef": "float" + }, + { + "Name": "Torque", + "TypeRef": "int16_t" + } + ] + }, + { + "Name": "EngineCoolant_If", + "Namespace": "vss::vehicle::powertrain::electricmotor", + "DataElements": [ + { + "Name": "Capacity", + "TypeRef": "float" + }, + { + "Name": "Level", + "TypeRef": "vss::vehicle::powertrain::electricmotor::enginecoolant::Level" + }, + { + "Name": "LifeRemaining", + "TypeRef": "int32_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "FuelSystem_If", + "Namespace": "vss::vehicle::powertrain", + "DataElements": [ + { + "Name": "AbsoluteLevel", + "TypeRef": "float" + }, + { + "Name": "AverageConsumption", + "TypeRef": "float", + "Min": 0.0 + }, + { + "Name": "ConsumptionSinceStart", + "TypeRef": "float" + }, + { + "Name": "HybridType", + "TypeRef": "vss::vehicle::powertrain::fuelsystem::HybridType" + }, + { + "Name": "InstantConsumption", + "TypeRef": "float", + "Min": 0.0 + }, + { + "Name": "IsEngineStopStartEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsFuelLevelLow", + "TypeRef": "bool" + }, + { + "Name": "IsFuelPortFlapOpen", + "TypeRef": "bool" + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "RefuelPortPosition", + "TypeRef": "vss::stringVector" + }, + { + "Name": "RelativeLevel", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "SupportedFuel", + "TypeRef": "vss::stringVector" + }, + { + "Name": "SupportedFuelTypes", + "TypeRef": "vss::stringVector" + }, + { + "Name": "TankCapacity", + "TypeRef": "float" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "TractionBattery_If", + "Namespace": "vss::vehicle::powertrain", + "DataElements": [ + { + "Name": "AccumulatedChargedEnergy", + "TypeRef": "float" + }, + { + "Name": "AccumulatedChargedThroughput", + "TypeRef": "float" + }, + { + "Name": "AccumulatedConsumedEnergy", + "TypeRef": "float" + }, + { + "Name": "AccumulatedConsumedThroughput", + "TypeRef": "float" + }, + { + "Name": "BatteryConditioning", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::BatteryConditioning" + }, + { + "Name": "CellVoltage", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::CellVoltage" + }, + { + "Name": "Charging", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::Charging" + }, + { + "Name": "CurrentCurrent", + "TypeRef": "float" + }, + { + "Name": "CurrentPower", + "TypeRef": "float" + }, + { + "Name": "CurrentVoltage", + "TypeRef": "float" + }, + { + "Name": "DCDC", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::DCDC" + }, + { + "Name": "ErrorCodes", + "TypeRef": "vss::stringVector" + }, + { + "Name": "GrossCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "Id", + "TypeRef": "vaf::string" + }, + { + "Name": "IsGroundConnected", + "TypeRef": "bool" + }, + { + "Name": "IsPowerConnected", + "TypeRef": "bool" + }, + { + "Name": "MaxVoltage", + "TypeRef": "uint16_t" + }, + { + "Name": "NetCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "NominalVoltage", + "TypeRef": "uint16_t" + }, + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "ProductionDate", + "TypeRef": "vaf::string" + }, + { + "Name": "Range", + "TypeRef": "uint32_t" + }, + { + "Name": "StateOfCharge", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::StateOfCharge" + }, + { + "Name": "StateOfHealth", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "Temperature", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::Temperature" + }, + { + "Name": "TimeRemaining", + "TypeRef": "uint32_t" + } + ] + }, + { + "Name": "BatteryConditioning_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "IsActive", + "TypeRef": "bool" + }, + { + "Name": "IsOngoing", + "TypeRef": "bool" + }, + { + "Name": "RequestedMode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::batteryconditioning::RequestedMode" + }, + { + "Name": "StartTime", + "TypeRef": "vaf::string" + }, + { + "Name": "TargetTemperature", + "TypeRef": "float" + }, + { + "Name": "TargetTime", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "CellVoltage_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "CellVoltages", + "TypeRef": "vss::floatVector" + }, + { + "Name": "IdMax", + "TypeRef": "uint16_t" + }, + { + "Name": "IdMin", + "TypeRef": "uint16_t" + }, + { + "Name": "Max", + "TypeRef": "float" + }, + { + "Name": "Min", + "TypeRef": "float" + } + ] + }, + { + "Name": "Charging_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "AveragePower", + "TypeRef": "float" + }, + { + "Name": "ChargeCurrent", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargeCurrent" + }, + { + "Name": "ChargeLimit", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "ChargePlugType", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargePortFlap", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargePortFlap" + }, + { + "Name": "ChargePortPosition", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargePortType", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ChargeRate", + "TypeRef": "float" + }, + { + "Name": "ChargeVoltage", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::ChargeVoltage" + }, + { + "Name": "EvseId", + "TypeRef": "vaf::string" + }, + { + "Name": "IsChargePortFlapOpen", + "TypeRef": "bool" + }, + { + "Name": "IsCharging", + "TypeRef": "bool" + }, + { + "Name": "IsChargingCableConnected", + "TypeRef": "bool" + }, + { + "Name": "IsChargingCableLocked", + "TypeRef": "bool" + }, + { + "Name": "IsDischarging", + "TypeRef": "bool" + }, + { + "Name": "Location", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Location" + }, + { + "Name": "MaxPower", + "TypeRef": "float" + }, + { + "Name": "MaximumChargingCurrent", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::MaximumChargingCurrent" + }, + { + "Name": "Mode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Mode" + }, + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "StartStopCharging", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::StartStopCharging" + }, + { + "Name": "Temperature", + "TypeRef": "float" + }, + { + "Name": "TimeToComplete", + "TypeRef": "uint32_t" + }, + { + "Name": "Timer", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::Timer" + } + ] + }, + { + "Name": "ChargeCurrent_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "DataElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + }, + { + "Name": "ChargeVoltage_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "DataElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + }, + { + "Name": "Location_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "DataElements": [ + { + "Name": "Altitude", + "TypeRef": "double" + }, + { + "Name": "Latitude", + "TypeRef": "double", + "Min": -90.0, + "Max": 90.0 + }, + { + "Name": "Longitude", + "TypeRef": "double", + "Min": -180.0, + "Max": 180.0 + } + ] + }, + { + "Name": "MaximumChargingCurrent_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "DataElements": [ + { + "Name": "DC", + "TypeRef": "float" + }, + { + "Name": "Phase1", + "TypeRef": "float" + }, + { + "Name": "Phase2", + "TypeRef": "float" + }, + { + "Name": "Phase3", + "TypeRef": "float" + } + ] + }, + { + "Name": "Timer_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery::charging", + "DataElements": [ + { + "Name": "Mode", + "TypeRef": "vss::vehicle::powertrain::tractionbattery::charging::timer::Mode" + }, + { + "Name": "Time", + "TypeRef": "vaf::string" + } + ] + }, + { + "Name": "DCDC_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "PowerLoss", + "TypeRef": "float" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "StateOfCharge_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "Current", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "CurrentEnergy", + "TypeRef": "float" + }, + { + "Name": "Displayed", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Temperature_If", + "Namespace": "vss::vehicle::powertrain::tractionbattery", + "DataElements": [ + { + "Name": "Average", + "TypeRef": "float" + }, + { + "Name": "CellTemperature", + "TypeRef": "vss::floatVector" + }, + { + "Name": "Max", + "TypeRef": "float" + }, + { + "Name": "Min", + "TypeRef": "float" + } + ] + }, + { + "Name": "Transmission_If", + "Namespace": "vss::vehicle::powertrain", + "DataElements": [ + { + "Name": "ClutchEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "ClutchWear", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "CurrentGear", + "TypeRef": "int8_t" + }, + { + "Name": "DiffLockFrontEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DiffLockRearEngagement", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DriveType", + "TypeRef": "vss::vehicle::powertrain::transmission::DriveType" + }, + { + "Name": "GearChangeMode", + "TypeRef": "vss::vehicle::powertrain::transmission::GearChangeMode" + }, + { + "Name": "GearCount", + "TypeRef": "int8_t" + }, + { + "Name": "IsElectricalPowertrainEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsLowRangeEngaged", + "TypeRef": "bool" + }, + { + "Name": "IsParkLockEngaged", + "TypeRef": "bool" + }, + { + "Name": "PerformanceMode", + "TypeRef": "vss::vehicle::powertrain::transmission::PerformanceMode" + }, + { + "Name": "SelectedGear", + "TypeRef": "int8_t" + }, + { + "Name": "Temperature", + "TypeRef": "int16_t" + }, + { + "Name": "TorqueDistribution", + "TypeRef": "float", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "TravelledDistance", + "TypeRef": "float" + }, + { + "Name": "Type", + "TypeRef": "vss::vehicle::powertrain::transmission::Type" + } + ] + }, + { + "Name": "Service_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "DistanceToService", + "TypeRef": "float" + }, + { + "Name": "IsServiceDue", + "TypeRef": "bool" + }, + { + "Name": "TimeToService", + "TypeRef": "int32_t" + } + ] + }, + { + "Name": "Trailer_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "IsConnected", + "TypeRef": "bool" + } + ] + }, + { + "Name": "VehicleIdentification_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "AcrissCode", + "TypeRef": "vaf::string" + }, + { + "Name": "BodyType", + "TypeRef": "vaf::string" + }, + { + "Name": "Brand", + "TypeRef": "vaf::string" + }, + { + "Name": "DateVehicleFirstRegistered", + "TypeRef": "vaf::string" + }, + { + "Name": "KnownVehicleDamages", + "TypeRef": "vaf::string" + }, + { + "Name": "LicensePlate", + "TypeRef": "vaf::string" + }, + { + "Name": "MeetsEmissionStandard", + "TypeRef": "vaf::string" + }, + { + "Name": "Model", + "TypeRef": "vaf::string" + }, + { + "Name": "OptionalExtras", + "TypeRef": "vss::stringVector" + }, + { + "Name": "ProductionDate", + "TypeRef": "vaf::string" + }, + { + "Name": "PurchaseDate", + "TypeRef": "vaf::string" + }, + { + "Name": "VIN", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleConfiguration", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleExteriorColor", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleInteriorColor", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleInteriorType", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleModelDate", + "TypeRef": "vaf::string" + }, + { + "Name": "VehicleSeatingCapacity", + "TypeRef": "uint16_t" + }, + { + "Name": "VehicleSpecialUsage", + "TypeRef": "vaf::string" + }, + { + "Name": "WMI", + "TypeRef": "vaf::string" + }, + { + "Name": "Year", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "VersionVSS_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Label", + "TypeRef": "vaf::string" + }, + { + "Name": "Major", + "TypeRef": "uint32_t" + }, + { + "Name": "Minor", + "TypeRef": "uint32_t" + }, + { + "Name": "Patch", + "TypeRef": "uint32_t" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/common/vss.py b/VAF/tests/unit/vafpy/test_data/common/vss.py new file mode 100644 index 0000000..eb5ad47 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/common/vss.py @@ -0,0 +1,1196 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "vss-derived-model.json")) + + + +class Vss: + # ModuleInterfaces + vehicle_if = get_module_interface( + "Vehicle_If", "vss" + ) + class Vehicle: + # ModuleInterfaces + adas_if = get_module_interface( + "ADAS_If", "vss::vehicle" + ) + acceleration_if = get_module_interface( + "Acceleration_If", "vss::vehicle" + ) + angular_velocity_if = get_module_interface( + "AngularVelocity_If", "vss::vehicle" + ) + body_if = get_module_interface( + "Body_If", "vss::vehicle" + ) + cabin_if = get_module_interface( + "Cabin_If", "vss::vehicle" + ) + chassis_if = get_module_interface( + "Chassis_If", "vss::vehicle" + ) + connectivity_if = get_module_interface( + "Connectivity_If", "vss::vehicle" + ) + current_location_if = get_module_interface( + "CurrentLocation_If", "vss::vehicle" + ) + diagnostics_if = get_module_interface( + "Diagnostics_If", "vss::vehicle" + ) + driver_if = get_module_interface( + "Driver_If", "vss::vehicle" + ) + exterior_if = get_module_interface( + "Exterior_If", "vss::vehicle" + ) + low_voltage_battery_if = get_module_interface( + "LowVoltageBattery_If", "vss::vehicle" + ) + obd_if = get_module_interface( + "OBD_If", "vss::vehicle" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle" + ) + powertrain_if = get_module_interface( + "Powertrain_If", "vss::vehicle" + ) + service_if = get_module_interface( + "Service_If", "vss::vehicle" + ) + trailer_if = get_module_interface( + "Trailer_If", "vss::vehicle" + ) + vehicle_identification_if = get_module_interface( + "VehicleIdentification_If", "vss::vehicle" + ) + version_vss_if = get_module_interface( + "VersionVSS_If", "vss::vehicle" + ) + class Adas: + # ModuleInterfaces + abs_if = get_module_interface( + "ABS_If", "vss::vehicle::adas" + ) + cruise_control_if = get_module_interface( + "CruiseControl_If", "vss::vehicle::adas" + ) + dms_if = get_module_interface( + "DMS_If", "vss::vehicle::adas" + ) + eba_if = get_module_interface( + "EBA_If", "vss::vehicle::adas" + ) + ebd_if = get_module_interface( + "EBD_If", "vss::vehicle::adas" + ) + esc_if = get_module_interface( + "ESC_If", "vss::vehicle::adas" + ) + lane_departure_detection_if = get_module_interface( + "LaneDepartureDetection_If", "vss::vehicle::adas" + ) + obstacle_detection_if = get_module_interface( + "ObstacleDetection_If", "vss::vehicle::adas" + ) + tcs_if = get_module_interface( + "TCS_If", "vss::vehicle::adas" + ) + class Esc: + # ModuleInterfaces + road_friction_if = get_module_interface( + "RoadFriction_If", "vss::vehicle::adas::esc" + ) + class Body: + # ModuleInterfaces + hood_if = get_module_interface( + "Hood_If", "vss::vehicle::body" + ) + horn_if = get_module_interface( + "Horn_If", "vss::vehicle::body" + ) + lights_if = get_module_interface( + "Lights_If", "vss::vehicle::body" + ) + mirrors_if = get_module_interface( + "Mirrors_If", "vss::vehicle::body" + ) + raindetection_if = get_module_interface( + "Raindetection_If", "vss::vehicle::body" + ) + trunk_if = get_module_interface( + "Trunk_If", "vss::vehicle::body" + ) + windshield_if = get_module_interface( + "Windshield_If", "vss::vehicle::body" + ) + class Lights: + # ModuleInterfaces + backup_if = get_module_interface( + "Backup_If", "vss::vehicle::body::lights" + ) + beam_if = get_module_interface( + "Beam_If", "vss::vehicle::body::lights" + ) + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::body::lights" + ) + direction_indicator_if = get_module_interface( + "DirectionIndicator_If", "vss::vehicle::body::lights" + ) + fog_if = get_module_interface( + "Fog_If", "vss::vehicle::body::lights" + ) + hazard_if = get_module_interface( + "Hazard_If", "vss::vehicle::body::lights" + ) + license_plate_if = get_module_interface( + "LicensePlate_If", "vss::vehicle::body::lights" + ) + parking_if = get_module_interface( + "Parking_If", "vss::vehicle::body::lights" + ) + running_if = get_module_interface( + "Running_If", "vss::vehicle::body::lights" + ) + class Beam: + # ModuleInterfaces + high_if = get_module_interface( + "High_If", "vss::vehicle::body::lights::beam" + ) + low_if = get_module_interface( + "Low_If", "vss::vehicle::body::lights::beam" + ) + class Directionindicator: + # ModuleInterfaces + left_if = get_module_interface( + "Left_If", "vss::vehicle::body::lights::directionindicator" + ) + right_if = get_module_interface( + "Right_If", "vss::vehicle::body::lights::directionindicator" + ) + class Fog: + # ModuleInterfaces + front_if = get_module_interface( + "Front_If", "vss::vehicle::body::lights::fog" + ) + rear_if = get_module_interface( + "Rear_If", "vss::vehicle::body::lights::fog" + ) + class Mirrors: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::body::mirrors" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::body::mirrors" + ) + class Trunk: + # ModuleInterfaces + front_if = get_module_interface( + "Front_If", "vss::vehicle::body::trunk" + ) + rear_if = get_module_interface( + "Rear_If", "vss::vehicle::body::trunk" + ) + class Windshield: + # ModuleInterfaces + front_if = get_module_interface( + "Front_If", "vss::vehicle::body::windshield" + ) + rear_if = get_module_interface( + "Rear_If", "vss::vehicle::body::windshield" + ) + class Front: + # ModuleInterfaces + washer_fluid_if = get_module_interface( + "WasherFluid_If", "vss::vehicle::body::windshield::front" + ) + wiping_if = get_module_interface( + "Wiping_If", "vss::vehicle::body::windshield::front" + ) + class Wiping: + # ModuleInterfaces + system_if = get_module_interface( + "System_If", "vss::vehicle::body::windshield::front::wiping" + ) + class Rear: + # ModuleInterfaces + washer_fluid_if = get_module_interface( + "WasherFluid_If", "vss::vehicle::body::windshield::rear" + ) + wiping_if = get_module_interface( + "Wiping_If", "vss::vehicle::body::windshield::rear" + ) + class Wiping: + # ModuleInterfaces + system_if = get_module_interface( + "System_If", "vss::vehicle::body::windshield::rear::wiping" + ) + class Cabin: + # ModuleInterfaces + convertible_if = get_module_interface( + "Convertible_If", "vss::vehicle::cabin" + ) + door_if = get_module_interface( + "Door_If", "vss::vehicle::cabin" + ) + hvac_if = get_module_interface( + "HVAC_If", "vss::vehicle::cabin" + ) + infotainment_if = get_module_interface( + "Infotainment_If", "vss::vehicle::cabin" + ) + light_if = get_module_interface( + "Light_If", "vss::vehicle::cabin" + ) + rear_shade_if = get_module_interface( + "RearShade_If", "vss::vehicle::cabin" + ) + rearview_mirror_if = get_module_interface( + "RearviewMirror_If", "vss::vehicle::cabin" + ) + seat_if = get_module_interface( + "Seat_If", "vss::vehicle::cabin" + ) + sunroof_if = get_module_interface( + "Sunroof_If", "vss::vehicle::cabin" + ) + class Door: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::cabin::door" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::cabin::door" + ) + class Row1: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::door::row1" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::door::row1" + ) + class Driverside: + # ModuleInterfaces + shade_if = get_module_interface( + "Shade_If", "vss::vehicle::cabin::door::row1::driverside" + ) + window_if = get_module_interface( + "Window_If", "vss::vehicle::cabin::door::row1::driverside" + ) + class Passengerside: + # ModuleInterfaces + shade_if = get_module_interface( + "Shade_If", "vss::vehicle::cabin::door::row1::passengerside" + ) + window_if = get_module_interface( + "Window_If", "vss::vehicle::cabin::door::row1::passengerside" + ) + class Row2: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::door::row2" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::door::row2" + ) + class Driverside: + # ModuleInterfaces + shade_if = get_module_interface( + "Shade_If", "vss::vehicle::cabin::door::row2::driverside" + ) + window_if = get_module_interface( + "Window_If", "vss::vehicle::cabin::door::row2::driverside" + ) + class Passengerside: + # ModuleInterfaces + shade_if = get_module_interface( + "Shade_If", "vss::vehicle::cabin::door::row2::passengerside" + ) + window_if = get_module_interface( + "Window_If", "vss::vehicle::cabin::door::row2::passengerside" + ) + class Hvac: + # ModuleInterfaces + station_if = get_module_interface( + "Station_If", "vss::vehicle::cabin::hvac" + ) + class Station: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::cabin::hvac::station" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::cabin::hvac::station" + ) + row3_if = get_module_interface( + "Row3_If", "vss::vehicle::cabin::hvac::station" + ) + row4_if = get_module_interface( + "Row4_If", "vss::vehicle::cabin::hvac::station" + ) + class Row1: + # ModuleInterfaces + driver_if = get_module_interface( + "Driver_If", "vss::vehicle::cabin::hvac::station::row1" + ) + passenger_if = get_module_interface( + "Passenger_If", "vss::vehicle::cabin::hvac::station::row1" + ) + class Row2: + # ModuleInterfaces + driver_if = get_module_interface( + "Driver_If", "vss::vehicle::cabin::hvac::station::row2" + ) + passenger_if = get_module_interface( + "Passenger_If", "vss::vehicle::cabin::hvac::station::row2" + ) + class Row3: + # ModuleInterfaces + driver_if = get_module_interface( + "Driver_If", "vss::vehicle::cabin::hvac::station::row3" + ) + passenger_if = get_module_interface( + "Passenger_If", "vss::vehicle::cabin::hvac::station::row3" + ) + class Row4: + # ModuleInterfaces + driver_if = get_module_interface( + "Driver_If", "vss::vehicle::cabin::hvac::station::row4" + ) + passenger_if = get_module_interface( + "Passenger_If", "vss::vehicle::cabin::hvac::station::row4" + ) + class Infotainment: + # ModuleInterfaces + hmi_if = get_module_interface( + "HMI_If", "vss::vehicle::cabin::infotainment" + ) + media_if = get_module_interface( + "Media_If", "vss::vehicle::cabin::infotainment" + ) + navigation_if = get_module_interface( + "Navigation_If", "vss::vehicle::cabin::infotainment" + ) + smartphone_projection_if = get_module_interface( + "SmartphoneProjection_If", "vss::vehicle::cabin::infotainment" + ) + smartphone_screen_mirroring_if = get_module_interface( + "SmartphoneScreenMirroring_If", "vss::vehicle::cabin::infotainment" + ) + class Media: + # ModuleInterfaces + played_if = get_module_interface( + "Played_If", "vss::vehicle::cabin::infotainment::media" + ) + class Navigation: + # ModuleInterfaces + destination_set_if = get_module_interface( + "DestinationSet_If", "vss::vehicle::cabin::infotainment::navigation" + ) + map_if = get_module_interface( + "Map_If", "vss::vehicle::cabin::infotainment::navigation" + ) + class Light: + # ModuleInterfaces + ambient_light_if = get_module_interface( + "AmbientLight_If", "vss::vehicle::cabin::light" + ) + interactive_light_bar_if = get_module_interface( + "InteractiveLightBar_If", "vss::vehicle::cabin::light" + ) + spotlight_if = get_module_interface( + "Spotlight_If", "vss::vehicle::cabin::light" + ) + class Ambientlight: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::cabin::light::ambientlight" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::cabin::light::ambientlight" + ) + class Row1: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::ambientlight::row1" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::ambientlight::row1" + ) + class Row2: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::ambientlight::row2" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::ambientlight::row2" + ) + class Spotlight: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::cabin::light::spotlight" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::cabin::light::spotlight" + ) + row3_if = get_module_interface( + "Row3_If", "vss::vehicle::cabin::light::spotlight" + ) + row4_if = get_module_interface( + "Row4_If", "vss::vehicle::cabin::light::spotlight" + ) + class Row1: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::spotlight::row1" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::spotlight::row1" + ) + class Row2: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::spotlight::row2" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::spotlight::row2" + ) + class Row3: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::spotlight::row3" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::spotlight::row3" + ) + class Row4: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::light::spotlight::row4" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::light::spotlight::row4" + ) + class Seat: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::cabin::seat" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::cabin::seat" + ) + class Row1: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::seat::row1" + ) + middle_if = get_module_interface( + "Middle_If", "vss::vehicle::cabin::seat::row1" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::seat::row1" + ) + class Driverside: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row1::driverside" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::driverside::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::driverside::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row1::driverside::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::driverside::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::driverside::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row1::driverside::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::driverside::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::driverside::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::driverside::switch::backrest" + ) + class Middle: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row1::middle" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::middle" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::middle" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row1::middle" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::middle" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row1::middle" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::middle::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::middle::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row1::middle::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::middle::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::middle::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row1::middle::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::middle::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::middle::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::middle::switch::backrest" + ) + class Passengerside: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row1::passengerside" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::passengerside::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::passengerside::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row1::passengerside::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row1::passengerside::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row1::passengerside::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row1::passengerside::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row1::passengerside::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row1::passengerside::switch::backrest" + ) + class Row2: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::cabin::seat::row2" + ) + middle_if = get_module_interface( + "Middle_If", "vss::vehicle::cabin::seat::row2" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::cabin::seat::row2" + ) + class Driverside: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row2::driverside" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::driverside::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::driverside::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row2::driverside::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::driverside::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::driverside::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row2::driverside::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::driverside::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::driverside::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::driverside::switch::backrest" + ) + class Middle: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row2::middle" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::middle" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::middle" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row2::middle" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::middle" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row2::middle" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::middle::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::middle::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row2::middle::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::middle::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::middle::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row2::middle::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::middle::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::middle::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::middle::switch::backrest" + ) + class Passengerside: + # ModuleInterfaces + airbag_if = get_module_interface( + "Airbag_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + occupant_if = get_module_interface( + "Occupant_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + switch_if = get_module_interface( + "Switch_If", "vss::vehicle::cabin::seat::row2::passengerside" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::passengerside::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::passengerside::backrest" + ) + class Occupant: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::cabin::seat::row2::passengerside::occupant" + ) + class Switch: + # ModuleInterfaces + backrest_if = get_module_interface( + "Backrest_If", "vss::vehicle::cabin::seat::row2::passengerside::switch" + ) + headrest_if = get_module_interface( + "Headrest_If", "vss::vehicle::cabin::seat::row2::passengerside::switch" + ) + massage_if = get_module_interface( + "Massage_If", "vss::vehicle::cabin::seat::row2::passengerside::switch" + ) + seating_if = get_module_interface( + "Seating_If", "vss::vehicle::cabin::seat::row2::passengerside::switch" + ) + class Backrest: + # ModuleInterfaces + lumbar_if = get_module_interface( + "Lumbar_If", "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest" + ) + side_bolster_if = get_module_interface( + "SideBolster_If", "vss::vehicle::cabin::seat::row2::passengerside::switch::backrest" + ) + class Sunroof: + # ModuleInterfaces + shade_if = get_module_interface( + "Shade_If", "vss::vehicle::cabin::sunroof" + ) + class Chassis: + # ModuleInterfaces + accelerator_if = get_module_interface( + "Accelerator_If", "vss::vehicle::chassis" + ) + axle_if = get_module_interface( + "Axle_If", "vss::vehicle::chassis" + ) + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis" + ) + parking_brake_if = get_module_interface( + "ParkingBrake_If", "vss::vehicle::chassis" + ) + steering_wheel_if = get_module_interface( + "SteeringWheel_If", "vss::vehicle::chassis" + ) + class Axle: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::chassis::axle" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::chassis::axle" + ) + class Row1: + # ModuleInterfaces + wheel_if = get_module_interface( + "Wheel_If", "vss::vehicle::chassis::axle::row1" + ) + class Wheel: + # ModuleInterfaces + left_if = get_module_interface( + "Left_If", "vss::vehicle::chassis::axle::row1::wheel" + ) + right_if = get_module_interface( + "Right_If", "vss::vehicle::chassis::axle::row1::wheel" + ) + class Left: + # ModuleInterfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + class Right: + # ModuleInterfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + class Row2: + # ModuleInterfaces + wheel_if = get_module_interface( + "Wheel_If", "vss::vehicle::chassis::axle::row2" + ) + class Wheel: + # ModuleInterfaces + left_if = get_module_interface( + "Left_If", "vss::vehicle::chassis::axle::row2::wheel" + ) + right_if = get_module_interface( + "Right_If", "vss::vehicle::chassis::axle::row2::wheel" + ) + class Left: + # ModuleInterfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + class Right: + # ModuleInterfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + class Currentlocation: + # ModuleInterfaces + gnss_receiver_if = get_module_interface( + "GNSSReceiver_If", "vss::vehicle::currentlocation" + ) + class Gnssreceiver: + # ModuleInterfaces + mounting_position_if = get_module_interface( + "MountingPosition_If", "vss::vehicle::currentlocation::gnssreceiver" + ) + class Driver: + # ModuleInterfaces + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::driver" + ) + class Obd: + # ModuleInterfaces + catalyst_if = get_module_interface( + "Catalyst_If", "vss::vehicle::obd" + ) + drive_cycle_status_if = get_module_interface( + "DriveCycleStatus_If", "vss::vehicle::obd" + ) + o2_wr_if = get_module_interface( + "O2WR_If", "vss::vehicle::obd" + ) + o2_if = get_module_interface( + "O2_If", "vss::vehicle::obd" + ) + status_if = get_module_interface( + "Status_If", "vss::vehicle::obd" + ) + class Catalyst: + # ModuleInterfaces + bank1_if = get_module_interface( + "Bank1_If", "vss::vehicle::obd::catalyst" + ) + bank2_if = get_module_interface( + "Bank2_If", "vss::vehicle::obd::catalyst" + ) + class O2: + # ModuleInterfaces + sensor1_if = get_module_interface( + "Sensor1_If", "vss::vehicle::obd::o2" + ) + sensor2_if = get_module_interface( + "Sensor2_If", "vss::vehicle::obd::o2" + ) + sensor3_if = get_module_interface( + "Sensor3_If", "vss::vehicle::obd::o2" + ) + sensor4_if = get_module_interface( + "Sensor4_If", "vss::vehicle::obd::o2" + ) + sensor5_if = get_module_interface( + "Sensor5_If", "vss::vehicle::obd::o2" + ) + sensor6_if = get_module_interface( + "Sensor6_If", "vss::vehicle::obd::o2" + ) + sensor7_if = get_module_interface( + "Sensor7_If", "vss::vehicle::obd::o2" + ) + sensor8_if = get_module_interface( + "Sensor8_If", "vss::vehicle::obd::o2" + ) + class O2Wr: + # ModuleInterfaces + sensor1_if = get_module_interface( + "Sensor1_If", "vss::vehicle::obd::o2wr" + ) + sensor2_if = get_module_interface( + "Sensor2_If", "vss::vehicle::obd::o2wr" + ) + sensor3_if = get_module_interface( + "Sensor3_If", "vss::vehicle::obd::o2wr" + ) + sensor4_if = get_module_interface( + "Sensor4_If", "vss::vehicle::obd::o2wr" + ) + sensor5_if = get_module_interface( + "Sensor5_If", "vss::vehicle::obd::o2wr" + ) + sensor6_if = get_module_interface( + "Sensor6_If", "vss::vehicle::obd::o2wr" + ) + sensor7_if = get_module_interface( + "Sensor7_If", "vss::vehicle::obd::o2wr" + ) + sensor8_if = get_module_interface( + "Sensor8_If", "vss::vehicle::obd::o2wr" + ) + class Occupant: + # ModuleInterfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::occupant" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::occupant" + ) + class Row1: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::occupant::row1" + ) + middle_if = get_module_interface( + "Middle_If", "vss::vehicle::occupant::row1" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::occupant::row1" + ) + class Driverside: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row1::driverside" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row1::driverside" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row1::driverside" + ) + class Middle: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row1::middle" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row1::middle" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row1::middle" + ) + class Passengerside: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row1::passengerside" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row1::passengerside" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row1::passengerside" + ) + class Row2: + # ModuleInterfaces + driver_side_if = get_module_interface( + "DriverSide_If", "vss::vehicle::occupant::row2" + ) + middle_if = get_module_interface( + "Middle_If", "vss::vehicle::occupant::row2" + ) + passenger_side_if = get_module_interface( + "PassengerSide_If", "vss::vehicle::occupant::row2" + ) + class Driverside: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row2::driverside" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row2::driverside" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row2::driverside" + ) + class Middle: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row2::middle" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row2::middle" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row2::middle" + ) + class Passengerside: + # ModuleInterfaces + head_position_if = get_module_interface( + "HeadPosition_If", "vss::vehicle::occupant::row2::passengerside" + ) + identifier_if = get_module_interface( + "Identifier_If", "vss::vehicle::occupant::row2::passengerside" + ) + mid_eye_gaze_if = get_module_interface( + "MidEyeGaze_If", "vss::vehicle::occupant::row2::passengerside" + ) + class Powertrain: + # ModuleInterfaces + combustion_engine_if = get_module_interface( + "CombustionEngine_If", "vss::vehicle::powertrain" + ) + electric_motor_if = get_module_interface( + "ElectricMotor_If", "vss::vehicle::powertrain" + ) + fuel_system_if = get_module_interface( + "FuelSystem_If", "vss::vehicle::powertrain" + ) + traction_battery_if = get_module_interface( + "TractionBattery_If", "vss::vehicle::powertrain" + ) + transmission_if = get_module_interface( + "Transmission_If", "vss::vehicle::powertrain" + ) + class Combustionengine: + # ModuleInterfaces + diesel_exhaust_fluid_if = get_module_interface( + "DieselExhaustFluid_If", "vss::vehicle::powertrain::combustionengine" + ) + diesel_particulate_filter_if = get_module_interface( + "DieselParticulateFilter_If", "vss::vehicle::powertrain::combustionengine" + ) + engine_coolant_if = get_module_interface( + "EngineCoolant_If", "vss::vehicle::powertrain::combustionengine" + ) + engine_oil_if = get_module_interface( + "EngineOil_If", "vss::vehicle::powertrain::combustionengine" + ) + class Electricmotor: + # ModuleInterfaces + engine_coolant_if = get_module_interface( + "EngineCoolant_If", "vss::vehicle::powertrain::electricmotor" + ) + class Tractionbattery: + # ModuleInterfaces + battery_conditioning_if = get_module_interface( + "BatteryConditioning_If", "vss::vehicle::powertrain::tractionbattery" + ) + cell_voltage_if = get_module_interface( + "CellVoltage_If", "vss::vehicle::powertrain::tractionbattery" + ) + charging_if = get_module_interface( + "Charging_If", "vss::vehicle::powertrain::tractionbattery" + ) + dcdc_if = get_module_interface( + "DCDC_If", "vss::vehicle::powertrain::tractionbattery" + ) + state_of_charge_if = get_module_interface( + "StateOfCharge_If", "vss::vehicle::powertrain::tractionbattery" + ) + temperature_if = get_module_interface( + "Temperature_If", "vss::vehicle::powertrain::tractionbattery" + ) + class Charging: + # ModuleInterfaces + charge_current_if = get_module_interface( + "ChargeCurrent_If", "vss::vehicle::powertrain::tractionbattery::charging" + ) + charge_voltage_if = get_module_interface( + "ChargeVoltage_If", "vss::vehicle::powertrain::tractionbattery::charging" + ) + location_if = get_module_interface( + "Location_If", "vss::vehicle::powertrain::tractionbattery::charging" + ) + maximum_charging_current_if = get_module_interface( + "MaximumChargingCurrent_If", "vss::vehicle::powertrain::tractionbattery::charging" + ) + timer_if = get_module_interface( + "Timer_If", "vss::vehicle::powertrain::tractionbattery::charging" + ) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_258/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_258/model.py new file mode 100644 index 0000000..559bc24 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_258/model.py @@ -0,0 +1,81 @@ +"""Definition of the CollisionDetection application module""" + +import os +from datetime import timedelta + +from silkit import AdasDemoApp, Af + +from vaf import BaseTypes, save_main_model, vafpy + +# define the provided interface +object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector(name="ObjectDetectionList", namespace="adas::interfaces", datatype=object_detection) + +od_list_if = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist" +) +od_list_if.add_data_element(name="object_detection_list", datatype=od_list) + +fake_if = vafpy.ModuleInterface( + name="FakeObjectInterface", namespace="nsapplicationunit::nsmoduleinterface::nsfakeobject" +) +fake_if.add_data_element(name="v", datatype=od_list) +fake_if.add_data_element(name="r", datatype=BaseTypes.FLOAT) + +metoo_if = vafpy.ModuleInterface(name="MeTooInterface", namespace="nsapplicationunit::nsmoduleinterface::nsmetoo") +metoo_if.add_data_element(name="a", datatype=BaseTypes.UINT16_T) +metoo_if.add_data_element(name="z", datatype=BaseTypes.FLOAT) + +p_200ms = timedelta(milliseconds=200) + +cd_mod = vafpy.ApplicationModule(name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection") +cd_mod.add_provided_interface(instance_name="BrakeServiceProvider", interface=Af.Adas_Demo_App.Services.brake_service) +cd_mod.add_provided_interface(instance_name="ImageServiceProvider1", interface=Af.Adas_Demo_App.Services.image_service) +cd_mod.add_consumed_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +cd_mod.add_task(vafpy.Task(name="PeriodicTask", period=p_200ms, preferred_offset=0)) + +sf_mod = vafpy.ApplicationModule(name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion") +sf_mod.add_provided_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +sf_mod.add_consumed_interface(instance_name="ImageServiceConsumer1", interface=Af.Adas_Demo_App.Services.image_service) +sf_mod.add_consumed_interface(instance_name="ImageServiceConsumer2", interface=Af.Adas_Demo_App.Services.image_service) +sf_mod.add_consumed_interface( + instance_name="SteeringAngleServiceConsumer", interface=Af.Adas_Demo_App.Services.steering_angle_service +) +sf_mod.add_consumed_interface( + instance_name="VelocityServiceConsumer", interface=Af.Adas_Demo_App.Services.velocity_service +) + +task1 = vafpy.Task(name="Step1", period=p_200ms, preferred_offset=0) +task2 = vafpy.Task(name="Step2", period=p_200ms, preferred_offset=0) +task3 = vafpy.Task(name="Step3", period=p_200ms, preferred_offset=0) +task4 = vafpy.Task(name="Step4", period=p_200ms, preferred_offset=0, run_after=[task3]) + +sf_mod.add_task(task=task1) +sf_mod.add_task_chain(tasks=[task2, task3], run_after=[task1]) +sf_mod.add_task(task=task4) + + +# add application modules +p_10ms = timedelta(milliseconds=10) +AdasDemoApp.executable.add_application_module( + sf_mod, + [ + ("Step1", p_10ms, 0), + ("Step2", p_10ms, 0), + ("Step3", p_10ms, 0), + ("Step4", p_10ms, 0), + ], +) +AdasDemoApp.executable.add_application_module(cd_mod, [("PeriodicTask", timedelta(milliseconds=1), 1)]) + +# connect intra process interfaces +AdasDemoApp.executable.connect_interfaces(sf_mod, "ObjectDetectionListModule", cd_mod, "ObjectDetectionListModule") + + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_260/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_260/model.json new file mode 100644 index 0000000..79112ed --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_260/model.json @@ -0,0 +1,295 @@ +{ + "DataTypeDefinitions": + { + "Strings": [ + { + "Name": "string", + "Namespace": "vaf" + } + ], + "Structs": [ + { + "Name": "Acceleration", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Lateral", + "TypeRef": "float" + }, + { + "Name": "Longitudinal", + "TypeRef": "float" + }, + { + "Name": "Vertical", + "TypeRef": "float" + } + ] + }, + { + "Name": "Driver", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "AttentiveProbability", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DistractionLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "FatigueLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeartRate", + "TypeRef": "uint16_t" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::driver::Identifier" + }, + { + "Name": "IsEyesOnRoad", + "TypeRef": "bool" + }, + { + "Name": "IsHandsOnWheel", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Vehicle", + "Namespace": "vss", + "SubElements": [ + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + } + ] + }, + { + "Name": "Identifier", + "Namespace": "vss::vehicle::driver", + "SubElements": [ + { + "Name": "Issuer", + "TypeRef": "vaf::string" + }, + { + "Name": "Subject", + "TypeRef": "vaf::string" + } + ] + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Vehicle_If", + "Namespace": "vss", + "DataElements": [ + { + "Name": "Vehicle", + "TypeRef": "vss::Vehicle" + }, + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + } + ] + }, + { + "Name": "Acceleration_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Acceleration", + "TypeRef": "vss::vehicle::Acceleration" + }, + { + "Name": "Lateral", + "TypeRef": "float" + }, + { + "Name": "Longitudinal", + "TypeRef": "float" + }, + { + "Name": "Vertical", + "TypeRef": "float" + } + ] + }, + { + "Name": "Driver_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Driver", + "TypeRef": "vss::vehicle::Driver" + }, + { + "Name": "AttentiveProbability", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "DistractionLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "FatigueLevel", + "TypeRef": "float", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeartRate", + "TypeRef": "uint16_t" + }, + { + "Name": "Identifier", + "TypeRef": "vss::vehicle::driver::Identifier" + }, + { + "Name": "IsEyesOnRoad", + "TypeRef": "bool" + }, + { + "Name": "IsHandsOnWheel", + "TypeRef": "bool" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "VssProvider", + "Namespace": "demo", + "ConsumedInterfaces": [ ], + "ProvidedInterfaces": [ + { + "InstanceName": "AccelerationProvider", + "ModuleInterfaceRef": "vss::vehicle::Acceleration_If" + }, + { + "InstanceName": "DriverProvider", + "ModuleInterfaceRef": "vss::vehicle::Driver_If" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + }, + { + "Name": "VssConsumer", + "Namespace": "demo", + "ConsumedInterfaces": [ + { + "InstanceName": "AccelerationConsumer", + "ModuleInterfaceRef": "vss::vehicle::Acceleration_If" + }, + { + "InstanceName": "DriverConsumer", + "ModuleInterfaceRef": "vss::vehicle::Driver_If" + } + ], + "ProvidedInterfaces": [ ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ], + "Executables": [ + { + "Name": "DemoExecutable", + "ExecutorPeriod": "10ms", + "InternalCommunicationModules": [ + { + "Name": "Acceleration_IfModule", + "Namespace": "application_communication", + "ModuleInterfaceRef": "vss::vehicle::Acceleration_If" + }, + { + "Name": "Driver_IfModule", + "Namespace": "application_communication", + "ModuleInterfaceRef": "vss::vehicle::Driver_If" + } + ], + "ApplicationModules": [ + { + "ApplicationModuleRef": "demo::VssProvider", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "AccelerationProvider", + "ModuleRef": "application_communication::Acceleration_IfModule" + }, + { + "InstanceName": "DriverProvider", + "ModuleRef": "application_communication::Driver_IfModule" + } + ], + "TaskMapping": [ + { + "TaskName": "PeriodicTask", + "Offset": 0, + "Budget": "1ms" + } + ] + }, + { + "ApplicationModuleRef": "demo::VssConsumer", + "InterfaceInstanceToModuleMappings": [ + { + "InstanceName": "AccelerationConsumer", + "ModuleRef": "application_communication::Acceleration_IfModule" + }, + { + "InstanceName": "DriverConsumer", + "ModuleRef": "application_communication::Driver_IfModule" + } + ], + "TaskMapping": [ + { + "TaskName": "PeriodicTask", + "Offset": 1, + "Budget": "1ms" + } + ] + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_260/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_260/model.py new file mode 100644 index 0000000..245984d --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_260/model.py @@ -0,0 +1,54 @@ +#!/bin/python3 +import os +import sys + +sys.path.append(".") + +from datetime import timedelta + +from vaf import vafpy, save_main_model +from vss import * + + +vss_provider = vafpy.ApplicationModule(name="VssProvider", namespace="demo") +vss_provider.add_provided_interface( + instance_name="AccelerationProvider", interface=Vss.Vehicle.acceleration_if +) +vss_provider.add_provided_interface( + instance_name="DriverProvider", interface=Vss.Vehicle.driver_if +) +vss_provider.add_task( + vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +) + +vss_consumer = vafpy.ApplicationModule(name="VssConsumer", namespace="demo") +vss_consumer.add_consumed_interface( + instance_name="AccelerationConsumer", interface=Vss.Vehicle.acceleration_if +) +vss_consumer.add_consumed_interface( + instance_name="DriverConsumer", interface=Vss.Vehicle.driver_if +) +vss_consumer.add_task( + vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +) + + +# Create application +app = vafpy.Executable("DemoExecutable", timedelta(milliseconds=10)) +app.add_application_module( + vss_provider, [("PeriodicTask", timedelta(milliseconds=1), 0)] +) +app.add_application_module( + vss_consumer, [("PeriodicTask", timedelta(milliseconds=1), 1)] +) + +# connect intra process interfaces +app.connect_interfaces( + vss_provider, "AccelerationProvider", vss_consumer, "AccelerationConsumer" +) +app.connect_interfaces(vss_provider, "DriverProvider", vss_consumer, "DriverConsumer") + + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.json new file mode 100644 index 0000000..47b5139 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.json @@ -0,0 +1,392 @@ +{ + "DataTypeDefinitions": { + "Strings": [ + { + "Name": "MaString", + "Namespace": "datatypes" + } + ], + "Enums": [ + { + "Name": "MyEnum", + "Namespace": "datatypes", + "Literals": [ + { + "Label": "Fui", + "Value": 6 + }, + { + "Label": "Yoh", + "Value": 10 + } + ] + } + ], + "Arrays": [ + { + "Name": "Array2", + "Namespace": "datatypes", + "TypeRef": "bool", + "Size": 6 + } + ], + "Maps": [ + { + "Name": "UsedMaps", + "Namespace": "datatypes", + "MapKeyTypeRef": "datatypes::MockUnusedTypeRef", + "MapValueTypeRef": "datatypes::Vector1" + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "MapKeyTypeRef": "uint64_t", + "MapValueTypeRef": "datatypes::PressureType" + } + ], + "TypeRefs": [ + { + "Name": "PressureType", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "AngleType", + "Namespace": "datatypes", + "TypeRef": "uint16_t" + } + ], + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "datatypes::AngleType" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "G", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "B", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "DMap", + "TypeRef": "datatypes::UsedMaps" + }, + { + "Name": "NewTop", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "Statuses", + "TypeRef": "datatypes::Array2" + }, + { + "Name": "ElectronicNum", + "TypeRef": "datatypes::MyEnum" + }, + { + "Name": "Owner", + "TypeRef": "datatypes::MaString" + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "adas::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "Vector1", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "MockUnusedTypeRef", + "Namespace": "datatypes", + "TypeRef": "float" + }, + { + "Name": "ObjectDetectionList", + "Namespace": "adas::interfaces", + "TypeRef": "adas::interfaces::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "adas::interfaces::ObjectDetectionList" + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer1" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer2" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_VelocityServiceConsumer" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_SteeringAngleServiceConsumer" + }, + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_BrakeServiceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_BrakeServiceProvider" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_SteeringAngleServiceProvider" + }, + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider1" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_VelocityServiceProvider" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider2" + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.py new file mode 100644 index 0000000..d6a7f0f --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/model.py @@ -0,0 +1,34 @@ +"""Definition of the CollisionDetection application module""" + +import os +from datetime import timedelta + +from silkit import Af + +from vaf import BaseTypes, save_main_model, vafpy + +# define the provided interface +object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector(name="ObjectDetectionList", namespace="adas::interfaces", datatype=object_detection) + +od_list_if = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist" +) +od_list_if.add_data_element(name="object_detection_list", datatype=od_list) + +collision_detection = vafpy.ApplicationModule( + name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection" +) +collision_detection.add_provided_interface( + instance_name="BrakeServiceProvider", interface=Af.Adas_Demo_App.Services.brake_service +) +collision_detection.add_consumed_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +collision_detection.add_task(vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200), preferred_offset=0)) + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/silkit-model.json b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/silkit-model.json new file mode 100644 index 0000000..03d25f8 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_260_bug/silkit-model.json @@ -0,0 +1,444 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "velocity", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "datatypes::AngleType" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "G", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "B", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "DMap", + "TypeRef": "datatypes::UsedMaps" + }, + { + "Name": "NewTop", + "TypeRef": "datatypes::Vector1" + }, + { + "Name": "Statuses", + "TypeRef": "datatypes::Array2" + }, + { + "Name": "ElectronicNum", + "TypeRef": "datatypes::MyEnum" + }, + { + "Name": "Owner", + "TypeRef": "datatypes::MaString" + } + ] + } + ], + "Strings": [ + { + "Name": "MockUnusedString", + "Namespace": "datatypes" + }, + { + "Name": "MaString", + "Namespace": "datatypes" + } + ], + "Vectors": [ + { + "Name": "Vector1", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "MockUnusedTypeRef", + "Namespace": "datatypes", + "TypeRef": "float" + } + ], + "Maps": [ + { + "Name": "MockUnusedMaps", + "Namespace": "datatypes", + "MapKeyTypeRef": "datatypes::Vector1", + "MapValueTypeRef": "datatypes::MockUnusedTypeRef" + }, + { + "Name": "UsedMaps", + "Namespace": "datatypes", + "MapKeyTypeRef": "datatypes::MockUnusedTypeRef", + "MapValueTypeRef": "datatypes::Vector1" + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "MapKeyTypeRef": "uint64_t", + "MapValueTypeRef": "datatypes::PressureType" + } + ], + "TypeRefs": [ + { + "Name": "PressureType", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + }, + { + "Name": "AngleType", + "Namespace": "datatypes", + "TypeRef": "uint16_t" + } + ], + "Arrays": [ + { + "Name": "Array1", + "Namespace": "datatypes", + "TypeRef": "bool", + "Size": 4 + }, + { + "Name": "Array2", + "Namespace": "datatypes", + "TypeRef": "bool", + "Size": 6 + } + ], + "Enums": [ + { + "Name": "MockUnusedEnums", + "Namespace": "datatypes", + "Literals": [ + { + "Label": "Hello", + "Value": 13 + }, + { + "Label": "Yellow", + "Value": 17 + } + ] + }, + { + "Name": "MyEnum", + "Namespace": "datatypes", + "Literals": [ + { + "Label": "Fui", + "Value": 6 + }, + { + "Label": "Yoh", + "Value": 10 + } + ] + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + } + ], + "PlatformConsumerModules": [ + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer1" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_ImageServiceConsumer2" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_VelocityServiceConsumer" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_SteeringAngleServiceConsumer" + }, + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_test_app::nsconsumermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_consumer_BrakeServiceConsumer" + } + ], + "PlatformProviderModules": [ + { + "Name": "BrakeService", + "Namespace": "nsadas_demo_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::BrakeService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_BrakeServiceProvider" + }, + { + "Name": "SteeringAngleService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::SteeringAngleService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_SteeringAngleServiceProvider" + }, + { + "Name": "ImageService1", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider1" + }, + { + "Name": "VelocityService", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::VelocityService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_VelocityServiceProvider" + }, + { + "Name": "ImageService2", + "Namespace": "nsadas_demo_test_app::nsprovidermodules", + "ModuleInterfaceRef": "af::adas_demo_app::services::ImageService", + "OriginalEcoSystem": "SILKIT", + "ConnectionPointRef": "ConnectionPoint_provider_ImageServiceProvider2" + } + ], + "SILKITAdditionalConfiguration": { + "ConnectionPoints": [ + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer1", + "ServiceInterfaceName": "Silkit_ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_ImageServiceConsumer2", + "ServiceInterfaceName": "Silkit_ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_SteeringAngleServiceConsumer", + "ServiceInterfaceName": "Silkit_SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_VelocityServiceConsumer", + "ServiceInterfaceName": "Silkit_VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_consumer_BrakeServiceConsumer", + "ServiceInterfaceName": "Silkit_BrakeService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_ImageServiceProvider1", + "ServiceInterfaceName": "Silkit_ImageService1", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_ImageServiceProvider2", + "ServiceInterfaceName": "Silkit_ImageService2", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_SteeringAngleServiceProvider", + "ServiceInterfaceName": "Silkit_SteeringAngleService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_VelocityServiceProvider", + "ServiceInterfaceName": "Silkit_VelocityService", + "RegistryUri": "silkit://localhost:8500" + }, + { + "Name": "ConnectionPoint_provider_BrakeServiceProvider", + "ServiceInterfaceName": "Silkit_BrakeService", + "RegistryUri": "silkit://localhost:8500" + } + ] + } +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_339/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_339/model.py new file mode 100644 index 0000000..b5a6285 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_339/model.py @@ -0,0 +1,75 @@ +"""Definition of the CollisionDetection application module""" + +import os +from datetime import timedelta + +from silkit import AdasDemoApp, Af + +from vaf import BaseTypes, Executable, save_main_model, vafpy + +# define the provided interface +object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector( + name="ObjectDetectionList", namespace="adas::interfaces", datatype=object_detection +) + +od_list_if = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist" +) +od_list_if.add_data_element(name="object_detection_list", datatype=od_list) + +p_200ms = timedelta(milliseconds=200) + +cd_mod = vafpy.ApplicationModule(name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection") +cd_mod.add_provided_interface(instance_name="BrakeServiceProvider", interface=Af.Adas_Demo_App.Services.brake_service) +cd_mod.add_provided_interface(instance_name="ImageServiceProvider1", interface=Af.Adas_Demo_App.Services.image_service) +cd_mod.add_consumed_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +cd_mod.add_task(vafpy.Task(name="PeriodicTask", period=p_200ms, preferred_offset=0)) + +sf_mod = vafpy.ApplicationModule(name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion") +sf_mod.add_provided_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +sf_mod.add_consumed_interface(instance_name="ImageServiceConsumer1", interface=Af.Adas_Demo_App.Services.image_service) +sf_mod.add_consumed_interface(instance_name="ImageServiceConsumer2", interface=Af.Adas_Demo_App.Services.image_service) +sf_mod.add_consumed_interface( + instance_name="SteeringAngleServiceConsumer", interface=Af.Adas_Demo_App.Services.steering_angle_service +) +sf_mod.add_consumed_interface( + instance_name="VelocityServiceConsumer", interface=Af.Adas_Demo_App.Services.velocity_service +) + +task1 = vafpy.Task(name="Step1", period=p_200ms, preferred_offset=0) +task2 = vafpy.Task(name="Step2", period=p_200ms, preferred_offset=0) +task3 = vafpy.Task(name="Step3", period=p_200ms, preferred_offset=0) +task4 = vafpy.Task(name="Step4", period=p_200ms, preferred_offset=0, run_after=[task3]) + +sf_mod.add_task(task=task1) +sf_mod.add_task_chain(tasks=[task2, task3], run_after=[task1]) +sf_mod.add_task(task=task4) + +# add application modules +p_10ms = timedelta(milliseconds=10) +AdasDemoApp.executable.add_application_module( + sf_mod, + [ + ("Step1", p_10ms, 0), + ("Step2", p_10ms, 0), + ("Step3", p_10ms, 0), + ("Step4", p_10ms, 0), + ], +) +AdasDemoApp.executable.add_application_module(cd_mod, [("PeriodicTask", timedelta(milliseconds=1), 1)]) + +# connect intra process interfaces +AdasDemoApp.executable.connect_interfaces(sf_mod, "ObjectDetectionListModule", cd_mod, "ObjectDetectionListModule") + +AdasDemoApp.executable = Executable("adas_demo_app", p_10ms) +AdasDemoApp.executable.add_application_module(cd_mod, [("PeriodicTask", timedelta(milliseconds=1), 1)]) + + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_354/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_354/model.py new file mode 100644 index 0000000..4bbdf6c --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_354/model.py @@ -0,0 +1,38 @@ +"""Definition of the CollisionDetection application module""" + +import os +from datetime import timedelta + +from silkit import Af + +from vaf import BaseTypes, save_main_model, vafpy + +# try to define Velocity (existing Velocity is datatypes::Velocity) +velocity = vafpy.datatypes.Struct(name="Velocity", namespace="MyInterface::Schmarrn") +velocity.add_subelement(name="Identifier", datatype=BaseTypes.INT16_T) +velocity.add_subelement(name="Velocity", datatype=BaseTypes.FLOAT) + +# try to define UInt8Vector (existing UInt8Vector is datatypes::UInt8Vector) +vector = vafpy.datatypes.Vector(name="UInt8Vector", namespace="ThouInterface::Tiramisu", datatype=velocity) + +# try to define VelocityService (existing VelocityService is datatypes::VelocityService) +vel_service = vafpy.ModuleInterface(name="VelocityService", namespace="FakeInterface::Salat") +vel_service.add_data_element(name="VelocityObj", datatype=vector) + +# try to redefine datatypes::SteeringAngle +steering_angle = vafpy.datatypes.Struct(name="SteeringAngle", namespace="datatypes") +steering_angle.add_subelement(name="Identifier", datatype=BaseTypes.INT16_T) +steering_angle.add_subelement(name="SteeringAngle", datatype=BaseTypes.FLOAT) + +# try to define datatypes::UInt8Vector +vector = vafpy.datatypes.Vector(name="UInt8Vector", namespace="datatypes", datatype=steering_angle) + +fake_mod = vafpy.ApplicationModule(name="FakeAppModule", namespace="FakeNamespace") +fake_mod.add_provided_interface(instance_name="BrakeServiceProvider", interface=Af.Adas_Demo_App.Services.brake_service) +fake_mod.add_consumed_interface(instance_name="VelocityServiceProvider", interface=vel_service) +fake_mod.add_task(vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200), preferred_offset=0)) + + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_386/app_module1.py b/VAF/tests/unit/vafpy/test_data/ftaf_386/app_module1.py new file mode 100644 index 0000000..719ea30 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_386/app_module1.py @@ -0,0 +1,12 @@ +from datetime import timedelta + +from imported_models.interface_project import * + +from vaf import vafpy + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") +app_module1.add_consumed_interface(instance_name="CostmapConsumer", interface=Localplanner.Costmap.costmap_interface) +app_module1.add_provided_interface( + instance_name="HvacControlProvider", interface=Nsprototype.Nsserviceinterface.Nshvaccontrol.hvac_control +) +app_module1.add_task(vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200))) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/InterfaceProject.json b/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/InterfaceProject.json new file mode 100644 index 0000000..0d50bb5 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/InterfaceProject.json @@ -0,0 +1,121 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Coordinate", + "Namespace": "localplanner::interfaces", + "SubElements": [ + { + "Name": "x", + "TypeRef": "int32_t" + }, + { + "Name": "y", + "TypeRef": "int32_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "Costmap", + "Namespace": "localplanner::interfaces", + "TypeRef": "uint8_t" + }, + { + "Name": "PathCoordinates", + "Namespace": "localplanner::interfaces", + "TypeRef": "localplanner::interfaces::Coordinate" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "HvacControl", + "Namespace": "nsprototype::nsserviceinterface::nshvaccontrol", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvaccontrol::internal::methods", + "DataElements": [ + { + "Name": "CompressorState", + "TypeRef": "uint8_t" + }, + { + "Name": "ValvePosition", + "TypeRef": "uint8_t" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t" + } + ], + "Operations": [ + { + "Name": "ChangeTemperature", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "HvacStatus", + "Namespace": "nsprototype::nsserviceinterface::nshvacstatus", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvacstatus::internal::methods", + "DataElements": [ + { + "Name": "CompressorStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "ValveStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "FanRightSpeed", + "TypeRef": "uint32_t" + }, + { + "Name": "FanLeftSpeed", + "TypeRef": "uint32_t" + } + ], + "Operations": [ + { + "Name": "SetDegree", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "CostmapInterface", + "Namespace": "localplanner::costmap", + "DataElements": [ + { + "Name": "costmap", + "TypeRef": "localplanner::interfaces::Costmap" + } + ] + }, + { + "Name": "PathInterface", + "Namespace": "localplanner::pathcoordinates", + "DataElements": [ + { + "Name": "path", + "TypeRef": "localplanner::interfaces::PathCoordinates" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/interface_project.py b/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/interface_project.py new file mode 100644 index 0000000..be315f8 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_386/imported_models/interface_project.py @@ -0,0 +1,34 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "InterfaceProject.json")) + + +class Localplanner: + class Costmap: + # ModuleInterfaces + costmap_interface = get_module_interface("CostmapInterface", "localplanner::costmap") + + class Pathcoordinates: + # ModuleInterfaces + path_interface = get_module_interface("PathInterface", "localplanner::pathcoordinates") + + +class Nsprototype: + class Nsserviceinterface: + class Nshvaccontrol: + # ModuleInterfaces + hvac_control = get_module_interface("HvacControl", "nsprototype::nsserviceinterface::nshvaccontrol") + + class Nshvacstatus: + # ModuleInterfaces + hvac_status = get_module_interface("HvacStatus", "nsprototype::nsserviceinterface::nshvacstatus") diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_386/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_386/model.json new file mode 100644 index 0000000..d91933c --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_386/model.json @@ -0,0 +1,54 @@ +{ + "DataTypeDefinitions": { + "Vectors": [ + { + "Name": "Costmap", + "Namespace": "localplanner::interfaces", + "TypeRef": "uint8_t" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "HvacControl", + "Namespace": "nsprototype::nsserviceinterface::nshvaccontrol", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvaccontrol::internal::methods", + "DataElements": [ + { + "Name": "CompressorState", + "TypeRef": "uint8_t" + }, + { + "Name": "ValvePosition", + "TypeRef": "uint8_t" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t" + } + ], + "Operations": [ + { + "Name": "ChangeTemperature", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "CostmapInterface", + "Namespace": "localplanner::costmap", + "DataElements": [ + { + "Name": "costmap", + "TypeRef": "localplanner::interfaces::Costmap" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_386/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_386/model.py new file mode 100644 index 0000000..da1051c --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_386/model.py @@ -0,0 +1,12 @@ +"""Execute to generate the complete model.""" + +import os + +from vaf import save_part_of_main_model + +# import the application module model to build up its model +import app_module1 + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_part_of_main_model(os.path.join(script_path, "model.json"),["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], cleanup = True) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_394/app_module1.py b/VAF/tests/unit/vafpy/test_data/ftaf_394/app_module1.py new file mode 100644 index 0000000..82476a0 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_394/app_module1.py @@ -0,0 +1,9 @@ +from datetime import timedelta + +from silkit import Vcandrive + +from vaf import vafpy + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") +app_module1.add_consumed_interface(instance_name="OcclusionMapConsumer", interface=Vcandrive.service_occlusion_map) +app_module1.add_task(vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200))) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_394/goal-model.json b/VAF/tests/unit/vafpy/test_data/ftaf_394/goal-model.json new file mode 100644 index 0000000..1bc17e9 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_394/goal-model.json @@ -0,0 +1,32 @@ +{ + "DataTypeDefinitions": { + "Arrays": [ + { + "Name": "Idt_OcclusionMap", + "Namespace": "vcandrive", + "TypeRef": "vcandrive::Idt_Blocked_Map_Entry_ref", + "Size": 12870 + } + ], + "TypeRefs": [ + { + "Name": "Idt_Blocked_Map_Entry_ref", + "Namespace": "vcandrive", + "TypeRef": "int8_t" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Service_occlusion_map", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_occlusion_map", + "TypeRef": "vcandrive::Idt_OcclusionMap" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_394/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_394/model.py new file mode 100644 index 0000000..27916db --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_394/model.py @@ -0,0 +1,12 @@ +"""Execute to generate the complete model.""" + +import os + +from vaf import save_part_of_main_model + +# import the application module model to build up its model +import app_module1 + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_part_of_main_model(os.path.join(script_path, "model.json"),["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], cleanup = False) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit-model.json b/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit-model.json new file mode 100644 index 0000000..1624f16 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit-model.json @@ -0,0 +1,771 @@ +{ + "DataTypeDefinitions": + { + "Arrays": [ + { + "Name": "Idt_LED_Array", + "Namespace": "vcandrive", + "TypeRef": "vcandrive::Idt_RGB_element", + "Size": 10 + }, + { + "Name": "Idt_OcclusionMap", + "Namespace": "vcandrive", + "TypeRef": "vcandrive::Idt_Blocked_Map_Entry_ref", + "Size": 12870 + }, + { + "Name": "Idt_Ultrasonic_Map", + "Namespace": "vcandrive", + "TypeRef": "vcandrive::Idt_Blocked_Map_Entry_ref", + "Size": 5500 + }, + { + "Name": "Idt_depth_camera_map", + "Namespace": "vcandrive", + "TypeRef": "vcandrive::Idt_Blocked_Map_Entry_ref", + "Size": 5280 + } + ], + "TypeRefs": [ + { + "Name": "Idt_12V_ref", + "Namespace": "vcandrive", + "TypeRef": "uint8_t" + }, + { + "Name": "Idt_Accerleration_ref", + "Namespace": "vcandrive", + "TypeRef": "float" + }, + { + "Name": "Idt_Blocked_Map_Entry_ref", + "Namespace": "vcandrive", + "TypeRef": "int8_t" + }, + { + "Name": "Idt_ColorValue_ref", + "Namespace": "vcandrive", + "TypeRef": "uint8_t" + }, + { + "Name": "Idt_Latitude_ref", + "Namespace": "vcandrive", + "TypeRef": "float" + }, + { + "Name": "Idt_Longitude_ref", + "Namespace": "vcandrive", + "TypeRef": "float" + }, + { + "Name": "Idt_MikroBUS_ref", + "Namespace": "vcandrive", + "TypeRef": "uint64_t" + }, + { + "Name": "Idt_Piezo_command_ref", + "Namespace": "vcandrive", + "TypeRef": "uint16_t" + }, + { + "Name": "Idt_Range_index_ref", + "Namespace": "vcandrive", + "TypeRef": "uint8_t" + }, + { + "Name": "Idt_Steer_ref", + "Namespace": "vcandrive", + "TypeRef": "int16_t" + }, + { + "Name": "Idt_Target_Reached", + "Namespace": "vcandrive", + "TypeRef": "bool" + }, + { + "Name": "Idt_brake_pressure_ref", + "Namespace": "vcandrive", + "TypeRef": "uint16_t" + }, + { + "Name": "Idt_button_ref", + "Namespace": "vcandrive", + "TypeRef": "bool" + }, + { + "Name": "Idt_compressed_Image_ref", + "Namespace": "vcandrive", + "TypeRef": "uint64_t" + }, + { + "Name": "Idt_direction_angle_ref", + "Namespace": "vcandrive", + "TypeRef": "float" + }, + { + "Name": "Idt_distance_ref", + "Namespace": "vcandrive", + "TypeRef": "uint16_t" + }, + { + "Name": "Idt_effects_ref", + "Namespace": "vcandrive", + "TypeRef": "uint16_t" + }, + { + "Name": "Idt_position_ref", + "Namespace": "vcandrive", + "TypeRef": "int32_t" + }, + { + "Name": "Idt_speed_command_ref", + "Namespace": "vcandrive", + "TypeRef": "int32_t" + }, + { + "Name": "Idt_steer_command_ref", + "Namespace": "vcandrive", + "TypeRef": "int32_t" + }, + { + "Name": "Idt_switch_ref", + "Namespace": "vcandrive", + "TypeRef": "uint8_t" + }, + { + "Name": "Idt_temperature_ref", + "Namespace": "vcandrive", + "TypeRef": "int16_t" + }, + { + "Name": "Idt_vehicle_angle_ref", + "Namespace": "vcandrive", + "TypeRef": "float" + }, + { + "Name": "Idt_velocity_ref", + "Namespace": "vcandrive", + "TypeRef": "int32_t" + }, + { + "Name": "Idt_voltage_ref", + "Namespace": "vcandrive", + "TypeRef": "uint16_t" + } + ], + "Structs": [ + { + "Name": "Idt_BMS", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "voltage_pack1", + "TypeRef": "vcandrive::Idt_voltage_ref" + }, + { + "Name": "temperature_pack1", + "TypeRef": "vcandrive::Idt_temperature_ref" + }, + { + "Name": "voltage_pack2", + "TypeRef": "vcandrive::Idt_voltage_ref" + }, + { + "Name": "temperature_pack2", + "TypeRef": "vcandrive::Idt_temperature_ref" + } + ] + }, + { + "Name": "Idt_Buttons", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "button0", + "TypeRef": "vcandrive::Idt_button_ref" + }, + { + "Name": "button1", + "TypeRef": "vcandrive::Idt_button_ref" + } + ] + }, + { + "Name": "Idt_COM_LED_Command", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "commands", + "TypeRef": "vcandrive::Idt_effects_ref" + }, + { + "Name": "colorFront", + "TypeRef": "vcandrive::Idt_LED_Array" + }, + { + "Name": "colorBack", + "TypeRef": "vcandrive::Idt_LED_Array" + } + ] + }, + { + "Name": "Idt_Coordinates", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "latitude", + "TypeRef": "vcandrive::Idt_Latitude_ref" + }, + { + "Name": "longitude", + "TypeRef": "vcandrive::Idt_Longitude_ref" + } + ] + }, + { + "Name": "Idt_Direction", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "velocity", + "TypeRef": "vcandrive::Idt_velocity_ref" + }, + { + "Name": "angle", + "TypeRef": "vcandrive::Idt_direction_angle_ref" + }, + { + "Name": "x", + "TypeRef": "vcandrive::Idt_position_ref" + }, + { + "Name": "y", + "TypeRef": "vcandrive::Idt_position_ref" + } + ] + }, + { + "Name": "Idt_Image", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "rgbImage", + "TypeRef": "vcandrive::Idt_compressed_Image_ref" + }, + { + "Name": "left", + "TypeRef": "vcandrive::Idt_compressed_Image_ref" + }, + { + "Name": "right", + "TypeRef": "vcandrive::Idt_compressed_Image_ref" + } + ] + }, + { + "Name": "Idt_LED_FRAME", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "index_start", + "TypeRef": "vcandrive::Idt_Range_index_ref" + }, + { + "Name": "index_end", + "TypeRef": "vcandrive::Idt_Range_index_ref" + }, + { + "Name": "RGB_data", + "TypeRef": "vcandrive::Idt_RGB_element" + }, + { + "Name": "effects", + "TypeRef": "vcandrive::Idt_effects_ref" + } + ] + }, + { + "Name": "Idt_Lightcontrol_LED_command", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "commands", + "TypeRef": "vcandrive::Idt_effects_ref" + }, + { + "Name": "colorLeftFront", + "TypeRef": "vcandrive::Idt_LED_Array" + }, + { + "Name": "colorRightFront", + "TypeRef": "vcandrive::Idt_LED_Array" + }, + { + "Name": "colorLeftRear", + "TypeRef": "vcandrive::Idt_LED_Array" + }, + { + "Name": "colorRightRear", + "TypeRef": "vcandrive::Idt_LED_Array" + } + ] + }, + { + "Name": "Idt_Piezos", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "command1", + "TypeRef": "vcandrive::Idt_Piezo_command_ref" + }, + { + "Name": "command2", + "TypeRef": "vcandrive::Idt_Piezo_command_ref" + } + ] + }, + { + "Name": "Idt_RGB_element", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "r", + "TypeRef": "vcandrive::Idt_ColorValue_ref" + }, + { + "Name": "g", + "TypeRef": "vcandrive::Idt_ColorValue_ref" + }, + { + "Name": "b", + "TypeRef": "vcandrive::Idt_ColorValue_ref" + } + ] + }, + { + "Name": "Idt_Remote_Data", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "steer", + "TypeRef": "vcandrive::Idt_steer_command_ref" + }, + { + "Name": "speed", + "TypeRef": "vcandrive::Idt_speed_command_ref" + } + ] + }, + { + "Name": "Idt_Signaling_LED", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "Brake", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "headlight", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "high_beam", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "indicator_left", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "indicator_right", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "reversing_light", + "TypeRef": "vcandrive::Idt_switch_ref" + }, + { + "Name": "effects", + "TypeRef": "vcandrive::Idt_effects_ref" + } + ] + }, + { + "Name": "Idt_Target", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "x", + "TypeRef": "vcandrive::Idt_position_ref" + }, + { + "Name": "y", + "TypeRef": "vcandrive::Idt_position_ref" + }, + { + "Name": "angle", + "TypeRef": "vcandrive::Idt_direction_angle_ref" + } + ] + }, + { + "Name": "Idt_Ultrasonic_Fusion_Map", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "ultrasonic_Map_front", + "TypeRef": "vcandrive::Idt_Ultrasonic_Map" + }, + { + "Name": "ultrasonic_Map_rear", + "TypeRef": "vcandrive::Idt_Ultrasonic_Map" + } + ] + }, + { + "Name": "Idt_Ultrasonic_Sensors", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "usLeft", + "TypeRef": "vcandrive::Idt_distance_ref" + }, + { + "Name": "usCenter", + "TypeRef": "vcandrive::Idt_distance_ref" + }, + { + "Name": "usRight", + "TypeRef": "vcandrive::Idt_distance_ref" + } + ] + }, + { + "Name": "Idt_Vehicle_Position", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "x", + "TypeRef": "vcandrive::Idt_position_ref" + }, + { + "Name": "y", + "TypeRef": "vcandrive::Idt_position_ref" + }, + { + "Name": "angle", + "TypeRef": "vcandrive::Idt_vehicle_angle_ref" + }, + { + "Name": "velocity", + "TypeRef": "vcandrive::Idt_velocity_ref" + }, + { + "Name": "acceleration", + "TypeRef": "vcandrive::Idt_Accerleration_ref" + } + ] + }, + { + "Name": "Idt_brake_force", + "Namespace": "vcandrive", + "SubElements": [ + { + "Name": "leftFront", + "TypeRef": "vcandrive::Idt_brake_pressure_ref" + }, + { + "Name": "rightFront", + "TypeRef": "vcandrive::Idt_brake_pressure_ref" + }, + { + "Name": "leftRear", + "TypeRef": "vcandrive::Idt_brake_pressure_ref" + }, + { + "Name": "rightRear", + "TypeRef": "vcandrive::Idt_brake_pressure_ref" + } + ] + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Service_12V", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_12V", + "TypeRef": "vcandrive::Idt_12V_ref" + } + ] + }, + { + "Name": "Service_BMS", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_BMS", + "TypeRef": "vcandrive::Idt_BMS" + } + ] + }, + { + "Name": "Service_COM_LED", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_COM_LED", + "TypeRef": "vcandrive::Idt_LED_Array" + } + ] + }, + { + "Name": "Service_COM_LED_command", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_COM_LED_command", + "TypeRef": "vcandrive::Idt_COM_LED_Command" + } + ] + }, + { + "Name": "Service_Coordinates", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_coordinates", + "TypeRef": "vcandrive::Idt_Coordinates" + } + ] + }, + { + "Name": "Service_LED_Frame", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_LED_Frame", + "TypeRef": "vcandrive::Idt_LED_FRAME" + } + ] + }, + { + "Name": "Service_Microbus", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_Microbus", + "TypeRef": "vcandrive::Idt_MikroBUS_ref" + } + ] + }, + { + "Name": "Service_Motor_Temp", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_Motor_Temp", + "TypeRef": "vcandrive::Idt_temperature_ref" + } + ] + }, + { + "Name": "Service_Remote_Data", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_Remote_Data", + "TypeRef": "vcandrive::Idt_Remote_Data" + } + ] + }, + { + "Name": "Service_Target_M", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "Operations": [ + { + "Name": "Set_Target", + "Parameters": [ + { + "Name": "Target", + "TypeRef": "vcandrive::Idt_Target", + "Direction": "IN" + }, + { + "Name": "Target_reachable", + "TypeRef": "vcandrive::Idt_Target_Reached", + "Direction": "OUT" + } + ] + } + ] + }, + { + "Name": "Service_US_Sensors", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_US_Sensors", + "TypeRef": "vcandrive::Idt_Ultrasonic_Sensors" + } + ] + }, + { + "Name": "Service_brake_force", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_brake_force", + "TypeRef": "vcandrive::Idt_brake_force" + } + ] + }, + { + "Name": "Service_depth_camera_map", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_depth_camera_map", + "TypeRef": "vcandrive::Idt_depth_camera_map" + } + ] + }, + { + "Name": "Service_direction", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_direction", + "TypeRef": "vcandrive::Idt_Direction" + } + ] + }, + { + "Name": "Service_image", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_image", + "TypeRef": "vcandrive::Idt_Image" + } + ] + }, + { + "Name": "Service_lightcontrol_LED_command", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_lightcontrol_LED_command", + "TypeRef": "vcandrive::Idt_Lightcontrol_LED_command" + } + ] + }, + { + "Name": "Service_occlusion_map", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_occlusion_map", + "TypeRef": "vcandrive::Idt_OcclusionMap" + } + ] + }, + { + "Name": "Service_piezos", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_piezos", + "TypeRef": "vcandrive::Idt_Piezos" + } + ] + }, + { + "Name": "Service_signaling_LED", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_signaling_LED", + "TypeRef": "vcandrive::Idt_Signaling_LED" + } + ] + }, + { + "Name": "Service_steer", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_Steer", + "TypeRef": "vcandrive::Idt_Steer_ref" + } + ] + }, + { + "Name": "Service_target", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_target", + "TypeRef": "vcandrive::Idt_Target" + } + ] + }, + { + "Name": "Service_ultrasonic_fusion_map", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_ultrasonic_fusion_map", + "TypeRef": "vcandrive::Idt_Ultrasonic_Fusion_Map" + } + ] + }, + { + "Name": "Service_vehicle_position", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_vehicle_position", + "TypeRef": "vcandrive::Idt_Vehicle_Position" + } + ] + }, + { + "Name": "Servie_Buttons", + "Namespace": "vcandrive", + "OperationOutputNamespace": "vcandrive::internal::methods", + "DataElements": [ + { + "Name": "Event_Buttons", + "TypeRef": "vcandrive::Idt_Buttons" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit.py b/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit.py new file mode 100644 index 0000000..145a527 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_394/silkit.py @@ -0,0 +1,44 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "silkit-model.json")) + +# Adapted to work with SIL Kit + + +# Service interfaces +class Vcandrive: + # Module Interfaces + service_12v = get_module_interface("Service_12V", "vcandrive") + service_bms = get_module_interface("Service_BMS", "vcandrive") + service_com_led = get_module_interface("Service_COM_LED", "vcandrive") + service_com_led_command = get_module_interface("Service_COM_LED_command", "vcandrive") + service_coordinates = get_module_interface("Service_Coordinates", "vcandrive") + service_led_frame = get_module_interface("Service_LED_Frame", "vcandrive") + service_microbus = get_module_interface("Service_Microbus", "vcandrive") + service_motor_temp = get_module_interface("Service_Motor_Temp", "vcandrive") + service_remote_data = get_module_interface("Service_Remote_Data", "vcandrive") + service_target_m = get_module_interface("Service_Target_M", "vcandrive") + service_us_sensors = get_module_interface("Service_US_Sensors", "vcandrive") + service_brake_force = get_module_interface("Service_brake_force", "vcandrive") + service_depth_camera_map = get_module_interface("Service_depth_camera_map", "vcandrive") + service_direction = get_module_interface("Service_direction", "vcandrive") + service_image = get_module_interface("Service_image", "vcandrive") + service_lightcontrol_led_command = get_module_interface("Service_lightcontrol_LED_command", "vcandrive") + service_occlusion_map = get_module_interface("Service_occlusion_map", "vcandrive") + service_piezos = get_module_interface("Service_piezos", "vcandrive") + service_signaling_led = get_module_interface("Service_signaling_LED", "vcandrive") + service_steer = get_module_interface("Service_steer", "vcandrive") + service_target = get_module_interface("Service_target", "vcandrive") + service_ultrasonic_fusion_map = get_module_interface("Service_ultrasonic_fusion_map", "vcandrive") + service_vehicle_position = get_module_interface("Service_vehicle_position", "vcandrive") + servie_buttons = get_module_interface("Servie_Buttons", "vcandrive") diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_399/app_module1.py b/VAF/tests/unit/vafpy/test_data/ftaf_399/app_module1.py new file mode 100644 index 0000000..e775fed --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_399/app_module1.py @@ -0,0 +1,9 @@ +from datetime import timedelta + +from vss import Vss + +from vaf import vafpy + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") +app_module1.add_consumed_interface(instance_name="AxleRow1Consumer", interface=Vss.Vehicle.Chassis.Axle.row1) +app_module1.add_task(vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200))) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_399/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_399/model.json new file mode 100644 index 0000000..2e2ff9f --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_399/model.json @@ -0,0 +1,471 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "AppModule1", + "Namespace": "demo", + "ConsumedInterfaces": [ + { + "InstanceName": "AxleRow1Consumer", + "ModuleInterfaceRef": "vss::vehicle::chassis::axle::Row1" + } + ], + "ProvidedInterfaces": [ ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_399/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_399/model.py new file mode 100644 index 0000000..da1051c --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_399/model.py @@ -0,0 +1,12 @@ +"""Execute to generate the complete model.""" + +import os + +from vaf import save_part_of_main_model + +# import the application module model to build up its model +import app_module1 + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_part_of_main_model(os.path.join(script_path, "model.json"),["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], cleanup = True) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_399/vss-derived-model.json b/VAF/tests/unit/vafpy/test_data/ftaf_399/vss-derived-model.json new file mode 100644 index 0000000..4851351 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_399/vss-derived-model.json @@ -0,0 +1,1131 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Vehicle", + "Namespace": "vss", + "SubElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + } + ], + "Strings": [ + { + "Name": "string", + "Namespace": "vaf" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Vehicle", + "Namespace": "vss", + "DataElements": [ + { + "Name": "Vehicle", + "TypeRef": "vss::Vehicle" + }, + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + }, + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_399/vss.py b/VAF/tests/unit/vafpy/test_data/ftaf_399/vss.py new file mode 100644 index 0000000..f7b3679 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_399/vss.py @@ -0,0 +1,109 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "vss-derived-model.json")) + + + +class Vss: + # ModuleInterfaces + vehicle = get_module_interface( + "Vehicle", "vss" + ) + class Vehicle: + # ModuleInterfaces + chassis = get_module_interface( + "Chassis", "vss::vehicle" + ) + class Chassis: + # ModuleInterfaces + accelerator = get_module_interface( + "Accelerator", "vss::vehicle::chassis" + ) + axle = get_module_interface( + "Axle", "vss::vehicle::chassis" + ) + brake = get_module_interface( + "Brake", "vss::vehicle::chassis" + ) + parking_brake = get_module_interface( + "ParkingBrake", "vss::vehicle::chassis" + ) + steering_wheel = get_module_interface( + "SteeringWheel", "vss::vehicle::chassis" + ) + class Axle: + # ModuleInterfaces + row1 = get_module_interface( + "Row1", "vss::vehicle::chassis::axle" + ) + row2 = get_module_interface( + "Row2", "vss::vehicle::chassis::axle" + ) + class Row1: + # ModuleInterfaces + wheel = get_module_interface( + "Wheel", "vss::vehicle::chassis::axle::row1" + ) + class Wheel: + # ModuleInterfaces + left = get_module_interface( + "Left", "vss::vehicle::chassis::axle::row1::wheel" + ) + right = get_module_interface( + "Right", "vss::vehicle::chassis::axle::row1::wheel" + ) + class Left: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + class Right: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + class Row2: + # ModuleInterfaces + wheel = get_module_interface( + "Wheel", "vss::vehicle::chassis::axle::row2" + ) + class Wheel: + # ModuleInterfaces + left = get_module_interface( + "Left", "vss::vehicle::chassis::axle::row2::wheel" + ) + right = get_module_interface( + "Right", "vss::vehicle::chassis::axle::row2::wheel" + ) + class Left: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + class Right: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row2::wheel::right" + ) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_421/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_421/model.py new file mode 100644 index 0000000..de63272 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_421/model.py @@ -0,0 +1,65 @@ +"""Definition of the CollisionDetection application module""" + +import os +from datetime import timedelta + +from silkit import AdasDemoApp, Af + +from vaf import BaseTypes, save_main_model, vafpy + +# define the provided interface +object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces") +object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector(name="ObjectDetectionList", namespace="adas::interfaces", datatype=object_detection) + +od_list_if = vafpy.ModuleInterface( + name="ObjectDetectionListInterface", namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist" +) +od_list_if.add_data_element(name="object_detection_list", datatype=od_list) + +p1 = timedelta(milliseconds=60) +p2 = timedelta(milliseconds=70) +p3 = timedelta(milliseconds=5) +p4 = timedelta(milliseconds=22) +p5 = timedelta(milliseconds=23) + +cd_mod = vafpy.ApplicationModule(name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection") +cd_mod.add_consumed_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) +cd_mod.add_task(vafpy.Task(name="PeriodicTask", period=p1, preferred_offset=0)) + +sf_mod = vafpy.ApplicationModule(name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion") +sf_mod.add_provided_interface(instance_name="ObjectDetectionListModule", interface=od_list_if) + +task1 = vafpy.Task(name="Step1", period=p2, preferred_offset=0) +task2 = vafpy.Task(name="Step2", period=p3, preferred_offset=0) +task3 = vafpy.Task(name="Step3", period=p4, preferred_offset=0) +task4 = vafpy.Task(name="Step4", period=p5, preferred_offset=0, run_after=[task3]) + +sf_mod.add_task(task=task1) +sf_mod.add_task_chain(tasks=[task2, task3], run_after=[task1]) +sf_mod.add_task(task=task4) + + +# add application modules +p_10ms = timedelta(milliseconds=10) +AdasDemoApp.executable.add_application_module( + sf_mod, + [ + ("Step1", p_10ms, 0), + ("Step2", p_10ms, 0), + ("Step3", p_10ms, 0), + ("Step4", p_10ms, 0), + ], +) +AdasDemoApp.executable.add_application_module(cd_mod, [("PeriodicTask", timedelta(milliseconds=1), 1)]) + +# connect intra process interfaces +AdasDemoApp.executable.connect_interfaces(sf_mod, "ObjectDetectionListModule", cd_mod, "ObjectDetectionListModule") + + +if __name__ == "__main__": + script_path = os.path.dirname(os.path.realpath(__file__)) + save_main_model(os.path.join(script_path, "model.json")) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_421/silkit.py b/VAF/tests/unit/vafpy/test_data/ftaf_421/silkit.py new file mode 100644 index 0000000..d756547 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_421/silkit.py @@ -0,0 +1,64 @@ +import os +from datetime import timedelta + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "silkit-model.json")) + +# Adapted to work with SIL Kit + + +# Service interfaces +class Af: + class Adas_Demo_App: + class Services: + # Module Interfaces + brake_service = get_module_interface("BrakeService", "af::adas_demo_app::services") + image_service = get_module_interface("ImageService", "af::adas_demo_app::services") + steering_angle_service = get_module_interface("SteeringAngleService", "af::adas_demo_app::services") + velocity_service = get_module_interface("VelocityService", "af::adas_demo_app::services") + + +# Executables and their ports +class AdasDemoApp: + # Executable + executable = Executable("adas_demo_app", timedelta(milliseconds=23)) + + # Required Ports + class ConsumerModules: + image_service1 = get_platform_consumer_module("ImageService1", "nsadas_demo_app::nsconsumermodules") + image_service2 = get_platform_consumer_module("ImageService2", "nsadas_demo_app::nsconsumermodules") + velocity_service = get_platform_consumer_module("VelocityService", "nsadas_demo_app::nsconsumermodules") + steering_angle_service = get_platform_consumer_module( + "SteeringAngleService", "nsadas_demo_app::nsconsumermodules" + ) + + # Provided Ports + class ProviderModules: + brake_service = get_platform_provider_module("BrakeService", "nsadas_demo_app::nsprovidermodules") + + +class AdasDemoTestApp: + # Executable + executable = Executable("adas_demo_test_app") + + # Required Ports + class ConsumerModules: + brake_service = get_platform_consumer_module("BrakeService", "nsadas_demo_test_app::nsconsumermodules") + + # Provided Ports + class ProviderModules: + steering_angle_service = get_platform_provider_module( + "SteeringAngleService", "nsadas_demo_test_app::nsprovidermodules" + ) + image_service1 = get_platform_provider_module("ImageService1", "nsadas_demo_test_app::nsprovidermodules") + velocity_service = get_platform_provider_module("VelocityService", "nsadas_demo_test_app::nsprovidermodules") + image_service2 = get_platform_provider_module("ImageService2", "nsadas_demo_test_app::nsprovidermodules") diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_422/app_module1.py b/VAF/tests/unit/vafpy/test_data/ftaf_422/app_module1.py new file mode 100644 index 0000000..9f1088d --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_422/app_module1.py @@ -0,0 +1,12 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from imported_models.interface import * + +app_module1 = vafpy.ApplicationModule(name="app-module1", namespace="demo") +app_module1.add_provided_interface(instance_name="ObjectDetectionListProvider", interface=Demo.object_detection_list_interface) +app_module1.add_consumed_interface(instance_name="HvacStatusConsumer", interface=Nsprototype.Nsserviceinterface.Nshvacstatus.hvac_status) +app_module1.add_consumed_interface(instance_name="ChassisLeftAxleConsumer", interface=Vss.Vehicle.Chassis.axle) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +app_module1.add_task(task=periodic_task) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.json b/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.json new file mode 100644 index 0000000..c4c9e4f --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.json @@ -0,0 +1,1232 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Vehicle", + "Namespace": "vss", + "SubElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "demo", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Strings": [ + { + "Name": "string", + "Namespace": "vaf" + } + ], + "Vectors": [ + { + "Name": "ObjectDetectionList", + "Namespace": "demo", + "TypeRef": "demo::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Vehicle", + "Namespace": "vss", + "DataElements": [ + { + "Name": "Vehicle", + "TypeRef": "vss::Vehicle" + }, + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + }, + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "HvacControl", + "Namespace": "nsprototype::nsserviceinterface::nshvaccontrol", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvaccontrol::internal::methods", + "DataElements": [ + { + "Name": "CompressorState", + "TypeRef": "uint8_t" + }, + { + "Name": "ValvePosition", + "TypeRef": "uint8_t" + }, + { + "Name": "FanSpeed", + "TypeRef": "uint8_t" + } + ], + "Operations": [ + { + "Name": "ChangeTemperature", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "HvacStatus", + "Namespace": "nsprototype::nsserviceinterface::nshvacstatus", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvacstatus::internal::methods", + "DataElements": [ + { + "Name": "CompressorStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "ValveStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "FanRightSpeed", + "TypeRef": "uint32_t" + }, + { + "Name": "FanLeftSpeed", + "TypeRef": "uint32_t" + } + ], + "Operations": [ + { + "Name": "SetDegree", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "demo", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "demo::ObjectDetectionList" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.py b/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.py new file mode 100644 index 0000000..d970b64 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_422/imported_models/interface.py @@ -0,0 +1,132 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "interface.json")) + + + +class Demo: + # ModuleInterfaces + object_detection_list_interface = get_module_interface( + "ObjectDetectionListInterface", "demo" + ) + + +class Nsprototype: + class Nsserviceinterface: + class Nshvaccontrol: + # ModuleInterfaces + hvac_control = get_module_interface( + "HvacControl", "nsprototype::nsserviceinterface::nshvaccontrol" + ) + class Nshvacstatus: + # ModuleInterfaces + hvac_status = get_module_interface( + "HvacStatus", "nsprototype::nsserviceinterface::nshvacstatus" + ) + + +class Vss: + # ModuleInterfaces + vehicle = get_module_interface( + "Vehicle", "vss" + ) + class Vehicle: + # ModuleInterfaces + chassis = get_module_interface( + "Chassis", "vss::vehicle" + ) + class Chassis: + # ModuleInterfaces + accelerator = get_module_interface( + "Accelerator", "vss::vehicle::chassis" + ) + axle = get_module_interface( + "Axle", "vss::vehicle::chassis" + ) + brake = get_module_interface( + "Brake", "vss::vehicle::chassis" + ) + parking_brake = get_module_interface( + "ParkingBrake", "vss::vehicle::chassis" + ) + steering_wheel = get_module_interface( + "SteeringWheel", "vss::vehicle::chassis" + ) + class Axle: + # ModuleInterfaces + row1 = get_module_interface( + "Row1", "vss::vehicle::chassis::axle" + ) + row2 = get_module_interface( + "Row2", "vss::vehicle::chassis::axle" + ) + class Row1: + # ModuleInterfaces + wheel = get_module_interface( + "Wheel", "vss::vehicle::chassis::axle::row1" + ) + class Wheel: + # ModuleInterfaces + left = get_module_interface( + "Left", "vss::vehicle::chassis::axle::row1::wheel" + ) + right = get_module_interface( + "Right", "vss::vehicle::chassis::axle::row1::wheel" + ) + class Left: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + class Right: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + class Row2: + # ModuleInterfaces + wheel = get_module_interface( + "Wheel", "vss::vehicle::chassis::axle::row2" + ) + class Wheel: + # ModuleInterfaces + left = get_module_interface( + "Left", "vss::vehicle::chassis::axle::row2::wheel" + ) + right = get_module_interface( + "Right", "vss::vehicle::chassis::axle::row2::wheel" + ) + class Left: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + class Right: + # ModuleInterfaces + brake = get_module_interface( + "Brake", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + tire = get_module_interface( + "Tire", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + + diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_422/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_422/model.json new file mode 100644 index 0000000..a28b077 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_422/model.json @@ -0,0 +1,998 @@ +{ + "DataTypeDefinitions": + { + "Structs": [ + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "ObjectDetection", + "Namespace": "demo", + "SubElements": [ + { + "Name": "x", + "TypeRef": "uint64_t" + }, + { + "Name": "y", + "TypeRef": "uint64_t" + }, + { + "Name": "z", + "TypeRef": "uint64_t" + } + ] + } + ], + "Vectors": [ + { + "Name": "ObjectDetectionList", + "Namespace": "demo", + "TypeRef": "demo::ObjectDetection" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + }, + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "DataElements": [ + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + }, + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + }, + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "HvacStatus", + "Namespace": "nsprototype::nsserviceinterface::nshvacstatus", + "OperationOutputNamespace": "nsprototype::nsserviceinterface::nshvacstatus::internal::methods", + "DataElements": [ + { + "Name": "CompressorStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "ValveStatus", + "TypeRef": "uint32_t" + }, + { + "Name": "FanRightSpeed", + "TypeRef": "uint32_t" + }, + { + "Name": "FanLeftSpeed", + "TypeRef": "uint32_t" + } + ], + "Operations": [ + { + "Name": "SetDegree", + "Parameters": [ + { + "Name": "Value", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ObjectDetectionListInterface", + "Namespace": "demo", + "DataElements": [ + { + "Name": "object_detection_list", + "TypeRef": "demo::ObjectDetectionList" + } + ] + } + ], + "ApplicationModules": [ + { + "Name": "app-module1", + "Namespace": "demo", + "ConsumedInterfaces": [ + { + "InstanceName": "HvacStatusConsumer", + "ModuleInterfaceRef": "nsprototype::nsserviceinterface::nshvacstatus::HvacStatus" + }, + { + "InstanceName": "ChassisLeftAxleConsumer", + "ModuleInterfaceRef": "vss::vehicle::chassis::Axle" + } + ], + "ProvidedInterfaces": [ + { + "InstanceName": "ObjectDetectionListProvider", + "ModuleInterfaceRef": "demo::ObjectDetectionListInterface" + } + ], + "ImplementationProperties": { + "GenerateUnitTestStubs": true + }, + "Tasks": [ + { + "Name": "PeriodicTask", + "Period": "200ms" + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_422/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_422/model.py new file mode 100644 index 0000000..dcfb2e5 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_422/model.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import os + +from vaf import (save_part_of_main_model) + +# Import the application module model +import app_module1 + + +def export_model(): + script_path = os.path.dirname(os.path.realpath(__file__)) + save_part_of_main_model( + os.path.join(script_path, "model.json"), + ["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], + cleanup=True, + ) + + +if __name__ == "__main__": + export_model() diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_457/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_457/model.py new file mode 100644 index 0000000..66e6f62 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_457/model.py @@ -0,0 +1,35 @@ +from pathlib import Path + +from vaf import BaseTypes, save_part_of_main_model, vafpy +from vaf.vafgeneration import generate_cac_support + +object_detection = vafpy.datatypes.Struct(name="ObjectDetection", namespace="demo") +object_detection.add_subelement(name="x", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="y", datatype=BaseTypes.UINT64_T) +object_detection.add_subelement(name="z", datatype=BaseTypes.UINT64_T) + +od_list = vafpy.datatypes.Vector(name="ObjectDetectionList", namespace="demo", datatype=object_detection) + +data_element_if = vafpy.ModuleInterface(name="DataElementInterface", namespace="demo") +data_element_if.add_data_element(name="object_detection_list", datatype=od_list) + +operation_if = vafpy.ModuleInterface(name="OperationInterface", namespace="demo") +operation_if.add_operation(name="my_operation") + +both_if = vafpy.ModuleInterface(name="BothInterface", namespace="demo") +both_if.add_data_element(name="object_detection_list", datatype=od_list) +both_if.add_operation(name="my_operation") + +empty_if = vafpy.ModuleInterface(name="EmptyInterface", namespace="demo") + + +def export_model(): + script_path = Path(__file__).resolve().parent + export_path = script_path / "export" + export_path.mkdir(parents=True, exist_ok=True) + save_part_of_main_model((export_path / "asdfIf.json").as_posix(), ["DataTypeDefinitions", "ModuleInterfaces"]) + generate_cac_support(export_path, "asdfIf.json", "asdfIf", script_path / "export") + + +if __name__ == "__main__": + export_model() diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_553/app_module1.py b/VAF/tests/unit/vafpy/test_data/ftaf_553/app_module1.py new file mode 100644 index 0000000..e5d6035 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_553/app_module1.py @@ -0,0 +1,17 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +from .imported_models.interfaces import * + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") +app_module1.add_consumed_interface( + instance_name="ParkingBrakeConsumer", + interface=Vss.Vehicle.Chassis.parking_brake_if, +) +app_module1.add_provided_interface( + instance_name="DataExchangeProvider", + interface=Demo.data_exchange_interface, +) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200)) +app_module1.add_task(task=periodic_task) diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/Interfaces.json b/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/Interfaces.json new file mode 100644 index 0000000..dcf4bd8 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/Interfaces.json @@ -0,0 +1,1279 @@ +{ + "DataTypeDefinitions": { + "Strings": [ + { + "Name": "string", + "Namespace": "vaf" + }, + { + "Name": "MyStringType", + "Namespace": "demo" + } + ], + "Structs": [ + { + "Name": "Velocity", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "speed", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "SteeringAngle", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "steering_angle", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "BrakePressure", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "brake_pressure", + "TypeRef": "uint8_t" + } + ] + }, + { + "Name": "Image", + "Namespace": "datatypes", + "SubElements": [ + { + "Name": "timestamp", + "TypeRef": "uint64_t" + }, + { + "Name": "height", + "TypeRef": "uint16_t" + }, + { + "Name": "width", + "TypeRef": "uint16_t" + }, + { + "Name": "R", + "TypeRef": "datatypes::UInt8Vector" + }, + { + "Name": "G", + "TypeRef": "datatypes::UInt8Vector" + }, + { + "Name": "B", + "TypeRef": "datatypes::UInt8Vector" + } + ] + }, + { + "Name": "Vehicle", + "Namespace": "vss", + "SubElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis", + "Namespace": "vss::vehicle", + "SubElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "SteeringWheel", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake", + "Namespace": "vss::vehicle::chassis", + "SubElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "Row1", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2", + "Namespace": "vss::vehicle::chassis::axle", + "SubElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row1", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Wheel", + "Namespace": "vss::vehicle::chassis::axle::row2", + "SubElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Right", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "SubElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Tire", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "SubElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + } + ], + "Vectors": [ + { + "Name": "UInt8Vector", + "Namespace": "datatypes", + "TypeRef": "uint8_t" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "BrakeService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "brake_action", + "TypeRef": "datatypes::BrakePressure" + }, + { + "Name": "brake_summand_coefficient_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "SumTwoSummands", + "Parameters": [ + { + "Name": "summand_one", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "summand_two", + "TypeRef": "uint16_t", + "Direction": "IN" + }, + { + "Name": "sum", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "brake_summand_coefficient_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "ImageService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "camera_image", + "TypeRef": "datatypes::Image" + }, + { + "Name": "image_scaling_factor_FieldNotifier", + "TypeRef": "uint64_t" + } + ], + "Operations": [ + { + "Name": "GetImageSize", + "Parameters": [ + { + "Name": "width", + "TypeRef": "uint16_t", + "Direction": "OUT" + }, + { + "Name": "height", + "TypeRef": "uint16_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldGetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "OUT" + } + ] + }, + { + "Name": "image_scaling_factor_FieldSetter", + "Parameters": [ + { + "Name": "data", + "TypeRef": "uint64_t", + "Direction": "IN" + } + ] + } + ] + }, + { + "Name": "SteeringAngleService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "steering_angle", + "TypeRef": "datatypes::SteeringAngle" + } + ] + }, + { + "Name": "VelocityService", + "Namespace": "af::adas_demo_app::services", + "OperationOutputNamespace": "af::adas_demo_app::services::internal::methods", + "DataElements": [ + { + "Name": "car_velocity", + "TypeRef": "datatypes::Velocity" + } + ] + }, + { + "Name": "Vehicle_If", + "Namespace": "vss", + "DataElements": [ + { + "Name": "Chassis", + "TypeRef": "vss::vehicle::Chassis" + } + ] + }, + { + "Name": "Chassis_If", + "Namespace": "vss::vehicle", + "DataElements": [ + { + "Name": "Accelerator", + "TypeRef": "vss::vehicle::chassis::Accelerator" + }, + { + "Name": "Axle", + "TypeRef": "vss::vehicle::chassis::Axle" + }, + { + "Name": "AxleCount", + "TypeRef": "uint8_t" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::Brake" + }, + { + "Name": "ParkingBrake", + "TypeRef": "vss::vehicle::chassis::ParkingBrake" + }, + { + "Name": "SteeringWheel", + "TypeRef": "vss::vehicle::chassis::SteeringWheel" + }, + { + "Name": "Wheelbase", + "TypeRef": "uint16_t" + } + ] + }, + { + "Name": "Accelerator_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "Axle_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Row1", + "TypeRef": "vss::vehicle::chassis::axle::Row1" + }, + { + "Name": "Row2", + "TypeRef": "vss::vehicle::chassis::axle::Row2" + } + ] + }, + { + "Name": "Row1_If", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row1::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel_If", + "Namespace": "vss::vehicle::chassis::axle::row1", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::Right" + } + ] + }, + { + "Name": "Left_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::left", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row1::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row1::wheel::right", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Row2_If", + "Namespace": "vss::vehicle::chassis::axle", + "DataElements": [ + { + "Name": "AxleWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "SteeringAngle", + "TypeRef": "float" + }, + { + "Name": "TireAspectRatio", + "TypeRef": "uint8_t" + }, + { + "Name": "TireDiameter", + "TypeRef": "float" + }, + { + "Name": "TireWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TrackWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "TreadWidth", + "TypeRef": "uint16_t" + }, + { + "Name": "Wheel", + "TypeRef": "vss::vehicle::chassis::axle::row2::Wheel" + }, + { + "Name": "WheelCount", + "TypeRef": "uint8_t" + }, + { + "Name": "WheelDiameter", + "TypeRef": "float" + }, + { + "Name": "WheelWidth", + "TypeRef": "float" + } + ] + }, + { + "Name": "Wheel_If", + "Namespace": "vss::vehicle::chassis::axle::row2", + "DataElements": [ + { + "Name": "Left", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Left" + }, + { + "Name": "Right", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::Right" + } + ] + }, + { + "Name": "Left_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::left::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::left", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Right_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel", + "DataElements": [ + { + "Name": "AngularSpeed", + "TypeRef": "float" + }, + { + "Name": "Brake", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Brake" + }, + { + "Name": "Speed", + "TypeRef": "float" + }, + { + "Name": "Tire", + "TypeRef": "vss::vehicle::chassis::axle::row2::wheel::right::Tire" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "FluidLevel", + "TypeRef": "uint8_t", + "Max": 100.0 + }, + { + "Name": "IsBrakesWorn", + "TypeRef": "bool" + }, + { + "Name": "IsFluidLevelLow", + "TypeRef": "bool" + }, + { + "Name": "PadWear", + "TypeRef": "uint8_t", + "Max": 100.0 + } + ] + }, + { + "Name": "Tire_If", + "Namespace": "vss::vehicle::chassis::axle::row2::wheel::right", + "DataElements": [ + { + "Name": "IsPressureLow", + "TypeRef": "bool" + }, + { + "Name": "Pressure", + "TypeRef": "uint16_t" + }, + { + "Name": "Temperature", + "TypeRef": "float" + } + ] + }, + { + "Name": "Brake_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "IsDriverEmergencyBrakingDetected", + "TypeRef": "bool" + }, + { + "Name": "PedalPosition", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "ParkingBrake_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "IsAutoApplyEnabled", + "TypeRef": "bool" + }, + { + "Name": "IsEngaged", + "TypeRef": "bool" + } + ] + }, + { + "Name": "SteeringWheel_If", + "Namespace": "vss::vehicle::chassis", + "DataElements": [ + { + "Name": "Angle", + "TypeRef": "int16_t" + }, + { + "Name": "Extension", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + }, + { + "Name": "HeatingCooling", + "TypeRef": "int8_t", + "Min": -100.0, + "Max": 100.0 + }, + { + "Name": "Tilt", + "TypeRef": "uint8_t", + "Min": 0.0, + "Max": 100.0 + } + ] + }, + { + "Name": "DataExchangeInterface", + "Namespace": "demo", + "DataElements": [ + { + "Name": "MyIntValue", + "TypeRef": "int32_t" + } + ], + "Operations": [ + { + "Name": "MyOperation", + "Parameters": [ + { + "Name": "InValue", + "TypeRef": "uint32_t", + "Direction": "IN" + }, + { + "Name": "OutValue", + "TypeRef": "demo::MyStringType", + "Direction": "OUT" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/interfaces.py b/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/interfaces.py new file mode 100644 index 0000000..7929da7 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_553/imported_models/interfaces.py @@ -0,0 +1,178 @@ +import os + +from vaf.vafpy import Executable +from vaf.vafpy.runtime import ( + get_datatype, + get_module_interface, + get_platform_consumer_module, + get_platform_provider_module, + import_model, +) + +script_path = os.path.dirname(os.path.realpath(__file__)) + +import_model(os.path.join(script_path, "Interfaces.json")) + +class Af: + class AdasDemoApp: + class Services: + # Module Interfaces + brake_service = get_module_interface( + "BrakeService", "af::adas_demo_app::services" + ) + image_service = get_module_interface( + "ImageService", "af::adas_demo_app::services" + ) + steering_angle_service = get_module_interface( + "SteeringAngleService", "af::adas_demo_app::services" + ) + velocity_service = get_module_interface( + "VelocityService", "af::adas_demo_app::services" + ) +class Datatypes: + # Vectors + u_int8_vector = get_datatype("UInt8Vector", "datatypes", "Vector") + # Structs + velocity = get_datatype("Velocity", "datatypes", "Struct") + steering_angle = get_datatype("SteeringAngle", "datatypes", "Struct") + brake_pressure = get_datatype("BrakePressure", "datatypes", "Struct") + image = get_datatype("Image", "datatypes", "Struct") +class Demo: + # Strings + my_string_type = get_datatype("MyStringType", "demo", "String") + # Module Interfaces + data_exchange_interface = get_module_interface( + "DataExchangeInterface", "demo" + ) +class Vaf: + # Strings + string = get_datatype("string", "vaf", "String") +class Vss: + # Structs + vehicle = get_datatype("Vehicle", "vss", "Struct") + # Module Interfaces + vehicle_if = get_module_interface( + "Vehicle_If", "vss" + ) + class Vehicle: + # Structs + chassis = get_datatype("Chassis", "vss::vehicle", "Struct") + # Module Interfaces + chassis_if = get_module_interface( + "Chassis_If", "vss::vehicle" + ) + class Chassis: + # Structs + accelerator = get_datatype("Accelerator", "vss::vehicle::chassis", "Struct") + axle = get_datatype("Axle", "vss::vehicle::chassis", "Struct") + brake = get_datatype("Brake", "vss::vehicle::chassis", "Struct") + steering_wheel = get_datatype("SteeringWheel", "vss::vehicle::chassis", "Struct") + parking_brake = get_datatype("ParkingBrake", "vss::vehicle::chassis", "Struct") + # Module Interfaces + accelerator_if = get_module_interface( + "Accelerator_If", "vss::vehicle::chassis" + ) + axle_if = get_module_interface( + "Axle_If", "vss::vehicle::chassis" + ) + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis" + ) + parking_brake_if = get_module_interface( + "ParkingBrake_If", "vss::vehicle::chassis" + ) + steering_wheel_if = get_module_interface( + "SteeringWheel_If", "vss::vehicle::chassis" + ) + class Axle: + # Structs + row1 = get_datatype("Row1", "vss::vehicle::chassis::axle", "Struct") + row2 = get_datatype("Row2", "vss::vehicle::chassis::axle", "Struct") + # Module Interfaces + row1_if = get_module_interface( + "Row1_If", "vss::vehicle::chassis::axle" + ) + row2_if = get_module_interface( + "Row2_If", "vss::vehicle::chassis::axle" + ) + class Row1: + # Structs + wheel = get_datatype("Wheel", "vss::vehicle::chassis::axle::row1", "Struct") + # Module Interfaces + wheel_if = get_module_interface( + "Wheel_If", "vss::vehicle::chassis::axle::row1" + ) + class Wheel: + # Structs + left = get_datatype("Left", "vss::vehicle::chassis::axle::row1::wheel", "Struct") + right = get_datatype("Right", "vss::vehicle::chassis::axle::row1::wheel", "Struct") + # Module Interfaces + left_if = get_module_interface( + "Left_If", "vss::vehicle::chassis::axle::row1::wheel" + ) + right_if = get_module_interface( + "Right_If", "vss::vehicle::chassis::axle::row1::wheel" + ) + class Left: + # Structs + tire = get_datatype("Tire", "vss::vehicle::chassis::axle::row1::wheel::left", "Struct") + brake = get_datatype("Brake", "vss::vehicle::chassis::axle::row1::wheel::left", "Struct") + # Module Interfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row1::wheel::left" + ) + class Right: + # Structs + tire = get_datatype("Tire", "vss::vehicle::chassis::axle::row1::wheel::right", "Struct") + brake = get_datatype("Brake", "vss::vehicle::chassis::axle::row1::wheel::right", "Struct") + # Module Interfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row1::wheel::right" + ) + class Row2: + # Structs + wheel = get_datatype("Wheel", "vss::vehicle::chassis::axle::row2", "Struct") + # Module Interfaces + wheel_if = get_module_interface( + "Wheel_If", "vss::vehicle::chassis::axle::row2" + ) + class Wheel: + # Structs + left = get_datatype("Left", "vss::vehicle::chassis::axle::row2::wheel", "Struct") + right = get_datatype("Right", "vss::vehicle::chassis::axle::row2::wheel", "Struct") + # Module Interfaces + left_if = get_module_interface( + "Left_If", "vss::vehicle::chassis::axle::row2::wheel" + ) + right_if = get_module_interface( + "Right_If", "vss::vehicle::chassis::axle::row2::wheel" + ) + class Left: + # Structs + brake = get_datatype("Brake", "vss::vehicle::chassis::axle::row2::wheel::left", "Struct") + tire = get_datatype("Tire", "vss::vehicle::chassis::axle::row2::wheel::left", "Struct") + # Module Interfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row2::wheel::left" + ) + class Right: + # Structs + tire = get_datatype("Tire", "vss::vehicle::chassis::axle::row2::wheel::right", "Struct") + brake = get_datatype("Brake", "vss::vehicle::chassis::axle::row2::wheel::right", "Struct") + # Module Interfaces + brake_if = get_module_interface( + "Brake_If", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + tire_if = get_module_interface( + "Tire_If", "vss::vehicle::chassis::axle::row2::wheel::right" + ) + diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_553/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_553/model.py new file mode 100644 index 0000000..4c2c294 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_553/model.py @@ -0,0 +1,19 @@ +from pathlib import Path + +from vaf.cli_core.common.utils import ProjectType +from vaf import save_part_of_main_model + +# Import the application module model +import app_module1 + +def export_model(): + script_path = Path(__file__).resolve().parent + save_part_of_main_model( + script_path / "model.json", + ["DataTypeDefinitions", "ModuleInterfaces", "ApplicationModules"], + project_type=ProjectType.APP_MODULE, + cleanup=True, + ) + +if __name__ == "__main__": + export_model() diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_576/model.json b/VAF/tests/unit/vafpy/test_data/ftaf_576/model.json new file mode 100644 index 0000000..399658a --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_576/model.json @@ -0,0 +1,42 @@ +{ + "DataTypeDefinitions": { + "Strings": [ + { + "Name": "string", + "Namespace": "demo" + }, + { + "Name": "string", + "Namespace": "vaf" + } + ] + }, + "ModuleInterfaces": [ + { + "Name": "HelloWorldIf", + "Namespace": "demo", + "DataElements": [ + { + "Name": "Message", + "TypeRef": "demo::string" + }, + { + "Name": "Message_base_string", + "TypeRef": "vaf::string" + } + ], + "Operations": [ + { + "Name": "SetMsgId", + "Parameters": [ + { + "Name": "MsgId", + "TypeRef": "uint8_t", + "Direction": "IN" + } + ] + } + ] + } + ] +} diff --git a/VAF/tests/unit/vafpy/test_data/ftaf_576/model.py b/VAF/tests/unit/vafpy/test_data/ftaf_576/model.py new file mode 100644 index 0000000..56778d6 --- /dev/null +++ b/VAF/tests/unit/vafpy/test_data/ftaf_576/model.py @@ -0,0 +1,21 @@ +from datetime import timedelta +from vaf import vafpy, BaseTypes + +# TODO: Import the CaC support from platform derive or interface import +# from .imported_models import * + +str_type = vafpy.String(name="string", namespace="demo") + +interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo") +interface.add_data_element("Message", datatype=str_type) +interface.add_data_element("Message_base_string", BaseTypes.STRING) +interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T}) + +app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo") + +# Add consumed and provided interfaces using the ApplicationModule API +app_module1.add_provided_interface("HelloWorldProvider", interface) + +periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=500)) +app_module1.add_task(task=periodic_task) + diff --git a/VAF/tests/unit/vafpy/test_example.py b/VAF/tests/unit/vafpy/test_example.py new file mode 100644 index 0000000..2027e1b --- /dev/null +++ b/VAF/tests/unit/vafpy/test_example.py @@ -0,0 +1,331 @@ +""" +Test +""" + +# pylint: disable=missing-class-docstring +# pylint: disable=too-few-public-methods +# pylint: disable=unused-variable +# pylint: disable=missing-function-docstring +# pylint: disable=dangerous-default-value +# pylint: disable=unused-argument +# pylint: disable=too-many-function-args +# pylint: disable=no-value-for-parameter +# pylint: disable=unexpected-keyword-arg + +# mypy: disable-error-code="union-attr, call-arg, arg-type" + +# Ruff: ignore unused variables +# ruff: noqa: F841 +import unittest +from datetime import timedelta + +import pytest + +from vaf import vafmodel, vafpy +from vaf.cli_core.common.utils import create_name_namespace_full_name +from vaf.vafpy.model_runtime import model_runtime + + +class TestMain(unittest.TestCase): + """ + TestMain class + """ + + def __get_type_ref_string(self, typeref: vafmodel.DataTypeRef | vafmodel.ModelElement) -> str: + return create_name_namespace_full_name(typeref.Name, typeref.Namespace) + + def setUp(self) -> None: + """Reset model runtime for each test""" + model_runtime.reset() + + def test_string(self) -> None: + """test string creation""" + vafpy.datatypes.String("FirstString", "test") + r = vafpy.datatypes.String(name="MyString", namespace="test") + assert isinstance(r, vafpy.datatypes.String) + + vafpy.datatypes.String._from_vaf_model(vafmodel.String(Name="Mulligan", Namespace="test")) # pylint:disable=protected-access + + assert len(model_runtime.element_by_namespace["test"]["Strings"]) == 3 + assert model_runtime.element_by_namespace["test"]["Strings"]["FirstString"].Name == "FirstString" + assert model_runtime.element_by_namespace["test"]["Strings"]["MyString"].Name == "MyString" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "FirstString" + assert model_runtime.main_model.DataTypeDefinitions.Strings[1].Name == "MyString" + assert model_runtime.main_model.DataTypeDefinitions.Strings[2].Name == "Mulligan" + + def test_invalid_data_types(self) -> None: + """Test unnamed vector creation""" + # invalid init arguments + with pytest.raises(TypeError): + vafpy.datatypes.String("test", "TestString", vafpy.BaseTypes.UINT16_T, 223, 815) + + # invalid namespace + with pytest.raises(vafpy.core.ModelError): + vafpy.datatypes.String("123test", "TestString") + + # invalid name + with pytest.raises(vafpy.core.ModelError): + vafpy.datatypes.String("aber::comb", "TestString") + vafpy.datatypes.String("aber", "comb::TestString") + + # duplicates + with pytest.raises(vafpy.core.ModelError): + vafpy.datatypes.String("valid", "TestString") + vafpy.datatypes.String("valid", "TestString") + + def test_invalid_vector_array(self) -> None: + """Test unnamed vector creation""" + + # vector doesn't accept sizes + with pytest.raises(TypeError): + vafpy.datatypes.Vector("test", vafpy.BaseTypes.UINT16_T, 223, "TestVector", 815) + + # invalid arguments + with pytest.raises(TypeError): + vafpy.datatypes.Vector( + namespace="test", name="TestVector", datatype=vafpy.BaseTypes.UINT16_T, abrakadabra=815 + ) + + # array with no size + with pytest.raises(TypeError): + vafpy.datatypes.Array(namespace="test", name="TestArray", datatype=vafpy.BaseTypes.UINT16_T) + + # vector and array without name + with pytest.raises(TypeError): + vafpy.datatypes.Array(namespace="test", datatype=vafpy.BaseTypes.UINT16_T, size=2) + with pytest.raises(TypeError): + vafpy.datatypes.Vector(namespace="test", datatype=vafpy.BaseTypes.UINT16_T) + + def test_named_vector(self) -> None: + """Test named vector creation""" + + vafpy.datatypes.Vector(name="MyVector", namespace="test", datatype=vafpy.BaseTypes.UINT16_T) + + assert "TypeRefs" not in model_runtime.element_by_namespace["test"] + self.assertEqual(model_runtime.element_by_namespace["test"]["Vectors"]["MyVector"].Name, "MyVector") + self.assertEqual( + self.__get_type_ref_string(model_runtime.element_by_namespace["test"]["Vectors"]["MyVector"].TypeRef), + "::uint16_t", + ) + assert len(model_runtime.main_model.DataTypeDefinitions.Vectors) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Vectors[0].Name == "MyVector" + assert model_runtime.main_model.DataTypeDefinitions.Vectors[0].TypeRef == vafmodel.DataType( + Name="uint16_t", Namespace="" + ) + + def test_named_vector_in_struct(self) -> None: + """Test named vectors as struct subelement""" + + my_struct = vafpy.datatypes.Struct(name="MyStruct", namespace="test") + my_struct.add_subelement(name="x", datatype=vafpy.BaseTypes.DOUBLE) + + my_vector = vafpy.datatypes.Vector(name="MyVector", namespace="test", datatype=my_struct) + + my_outer_struct = vafpy.datatypes.Struct(name="MyStruct2", namespace="test") + my_outer_struct.add_subelement(name="y", datatype=my_vector) + + self.assertEqual(len(model_runtime.main_model.DataTypeDefinitions.Structs), 2) + self.assertEqual( + self.__get_type_ref_string(model_runtime.main_model.DataTypeDefinitions.Structs[1].SubElements[0].TypeRef), + "test::MyVector", + ) + self.assertEqual(len(model_runtime.main_model.DataTypeDefinitions.Vectors), 1) + self.assertEqual(model_runtime.main_model.DataTypeDefinitions.Vectors[0].Name, "MyVector") + + def test_exe(self) -> None: + """Test creating a simple but complete model""" + + my_interface = vafpy.ModuleInterface(name="MyInterface", namespace="interfaces") + my_interface.add_data_element(name="data_element1", datatype=vafpy.BaseTypes.UINT16_T) + + app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="app_modules") + app_module1.add_provided_interface(instance_name="Instance1", interface=my_interface) + + app_module2 = vafpy.ApplicationModule(name="AppModule2", namespace="app_modules") + app_module2.add_consumed_interface(instance_name="Instance1", interface=my_interface) + + exe = vafpy.Executable("exe", timedelta(milliseconds=10)) + exe.add_application_module(app_module1, []) + exe.add_application_module(app_module2, []) + exe.connect_interfaces(app_module1, "Instance1", app_module2, "Instance1") + + vafpy.runtime.get_main_model() + + def test_complex(self) -> None: + """Test creating a complex and complete model""" + + my_string = vafpy.datatypes.String(name="MyString", namespace="complex") + + my_struct = vafpy.datatypes.Struct(name="MyStruct", namespace="complex") + my_struct.add_subelement(name="a", datatype=my_string) + my_struct.add_subelement(name="b", datatype=vafpy.BaseTypes.BOOL) + + my_vector = vafpy.datatypes.Vector(name="MyVector", namespace="complex1", datatype=my_struct) + my_map = vafpy.datatypes.Map( + name="MyMap", + namespace="complex3", + key_type=vafpy.BaseTypes.UINT16_T, + value_type=vafpy.BaseTypes.DOUBLE, + ) + + my_array = vafpy.datatypes.Array(name="MyArray", namespace="complex2", datatype=my_map, size=100) + + my_type_ref = vafpy.datatypes.TypeRef(name="MyTypeRef", namespace="other", datatype=my_vector) + + my_enum = vafpy.datatypes.Enum(name="MyEnum", namespace="complex") + my_enum.add_entry(label="ABC", value=1) + my_enum.add_entry(label="DEF", value=2) + + my_interface = vafpy.ModuleInterface(name="MyInterface", namespace="inter") + my_interface.add_data_element(name="a", datatype=my_string) + my_interface.add_data_element(name="b", datatype=my_struct) + my_interface.add_data_element(name="c", datatype=my_vector) + my_interface.add_data_element(name="d", datatype=my_map) + my_interface.add_data_element(name="e", datatype=my_array) + my_interface.add_data_element(name="f", datatype=my_type_ref) + my_interface.add_data_element(name="g", datatype=my_enum) + + app1 = vafpy.ApplicationModule(name="App1", namespace="app1") + app1.add_provided_interface(instance_name="Instance1", interface=my_interface) + + app2 = vafpy.ApplicationModule(name="App2", namespace="app2") + app2.add_consumed_interface(instance_name="Instance2", interface=my_interface) + + exe = vafpy.Executable("exe", timedelta(milliseconds=10)) + exe.add_application_module(app1, []) + exe.add_application_module(app2, []) + exe.connect_interfaces(app1, "Instance1", app2, "Instance2") + + def test_operations(self) -> None: + """Test creating operations""" + + my_array = vafpy.datatypes.Array( + name="MyArray", namespace="operations_types", datatype=vafpy.BaseTypes.DOUBLE, size=100 + ) + + my_interface = vafpy.ModuleInterface(name="MyInterface", namespace="interfaces1") + my_interface.add_operation( + name="func1", + in_parameter={"in1": vafpy.BaseTypes.BOOL, "in2": my_array}, + out_parameter={"out1": vafpy.BaseTypes.BOOL, "out2": my_array}, + inout_parameter={"inout1": vafpy.BaseTypes.BOOL, "inout2": my_array}, + ) + my_interface.add_operation(name="func2", out_parameter={"out": vafpy.BaseTypes.BOOL}) + my_interface.add_operation( + name="func3", out_parameter={"out": vafpy.BaseTypes.BOOL}, inout_parameter={"inout": vafpy.BaseTypes.BOOL} + ) + + def test_tasks(self) -> None: + """Test creating tasks and task chains""" + + app = vafpy.ApplicationModule(name="App", namespace="app") + + p_10ms = timedelta(milliseconds=10) + step1 = vafpy.Task(name="Step1", period=p_10ms, preferred_offset=0) + step2 = vafpy.Task(name="Step2", period=p_10ms, preferred_offset=0, run_after=[step1]) + step3 = vafpy.Task(name="Step3", period=p_10ms, preferred_offset=0, run_after=[step1]) + step4 = vafpy.Task(name="Step4", period=p_10ms, preferred_offset=0, run_after=[step1, step2, step3]) + + app.add_task_chain(tasks=[step1]) + app.add_task_chain(tasks=[step2], run_after=[step3]) + app.add_task_chain(tasks=[step4, step3], run_after=[step1], increment_preferred_offset=True) + + def test_vaf_string_base_datatype(self) -> None: + """FTAF-597: Add vaf::string in model is used""" + # datatypes: vector/array/typeref + vafpy.Vector("test", "MacVector", vafpy.BaseTypes.STRING) + + assert isinstance( + model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).get("string", None), vafpy.String + ) + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + vafpy.Array("test", "MaXRay", vafpy.BaseTypes.STRING, 2) + + assert isinstance( + model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).get("string", None), vafpy.String + ) + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + vafpy.TypeRef("test", "T-Rex", vafpy.BaseTypes.STRING) + + assert isinstance( + model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).get("string", None), vafpy.String + ) + vafpy.Array("test", "MaXRay", vafpy.BaseTypes.STRING, 2) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + vafpy.Vector("test", "MacVector", vafpy.BaseTypes.BOOL) + assert model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).get("string", None) is None + assert len(model_runtime.main_model.DataTypeDefinitions.Strings) == 0 + + # struct + model_runtime.reset() + struct = vafpy.Struct(name="MyStruct", namespace="demo") + struct.add_subelement(name="MaStr", datatype=vafpy.BaseTypes.STRING) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + def test_vaf_string_base_module_interface(self) -> None: + """FTAF-597: Add vaf::string in model is used""" + + # module interface + model_runtime.reset() + interface = vafpy.ModuleInterface("Milan", "Inter") + assert model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).get("string", None) is None + assert len(model_runtime.main_model.DataTypeDefinitions.Strings) == 0 + + # via add data elements + interface.add_data_element("Stringulation", vafpy.BaseTypes.STRING) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + interface = vafpy.ModuleInterface("Milan", "Inter") + + # via add operations in + interface.add_operation("inopt", in_parameter={"in_string": vafpy.BaseTypes.STRING}) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + interface = vafpy.ModuleInterface("Milan", "Inter") + + # via add operations out + interface.add_operation("outopt", out_parameter={"out_string": vafpy.BaseTypes.STRING}) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + model_runtime.reset() + interface = vafpy.ModuleInterface("Milan", "Inter") + + # via add operations inout + interface.add_operation("twoway", inout_parameter={"bidirect_string": vafpy.BaseTypes.STRING}) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" + + # full add + model_runtime.reset() + interface = vafpy.ModuleInterface("Milan", "Inter") + interface.add_operation( + "inopt", + in_parameter={"in_string": vafpy.BaseTypes.STRING}, + out_parameter={"out_string": vafpy.BaseTypes.STRING}, + inout_parameter={"bidirect_string": vafpy.BaseTypes.STRING}, + ) + interface.add_data_element("Stringulation", vafpy.BaseTypes.STRING) + assert len(model_runtime.element_by_namespace.get("vaf", {}).get("Strings", {}).keys()) == 1 + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Namespace == "vaf" + assert model_runtime.main_model.DataTypeDefinitions.Strings[0].Name == "string" diff --git a/VAF/tests/unit/vafvssimport/__init__.py b/VAF/tests/unit/vafvssimport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/VAF/tests/unit/vafvssimport/test_data/minimal_vss.json b/VAF/tests/unit/vafvssimport/test_data/minimal_vss.json new file mode 100644 index 0000000..65636fe --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_data/minimal_vss.json @@ -0,0 +1,7 @@ +{ + "Vehicle": { + "children": { }, + "description": "High-level vehicle data.", + "type": "branch" + } +} diff --git a/VAF/tests/unit/vafvssimport/test_export_arrays.py b/VAF/tests/unit/vafvssimport/test_export_arrays.py new file mode 100644 index 0000000..ba8fb92 --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_export_arrays.py @@ -0,0 +1,131 @@ +""" +Unit tests for ensuring that arrays are correctly exported. +""" + +import unittest + +from vaf import vafpy +from vaf.vafvssimport.vss.vss_model import VSS + + +class TestExportArrays(unittest.TestCase): + """Tests the export of arrays from VSS JSON.""" + + def setUp(self) -> None: + """Set up mock data for testing.""" + self.mock_vss_data = { + "SeatConfiguration": { + "children": { + "SeatRowCounts": { + "datatype": "uint8[]", + "description": "Number of seats in each row.", + "arraysize": 5, + "type": "sensor", + }, + "TemperatureLevels": { + "datatype": "float[]", + "description": "Temperature settings for each zone.", + "arraysize": 10, + "type": "sensor", + }, + "DynamicArray": { + "datatype": "int32[]", + "description": "Dynamically sized array example.", + "type": "sensor", + }, + }, + "type": "branch", + } + } + + self.mock_vss_data_duplicates = { + "SeatConfiguration": { + "children": { + "SeatRowCounts": { + "datatype": "float[]", + "description": "Number of seats in each row.", + "arraysize": 5, + "type": "sensor", + }, + "TemperatureLevels": { + "datatype": "float[]", + "description": "Temperature settings for each zone.", + "arraysize": 10, + "type": "sensor", + }, + "DynamicArray": { + "datatype": "int32[]", + "description": "Dynamically sized array example.", + "type": "sensor", + }, + "DuplicateVec": { + "datatype": "int32[]", + "description": "Dynamically sized array example.", + "type": "sensor", + }, + "DuplicateArr": { + "datatype": "float[]", + "description": "Dynamically sized array example.", + "type": "sensor", + "arraysize": 10, + }, + }, + "type": "branch", + } + } + + def test_export_fixed_size_arrays(self) -> None: + """Test that fixed-size arrays are correctly exported.""" + expected_arrays = { + "uint8ArraySize5": {"size": 5, "type": vafpy.BaseTypes.UINT8_T.TypeRef, "passed": False}, + "floatArraySize10": {"size": 10, "type": vafpy.BaseTypes.FLOAT.TypeRef, "passed": False}, + } + expected_vectors = { + "int32Vector": {"type": vafpy.BaseTypes.INT32_T.TypeRef, "passed": False}, + } + + vss_model = VSS(self.mock_vss_data) + derived_model = vss_model.export() + + for array in derived_model.DataTypeDefinitions.Arrays: + self.assertEqual(array.Size, expected_arrays[array.Name]["size"]) + self.assertEqual(array.TypeRef, expected_arrays[array.Name]["type"]) + expected_arrays[array.Name]["passed"] = True + + for vector in derived_model.DataTypeDefinitions.Vectors: + self.assertEqual(vector.TypeRef, expected_vectors[vector.Name]["type"]) + expected_vectors[vector.Name]["passed"] = True + + for key, value in (expected_arrays | expected_vectors).items(): + assert value["passed"], f"Expected element {key} not found" + + def test_export_duplicated_arrays(self) -> None: + """Test that duplicated arrays and vectors are correctly only exported once.""" + expected_arrays = { + "floatArraySize10": {"size": 10, "type": vafpy.BaseTypes.FLOAT.TypeRef, "passed": False}, + "floatArraySize5": {"size": 5, "type": vafpy.BaseTypes.FLOAT.TypeRef, "passed": False}, + } + expected_vectors = { + "int32Vector": {"type": vafpy.BaseTypes.INT32_T.TypeRef, "passed": False}, + } + + vss_model = VSS(self.mock_vss_data_duplicates) + derived_model = vss_model.export() + + for array in derived_model.DataTypeDefinitions.Arrays: + if array.Namespace == "vss": + self.assertEqual(array.Size, expected_arrays[array.Name]["size"]) + self.assertEqual(array.TypeRef, expected_arrays[array.Name]["type"]) + expected_arrays[array.Name]["passed"] = True + + for vector in derived_model.DataTypeDefinitions.Vectors: + if vector.Namespace == "vss": + self.assertEqual(vector.TypeRef, expected_vectors[vector.Name]["type"]) + expected_vectors[vector.Name]["passed"] = True + + for key, value in (expected_arrays | expected_vectors).items(): + assert value["passed"], f"Expected element {key} not found" + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/unit/vafvssimport/test_export_enum.py b/VAF/tests/unit/vafvssimport/test_export_enum.py new file mode 100644 index 0000000..58c18af --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_export_enum.py @@ -0,0 +1,99 @@ +""" +Unit tests for ensuring that string-based enums are correctly created and exported. +""" + +import unittest + +from vaf import vafmodel +from vaf.vafvssimport.vss.vss_model import VSS +from vaf.vafvssimport.vss.vss_types import EnumType + +# pylint: disable=duplicate-code + + +class TestExportStringEnums(unittest.TestCase): + """Tests the creation and export of string-based enums from VSS JSON.""" + + def setUp(self) -> None: + """Set up mock data for testing.""" + self.mock_vss_data = { + "MirrorState": { + "children": { + "Active": { + "datatype": "string", + "allowed": ["NONE", "ACTIVE", "INACTIVE"], + "description": "Mirror state values.", + "type": "actuator", + }, + "Mode": { + "datatype": "string", + "allowed": ["AUTO", "MANUAL"], + "description": "Mirror mode.", + "type": "actuator", + }, + "UnsupportedField": { + "datatype": "float", + "allowed": [1.0, 5.0], + "description": "A non-enum field.", + "type": "sensor", + }, + }, + "type": "branch", + } + } + + def test_create_and_export_enums(self) -> None: + """Test that enums are correctly created and exported.""" + expected_enums = [ + vafmodel.VafEnum( + Name="Active", + Namespace="vss::mirrorstate", + Literals=[ + vafmodel.EnumLiteral(Label="NONE", Value=1), + vafmodel.EnumLiteral(Label="ACTIVE", Value=2), + vafmodel.EnumLiteral(Label="INACTIVE", Value=3), + ], + BaseType=vafmodel.DataType(Name="uint8_t", Namespace=""), + ), + vafmodel.VafEnum( + Name="Mode", + Namespace="vss::mirrorstate", + Literals=[ + vafmodel.EnumLiteral(Label="AUTO", Value=1), + vafmodel.EnumLiteral(Label="MANUAL", Value=2), + ], + BaseType=vafmodel.DataType(Name="uint8_t", Namespace=""), + ), + ] + + vss_model = VSS(self.mock_vss_data) + derived_model = vss_model.export() + + # Assertions for enums + self.assertEqual( + len(derived_model.DataTypeDefinitions.Enums), len(expected_enums) + ) # Only 2 enums created (Active, Mode) + for enum in expected_enums: + self.assertTrue(enum in derived_model.DataTypeDefinitions.Enums, f"Enum {enum.Name} not found") + + def test_export_enum(self) -> None: + """Test the export functionality for enums.""" + enum_type = EnumType(name="Active", namespace="example") + enum_type.add_literal(label="NONE", value=1) + enum_type.add_literal(label="ACTIVE", value=2) + enum_type.add_literal(label="INACTIVE", value=3) + + exported_enum = enum_type.export() + + # Assertions for exported enum + self.assertEqual(exported_enum.Name, "Active") + self.assertEqual(exported_enum.BaseType.Name, "uint8_t") # type: ignore + self.assertEqual(len(exported_enum.Literals), 3) + self.assertEqual(exported_enum.Literals[0].Label, "NONE") + self.assertEqual(exported_enum.Literals[0].Value, 1) + self.assertEqual(exported_enum.Literals[2].Label, "INACTIVE") + self.assertEqual(exported_enum.Literals[2].Value, 3) + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/unit/vafvssimport/test_export_min_max.py b/VAF/tests/unit/vafvssimport/test_export_min_max.py new file mode 100644 index 0000000..562d58d --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_export_min_max.py @@ -0,0 +1,69 @@ +""" +Unit tests for ensuring that min and max values are correctly exported for elements with unit 'percent'. +""" + +import unittest +from typing import Any + +from vaf.vafvssimport.vss.vss_model import VSS + +# pylint: disable=duplicate-code + + +class TestExportMinMaxForPercent(unittest.TestCase): + """Tests the export of min and max values from VSS JSON.""" + + def setUp(self) -> None: + """Set up mock data for testing.""" + self.mock_vss_data = { + "RoadFriction": { + "children": { + "LowerBound": { + "datatype": "float", + "description": "Lower bound road friction", + "max": 100, + "min": 0, + "type": "sensor", + "unit": "percent", + }, + "NonPercentField": { + "datatype": "float", + "description": "A non-percent field", + "max": 55.3, + "min": 0, + "type": "sensor", + }, + "NonLimitField": { + "datatype": "float", + "description": "A field wihtout limits", + "type": "sensor", + }, + }, + "type": "branch", + } + } + + def test_export_with_min_max(self) -> None: + """Test that min and max values for percent-based fields are correctly exported.""" + vss_model = VSS(self.mock_vss_data) + derived_model = vss_model.export() + elements = [element for struct in derived_model.DataTypeDefinitions.Structs for element in struct.SubElements] + + expected_elements: dict[str, Any] = { + "LowerBound": {"min": 0, "max": 100, "passed": False}, + "NonPercentField": {"min": 0, "max": 55.3, "passed": False}, + "NonLimitField": {"min": None, "max": None, "passed": False}, + } + + self.assertEqual(len(elements), len(expected_elements)) + for element in elements: + self.assertEqual(element.Min, expected_elements[element.Name]["min"], f"in subelement {element.Name}") + self.assertEqual(element.Max, expected_elements[element.Name]["max"], f"in subelement {element.Name}") + expected_elements[element.Name]["passed"] = True + + for key, value in expected_elements.items(): + assert value["passed"], f"Expected element {key} not found" + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/unit/vafvssimport/test_export_struct.py b/VAF/tests/unit/vafvssimport/test_export_struct.py new file mode 100644 index 0000000..cddb66f --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_export_struct.py @@ -0,0 +1,147 @@ +""" +Unit tests for ensuring that string-based enums are correctly created and exported. +""" + +import unittest + +from vaf import vafmodel +from vaf.vafvssimport.vss.vss_model import VSS + +# pylint: disable=duplicate-code + + +class TestExportStringEnums(unittest.TestCase): + """Tests the creation and export of string-based enums from VSS JSON.""" + + def setUp(self) -> None: + """Set up mock data for testing.""" + self.mock_vss_data_simple = { + "SeatConfiguration": { + "children": { + "NonPercentField": { + "datatype": "float", + "description": "A non-percent field", + "max": 55.3, + "min": 0, + "type": "sensor", + }, + "NonLimitField": { + "datatype": "float", + "description": "A field wihtout limits", + "type": "sensor", + }, + "Mode": { + "datatype": "string", + "allowed": ["AUTO", "MANUAL"], + "description": "Mirror mode.", + "type": "actuator", + }, + }, + "type": "branch", + } + } + + self.mock_vss_data_nested = { + "SeatConfiguration": { + "children": { + "NonPercentField": { + "datatype": "float", + "description": "A non-percent field", + "max": 55.3, + "min": 0, + "type": "sensor", + }, + "NonLimitField": { + "datatype": "float", + "description": "A field wihtout limits", + "type": "sensor", + }, + "Mode": { + "datatype": "string", + "allowed": ["AUTO", "MANUAL"], + "description": "Mirror mode.", + "type": "actuator", + }, + "Acceleration": { + "children": { + "Lateral": { + "datatype": "float", + "description": "Vehicle acceleration in Y (lateral acceleration).", + "type": "sensor", + "unit": "m/s^2", + }, + "Longitudinal": { + "datatype": "float", + "description": "Vehicle acceleration in X (longitudinal acceleration).", + "type": "sensor", + "unit": "m/s^2", + }, + "Vertical": { + "datatype": "float", + "description": "Vehicle acceleration in Z (vertical acceleration).", + "type": "sensor", + "max": 5.8, + "min": 0, + "unit": "m/s^2", + }, + }, + "description": "Spatial acceleration. Axis definitions according to ISO 8855.", + "type": "branch", + }, + }, + "type": "branch", + } + } + + def test_create_and_export_structs(self) -> None: + """Test that structs are correctly created and exported.""" + + expected_data_elements = { + "NonPercentField": vafmodel.DataType(Name="float", Namespace=""), + "NonLimitField": vafmodel.DataType(Name="float", Namespace=""), + "Mode": vafmodel.DataType(Name="Mode", Namespace="vss::seatconfiguration"), + } + + vss_model = VSS(self.mock_vss_data_simple) + derived_model = vss_model.export() + data_elements = derived_model.ModuleInterfaces[0].DataElements + + # Assertions for data_elements + self.assertEqual(len(data_elements), len(expected_data_elements)) + for de in data_elements: + self.assertEqual(expected_data_elements[de.Name], de.TypeRef) + + def test_create_and_export_nested_structs(self) -> None: + """Test that nested structs are correctly created and exported.""" + + expected_outer_de = { + "NonPercentField": vafmodel.DataType(Name="float", Namespace=""), + "NonLimitField": vafmodel.DataType(Name="float", Namespace=""), + "Mode": vafmodel.DataType(Name="Mode", Namespace="vss::seatconfiguration"), + "Acceleration": vafmodel.DataType(Name="Acceleration", Namespace="vss::seatconfiguration"), + } + + expected_inner_de = { + "Lateral": vafmodel.DataType(Name="float", Namespace=""), + "Longitudinal": vafmodel.DataType(Name="float", Namespace=""), + "Vertical": vafmodel.DataType(Name="float", Namespace=""), + } + + vss_model = VSS(self.mock_vss_data_nested) + derived_model = vss_model.export() + + # Assertions for outer struct + data_elements = derived_model.ModuleInterfaces[0].DataElements + self.assertEqual(len(data_elements), len(expected_outer_de)) + for de in data_elements: + self.assertEqual(expected_outer_de[de.Name], de.TypeRef) + + # Assertions for inner struct + data_elements = derived_model.ModuleInterfaces[1].DataElements + self.assertEqual(len(data_elements), len(expected_inner_de)) + for de in data_elements: + self.assertEqual(expected_inner_de[de.Name], de.TypeRef) + + +if __name__ == "__main__": + unittest.main() diff --git a/VAF/tests/unit/vafvssimport/test_vss_import.py b/VAF/tests/unit/vafvssimport/test_vss_import.py new file mode 100644 index 0000000..9a069e6 --- /dev/null +++ b/VAF/tests/unit/vafvssimport/test_vss_import.py @@ -0,0 +1,24 @@ +""" +example tests +""" + +from pathlib import Path + +from vaf.vafvssimport.vss_import import run_import + +# pylint: disable=too-few-public-methods +# pylint: disable=duplicate-code +# pylint: disable=missing-param-doc +# pylint: disable=missing-type-doc +# mypy: disable-error-code="no-untyped-def" + + +class TestUnit: + """Basic generation test class""" + + def test_run_import(self, tmp_path) -> None: + """Basic test for interface generation""" + + run_import(str(tmp_path), str(Path(__file__).parent / "test_data/minimal_vss.json")) + + assert (tmp_path / "vss-derived-model.json").is_file() diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..09a3acf --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.6.0 \ No newline at end of file -- GitLab