/*! * * Copyright (c) 2020-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 MessageDispatcher.cpp * \author (last) Stephen Quong * \date (last) 12-Jun-2026 * \author (original) Behrouz NematiPour * \date (original) 26-Aug-2020 * */ // SQ Ported from luis application/sources/canbus/MessageDispatcher.cpp. // SQ Only the inbound per-CAN-id frame reassembly path is kept active; the // SQ GUI/action/acknowledge machinery is commented out (not deleted). #include "MessageDispatcher.h" // Qt #include // SQ added: replaces luis Logger.h macros with qDebug() // #include // SQ commented out: thread mgmt removed // #include // SQ commented out: no QApplication here // Project // #include "Logger.h" // SQ commented out: luis logging infra // #include "ApplicationController.h" // SQ commented out: GUI app controller // #include "FrameInterface.h" // SQ commented out: luis frame interface // #include "MessageAcknowModel.h" // SQ commented out: acknowledge model //#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) { } // SQ commented out: init()/quit() thread lifecycle -- LeahiRtController owns threading. #if 0 /*! * \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 } #endif /*! * \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 vCanId messages. * \param vCanId - CANBus channel of the frame // SQ Can_Id -> CanId * \param vPayload - Payload of the frame */ void MessageDispatcher::onFrameReceive(CanId vCanId, const QByteArray &vPayload) // SQ Can_Id -> CanId { // Append a message to the list // because if the list is empty there is no last() item if (_messageList[vCanId].isEmpty() || _messageList[vCanId].last().isComplete()) { _messageList[vCanId].append(Message()); } // build the message and check. if (! buildMessage(vCanId, vPayload)) { return; } Message mMessage = _messageList[vCanId].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); // SQ commented out: GUI interpretation emit didActionReceive(mMessage); // SQ emit completed message for the controller to forward _messageList[vCanId].removeLast(); // SQ done with this message (luis did this inside interpretMessage) } } // SQ commented out: outbound transmit, action, settings, adjustment, acknowledge, and // SQ interpret paths -- all GUI/action specific and rely on Message::actionId / GuiActionType // SQ / ApplicationController / MessageInterpreter, none of which exist in this project. #if 0 /*! * \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); } // ... (luis onFailedTransmit / onActionTransmit / onSettingsDone / ~60 onAdjustment overloads, // actionTransmit / framesTransmit / interpretMessage / checkAcknowReceived / // checkAcknowTransmit / needsAcknow / txCount preserved here in the luis original) ... #endif /*! * \brief MessageDispatcher::buildMessage * \details Calls the messageBuilder buildMessage method. * \param vCanId - CANBus channel of the frame // SQ Can_Id -> CanId * \param vPayload - Payload of the frame * \return false on error */ bool MessageDispatcher::buildMessage(CanId vCanId, const QByteArray &vPayload) // SQ Can_Id -> CanId { if (vPayload.length() < eLenCanFrame) { // Each frame has to have exactly 8 (eLenCanFrame) bytes of data and unused bytes should be passed as 00. qDebug() << QString("Incorrect frame length. Exp:%1,got:%2").arg(eLenCanFrame).arg(vPayload.length()); // SQ LOG_DEBUG -> qDebug return false; } if (! _builder.buildMessage(vPayload, _messageList[vCanId].last(), vCanId)) { _messageList[vCanId].removeLast(); return false; } return true; } /*! * \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; }