/*! * * 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.cpp * \author (last) Behrouz NematiPour * \date (last) 31-Jul-2024 * \author (original) Behrouz NematiPour * \date (original) 26-Aug-2020 * */ #include "MessageDispatcher.h" // Qt #include #include // Project #include "Logger.h" #include "ApplicationController.h" #include "FrameInterface.h" #include "MessageAcknowModel.h" //#define DEBUG_ACKBACK_HD_TO_UI //#define DEBUG_OUT_OF_SYNC using namespace Can; /*! * \brief MessageDispatcher::MessageDispatcher * \details Constructor * \param parent - QObject parent owner object. * Qt handles the children destruction by their parent objects life-cycle. */ MessageDispatcher::MessageDispatcher(QObject *parent) : QObject(parent) { } /*! * \brief Message Handler initializer */ bool MessageDispatcher::init() { if ( _init ) return false; _init = true; // runs in the thread initConnections(); LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } /*! * \brief MessageDispatcher::init * \details Initialized the Class by calling the init() method first * And initializes the thread vThread by calling initThread * on success init(). * \param vThread - the thread * \return returns the return value of the init() method */ bool MessageDispatcher::init(QThread &vThread) { if ( ! init() ) return false; initThread(vThread); return true; } /*! * \brief MessageDispatcher::quit * \details quits the class * Calls quitThread */ void MessageDispatcher::quit() { quitThread(); // validated } /*! * \brief Message Handler connections definition * \details Initializes the required signal/slot connection between this class and other objects * to be able to communicate. */ void MessageDispatcher::initConnections() { // From GUI connect(&_ApplicationController, SIGNAL(didActionTransmit(GuiActionType , const QVariantList &)), this , SLOT( onActionTransmit(GuiActionType , const QVariantList &))); // From HD connect(&_FrameInterface , SIGNAL(didFrameReceive (Can_Id , const QByteArray &)), this , SLOT( onFrameReceive (Can_Id , const QByteArray &))); // From Message Acknow Model timer timeout. connect(&_MessageAcknowModel , SIGNAL(didFramesTransmit(Can_Id, Sequence, const FrameList &)), this , SLOT( onFramesTransmit(Can_Id, Sequence, const FrameList &))); connect(&_MessageAcknowModel , SIGNAL(didFailedTransmit( Sequence )), this , SLOT( onFailedTransmit( Sequence ))); // Application Settings are ready connect(&_ApplicationController, SIGNAL(didSettingsDone ()), this , SLOT( onSettingsDone ())); // ---- Signal/Slots ADJUST_TRANSMT_MODEL_BRIDGE_CONNECTIONS(_ApplicationController) ACTION_RECEIVE_MODEL_BRIDGE_CONNECTIONS(_interpreter ) } /*! * \brief ApplicationController::initThread * \details Moves this object into the thread vThread. * And checks that this method is called from main thread. * Also connects quitThread to application aboutToQuit. * \param vThread - the thread */ void MessageDispatcher::initThread(QThread &vThread) { // runs in main thread Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread" ); _thread = &vThread; _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); moveToThread(_thread); _thread->start(); } /*! * \brief MessageDispatcher::quitThread * \details Moves this object to main thread to be handled by QApplication * And to be destroyed there. */ void MessageDispatcher::quitThread() { if ( ! _thread ) return; // runs in thread moveToThread(qApp->thread()); // validated } /*! * \brief MessageDispatcher::onFrameReceive * \details Upon message has been received over CANBus this slot will be called * by FrameInterface::didFrameReceive signal to process the frame * Upon completion of collected all the required frames * on successful interpretation of the message, emits didActionReceived signal. * The message will be removed from list of the channel vCan_Id messages. * \param vCan_Id - CANBus channel of the frame * \param vPayload - Payload of the frame */ void MessageDispatcher::onFrameReceive(Can_Id vCan_Id, const QByteArray &vPayload) { // Append a message to the list // because if the list is empty there is no last() item if (_messageList[vCan_Id].isEmpty() || _messageList[vCan_Id].last().isComplete()) { _messageList[vCan_Id].append(Message()); } // build the message and check. if (! buildMessage(vCan_Id, vPayload)) { return; } Message mMessage = _messageList[vCan_Id].last(); // TODO : must be moved to a MessageModel class if (mMessage.isComplete()) { rxCount(); #ifdef DEBUG_OUT_OF_SYNC if (_rxSequence != mMessage.sequence) { qDebug() << tr("Out of Sync : %1 , %2").arg(_rxSequence).arg(mMessage.sequence); } #endif interpretMessage(mMessage); } } /*! * \brief MessageDispatcher::onFramesTransmit * \details this slots calls the framesTransmit to emit the didFrameTransmit signal * to queue the frame(s) to be sent * \param vSequence - sequence of the message which is going to be resent. (not used) * \param vFrameList - frame(s) to be sent */ void MessageDispatcher::onFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) { Q_UNUSED(vSequence) framesTransmit(vCan_Id, vFrameList); } /*! * \brief MessageDispatcher::onFailedTransmit * \details the slot which will be called on transmit failed on MessageAcknowModel * \param vSequence */ void MessageDispatcher::onFailedTransmit(Sequence vSequence) { emit didFailedTransmit(vSequence); } /*! * \brief MessageDispatcher::onActionTransmit * \details This slot will be called by ApplicationController::didActionTransmit * upon UI message transmit request and calls MessageDispatcher::actionTransmit method. * \param vActionId - The ActionID of the message * \param vData - The data of the Message */ void MessageDispatcher::onActionTransmit(GuiActionType vActionId, const QVariantList &vData) { actionTransmit(vActionId, vData); } /*! * \brief MessageDispatcher::onSettingsDone * \details The slot to handle didSettingsDone signal of the ApplicationController */ void MessageDispatcher::onSettingsDone() { _interpreter.updateUnhandledMessages(); } // ---------------------------------------------------------------------------------------------------- /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Blood/Dialysate Adjustment Denali message. * \param vData - Data model contains Blood Flow Rate and Dialysate Flow Rate * \return void */ void MessageDispatcher::onAdjustment(const AdjustBloodDialysateRequestData &vData) { QVariantList mData; mData += vData.bloodFlow; mData += vData.dialysateFlow; onActionTransmit(GuiActionType::ID_AdjustBloodDialysateReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the treatment duration Adjustment Denali message. * \param vData - Data model contains treatment duration adjustment value in minutes * \return void */ void MessageDispatcher::onAdjustment(const AdjustDurationRequestData &vData) { QVariantList mData; mData += vData.duration; onActionTransmit(GuiActionType::ID_AdjustDurationReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Ultrafiltration State Adjustment Denali message. * \param vData - Data model contains treatment ultrafiltration state adjustment * \return void */ void MessageDispatcher::onAdjustment(const AdjustUltrafiltrationStateRequestData &vData) { QVariantList mData; mData += vData.requestedState; actionTransmit(GuiActionType::ID_AdjustUltrafiltrationStateReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Ultrafiltration Adjustment Denali message. * \param vData - Data model contains treatment ultrafiltration adjustment volume * \return void */ void MessageDispatcher::onAdjustment(const AdjustUltrafiltrationEditRequestData &vData) { QVariantList mData; mData += vData.volume; onActionTransmit(GuiActionType::ID_AdjustUltrafiltrationEditReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Ultrafiltration Adjustment User Selected Option Denali message. * \param vData - Data model contains treatment ultrafiltration adjustment volume and user selected option. * \return void */ void MessageDispatcher::onAdjustment(const AdjustUltrafiltrationConfirmRequestData &vData) { QVariantList mData; mData += vData.volume; onActionTransmit(GuiActionType::ID_AdjustUltrafiltrationConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Alarm Request Silence message. * \param vData - Data model contains the silence request information. * \return void */ void MessageDispatcher::onAdjustment(const AlarmSilenceRequestData &vData) { QVariantList mData; mData += vData.silence; onActionTransmit(GuiActionType::ID_AlarmSilenceReq, mData); } /** * \brief MessageDispatcher::onAdjustment * \details This method transmits the User Action Denali message. * \param vData - Data model contains User Action on the alarm dialog. * \return void */ void MessageDispatcher::onAdjustment(const AlarmUserActionRequestData &vData) { QVariantList mData; mData += vData.action; onActionTransmit(GuiActionType::ID_AlarmUserActionReq, mData); } /** * \brief MessageDispatcher::onAdjustment * \details This method transmits the Alarm Active List Request denali message. * \param vData - Data model contains Alarm Active List payload. * \return void */ void MessageDispatcher::onAdjustment(const AlarmActiveListRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AlarmActiveListReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the DG Set Date Time Denali message. * \details This method transmits the request to set the alarm volume. * \param vData - Data model contains the alarm volume * \return void */ void MessageDispatcher::onAdjustment(const AdjustHDAlarmVolumeRequestData &vData) { QVariantList mData; mData += vData.volume2HD(); onActionTransmit(GuiActionType::ID_AlarmVolumeSetReq, mData); } /** * \details This method transmits the Saline Bolus Adjustment Denali message. * \param vData - Data model contains treatment Saline Bolus adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustSalineRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustSalineReq, mData); } /** * \details This method transmits the Vitals Adjustment Denali message. * \param vData - Data model contains treatment Vitals adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustVitalsRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustVitalsReq, mData); } /** * \details This method transmits the Heparin Adjustment Denali message. * \param vData - Data model contains treatment Heparin adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustHeparinRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustHeparinReq, mData); } /** * \details This method transmits the Rinseback Adjustment Denali message. * \param vData - Data model contains treatment Rinseback adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustRinsebackRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustRinsebackReq, mData); } /** * \details This method transmits the Recirculate Adjustment Denali message. * \param vData - Data model contains treatment Recirculate adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustRecirculateRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustRecirculateReq, mData); } /** * \details This method transmits the Treatment End Adjustment Denali message. * \param vData - Data model contains treatment end adjustment state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustTreatmentEndRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustTreatmentEndReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the HD Version Denali message. * \param vData - Data model contains HD Version state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustVersionsRequestData &vData) { QVariantList mData; mData += QVariant::fromValue(vData.ver_major); mData += QVariant::fromValue(vData.ver_minor); mData += QVariant::fromValue(vData.ver_micro); mData += QVariant::fromValue(vData.ver_revis); mData += QVariant::fromValue(vData.ver_comp ); onActionTransmit(GuiActionType::ID_AdjustVersionsUIReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the HD Version Denali message. * \param vData - Data model contains HD Version state. * \return void */ void MessageDispatcher::onAdjustment(const AdjustVersionsResponseData &vData) { QVariantList mData; mData += QVariant::fromValue(vData.ver_major); mData += QVariant::fromValue(vData.ver_minor); mData += QVariant::fromValue(vData.ver_micro); mData += QVariant::fromValue(vData.ver_revis); mData += QVariant::fromValue(vData.ver_comp ); onActionTransmit(GuiActionType::ID_AdjustVersionsUIRsp, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the DG Set Date Time Denali message. * \param vData - Data model contains the epoch time * \return void */ void MessageDispatcher::onAdjustment(const AdjustServiceDatesRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustServiceDatesReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disposables Removal Confirm Adjustment Denali message. * \param vData - Data model contains Service Mode adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustServiceModeRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustServiceModeReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Pressures Limits Adjustment Denali message. * \param vData - Data model contains treatment Pressures Limits adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustPressuresLimitsRequestData &vData) { QVariantList mData; mData += vData.mArterialPressureLimitWindow ; mData += vData.mVenousPressureLimitWindow ; mData += vData.mVenousPressureLimitAsymtrc ; mData += vData.mTmpLimitWindow ; onActionTransmit(GuiActionType::ID_AdjustPressuresLimitsReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the InitTreatment request message. * \param vData - Data model contains the init treatment request information. * \return void */ void MessageDispatcher::onAdjustment(const AdjustInitTreatmentRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustInitTreatmentReq, mData); } /** * \details This method transmits the Treatment Parameter request message. * \param vData - Data model contains treatment parameter adjustment data structure * \return void */ void MessageDispatcher::onAdjustment(const AdjustParametersValidationRequestData &vData) { QVariantList mData; mData += vData.mBloodFlowRate ; mData += vData.mDialysateFlowRate ; mData += vData.mTreatmentDuration ; mData += vData.mSalineBolusVolume ; mData += vData.mHeparinStopTime ; mData += vData.mHeparinType ; mData += vData.mAcidConcentrate ; mData += vData.mBicarbonateConcentrate ; mData += vData.mDialyzerType ; mData += vData.mBloodPressureMeasureInterval ; mData += vData.mRinsebackFlowRate ; mData += vData.mRinsebackVolume ; mData += vData.mArterialPressureLimitWindow ; mData += vData.mVenousPressureLimitWindow ; mData += vData.mVenousPressureLimitAsymtrc ; mData += vData.mTrancembrncPressureLimitWindow ; mData += vData.mDialysateTemp ; mData += vData.mHeparinDispensingRate ; mData += vData.mHeparinBolusVolume ; onActionTransmit(GuiActionType::ID_AdjustParametersValidationReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Confirm Treatment request message. * \param vData - Data model contains the confirm treatment request * \return void */ void MessageDispatcher::onAdjustment(const AdjustParametersConfirmRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustParametersConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Water Sample Adjustment Denali message. * \param vData - Data model contains Water Sample adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustWaterSampleRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustWaterSampleReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Water Sample Result Adjustment Denali message. * \param vData - Data model contains Water Sample Result adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustWaterSampleResultRequestData &vData) { QVariantList mData; mData += vData.requestedState; onActionTransmit(GuiActionType::ID_AdjustWaterSampleResultReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Consumables Confirm Adjustment Denali message. * \param vData - Data model contains Consumables Confirm adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustConsumablesConfirmRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustConsumablesConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disposables Confirm Adjustment Denali message. * \param vData - Data model contains Disposables Confirm adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustDisposablesConfirmRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustDisposablesConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disposables Prime Adjustment Denali message. * \param vData - Data model contains Disposables Prime adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustDisposablesPrimeRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustDisposablesPrimeReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Patient Connection Begin Adjustment Denali message. * \param vData - Data model contains Patient Connection Begin adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustPatientConnectionBeginRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustPatientConnectionBeginReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Ultrafiltration Adjustment Denali message. * \param vData - Data model contains treatment ultrafiltration adjustment volume * \return void */ void MessageDispatcher::onAdjustment(const AdjustUltrafiltrationInitRequestData &vData) { QVariantList mData; mData += vData.volume; onActionTransmit(GuiActionType::ID_AdjustUltrafiltrationInitReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Patient Connection Confirm Adjustment Denali message. * \param vData - Data model contains Patient Connection Confirm adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustPatientConnectionConfirmRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustPatientConnectionConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Start Treatment Adjustment Denali message. * \param vData - Data model contains Start Treatment adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustStartTreatmentRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustStartTreatmentReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Patient Disconnection Notify Adjustment Denali message. * \param vData - Data model contains Patient Disconnection Notify adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustPatientDisconnectionNotifyRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustPatientDisconnectNotifyReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Patient Disconnection Confirm Adjustment Denali message. * \param vData - Data model contains Patient Disconnection Confirm adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustPatientDisconnectionConfirmRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustPatientDisconnectConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disposables Removal Confirm Adjustment Denali message. * \param vData - Data model contains Disposables Removal Confirm adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustDisposablesRemovalConfirmRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustDisposablesRemovalConfirmReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Treatment Log Adjustment Denali message. * \param vData - Data model contains Treatment Log adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustTreatmentLogRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustTreatmentLogReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the HD Set Date Time Denali message. * \param vData - Data model contains the epoch time * \return void */ void MessageDispatcher::onAdjustment(const AdjustHDDateTimeRequestData &vData) { QVariantList mData; mData += vData.mEpoch ; onActionTransmit(GuiActionType::ID_AdjustHDDateTimeReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the DG Set Date Time Denali message. * \param vData - Data model contains the epoch time * \return void */ void MessageDispatcher::onAdjustment(const AdjustDGDateTimeRequestData &vData) { QVariantList mData; mData += vData.mEpoch ; onActionTransmit(GuiActionType::ID_AdjustDGDateTimeReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the DG Cleaning Usage request message. * \return void */ void MessageDispatcher::onAdjustment(const AdjustDGCleaningUsageRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustDGCleaningUsageReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disinfect request Denali message. * \param vData - Data model contains the epoch time * \return void */ void MessageDispatcher::onAdjustment(const AdjustDisinfectStartRequestData &vData) { QVariantList mData; mData += vData.mState; onActionTransmit(GuiActionType::ID_AdjustDisinfectStartReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disinfect mode request Denali message. * \param vData - Data model contains the initiate/cancel boolean disinfection mode * \return void */ void MessageDispatcher::onAdjustment(const AdjustDisinfectModeRequestData &vData) { QVariantList mData; mData += vData.mInititate; onActionTransmit(GuiActionType::ID_AdjustDisinfectModeReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the UI power on self test final result * \param vData - Data model contains the final result of the UI POST * \return void */ void MessageDispatcher::onAdjustment(const AdjustUIPostFinalResultRequestData &vData) { QVariantList mData; mData += vData.mResult; onActionTransmit(GuiActionType::ID_UIPostFinalResultData, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the UI Generic User Confirmation result. * \param vData - Data model contains the Generic User Confirmation result. * \return void */ void MessageDispatcher::onAdjustment(const DuetConfirmUIrData &vData) { QVariantList mData; mData += vData.mId; mData += vData.mConfirm; onActionTransmit(GuiActionType::ID_DuetConfirmUIr, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the UI RO Water Mode adjustment request. * \param vData - Data model contains the UI RO Water Mode adjustment request data. * \return void */ void MessageDispatcher::onAdjustment(const DuetRoWaterModeUIiData &vData) { QVariantList mData; mData += vData.mStatus; onActionTransmit(GuiActionType::ID_DuetRoWaterModeUIi, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the HD Usage Info Denali message. * \param vData - * \return void */ void MessageDispatcher::onAdjustment(const HDUsageInfoRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_HDUsageInfoReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the HD institutional record request to HD. * \param vData - * \return void */ void MessageDispatcher::onAdjustment(const AdjustInstitutionalRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_AdjustInstitutionalRecordReq, mData); } /*! * \brief MessageDispatcher::onAdjustment * \details This method transmits the Disposables Removal Confirm Adjustment Denali message. * \param vData - Data model contains Service Mode adjustment. * \return void */ void MessageDispatcher::onAdjustment(const AdjustHDResetInSrvcRequestData &) { QVariantList mData; onActionTransmit(GuiActionType::ID_ResetHDInServiceModeReq, mData); } // ---------------------------------------------------------------------------------------------------- /*! * \brief MessageDispatcher::actionTransmit * \details This method is called by slot MessageDispatcher::onActionTransmit * which emits didFrameTransmit on successful interpretation of the requested message * and successfully creating of frame(s). * \param vActionId - The ActionID of the message * \param vData - The data of the Message */ void MessageDispatcher::actionTransmit(GuiActionType vActionId, const QVariantList &vData, Sequence vSequence, Can_Id vCanId) { txCount(); if (vSequence == 0) { // initialize // it's obvious that this assignment does not effect outside of the function. // but is make it easier to just assume the correct value has been passed // and still using the same variable (function parameter) as a local variable. vSequence = _txSequence; } QByteArray mData; Can_Id canid = vCanId; if (! _interpreter.interpretMessage(vActionId, vData, mData, canid)) { LOG_DEBUG(QString("Incorrect Message, cannot be interpreted, %1").arg(Format::toHexString(vActionId))); // TODO : LogInfo Improvement return; } // TODO : Create a buildFrames method FrameList frameList; Sequence mSequence = vSequence; bool mNeedsAcknow = needsAcknow(vActionId); if (mNeedsAcknow) { mSequence = -mSequence; if ( ! gDisableAcknowLog ) { LOG_APPED_UI(tr("Ack Req, Sq:%1, ID:%2").arg(mSequence).arg(Format::toHexString(vActionId))); } #ifdef DEBUG_ACKBACK_HD_TO_UI qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckReq : %1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence); #endif } // still checking here in case the logic has changed therefore buildFrame should still validate the message for developer safety. if ( ! _builder.buildFrames(vActionId, mData, frameList, mSequence) ) { LOG_DEBUG(QString("Incorrect Message cannot be built")); // TODO : LogInfo Improvement return; } if (mNeedsAcknow) { // NOTE : here vSequence should be used which is not negative // because when we get the Acknow it is not the negative // since it does not need Re-Acknow // and this is the sequence number which will be used // to remove the message from the Acknow list. emit didAcknowTransmit(canid, vSequence, frameList); } framesTransmit(canid, frameList); } /*! * \brief MessageDispatcher::framesTransmit * \details iterates through all the frames and emits to send the frames * \param vCan_Id - The channel to send the frames to * \param vFrameList - List of the frames to be sent */ void MessageDispatcher::framesTransmit(Can_Id vCan_Id, const FrameList &vFrameList) { for (const auto &frame : vFrameList) { emit didFrameTransmit(vCan_Id, frame); } } /*! * \brief MessageDispatcher::buildMessage * \details Calls the messageBuilder buildMessage method. * \param vCan_Id - CANBus channel of the frame * \param vPayload - Payload of the frame * \return false on error */ bool MessageDispatcher::buildMessage(Can_Id vCan_Id, const QByteArray &vPayload) { if (vPayload.length() < eLenCanFrame) { // Each frame has to have exactly 8 (eLenCanFrame) bytes of data and unused bytes should be passed as 00. LOG_DEBUG(QString("Incorrect frame length. Exp:%1,got:%2").arg(eLenCanFrame).arg(vPayload.length())); return false; } if (! _builder.buildMessage(vPayload, _messageList[vCan_Id].last(), vCan_Id)) { _messageList[vCan_Id].removeLast(); return false; } return true; } /*! * \brief MessageDispatcher::checkAcknowReceived * \details check if the message was an acknowledge. * \param vMessage - The received message * \param vSrcText - The source entity identifier text * \return true if the message is Acknow */ bool MessageDispatcher::checkAcknowReceived(const Message &vMessage, const QString &vSrcText) { GuiActionType mActionId = vMessage.actionId; Sequence mSequence = vMessage.sequence; bool ok = false; if ( mActionId == GuiActionType::ID_Acknow ) { ok = true; if ( ! gDisableAcknowLog ) { LOG_APPED(tr(" ,%1,Ack Bak, Sq:%2").arg(vSrcText).arg(mSequence)); } #ifdef DEBUG_ACKBACK_HD_TO_UI qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckBak : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence).arg(vMessage.actionId); #endif emit didAcknowReceive(mSequence); } return ok; } /*! * \brief MessageDispatcher::checkAcknowTransmit * \details Sends the Ack message. * \param vMessage - the received message which to check if it may need Ack. * \param vSrcText - the source of the message which needs Ack. * \return returns true if the message needs an Ack (Negative Sequence) */ bool MessageDispatcher::checkAcknowTransmit(const Message &vMessage, const QString &vSrcText) { bool ok = false; GuiActionType mActionId = vMessage.actionId; Sequence mSequence = vMessage.sequence; // UI shall acknowledge the messages is intended for UI. if ( ! needsAcknow(vMessage.can_id)) return ok; // false if (mSequence < 0) { ok = true; if ( ! gDisableAcknowLog ) { LOG_APPED(tr(" ,%1,Ack Req, Sq:%2, ID:%3").arg(vSrcText).arg(mSequence).arg(Format::toHexString(mActionId))); } #ifdef DEBUG_ACKBACK_HD_TO_UI qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckReq : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence).arg(vMessage.actionId); #endif // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckBak is immediately handled at the same place. QString dstText; Can_Id dstID = MessageInterpreter::identifyDestination(vMessage.can_id, &dstText); actionTransmit(GuiActionType::ID_Acknow, {}, -mSequence, dstID); if ( ! gDisableAcknowLog ) { LOG_APPED_UI(tr("Ack Bak, Sq:%1, Dst:%2").arg(-mSequence).arg(dstText)); } #ifdef DEBUG_ACKBACK_HD_TO_UI qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckBak : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(-mSequence).arg(vMessage.actionId); #endif } return ok; } /*! * \brief MessageDispatcher::interpretMessage * \details Calls the MessageInterpreter interpretMessage method * Regarding the Message Id and the sequence emit different signals * to handle the normal or acknowledge messages. * \param vMessage - The Message * \return false on error */ bool MessageDispatcher::interpretMessage(const Message &vMessage) { bool ok = false; QVariantList mData; QString srcText; MessageInterpreter::identifySource(vMessage.can_id, &srcText); if ( ! checkAcknowReceived(vMessage, srcText) ) { // check if the message was an acknowledge. checkAcknowTransmit(vMessage, srcText); // then if needs acknow send it immediately. } if ( _interpreter.interpretMessage( vMessage, mData ) ) { ok = true; emit didActionReceive(vMessage.actionId, mData); } _messageList[vMessage.can_id].removeLast(); return ok; } /*! * \brief MessageDispatcher::rxCount * \details count received messages up the size of the Sequence type size * \return message count */ Sequence MessageDispatcher::rxCount() { if ( _rxSequence < SEQUENCE_MAX ) { ++_rxSequence; } else { _rxSequence = 1; } return _rxSequence; } /*! * \brief MessageDispatcher::txCount * \details count transmitted messages up the size of the Sequence type size * \return message count */ Sequence MessageDispatcher::txCount() { if ( _txSequence < SEQUENCE_MAX ) { ++_txSequence; } else { _txSequence = 1; } return _txSequence; } /*! * \brief MessageDispatcher::needsAcknow * \details List of the Action types which need Acknow * \param vActionId - Action Type id * \return true if needs an Acknow */ bool MessageDispatcher::needsAcknow(GuiActionType vActionId) { return _needsAcknow.contains(vActionId); } /*! * \brief MessageDispatcher::needsAcknow * \details List of the CAN channels which need Acknow * \param vCan_Id - The message CANBus id * \return true if needs an Acknow */ bool MessageDispatcher::needsAcknow(Can_Id vCan_Id) { bool ok = true; switch(vCan_Id) { // list if the channels UI shall not Ack case eChlid_TD_DD : case eChlid_DD_TD : case eChlid_DD_FP : case eChlid_FP_DD : case eDialin_TD : case eTD_Dialin : case eDialin_DD : case eDD_Dialin : case eDialin_FP : case eFP_Dialin : ok = false; break; default: break; } return ok; }