Skip to content
Snippets Groups Projects
Commit 7c074c1f authored by Constantin Christmann's avatar Constantin Christmann
Browse files

Upload of initial contribution from Vector.

parent 6403a38a
No related branches found
No related tags found
No related merge requests found
Showing
with 10399 additions and 0 deletions
/*!********************************************************************************************************************
* 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
# 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:
![vss](../figures/vss.drawio.svg)
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
```
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,
)
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)
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)
This diff is collapsed.
/*!********************************************************************************************************************
* 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
/*!********************************************************************************************************************
* 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
<?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="&lt;mxfile host=&quot;Electron&quot; agent=&quot;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&quot; version=&quot;26.2.2&quot;&gt;&#10; &lt;diagram id=&quot;qchfyPlCbnvhXIaJ2EZ1&quot; name=&quot;Page-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;624&quot; dy=&quot;567&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;827&quot; pageHeight=&quot;1169&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;2&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 14px;&amp;quot;&amp;gt;HelloVaf&amp;amp;nbsp;&amp;lt;/font&amp;gt;&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;dashed=1;align=right;verticalAlign=top;spacingRight=3;spacing=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;80&quot; y=&quot;160&quot; width=&quot;280&quot; height=&quot;110&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;35&quot; value=&quot;&quot; style=&quot;edgeStyle=none;html=1;endArrow=none;endFill=0;&quot; parent=&quot;1&quot; source=&quot;34&quot; target=&quot;4&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;36&quot; value=&quot;&quot; style=&quot;edgeStyle=none;html=1;endArrow=none;endFill=0;&quot; parent=&quot;1&quot; source=&quot;34&quot; target=&quot;3&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;34&quot; value=&quot;&quot; style=&quot;shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=0;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;210&quot; y=&quot;212&quot; width=&quot;20&quot; height=&quot;20&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;n_8MEDxsc1R7JmpyKjgA-36&quot; value=&quot;&quot; style=&quot;endArrow=none;dashed=1;html=1;strokeWidth=1;rounded=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;370&quot; y=&quot;170&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;410&quot; y=&quot;160&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;410&quot; y=&quot;160&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;n_8MEDxsc1R7JmpyKjgA-37&quot; value=&quot;Executable&quot; style=&quot;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;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;410&quot; y=&quot;145&quot; width=&quot;80&quot; height=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;3&quot; value=&quot;AppModule1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;99&quot; y=&quot;192&quot; width=&quot;90&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;4&quot; value=&quot;AppModule2&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;250&quot; y=&quot;192&quot; width=&quot;90&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;/root&gt;&#10; &lt;/mxGraphModel&gt;&#10; &lt;/diagram&gt;&#10;&lt;/mxfile&gt;&#10;"><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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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
This diff is collapsed.
Demo/figures/vscode-remote-window.png

4.49 KiB

Demo/figures/vscode-reopen-container.png

18.6 KiB

<?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="&lt;mxfile host=&quot;Electron&quot; agent=&quot;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&quot; version=&quot;26.2.2&quot;&gt;&#10; &lt;diagram id=&quot;qchfyPlCbnvhXIaJ2EZ1&quot; name=&quot;Page-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;437&quot; dy=&quot;397&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;827&quot; pageHeight=&quot;1169&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;2&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 14px;&amp;quot;&amp;gt;DemoExecutable&amp;amp;nbsp;&amp;lt;/font&amp;gt;&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;dashed=1;align=right;verticalAlign=top;spacing=1;spacingRight=3;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;80&quot; y=&quot;154&quot; width=&quot;290&quot; height=&quot;115&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;3&quot; value=&quot;VssProvider&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;100&quot; y=&quot;190&quot; width=&quot;90&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;4&quot; value=&quot;VssConsumer&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#4195C9;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;250&quot; y=&quot;190&quot; width=&quot;100&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;35&quot; value=&quot;&quot; style=&quot;edgeStyle=none;html=1;endArrow=none;endFill=0;&quot; parent=&quot;1&quot; source=&quot;34&quot; target=&quot;4&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;36&quot; value=&quot;&quot; style=&quot;edgeStyle=none;html=1;endArrow=none;endFill=0;&quot; parent=&quot;1&quot; source=&quot;34&quot; target=&quot;3&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;34&quot; value=&quot;&quot; style=&quot;shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;strokeColor=#000000;rotation=0;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;210&quot; y=&quot;210&quot; width=&quot;20&quot; height=&quot;20&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;/root&gt;&#10; &lt;/mxGraphModel&gt;&#10; &lt;/diagram&gt;&#10;&lt;/mxfile&gt;&#10;"><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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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: &quot;Helvetica&quot;; 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="&quot;Helvetica&quot;" 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
# 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/
**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.
# 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.
**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.
# 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>
# 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>
# 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.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment