C
Monitor: Verifying the Rendering Output
// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial // This file is part of the Qt Safe Renderer module #include <QThread> #include <QDebug> #include <signal.h> #include <string.h> #include <QtSafeRenderer/qsafeglobal.h> // We must use the SafeRenderer namespace here because // the Monitor library is written in C, and its types // are implemented without a namespace. using namespace SafeRenderer; extern "C" { #include <QtSafeRenderer/qsafeglobal.h> #include <QtSafeMonitor/message.h> #include <QtSafeMonitor/eventProcessor.h> #include <QtSafeMonitor/errorcode.h> #include <QtSafeMonitor/message.h> #include <QtSafeMonitor/endian.h> #include <QtSafeMonitor/qsafechecksum.h> #include <QtSafeMonitor/crccache.h> #include <QtSafeMonitor/monitorconfig.h> #include "controller.h" #include "sendevent.h" #include "goldencrccalculator.h" } #define MONITOR_MSG_BUF_SIZE 128U static volatile sig_atomic_t g_running = 1; static quint32 g_errorCalled = 0; static void ctrlCHandler(qint32 receivedSignal) { if (receivedSignal == SIGINT) { g_running = 0; } else { /* Nothing */ } } static void defaultErrorHandler(ErrorCode errorType, qint64 arg1, qint64 arg2) { static qchar msgBuf[MONITOR_MSG_BUF_SIZE]; g_errorCalled = 1U; showInfoPanelOnError(1, msgBuf, sizeof(msgBuf)); qWarning() << "Error:" << errorCodeToString(errorType); qWarning() << "Error arguments:" << arg1 << "," << arg2; } static void requestOutpuVerificationUpdate(qchar *msgBuf, const size_t len, errorFunc errorHandler) { for (quint32 i = 0; i < itemsCount(); i++) { const quint32 itemId = getItemIdAtIndex(i); if (getEventOutputVerificationVerifyItem(itemId, msgBuf, len) != NULL) { if (sendEvent(msgBuf, len) < 0) { errorHandler(FailedToSendRequest, 0, __LINE__); break; } } } } static qint32 verifyEventOutput(qchar *msgBuf, const size_t len, errorFunc errorHandler) { qint32 ret = -1; qchar replyBuffer[MONITOR_MSG_BUF_SIZE]; getEventOutputVerificationRequest(msgBuf, len); // Send the event and then receive a reply. Use sendEventWithReply for this. if (sendEventWithReply(msgBuf, len, msgBuf, len) == 0) { // Successful reply received. ret = processEvent(msgBuf, len, errorHandler); } else { errorHandler(FailedToReceiveMessage, (qint64)ret, __LINE__); } return ret; } static void monitorLoop(void) { qchar msgBuf[MONITOR_MSG_BUF_SIZE]; qint32 ret = 0; quint32 speedTextExpectedCRC = 0U; const quint32 speedTextItemId = qsafe_hash("safetextitem", strlen("safetextitem")); /* Read the layout for mirroring */ SafeLayoutHandle layoutHandle = qsrCreateLayoutFromResource("/layoutData/MainForm/MainForm.ui.srl"); GoldenCrcCalculatorHandle crcCalculator = qsrGoldenCrcCalculatorCreate(layoutHandle); while (g_running > 0) { g_errorCalled = 0U; // Request renderer to read the CRC values of static items requestOutpuVerificationUpdate(msgBuf, sizeof(msgBuf), &defaultErrorHandler); // Request renderer to read the dynamic text getEventOutputVerificationVerifyItem(speedTextItemId, msgBuf, MONITOR_MSG_BUF_SIZE); sendEvent(msgBuf, MONITOR_MSG_BUF_SIZE); // Wait for to VSync period to settle QThread::msleep(100); // Read back the actual CRC values from renderer do { ret = verifyEventOutput(msgBuf, sizeof(msgBuf), &defaultErrorHandler); } while (ret > 0); // Tick the simulator to change the states advanceState(msgBuf, sizeof(msgBuf), &defaultErrorHandler); // Calculate the dynamic text Golden CRC value const qchar* speedTextStr = getCurrentSpeedText(); qsrSetTextForItem(speedTextItemId, speedTextStr, layoutHandle); qsrCalculateItemCrc(crcCalculator, speedTextItemId, 0U, &speedTextExpectedCRC); // Set the CRC value to cache crcCache_setCRC(speedTextItemId, speedTextExpectedCRC); // Delay to have 100 msec loop QThread::msleep(100); // Clear the info panel if errors are cleared if (g_errorCalled == 0U) { showInfoPanelOnError(0, msgBuf, sizeof(msgBuf)); } } } qint32 main(qint32 argc, char *argv[]) { qint32 c = 0; qint32 ret = 0; if (signal(SIGINT, &ctrlCHandler) == SIG_ERR) { ret = 3; } else { monitorLoop(); } return ret; }