/**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the QtIvi module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage ** Licensees holding valid commercial Qt Automotive Suite licenses may use ** this file in accordance with the commercial license agreement provided ** with the Software or, alternatively, in accordance with the terms ** contained in a written agreement between you and The Qt Company. For ** licensing terms and conditions see https://www.qt.io/terms-conditions. ** For further information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page simulation-system.html \title Qt IVI Simulation System \previouspage Qt IVI Query Language When you develop new APIs, a service that the API requires may not exist yet. This is because, the API is already designed but the service itself is still being developed. For example, with new concepts like Autonomous Driving, the UI interaction and its API are designed, but the Autonomous Drive Service is not yet completed. This development cycle requires the need to separate the API developemnt from the service. The \l{Dynamic Backend System} provides the architecture to enable this separation. Once we have this separation in place, the next step for devleoping the API is a way to simulate its behavior to mirror the original service. The Qt IVI Simulation System enables the following use cases: \list \li An easy to define simulation logic in QML \li A flexible system to provide simulation for any C++ API \li A clear split between simulation data and simulation logic \li An override mechanism to change the simulation at runtime; useful for autotests \li An integration with the IVIGenerator tools \endlist \section1 Architecture Since the simulation system builds on top of the \l{Dynamic Backend System}, the API split follows the same schema: \image feature-backend.png "Relationship between the Feature and the Backend" Each backend plugin needs to implement the backend interface to provide the necessary functionality to the frontend. For example, the QIviClimateControlBackendInterface class for the QIviClimateControl frontend API. In the backend, every call from the frontend is forwarded to QML, where we can script a simulation behavior. \image simulation-system.png "QtIvi Simulation System" \section1 QML API The core of the Qt IVI Simulation System is the QIviSimulationEngine. This engine extends QQmlApplicationEngine and provides the extra functionality to connect C++ and QML logic together. Each backend uses its own simulation engine to separate the frontend code from the backend QML code. To provide a binding between QML and C++ objects, the C++ instance must be registered with the QIviSimulationEngine under a certain name. For each registered C++ instance, the engine creates a proxy object and exposes it as a QML type. These QML types can be used to provide the behavior for functions or to update properties. For example, suppose your feature has a function called \c increment() and a property called \c counter. The actual behavior for \c increment() is implemented in the backend: \code void increment() { counter++; } \endcode When we autogenerate classes, the actual bevhavior of \c increment() cannot be autogenerated, because there's no way to tell the autogenerator the kind of behavior this function should have. To define this behavior, you need to implement a complete backend in C++. The QIviSimulationEngine makes this task more flexible, as it forwards all of the C++ calls to QML, allowing you to use QML to define the behavior, via scripting. Consequently, you can override the behavior and also script a default behavior without touching any of the C++ code. For more information on working with the simulation engine, see \l{QIviSimulationEngine}. \section1 Separate Data from Logic The simulation system makes it possible to separate the simulation business logic from the simulation data. The simulation data is stored in JSON files, for the QIviSimulationEngine::loadSimulationData() function to load. Once the simulation data is loaded, the IviSimulator global object provides the content to all QML simulation files. For example, you can use the IviSimulator::findData function to read the data for a specific interface only: \qml property var settings : IviSimulator.findData(IviSimulator.simulationData, "QIviClimateControl") \endqml \section2 Boundary Checks The IviSimulator global object also provides functions to make boundary checks easier. The property boundaries are defined in the JSON files, while the QML code stays generic, to work with multiple different boundary checks: \qml function setAirConditioningEnabled(airConditioningEnabled) { if (IviSimulator.checkSettings(airConditioningEnabled, settings["airConditioningEnabled"])) { console.log("SIMULATION airConditioningEnabled changed to: " + airConditioningEnabled); backend.airConditioningEnabled = airConditioningEnabled } else { setError("SIMULATION changing airConditioningEnabled is not possible: provided: " + airConditioningEnabled + " constraint: " + IviSimulator.constraint_string(settings["airConditioningEnabled"])); } } \endqml Use the IviSimulator::checkSettings() function to check the specified \e airConditioningEnabled value against the boundaries defined in the JSON file. If the value is within the boundaries, then it is updated; otherwise an error is returned together with the constraint in a human-readable form. For more information about simulation and the data format, see \l{IviSimulator}. \section1 Override Mechanism For app development or unit testing, it is often useful to trigger a certain behavior in the backend. For example, when implementing message boxes for error recovery, the app developer may need a way to easily trigger this exact error condition. Suppose that the simulation behavior provided by the backend developer, for this use case, is not be sufficient. In this case, the Qt IVI Simulation System provides an override system to load your own simulation behavior file or data file, via an environment variable. Each QIviSimulationEngine can have an additional identifier to override the default behavior file or data file, using the following environment variables: \badcode QTIVI_SIMULATION_OVERRIDE==[;=] QTIVI_SIMULATION_DATA_OVERRIDE==[;=] \endcode \section1 Integrate with IVIGenerator The simulation system is already integrated into the IVIGenerator tools and it is used automatically when generating code with the \l{Backend Simulator}{backend_simulator} format. The autogenerated plugin uses the QFace module name as the QIviSimulationEngine identifier, to allow overriding at runtime. All boundary annotations defined in \l{config_simulator_default}{config_simulator} are then transformed into a JSON file, and embedded as a resource file into the backend. For each interface, a QML simulation file is created, providing a default implementation to check the boundaries of each property. \section2 Define Your Own Simulation Files It's not always convenient to use the autogenerated QML simulation files. You can also define your own QML file by using the \l{config_simulator_simulationFile}{simulationFile annotation}. \note If your QFace file provides multiple interfaces, the corresponding simulation file must provide a simulation for all of these interfaces. To reuse the autogenerated simulation files from an existing interface as a starting point, you can load these autogenerated simulation files using a QML import statement: \qml import 'qrc:/simulation/' \endqml Afterwards you should be able to load your modified simulation files like a regular QML file. */