/*! * * 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.h * \author (original) Stephen Quong * \date (original) 24-May-2026 * */ #pragma once #include #include #include #include #include #include #include #include #include #include "AgentInterface.h" #include "AgentMessage.h" #include "CanInterface.h" #include "CanMessage.h" #include "MessageDispatcher.h" using namespace Can; /*! * \brief Real-time CAN to cloud controller * \details Owns the CAN→cloud pipeline. CanInterface receives frames, the * MessageDispatcher reassembles them per CAN id, and completed messages * are converted to protobuf and forwarded to the Connectivity Agent * over the AgentInterface. */ class LeahiRtController : public QObject { Q_OBJECT public: explicit LeahiRtController(const QString &configPath, const QString &msgHandlingPath, QObject *parent = nullptr); ~LeahiRtController(); /*! * \brief connectToAgent * \details Initialises the AgentInterface using the socket path and reconnect * interval from the settings file. */ void connectToAgent(); private: /*! * \brief Send message handling policy for a CAN message. */ enum class MsgAction { Drop, ///< Discard the message; do not forward to the Agent. SendAlways, ///< Forward unconditionally. SendDelta, ///< Forward only when the payload has changed since the last send. }; /*! * \brief Message handling entry loaded from message handling INI. */ struct MsgHandling { MsgAction action = MsgAction::Drop; AgentMessage::MsgId topic = AgentMessage::MsgId::ClinicalData; }; void loadMsgHandling(const QString &msgHandlingPath); QSettings _settings; Can::CanInterface _canInterface; QThread _canThread; Can::MessageDispatcher _dispatcher; QMap> _msgCache; QHash _msgHandling; AgentInterface _agentInterface; QThread _agentThread; quint16 _txSequence = 0; Q_SIGNALS: /*! * \brief didCanMessageReceive * \details Emitted when a complete CAN message has been reassembled. * \param timestamp - time the message was completed * \param msg - the completed message */ void didCanMessageReceive(const QDateTime timestamp, const Can::Message msg); private Q_SLOTS: /*! * \brief onFrameReceive * \details Unpacks a CAN frame and feeds it to the dispatcher for reassembly. * \param frame - the received CAN frame */ void onFrameReceive(const QCanBusFrame frame); /*! * \brief onMessageReceive * \details Applies the message handling policy: drops, forwards unconditionally, * or forwards only on payload change, using the INI-configured topic. * \param msg - the reassembled message */ void onMessageReceive(const Can::Message &msg); /*! * \brief onAgentDisconnect * \details Resets the received flag on all cache entries so that send_delta * messages are treated as new on the next connection. */ void onAgentDisconnect(); };