C
Qt Quick Ultralite instrument_cluster Example
Demonstrates how to control user interface elements from a C application.
Overview
This example demonstrates how to control user interface elements from a C application.

Target platforms
Project structure
The instrument_cluster example consists of the following files:
src/VehicleStatus.cppsrc/VehicleStatus.hCMakeLists.txtmcu_instrument_cluster.qmlprojectinstrument_cluster.qml
The CMake project file contains a basic build script, instrument_cluster.qml which defines the application's UI. The project configuration is defined in mcu_instrument_cluster.qmlproject.
In addition to these files, the src/simulation folder contains a simple simulator to provide input data for the instrument cluster on non-AUTOSAR platforms:
src/simulation/baremetal/main.cppsrc/simulation/freertos/main.cppsrc/simulator.cppsrc/simulator.h
The fonts folder contains the font files of the application:
fonts/TitilliumWeb-Light.ttffonts/TitilliumWeb-SemiBold.ttf
CMake project file
Note: Simulation files are added only for non-AUTOSAR targets.
cmake_minimum_required (VERSION 3.21.1)
project(instrument_cluster VERSION 0.0.1 LANGUAGES C CXX ASM)
if (NOT TARGET Qul::Core)
    find_package(Qul)
endif()
set(TARGET_SOURCES src/VehicleStatus.cpp)
set(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(GENERATE_ENTRYPOINT_ARG "")
if(NOT QUL_PLATFORM MATCHES "autosar")
    set(SIMULATOR_DIR src/simulation)
    set(TARGET_SOURCES
        ${TARGET_SOURCES}
        ${SIMULATOR_DIR}/simulator.cpp
        ${SIMULATOR_DIR}/${QUL_OS_LOWERCASE}/main.cpp
    )
    set(INCLUDE_DIRECTORIES
        ${INCLUDE_DIRECTORIES}
        ${CMAKE_CURRENT_SOURCE_DIR}/src/simulation
    )
else()
    set(GENERATE_ENTRYPOINT_ARG GENERATE_ENTRYPOINT)
endif()
qul_add_target(instrument_cluster
    ${TARGET_SOURCES}
    QML_PROJECT mcu_instrument_cluster.qmlproject
    ${GENERATE_ENTRYPOINT_ARG}
)
app_target_setup_os(instrument_cluster)
target_include_directories(instrument_cluster PRIVATE
    ${INCLUDE_DIRECTORIES}
)
if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
    add_custom_command(TARGET instrument_cluster
        COMMAND strip instrument_cluster -o instrument_cluster.stripped
        DEPENDS instrument_cluster)
endif()QmlProject file
import QmlProject 1.3
Project {
    mainFile: "instrument_cluster.qml"
    MCU.Config {
        defaultFontFamily: "Titillium Web"
    }
    FontFiles {
        files: [
            "fonts/TitilliumWeb-Light.ttf",
            "fonts/TitilliumWeb-SemiBold.ttf"
        ]
    }
    QmlFiles {
        files: [
            "instrument_cluster.qml"
        ]
    }
    InterfaceFiles {
        files: ["src/VehicleStatus.h"]
    }
}VehicleStatus singleton
The VehicleStatus singleton is responsible for storing the vehicle parameters for the user interface. It inherits from Qul::Singleton to expose the public signals and properties to QML. It also inherits from Qul::EventQueue to provide an event queue to trigger user interface update when the property values are changed.
    ...
    Qul::Property<int> speed;
    Qul::Property<double> tripMeter;
    Qul::Signal<void(bool leftBlinkerState)> leftBlinkerStateChange;
    Qul::Signal<void(bool rightBlinkerState)> rightBlinkerStateChange;
    ...The QML code accesses these values via VehicleStatus singleton:
    ...
    Text {
        id: speedometer
        color: "#2CDE85"
        anchors.centerIn: parent
        font.weight: Font.DemiBold
        font.pixelSize: 90
        text: VehicleStatus.speed
    }
    ...The repainting of the instrument cluster is triggered by using a dummy event queue. Event handling requires Qt Quick Ultralite engine to do an update.
... void qul_application_send_value_change_event() { VehicleStatus::instance().postEvent(true); } ...
The actual event handler does nothing:
    ...
    void onEvent(const bool &value)
    {
        // Dummy event queue to trigger UI updates
        (void) value;
    }
    ...C linkage functions are exposed to the non-GUI code to control instrument cluster content:
... extern "C" { void qul_application_set_speed(int speed) { VehicleStatus::instance().speed.setValue(speed); } ...
AUTOSAR example
In an AUTOSAR project, the Qt Quick Ultralite Complex Device Driver calls the C linkage APIs as shown below:
#include "VehicleStatus.h"
...
// QUL Complex Device Driver Runnable with a periodic trigger
void Cdd_Qul_Update(void)
{
    int changedValuesCount = 0;
    static int previousSpeed = 0;
    int speed;
    // Read the speed value via the AUTOSAR Interface
    // Rte_Read_Cdd_Qul_Speed(&speed);
    if (speed != previousSpeed) {
        changedValuesCount++;
        qul_application_set_speed(speed);
        previousSpeed = speed;
    }
    ...
    if (changedValuesCount > 0) {
        // Send an event to trigger repainting of the UI
        qul_application_send_value_change_event();
    }
    qul_update_engine(); // Calls Qul::Application::update()
}Files:
- instrument_cluster/CMakeLists.txt
 - instrument_cluster/instrument_cluster.qml
 - instrument_cluster/mcu_instrument_cluster.qmlproject
 - instrument_cluster/src/VehicleStatus.cpp
 - instrument_cluster/src/VehicleStatus.h
 - instrument_cluster/src/simulation/baremetal/main.cpp
 - instrument_cluster/src/simulation/simulator.cpp
 - instrument_cluster/src/simulation/simulator.h
 
See also Integrating C++ code with QML.
Available under certain Qt licenses.
Find out more.