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;
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[])
{
(void)argc;
(void)argv;
qint32 ret = 0;
if (signal(SIGINT, &ctrlCHandler) == SIG_ERR) {
ret = 3;
} else {
monitorLoop();
}
return ret;
}