/*! * * Copyright (c) 2024-2026 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file LeahiRtController.cpp * \author (original) Stephen Quong * \date (original) 24-May-2026 * */ #include #include #include "LeahiRtController.h" #include "LeahiMsgProtoUtils.h" /*! * \brief LeahiRtController::LeahiRtController * \details Constructor. Starts the CAN interface and wires the frame→dispatcher→ * completed-message pipeline. * \param configPath - path to the settings file * \param parent - optional QObject parent */ LeahiRtController::LeahiRtController(const QString &configPath, QObject *parent) : QObject(parent), _settings(configPath, QSettings::IniFormat), _canInterface(), _canThread(this), _dispatcher(this) { _canInterface.init(_canThread); connect(&_canInterface, &Can::CanInterface::didFrameReceive, this, &LeahiRtController::onFrameReceive); connect(&_dispatcher, &Can::MessageDispatcher::didActionReceive, this, &LeahiRtController::onMessageReceive); } /*! * \brief LeahiRtController::~LeahiRtController * \details Destructor. Stops and joins the CAN and Agent worker threads. */ LeahiRtController::~LeahiRtController() { _canThread.quit(); _canThread.wait(); _agentThread.quit(); _agentThread.wait(); } /*! * \brief LeahiRtController::connectToAgent * \details Initialises the AgentInterface using the socket path and reconnect * interval from the settings file. */ void LeahiRtController::connectToAgent() { const QString socketPath = _settings.value("Socket/LocalSocketName", "/tmp/leahi_rt.sock").toString(); const int reconnectIntervalMs = _settings.value("Socket/ReconnectIntervalMs", 5000).toInt(); _agentInterface.init(socketPath, reconnectIntervalMs, _agentThread); } /*! * \brief LeahiRtController::onFrameReceive * \details Unpacks a CAN frame and feeds it to the dispatcher, which reassembles * multi-frame messages per CAN id. * \param frame - the received CAN frame */ void LeahiRtController::onFrameReceive(const QCanBusFrame frame) { _dispatcher.onFrameReceive(Can::CanId(frame.frameId()), frame.payload()); } /*! * \brief LeahiRtController::onMessageReceive * \details Converts a fully reassembled message to protobuf and forwards it to * the Agent. * \param msg - the reassembled message */ void LeahiRtController::onMessageReceive(const Can::Message &msg) { Can::Message &cachedMsg = _msgCache[msg.msgId]; qDebug().noquote() << QString("Received message with MsgId=0x%1").arg(QString("%1").arg(msg.msgId, 4, 16, QChar('0')).toUpper()); // only send the message if the data is different // SQ if (cachedMsg.data != msg.data) { // SQ if (msg.msgId == leahi::MSG_ID_TD_OP_MODE_DATA) { const QByteArray payload = leahi::canMessageToProtobufByteArray( QDateTime::currentDateTime(), QStringLiteral("test_device"), msg); _agentInterface.send(AgentMessage::MsgId::ClinicalData, _txSequence++, payload); // SQ } // SQ } cachedMsg = msg; msg.dump(); }