The Qt IVI Attribute System

In the IVI world a system often needs to support a lot of different car configurations. These configurations could vary in display sizes and resolutions are used or the actual hardware changes to a e.g. less powerful cpu and less memory to software configurations where certain features are disabled, as well as simply disabling features via software.

Most of the configurations are actually hardware related, while the ECU and UI software still stay the same. Something along these lines would be an example on what configurations an IVI system may need to support:

Example Configurations

Low

  • Display Resolution: 1280x768
  • CPU: Single-Core 1 GB memory
  • Other Hardware:
  • 2 Zone Climate Control
  • Air conditioning system
  • Bluetooth Media Streaming

Medium

  • Display Resolution: 1920x1080
  • CPU: Dual-Core 1 GB memory
  • Other Hardware:
  • 3 Zone Climate Control
  • Electric Window Opener
  • Automatic Air conditioning system
  • Bluetooth Media Streaming
  • Wifi (client)

High

  • Display Resolution: 1920x1080
  • CPU: Quad-Core 2 GB memory
  • Other Hardware:
  • Massage Seats
  • 5 Zone Climate Control
  • Electric Window Opener
  • Window Heater
  • Window Sun Blinds
  • 2 RSE systems
  • Automatic Air conditioning system
  • Automatic Air Quality System
  • Bluetooth Media Streaming
  • Wifi (host and client)
  • Companion App

QtIVI tries to provide an API which can cope with the all these configurations, thus requiring a lot of flexibility. This is the reason the Attribute System was created: the Attribute System is mainly used for Vehicle Function APIs as there is no common ground in this area and whether a specific feature is supported or not varies a lot.

The heart of the attribute system is the QIviProperty. This class defines a special property of a given type, which can be controlled using a QIviPropertyAttribute. The QIviPropertyAttribute defines whether the property is available in the current configuration as well as its value boundaries. Such an attribute can support the following scenarios:

  • The property is not available.
  • The property is available and the values can be between a minimum and a maximum value.
  • The property is available and only specific values from a given list are supported.

The QIviPropertyAttribute is mainly used by the backend implementation to inform the QIvi Feature about the availability of a certain property, its underlying functionality and its expected value range. Usually the range doesn't change between different car configurations but different OEM backend implementations may even result in range changes.

In QIviClimateControl attributes are used for every property. The backend can do the following to state its capabilities:

// The zone synchronization is not supported
zoneSynchronizationAttribute = QIviPropertyAttribute<bool>(false);

// The air recirculation is off
airRecirculation = false;
// The air recirculation is supported by the system. No minimum and maximum values are needed for an bool
airRecirculationAttribute = QIviPropertyAttribute<bool>(true);

// The seat cooler is set to the intensity 10
seatCooler = 10;
// The seat cooler is supported by the system and the minimum and maximum values are set to 0 and 10
seatCoolerAttribute = QIviPropertyAttribute<int>(0, 10);

// The current air flow direction is to the Floor
airflowDirection = QIviClimateControl::Floor;
// The system supports multiple air flows and all valid configurations are passed
QVector<QIviClimateControl::AirflowDirections> airflow { (QIviClimateControl::Floor | QIviClimateControl::Dashboard), QIviClimateControl::Floor, QIviClimateControl::Dashboard };
airflowDirectionAttribute = QIviPropertyAttribute<QIviClimateControl::AirflowDirections>(airflow));

Because the actual value for each property is changed more often than its attribute, these two values are separated from each other. To make this still convenient to use within Qt's meta-type system the QIviProperty class was created: QIviProperty is a convenience class which lets you access the value and the attribute in an easy and type-safe way. The following snippet shows how a QIviProperty is used within a class.

class SimpleControl : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QIviProperty *temperature READ temperatureProperty CONSTANT)

    SimpleControl(QObject *parent = nullptr);
    ~SimpleControl();

    int temperature() const;
    QIviPropertyAttribute<int> temperatureAttribute() const;
    QIviProperty *temperatureProperty() const;

public slots:
    void setTemperature(int temperature);

signals:
    void temperatureChanged(int temperature);
    void temperatureAttributeChanged(const QIviPropertyAttribute<int> &attribute);
}

SimpleControl has a property to get and set the temperature. The setter and getter for the property work like any other setter/getter in C++ and also have a corresponding changed signal. In addition a QIviPropertyAttribute for the property is also provided with a getter and a changed signal. Usually the attribute is defined by the backend and thus no setter is available. To use the features of the QIviProperty, it is registered as a constant Qt property using the Q_PROPERTY and in addition a getter function is provided.

This split makes it possible to use the class from C++ without any hurdles:

SimpleControl *control = new SimpleControl();
// Create a SpinBox and enable it only if the system supports reading/writing the temperature
QSpinBox *spinBox = new QSpinBox();
spinBox->setEnabled(control->temperatureAttribute()->isAvailable());
// Also setup the minimum and maximum of the SpinBox according to the values defined by the backend
spinBox->setMinimum(control->temperatureAttribute()->minimumValue());
spinBox->setMaximum(control->temperatureAttribute()->maximumValue());
connect(spinBox, &QSpinBox::valueChanged, control, &SimpleControl::setTemperature);

See the climate_widget example for a complete example.

From QML this is done using the QIviProperty directly:

import QtQuick 2.0
import QtQuick.Controls 1.4

Item {
    width: 200
    height: 200

    SimpleControl {
        id: simpleControl
    }

    SpinBox {
        value: simpleControl.temperature.value
        minimumValue: simpleControl.temperature.minimumValue
        maximumValue: simpleControl.temperature.maximumValue
        enabled: simpleControl.temperature.available
        onValueChanged: {
            simpleControl.temperature.value = value
        }
    }
}

The SpinBox is connected to the value property of temperature using a binding. The binding will be updated once the value changes. This is handled by the QIviProperty property by telling it which signal to relay. For the temperature property, the SimpleControl::temperatureChanged signal is forwarded to temperature.valueChanged. See the climate_qml example for a complete example.

In the implementation of the SimpleControl class, the QIviProperty needs to be setup correctly. The QIviProperty doesn't store any values and is simply forwarding the function calls and signal emissions to the corresponding functionality of the SimpleControl class.

TemperatureProperty = QIviPropertyFactory<int>::create(q,
                                                       &SimpleControl::temperatureAttribute,
                                                       &SimpleControl::temperatureAttributeChanged,
                                                       &SimpleControl::temperature,
                                                       &SimpleControl::temperatureChanged,
                                                       &SimpleControl::setTemperature);

Read-only properties are supported as well, by simply not providing the last argument (pointer to the setter function).

© 2018 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.