C
Event Sender: Sending Messages to Applications
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
// This file is part of the Qt Safe Renderer module
#include <QHostAddress>
#include <QSettings>
#include <QTimer>
#include <QProcess>
#include <QNetworkInterface>
#include "tcpdatacontrol.h"
#include <QtSafeRenderer/qsafestring.h>
TCPDataControl::TCPDataControl(QObject *parent)
: DataControlInterface(parent)
{
const QString items[] = {
"turnleft",
"turnright",
"iconCoolant",
"iconFuel",
"iconParkingBrake",
"iconTyre",
"iconBattery",
"iconSeatbelt",
"iconLamp",
"iconLowBeam"
};
for (const QString& item : items) {
m_stringList.append(item);
}
// Connect the stateChanged signal of sockets to the ConnectionStateChanged slots
connect(&m_telltalesSocket, &QAbstractSocket::stateChanged, this, &TCPDataControl::onTelltalesConnectionStateChanged);
connect(&m_tcpSocket, &QAbstractSocket::stateChanged, this, &TCPDataControl::onClusterConnectionStateChanged);
}
bool TCPDataControl::checkConnection(const QString &ip, int port)
{
QTcpSocket testSocket;
testSocket.connectToHost(ip, port);
if (testSocket.waitForConnected(3000)) {
testSocket.disconnectFromHost();
return true;
}
return false;
}
TCPDataControl::~TCPDataControl()
{
m_tcpSocket.close();
m_telltalesSocket.close();
}
void TCPDataControl::establishConnection(const QStringList &ips, int port)
{
// Get environment variables for IP and port
QString envIp = QString::fromLocal8Bit(qgetenv("QT_SAFERENDER_HOST"));
int envPort = QString::fromLocal8Bit(qgetenv("QT_SAFERENDER_PORT")).toInt();
// Use the environment port if set, otherwise use the provided port
int finalPort = (envPort == 0) ? port : envPort;
// Check if the port is valid before entering the loop
if (finalPort != TELLTALES_HOST_PORT && finalPort != TELLTALES_TARGET_PORT && finalPort != CLUSTER_PORT) {
qInfo() << "Invalid port. Use one of the following:";
qInfo() << "Telltales on host environment:" << TELLTALES_HOST_PORT;
qInfo() << "Telltales on target device:" << TELLTALES_TARGET_PORT;
qInfo() << "Qt Cluster:" << CLUSTER_PORT;
return;
}
// Iterate over the list of IP addresses
for (const auto &ip : ips) {
// Use the environment IP if set, otherwise use the current IP from the list
QString finalIp = envIp.isEmpty() ? ip : envIp;
// Check if the port is for Telltales
if (finalPort == TELLTALES_HOST_PORT || finalPort == TELLTALES_TARGET_PORT) {
m_telltalesService = "Telltales";
// Check if the IP is for a host environment
if (isHostEnvironment(finalIp)) {
finalPort = TELLTALES_HOST_PORT;
} else {
finalPort = TELLTALES_TARGET_PORT;
}
// Check if already connected
if (m_telltalesSocket.state() == QAbstractSocket::ConnectedState) {
qInfo() << "Already connected to" << finalIp << ":" << finalPort;
break;
}
// Attempt to establish a connection
if (!checkConnection(finalIp, finalPort)) {
qWarning() << "Failed to connect to" << finalIp << ":" << finalPort;
continue;
} else {
qInfo() << "Connected to" << finalIp << ":" << finalPort;
}
m_telltalesSocket.connectToHost(finalIp, finalPort);
emit telltalesRunningServiceChanged(m_telltalesService);
} else if (finalPort == CLUSTER_PORT) {
m_clusterService = "Cluster";
// Check if already connected
if (m_tcpSocket.state() == QAbstractSocket::ConnectedState) {
qInfo() << "Already connected to" << finalIp << ":" << finalPort;
break;
}
// Attempt to establish a connection
if (!checkConnection(finalIp, finalPort)) {
qWarning() << "Failed to connect to" << finalIp << ":" << finalPort;
continue;
} else {
qInfo() << "Connected to" << finalIp << ":" << finalPort;
}
m_tcpSocket.connectToHost(finalIp, finalPort);
emit clusterRunningServiceChanged(m_clusterService);
}
}
}
void TCPDataControl::onTelltalesConnectionStateChanged(QAbstractSocket::SocketState socketState)
{
ConnectionState connectionState = Disconnected;
if (socketState == QAbstractSocket::UnconnectedState) {
connectionState = Disconnected;
setConnectionBool(false);
} else if (socketState == QAbstractSocket::ConnectedState) {
connectionState = Connected;
setConnectionBool(true);
} else if (socketState == QAbstractSocket::ConnectingState) {
connectionState = Connecting;
}
emit telltalesConnectionStateChanged(connectionState);
}
void TCPDataControl::onClusterConnectionStateChanged(QAbstractSocket::SocketState socketState)
{
ConnectionState connectionState = Disconnected;
if (socketState == QAbstractSocket::UnconnectedState) {
connectionState = Disconnected;
} else if (socketState == QAbstractSocket::ConnectedState) {
connectionState = Connected;
setConnectionBool(true);
} else if (socketState == QAbstractSocket::ConnectingState) {
connectionState = Connecting;
}
emit clusterConnectionStateChanged(connectionState);
}
bool TCPDataControl::isHostEnvironment(const QString &ip) const
{
// Check if the IP is explicitly 127.0.0.1 or localhost
if (ip == "127.0.0.1" || ip == "localhost") {
return true;
}
const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
// Iterate through each network interface and check if the
// given IP matches any of the interface's IP addresses
for (const QNetworkInterface &interface : interfaces) {
const QList<QNetworkAddressEntry> entries = interface.addressEntries();
for (const QNetworkAddressEntry &entry : entries) {
if (entry.ip().toString() == ip) {
return true;
}
}
}
// Return false if no match was found
return false;
}
TCPDataControl::ConnectionState TCPDataControl::mapSocketState(QAbstractSocket::SocketState socketState)
{
switch (socketState) {
case QAbstractSocket::UnconnectedState:
// If the socket is not connected, return 'Disconnected'
return TCPDataControl::Disconnected;
case QAbstractSocket::HostLookupState:
case QAbstractSocket::ConnectingState:
// If the socket is looking up the host or connecting, return 'Connecting'
return TCPDataControl::Connecting;
case QAbstractSocket::ConnectedState:
// If the socket is connected, return 'Connected'
return TCPDataControl::Connected;
default:
// As default, return 'Disconnected'
return TCPDataControl::Disconnected;
}
}
TCPDataControl::ConnectionState TCPDataControl::telltalesConnectionState() const
{
return mapSocketState(m_telltalesSocket.state());
}
TCPDataControl::ConnectionState TCPDataControl::clusterConnectionState() const
{
return mapSocketState(m_tcpSocket.state());
}
void TCPDataControl::setAddress(const QString &ip, int port)
{
if (ip.isEmpty()) {
return;
}
if (ip != m_address) {
m_address = ip;
}
if (port != m_port) {
m_port = port;
}
}
void TCPDataControl::handleTcpError(QAbstractSocket::SocketError socketError)
{
Q_UNUSED(socketError);
qWarning() << "TCP Error:" << m_tcpSocket.errorString();
}
int TCPDataControl::carId() const
{
return m_carId;
}
bool TCPDataControl::headLight() const
{
return m_headLight;
}
bool TCPDataControl::parkLight() const
{
return m_parkLight;
}
bool TCPDataControl::rightTurnLight() const
{
return m_rightTurnLight;
}
bool TCPDataControl::leftTurnLight() const
{
return m_leftTurnLight;
}
int TCPDataControl::gear() const
{
return m_gear;
}
bool TCPDataControl::lightFailure() const
{
return m_lightFailure;
}
bool TCPDataControl::frontLeftDoorOpen() const
{
return m_frontLeftDoorOpen;
}
bool TCPDataControl::frontRightDoorOpen() const
{
return m_frontRightDoorOpen;
}
bool TCPDataControl::rearLeftDoorOpen() const
{
return m_rearLeftDoorOpen;
}
bool TCPDataControl::rearRightDoorOpen() const
{
return m_rearRightDoorOpen;
}
bool TCPDataControl::hoodOpen() const
{
return m_hoodOpen;
}
bool TCPDataControl::trunkOpen() const
{
return m_trunkOpen;
}
bool TCPDataControl::flatTire() const
{
return m_flatTire;
}
double TCPDataControl::direction() const
{
return m_direction;
}
double TCPDataControl::longitude() const
{
return m_longitude;
}
double TCPDataControl::latitude() const
{
return m_latitude;
}
double TCPDataControl::vehicleSpeed() const
{
return m_vehicleSpeed;
}
bool TCPDataControl::hazardSignal() const
{
return m_hazardSignal;
}
bool TCPDataControl::brake() const
{
return m_brake;
}
double TCPDataControl::oilTemp() const
{
return m_oilTemp;
}
int TCPDataControl::oilPressure() const
{
return m_oilPressure;
}
double TCPDataControl::batteryPotential() const
{
return m_batteryPotential;
}
double TCPDataControl::gasLevel() const
{
return m_gasLevel;
}
int TCPDataControl::rpm() const
{
return m_rpm;
}
int TCPDataControl::engineTemp() const
{
return m_engineTemp;
}
bool TCPDataControl::crashArg() const
{
return m_crash;
}
bool TCPDataControl::connectionBool() const {
return m_connection;
}
void TCPDataControl::setVehicleSpeed(double vehicleSpeed)
{
if (m_vehicleSpeed == vehicleSpeed) {
return;
}
QString msg("vehicleSpeed:" + QString::number(vehicleSpeed) + " ");
write(msg.toLatin1());
m_vehicleSpeed = vehicleSpeed;
emit vehicleSpeedChanged(vehicleSpeed);
}
void TCPDataControl::setLatitude(double latitude)
{
if (m_latitude == latitude) {
return;
}
QString msg("latitude:" + QString::number(latitude) + " ");
write(msg.toLatin1(), msg.length());
m_latitude = latitude;
emit latitudeChanged(latitude);
}
void TCPDataControl::setLongitude(double longitude)
{
if (m_longitude == longitude) {
return;
}
QString msg("longitude:" + QString::number(longitude) + " ");
write(msg.toLatin1());
m_longitude = longitude;
emit longitudeChanged(longitude);
}
void TCPDataControl::setDirection(double direction)
{
if (m_direction == direction) {
return;
}
QString msg("direction:" + QString::number(direction) + " ");
write(msg.toLatin1());
m_direction = direction;
emit directionChanged(direction);
}
void TCPDataControl::setFlatTire(bool flatTire)
{
if (m_flatTire == flatTire) {
return;
}
QString msg("flatTire:" + QString::number(flatTire) + " ");
write(msg.toLatin1());
m_flatTire = flatTire;
emit flatTireChanged(flatTire);
}
void TCPDataControl::setFrontLeftDoorOpen(bool doorOpen)
{
if (m_frontLeftDoorOpen == doorOpen) {
return;
}
QString msg("frontLeftDoorOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_frontLeftDoorOpen = doorOpen;
emit frontLeftDoorOpenChanged(doorOpen);
}
void TCPDataControl::setFrontRightDoorOpen(bool doorOpen)
{
if (m_frontRightDoorOpen == doorOpen) {
return;
}
QString msg("frontRightDoorOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_frontRightDoorOpen = doorOpen;
emit frontRightDoorOpenChanged(doorOpen);
}
void TCPDataControl::setRearLeftDoorOpen(bool doorOpen)
{
if (m_rearLeftDoorOpen == doorOpen) {
return;
}
QString msg("rearLeftDoorOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_rearLeftDoorOpen = doorOpen;
emit rearLeftDoorOpenChanged(doorOpen);
}
void TCPDataControl::setHoodOpen(bool doorOpen)
{
if (m_hoodOpen == doorOpen) {
return;
}
QString msg("hoodOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_hoodOpen = doorOpen;
emit hoodOpenChanged(doorOpen);
}
void TCPDataControl::setTrunkOpen(bool doorOpen)
{
if (m_trunkOpen == doorOpen) {
return;
}
QString msg("trunkOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_trunkOpen = doorOpen;
emit rearRightDoorOpenChanged(doorOpen);
}
void TCPDataControl::setRearRightDoorOpen(bool doorOpen)
{
if (m_rearRightDoorOpen == doorOpen) {
return;
}
QString msg("rearRightDoorOpen:" + QString::number(doorOpen) + " ");
write(msg.toLatin1());
m_rearRightDoorOpen = doorOpen;
emit rearRightDoorOpenChanged(doorOpen);
}
void TCPDataControl::setLightFailure(bool lightFailure)
{
if (m_lightFailure == lightFailure) {
return;
}
QString msg("lightFailure:" + QString::number(lightFailure) + " ");
write(msg.toLatin1());
m_lightFailure = lightFailure;
emit lightFailureChanged(lightFailure);
}
void TCPDataControl::setGear(int gear)
{
if (m_gear == gear) {
return;
}
QString msg("gear:" + QString::number(gear) + " ");
write(msg.toLatin1());
m_gear = gear;
emit gearChanged(gear);
}
void TCPDataControl::setLeftTurnLight(bool leftTurnLight)
{
if (m_leftTurnLight == leftTurnLight) {
return;
}
QString msg("leftTurnLight:" + QString::number(leftTurnLight) + " ");
write(msg.toLatin1());
m_leftTurnLight = leftTurnLight;
emit leftTurnLightChanged(leftTurnLight);
}
void TCPDataControl::setRightTurnLight(bool rightTurnLight)
{
if (m_rightTurnLight == rightTurnLight) {
return;
}
QString msg("rightTurnLight:" + QString::number(rightTurnLight) + " ");
write(msg.toLatin1());
m_rightTurnLight = rightTurnLight;
emit rightTurnLightChanged(rightTurnLight);
}
void TCPDataControl::setHeadLight(bool headLight)
{
if (m_headLight == headLight) {
return;
}
QString msg("headLight:" + QString::number(headLight) + " ");
write(msg.toLatin1());
m_headLight = headLight;
emit headLightChanged(headLight);
}
void TCPDataControl::setParkLight(bool parkLight)
{
if (m_parkLight == parkLight) {
return;
}
QString msg("parkLight:" + QString::number(parkLight) + " ");
write(msg.toLatin1());
m_parkLight = parkLight;
emit parkLightChanged(parkLight);
}
void TCPDataControl::setCarId(int carId)
{
if (m_carId == carId) {
return;
}
QString msg("carId:" + QString::number(carId) + " ");
write(msg.toLatin1());
m_carId = carId;
emit carIdChanged(carId);
}
void TCPDataControl::setHazardSignal(bool hazardSignal)
{
if (m_hazardSignal == hazardSignal) {
return;
}
QString msg("hazardSignal:" + QString::number(hazardSignal) + " ");
write(msg.toLatin1());
m_hazardSignal = hazardSignal;
emit hazardSignalChanged(hazardSignal);
}
void TCPDataControl::setBrake(bool brake)
{
if (m_brake == brake) {
return;
}
QString msg("brake:" + QString::number(brake) + " ");
write(msg.toLatin1());
m_brake = brake;
emit brakeChanged(brake);
}
void TCPDataControl::setOilTemp(double oilTemp)
{
if (m_oilTemp == oilTemp) {
return;
}
QString msg("oilTemp:" + QString::number(oilTemp) + " ");
write(msg.toLatin1());
m_oilTemp = oilTemp;
emit oilTempChanged(oilTemp);
}
void TCPDataControl::setOilPressure(int oilPressure)
{
if (m_oilPressure == oilPressure) {
return;
}
QString msg("oilPressure:" + QString::number(oilPressure) + " ");
write(msg.toLatin1());
m_oilPressure = oilPressure;
emit oilPressureChanged(oilPressure);
}
void TCPDataControl::setBatteryPotential(double batteryPotential)
{
if (m_batteryPotential == batteryPotential) {
return;
}
QString msg("batteryPotential:" + QString::number(batteryPotential) + " ");
write(msg.toLatin1());
m_batteryPotential = batteryPotential;
emit batteryPotentialChanged(batteryPotential);
}
void TCPDataControl::setGasLevel(double gasLevel)
{
if (m_gasLevel == gasLevel) {
return;
}
QString msg("gasLevel:" + QString::number(gasLevel) + " ");
write(msg.toLatin1());
m_gasLevel = gasLevel;
emit gasLevelChanged(gasLevel);
}
void TCPDataControl::setRpm(int rpm)
{
if (m_rpm == rpm) {
return;
}
QString msg("rpm:" + QString::number(rpm) + " ");
write(msg.toLatin1());
m_rpm = rpm;
emit rpmChanged(rpm);
}
void TCPDataControl::setEngineTemp(int engineTemp)
{
if (m_engineTemp == engineTemp) {
return;
}
QString msg("engineTemp:" + QString::number(engineTemp) + " ");
write(msg.toLatin1());
m_engineTemp = engineTemp;
emit engineTempChanged(engineTemp);
}
void TCPDataControl::setCrash(bool crashArg)
{
if (m_crash == crashArg) {
return;
}
QString msg("crash:" + QString::number(crashArg) + " ");
write(msg.toLatin1());
m_crash = crashArg;
emit crashChanged(crashArg);
m_crash = false;
}
void TCPDataControl::write(const char *data, qint64 length)
{
if ((m_tcpSocket.state() == QTcpSocket::ConnectedState)) {
m_tcpSocket.write(data, length);
}
}
void TCPDataControl::write(const char *data)
{
if ((m_tcpSocket.state() == QTcpSocket::ConnectedState)) {
m_tcpSocket.write(data);
}
}
void TCPDataControl::setConnectionBool(bool b)
{
m_connection = b;
emit myConnectionChanged();
}
QVariantList TCPDataControl::getStringList() const
{
return m_stringList;
}
QString TCPDataControl::telltalesHostPort() const
{
return QString::number(TELLTALES_HOST_PORT);
}
QString TCPDataControl::clusterPort() const
{
return QString::number(CLUSTER_PORT);
}