/*! * * 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 frameinterface.cpp * date 10/26/2019 * author Behrouz NematiPour * */ #include "frameinterface.h" // Qt #include #include // Project #include "logger.h" #include "messagedispatcher.h" #include "caninterface.h" // namespace using namespace Can; /*! * \brief FrameInterface Constructor * \param parent */ FrameInterface::FrameInterface(QObject *parent) : QObject(parent) { } /*! * \brief Message Handler initializer */ bool FrameInterface::init() { if ( _init ) return false; _init = true; initConnections(); LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); return true; } /*! * \brief FrameInterface::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 FrameInterface::init(QThread &vThread) { if ( init() ) return false; initThread(vThread); return true; } /*! * \brief FrameInterface::quit * \details quits the class * Calls quitThread */ void FrameInterface::quit() { quitThread(); } /*! * \brief FrameInterface connections definition * \details Initializes the required signal/slot connection between this class and other objects * to be able to communicate. */ void FrameInterface::initConnections() { // From GUI connect(&_MessageDispatcher, SIGNAL(didFrameTransmit(Can_Id, const QByteArray &)), this , SLOT( onFrameTransmit(Can_Id, const QByteArray &))); // From CAN connect(&_CanInterface , SIGNAL( didFrameReceive( const QCanBusFrame &)), this , SLOT( onFrameReceive( const QCanBusFrame &))); } /*! * \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 FrameInterface::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 FrameInterface::quitThread * \details Moves this object to main thread to be handled by QApplicaiton * And to be destroyed there. */ void FrameInterface::quitThread() { if ( ! _thread ) return; // runs in thread moveToThread(qApp->thread()); } /*! * \brief FrameInterface::transmitFrame * \details Prepares a frame to be transmitted * and emit signal didFrameTransmit with the frame as its argument * \param vFrameId - Channel id of the CANBUS frame * \param vData - The Data this frame is going to carry * \note This frame is created by MessageBuilder * and it can be one of the frames of a message * which has been chopped into frames. */ void FrameInterface::transmitFrame(Can_Id vFrameId, const QByteArray &vData) { QCanBusFrame mFrame; mFrame.setFrameId(vFrameId); if (vData.length() > Can::eLenCanFrame) { LOG_ERROR(tr("Payload can't be larger than %1 bytes").arg(Can::eLenCanFrame)); return; } mFrame.setPayload(vData); emit didFrameTransmit(mFrame); } /*! * \brief FrameInterface::checkChannel * \details Checks for the channel id of the received frame * which needs to be handled or ignored. * \param vFrameId - Channel id of the frame * \param vOK - will be set to true if the channel * is valid and a variable has been passed to * \return The Category if the channels from the UI * perspective FrameInterface::ChannelGroup */ FrameInterface::ChannelGroup FrameInterface::checkChannel(quint32 vFrameId, bool *vOK) { bool ok = true; FrameInterface::ChannelGroup channelGroup = ChannelGroup::eChannel_Unknown; switch (vFrameId) { case eChlid_HD_DG : case eChlid_DG_HD : channelGroup = ChannelGroup::eChannel_Ignores; break; case eChlid_HD : case eChlid_HD_Alarm : case eChlid_DG_Alarm : case eChlid_HD_Sync : case eChlid_DG_Sync : //case eChlid_DG_UI : // has duplicate value as eChlid_DG_Alarm //case eChlid_UI_DG : // has duplicate value as eChlid_UI_Sync channelGroup = ChannelGroup::eChannel_Listens; break; case eChlid_UI_Alarm : case eChlid_UI_Sync : case eChlid_UI : channelGroup = ChannelGroup::eChannel_Outputs; break; default: ok = false; break; } if (vOK) *vOK = ok; return channelGroup; } /*! * \brief FrameInterface::onFrameTransmit * \details This the slot connected to the MessageDispatcher didFrameTransmit signal. * When a frame needs to be send to CANBUS, * this slot will call transmitFrame method to do the job. * \param vCan_ID - CANBUS Can Id target of the frame. * \param vData - The data which this frame will carry. */ void FrameInterface::onFrameTransmit(Can_Id vCan_ID, const QByteArray &vData) { transmitFrame(vCan_ID, vData); } /*! * \brief FrameInterface::onFrameReceive * \details This the slot connected to the CanInterface didFrameReceive signal. * When a frame received over the CANBUS, * this slot will be called to check the channel if should be listened to. * and will emit didFrameReceive if should be handled and ignored otherwise. * \param vFrame - The frame has to be sent */ void FrameInterface::onFrameReceive(const QCanBusFrame &vFrame) { bool ok = false; quint32 mFrameId = vFrame.frameId(); ChannelGroup channelGroup = checkChannel(mFrameId, &ok); if (!ok){ LOG_ERROR("Unexpected Channel\r\n" + Format::toHexString(mFrameId, false, eLenChannelDigits) + " -- " + vFrame.payload().toHex(' ')); return; } if ( channelGroup != ChannelGroup::eChannel_Listens) { return; } Can_Id mCanId = static_cast(mFrameId); emit didFrameReceive(mCanId, vFrame.payload()); }