/*! * * Copyright (c) 2019-2020 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 MessageAcknowModel.cpp * \author (last) Behrouz NematiPour * \date (last) 26-Aug-2020 * \author (original) Behrouz NematiPour * \date (original) 26-Aug-2020 * */ #include "MessageAcknowModel.h" // Qt #include #include // Project #include "MessageDispatcher.h" // namespace using namespace Can; /*! * \brief MessageAcknowModel::MessageAcknowModel * \details Constructor * \param parent - QObject parent owner object. * Qt handles the children destruction by their parent objects life-cycle. */ MessageAcknowModel::MessageAcknowModel(QObject *parent) : QObject(parent) { } /*! * \brief MessageAcknowModel::init * \details Initializes the class by setting the connections and starting the timer * \return False if it has been called before. */ bool MessageAcknowModel::init() { if ( _init ) return false; _init = true; // runs in MessageAcknowModel thread initConnections(); LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); return true; } /*! * \brief MessageAcknowModel::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 MessageAcknowModel::init(QThread &vThread) { if ( ! init() ) return false; initThread(vThread); return true; } /*! * \brief MessageAcknowModel::quit * \details quits the class * Calls quitThread */ void MessageAcknowModel::quit() { qDeleteAll(_acknowList); // coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. quitThread(); // validated } // coco end /*! * \brief MessageAcknowModel::initConnections * \details Initializes the required signal/slot connection between this class and other objects * to be able to communicate. */ void MessageAcknowModel::initConnections() { connect(&_MessageDispatcher, SIGNAL(didAcknowTransmit(Can_Id, Sequence, const FrameList &)), this , SLOT( onAcknowTransmit(Can_Id, Sequence, const FrameList &))); connect(&_MessageDispatcher, SIGNAL(didAcknowReceive ( Sequence )), this , SLOT( onAcknowReceive ( Sequence ))); } /*! * \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 MessageAcknowModel::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 MessageAcknowModel::quitThread * \details Moves this object to main thread to be handled by QApplication * And to be destroyed there. */ void MessageAcknowModel::quitThread() { // coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. if ( ! _thread ) return; // runs in thread moveToThread(qApp->thread()); // validated } // coco end /*! * \brief MessageAcknowModel::onAcknowTransmit * \details This slot is called MessageDispatcher sends a message from UI which requires Acknow. * An Acknow model will be added to list of the Acknow required messages. * The connection will be made to be notified by that message when it's timed out. * And the timer for that message will be started. * \param vCan_Id - Denali message Can channel * \param vSequence - Sequence number of the message which requires Acknow * \param vFrameList - List of the frames to be sent on retries. */ void MessageAcknowModel::onAcknowTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) { _acknowList[vSequence] = new Private::AcknowModel(vCan_Id, vSequence, vFrameList); connect(_acknowList[vSequence] , SIGNAL(didFramesTransmit(Can_Id, Sequence, const FrameList &)), this , SLOT( onFramesTransmit(Can_Id, Sequence, const FrameList &))); connect(_acknowList[vSequence] , SIGNAL(didFailedTransmit( Sequence )), this , SLOT( onFailedTransmit( Sequence ))); _acknowList[vSequence]->start(); } /*! * \brief Private::AcknowModel::start * \details It starts the message timer which is waiting for the Acknow * on each interval will notify the MessageDispatcher to retry */ void Private::AcknowModel::start() { _timerId = startTimer(_interval); } /*! * \brief MessageAcknowModel::onAcknowReceive * \details This slot is called when the Acknow request for the specific message with the sequence number vSequence * has been received. * \param vSequence - Sequence number of the message which required Acknow */ void MessageAcknowModel::onAcknowReceive(Sequence vSequence) { if (_acknowList.contains(vSequence)) { _acknowList[vSequence]->deleteLater(); _acknowList.remove(vSequence); } } /*! * \brief MessageAcknowModel::onFramesTransmit * \details This slot will be called when a message which is waiting for Acknow didn't get the Acknow * during the interval and retries to transmit the message again. * \param vCan_Id - The can channel for the Denali message * \param vSequence - The sequence number of the message * \param vFrameList - The list of the frame(s) needs to be sent. */ void MessageAcknowModel::onFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) { emit didFramesTransmit(vCan_Id, vSequence, vFrameList); } /*! * \brief MessageAcknowModel::onFailedTransmit * \details After the _retry amount of retries this slot will be called * to notify the outside of the failure Acknow. * \param vSequence - The sequence number of the message */ void MessageAcknowModel::onFailedTransmit(Sequence vSequence) { _acknowList[vSequence]->deleteLater(); _acknowList.remove(vSequence); emit didFailedTransmit(vSequence); LOG_DEBUG( QString("Acknow retry failed for sequence %1").arg(vSequence) ); }