/*! * * Copyright (c) 2019-2019 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 messagepacker.cpp * date 12/9/2019 * author Behrouz NematiPour * */ #include "messagedispatcher.h" // Qt #include #include // Project #include "logger.h" #include "applicationcontroller.h" #include "frameinterface.h" using namespace Can; /*! * \brief MessageDispatcher Constructor * \param parent */ MessageDispatcher::MessageDispatcher(QObject *parent) : QObject(parent) { } /*! * \brief Message Handler initializer */ bool MessageDispatcher::init() { if ( _init ) return false; _init = true; // runs in USBWatcher thread initConnections(); LOG_EVENT(QObject::tr("%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(); } /*! * \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 &))); } /*! * \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())); _thread->start(); moveToThread(_thread); } /*! * \brief MessageDispatcher::quitThread * \details Moves this object to main thread to be handled by QApplicaiton * And to be destroyed there. */ void MessageDispatcher::quitThread() { if ( ! _thread ) return; // runs in thread moveToThread(qApp->thread()); } /*! * \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 vCanId - CANBUS channel of the frame * \param vPayload - Payload of the frame */ void MessageDispatcher::onFrameReceive(Can_Id vCanId, const QByteArray &vPayload) { // Append a message to the list if (_messageList[vCanId].isEmpty() || _messageList[vCanId].last().isComplete()) { _messageList[vCanId].append(Message()); //qDebug() << tr("Created a message for channel %1#%2").arg(vCanId).arg(Format::toHexString(vPayload)); } /*else { qDebug() << tr("Data for message on channel %1#%2").arg(vCanId).arg(Format::toHexString(vPayload)); }*/ //for (int i = 0; i < _messageList[vCanId].count(); ++i) { // qDebug() << _messageList[vCanId][i].data.toHex('.'); //} // build the message if (! _builder.buildMessage(vPayload, _messageList[vCanId].last(), vCanId)) { _messageList[vCanId].removeLast(); return; } Message mMessage = _messageList[vCanId].last(); // TODO : must be moved to a MessageModel class if (mMessage.isComplete()) { GuiActionType mActionId; QVariantList mData; if (_interpreter.interpretMessage(vCanId, mMessage, mActionId, mData)) { emit didActionReceive(mActionId, mData); } _messageList[vCanId].removeLast(); } } /*! * \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::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) { QByteArray mData; if (! _interpreter.interpretMessage(vActionId, vData, mData)) { LOG_ERROR(tr("Incorrect Message, can't be interpreted")); return; } FrameList frameList; if ( ! _builder.buildFrames(vActionId, mData, frameList) ) { LOG_ERROR(tr("Incorrect Message can't be built")); return; } for (const auto &frame : frameList) { emit didFrameTransmit(eChlid_UI, frame); } }