/*! * * Copyright (c) 2020-2024 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 MessageDispatcher.h * \author (last) Dara Navaei * \date (last) 06-May-2024 * \author (original) Behrouz NematiPour * \date (original) 26-Aug-2020 * */ #pragma once // Qt #include // Project #include "main.h" // Doxygen : do not remove #include "MessageBuilder.h" #include "MessageInterpreter.h" // define #define _MessageDispatcher Can::MessageDispatcher::I() // forward declarations class tst_canbus; class tst_acknow; class tst_messaging; // since this class is the interface between GUI and Can // it needs to use Gui namespace otherwise it makes code hard to read. using namespace Gui; namespace Can { /*! * \brief The MessageDispatcher class \n * \details Message Dispatcher is the class which is the mediator between CanBus Frames \n * and Application Messages. \n * The massages and frames need to be interpreted form/to hex \n * and also need to be split into frames or constructor from frames to be a message. \n * ---------------------------------------------------------------------------------------- \n * \n * Interpreter : message [ toHex , fromHex] \n * \n * Builder : message [ toFrame , fromFrame ] \n * \n * Dispatcher : signal->Handler( .. frame .. ) \n * \n * Handler : signal->Dispatcher( .. frame .. ) \n * \n * ---------------------------------------------------------------------------------------- \n * \n * *** UI <-> AppController <-> Dispatcher <-> Handler <-> HD *** \n * \n * ---------------------------------------------------------------------------------------- \n * \n * UI -> message -> \n * AppController { \n * signal->Dispatcher ( .. message .. ) \n * } \n * \n * Dispatcher { \n * .. \n * messageList[ch][frameList] += Builder.toFrame ( Interpreter.toHex ( message ) ) \n * .. \n * signal->Handler( .. frame .. ) \n * } \n * \n * ---------------------------------------------------------------------------------------- \n * \n * HD -> frame -> \n * Handler { \n * signal->Dispatcher ( .. frame .. ) \n * } \n * \n * Dispatcher { \n * messageList[ch][frameList] += Interpreter.fromHex( frame ) \n * isComplete => Builder.fromFrame( frameList ) : signal->AppController \n * } \n * \n * ---------------------------------------------------------------------------------------- \n */ class MessageDispatcher : public QObject { Q_OBJECT // Singleton SINGLETON(MessageDispatcher) // friends friend class ::tst_canbus; friend class ::tst_acknow; friend class ::tst_messaging; QHash _messageList; Sequence _txSequence = 0; Sequence _rxSequence = 0; MessageBuilder _builder; MessageInterpreter _interpreter; QThread *_thread = nullptr; bool _init = false; // List of the transmit(request) only, messages which require acknowledge back(AckBack). QList _needsAcknow { // FIXME: check this on device first. It is not working with dialin. GuiActionType::ID_TDCheckIn , // CONFIRM GuiActionType::ID_DuetConfirmUIr , // POST GuiActionType::ID_UIPostFinalResultData , // Alarm GuiActionType::ID_AlarmUserActionReq , GuiActionType::ID_AlarmSilenceReq , GuiActionType::ID_AlarmActiveListReq , GuiActionType::ID_AlarmVolumeSetReq , // Pre-Treatment GuiActionType::ID_AdjustInitTreatmentReq , GuiActionType::ID_AdjustWaterSampleReq , GuiActionType::ID_AdjustWaterSampleResultReq , GuiActionType::ID_AdjustConsumablesConfirmReq , GuiActionType::ID_AdjustDisposablesConfirmReq , GuiActionType::ID_AdjustDisposablesPrimeReq , GuiActionType::ID_AdjustPatientConnectionBeginReq , GuiActionType::ID_AdjustUltrafiltrationInitReq , GuiActionType::ID_AdjustPatientConnectionConfirmReq , GuiActionType::ID_AdjustStartTreatmentReq , // In-Treatment GuiActionType::ID_AdjustBloodDialysateReq , GuiActionType::ID_AdjustDurationReq , GuiActionType::ID_AdjustUltrafiltrationStateReq , GuiActionType::ID_AdjustUltrafiltrationEditReq , GuiActionType::ID_AdjustUltrafiltrationConfirmReq , GuiActionType::ID_AdjustSalineReq , GuiActionType::ID_AdjustHeparinReq , GuiActionType::ID_AdjustPressuresLimitsReq , // End-Treatment GuiActionType::ID_AdjustRinsebackReq , GuiActionType::ID_AdjustRecirculateReq , GuiActionType::ID_AdjustTreatmentEndReq , // Post-Treatment GuiActionType::ID_AdjustPatientDisconnectNotifyReq , GuiActionType::ID_AdjustPatientDisconnectConfirmReq , GuiActionType::ID_AdjustDisposablesRemovalConfirmReq , // Disinfect GuiActionType::ID_AdjustDisinfectModeReq , GuiActionType::ID_AdjustDisinfectStartReq , // DG Cleaning GuiActionType::ID_AdjustDGCleaningUsageReq , // Settings GuiActionType::ID_AdjustServiceModeReq , GuiActionType::ID_AdjustVersionsUIReq , GuiActionType::ID_AdjustVersionsUIRsp , GuiActionType::ID_AdjustServiceDatesReq , GuiActionType::ID_AdjustHDDateTimeReq , GuiActionType::ID_AdjustDGDateTimeReq , GuiActionType::ID_HDUsageInfoReq , GuiActionType::ID_AdjustInstitutionalRecordReq , // Treatment Log GuiActionType::ID_AdjustTreatmentLogReq , GuiActionType::ID_TreatmentLogAvrgeData , GuiActionType::ID_TreatmentLogAlarmData , GuiActionType::ID_TreatmentLogEventData , // HD reset request in service mode GuiActionType::ID_ResetHDInServiceModeReq , }; public slots: bool init(); bool init(QThread &vThread); void quit(); public: void enableConsoleOut(bool vEnable) { _builder.enableConsoleOut(vEnable); } private: void initConnections(); void initThread(QThread &vThread); void quitThread(); void actionTransmit (GuiActionType vActionId, const QVariantList &vData, Sequence vSequence = 0, Can_Id vCanId = Can::Can_Id::eChlid_UI_TD); void framesTransmit (Can_Id vCan_Id, const FrameList &vFrameList); bool needsAcknow (GuiActionType vActionId); bool needsAcknow (Can_Id vCan_Id); bool buildMessage (Can_Id vCan_Id, const QByteArray &vPayload); bool interpretMessage(const Message &vMessage); Sequence txCount(); Sequence rxCount(); bool checkAcknowReceived(const Message &vMessage, const QString &vSrcText); bool checkAcknowTransmit(const Message &vMessage, const QString &vSrcText); signals: /*! * \brief didActionReceive * \details When a message received over the CANBus this signal is emitted * on successful collecting all required payloads from different frames if any * and successfully has been built into a message and can be interpreted * \param vAction - The action has been extracted from CANBus message header to be done * \param vData - The data has been collected from CANBus frame(s) */ void didActionReceive (GuiActionType vAction , const QVariantList &vData); /*! * \brief didActionReceive * \details Emits when a message requires * \param vData */ void didActionReceive (const Message &vMessage); /*! * \brief didAcknowReceive * \details if the type the received message id is and Acknow this signal will be emitted * \param vData - the data of the Acknow message which is the message Sequence * which we got the Ack for. */ void didAcknowReceive (Sequence vSequence); /*! * \brief didAcknowTransmit * \details this signal will be emitted when the message which has been sent * needs Acknowledge back. * \param vFrameList - the frames which has been send * and will be used to be send on retries. */ void didAcknowTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); /*! * \brief didFrameTransmit * \details When a message is requested to be transmitted this signal is emitted * on successful interpretation and building the message into frames * \param vCan_Id - Target channel of the CANBus message * \param vPayload - The payload of the message to be sent */ void didFrameTransmit (Can_Id vCan_Id, const QByteArray &vPayload); /*! * \brief didFailedTransmit * \details When a message fails to transmit to the HD, emit this signal. * \param vSequence - The message Sequence we that failed to send. */ void didFailedTransmit(Sequence vSequence); private slots: // A Frame has been received from CanInterface void onFrameReceive (Can_Id vCan_Id, const QByteArray &vPayload); // void onFramesTransmit (Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); void onFailedTransmit ( Sequence vSequence); // An Action has been requested to be transmitted. void onActionTransmit (GuiActionType vActionId, const QVariantList &vData); void onSettingsDone (); // ---- Signal/Slots ADJUST_TRANSMT_MODEL_BRIDGE_DEFINITIONS_NOEMIT ACTION_RECEIVE_MODEL_BRIDGE_DEFINITIONS ACTION_RECEIVE_PRIVATE_SLOT(UIPostFinalResultHDRequestData) }; }