C

Telltales: Rendering Safety-Critical UI

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial

// This file is part of the Qt Safe Renderer module
/*
Purpose of this example is to enable development of Qt Safe Renderer
in desktop environment (Windows and Linux).

Note that this example is NOT implemented according Misra C++ 2008 nor ISO26262
functional safety standards and it depends on Qt classes.

You should not use this example in production environment.
*/
#include <QtSafeRenderer/qsafelayout.h>
#include <QtSafeRenderer/qsafelayoutresourcereader.h>
#include <QtSafeRenderer/statemanager.h>
#include <QtSafeRenderer/qsafechecksum.h>
#include <QGuiApplication>

#if defined(USE_OUTPUTVERIFIER)
#include <outputverifier.h>
#endif

#include "safewindow.h"
#include <QtSafeEventHandlerAdaptation/eventhandler.h>

using namespace SafeRenderer;

class CustomEventFilter : public QSafeEventFilter {
public:
    CustomEventFilter(EventHandler* eventHandler) : m_eventHandlerPtr(eventHandler) {}

    // Don't use the ackReplyHandled so that the runtime handles ack reply for this message
    bool handleEvent(const QSafeEvent &event, [[maybe_unused]] bool *ackReplyHandled = nullptr) override {
        bool eventHandled = false;
        // Handle EventHeartbeatTimeout event
        if (m_eventHandlerPtr != nullptr && EventId::EventHeartbeatTimeout == event.getEventId()) {
            eventHandled = true;
            QSafeEventHeartbeatTimeout timeout(event);
            bool showNotif = timeout.getValue();
            //Show or hide the error notification.
            QSafeEventVisibility notification;
            notification.setItemId(qsafe_hash_string("safeText"));
            notification.setValue(showNotif);
            m_eventHandlerPtr->processEvent(notification);
        }
        return eventHandled;
    }

private:
    EventHandler *m_eventHandlerPtr = nullptr;
};

static void hideIcons(StateManager &stateManager, QSafeLayout &layout)
{
    for (quint32 i=0; i<layout.count(); i++) {
        if (layout.item(i).id() == qsafe_hash_string("speedText") ) {
            continue;
        } else if (layout.item(i).id() == qsafe_hash_string("turnleft") ||
                   layout.item(i).id() == qsafe_hash_string("turnright") ) {
            QSafeEventChangeState changeState;
            changeState.setItemId(layout.item(i).id());
            changeState.setStateId(qsafe_hash_string("hidden"));
            stateManager.handleEvent(changeState);
        } else {
            QSafeEventVisibility hideItem;
            hideItem.setItemId(layout.item(i).id());
            hideItem.setValue(0U);
            stateManager.handleEvent(hideItem);
        }
    }
}

int main(int argc, char **argv)
{
#ifdef HOST_BUILD
    // In host build when using QtGUI, we need to initialize QApplication before SafeWindow.
    QGuiApplication app(argc, argv);
#endif

    static QSafeLayoutResourceReader hybrid;
    hybrid.readLayout("/layoutData/DashboardForm/DashboardForm.ui.srl");
    static QSafeLayoutResourceReader sport;
    sport.readLayout("/layoutData/DashboardSportForm/DashboardSportForm.ui.srl");

    hybrid.setLayoutId(qsafe_hash_string("hybrid"));
    sport.setLayoutId(qsafe_hash_string("sport"));

    SafeWindow telltaleWindow(hybrid.size(), QSafePoint(0U, 0U));

    static StateManager stateManager(telltaleWindow, hybrid);
    stateManager.addLayout(&sport);
    hideIcons(stateManager, hybrid);
    telltaleWindow.requestUpdate();

#if defined(USE_OUTPUTVERIFIER)
    EventHandler msgHandler(stateManager, telltaleWindow, outputVerifier);
#else
    EventHandler msgHandler(stateManager, telltaleWindow);
#endif

    CustomEventFilter customEventFilter(&msgHandler);
    msgHandler.installSafeEventFilter(&customEventFilter);
    msgHandler.handleEvents();

    return 0;
}