Index: denali.pro =================================================================== diff -u -r8c69137f18382bdc55a5678e6ed44a7683fe4dea -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- denali.pro (.../denali.pro) (revision 8c69137f18382bdc55a5678e6ed44a7683fe4dea) +++ denali.pro (.../denali.pro) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -38,6 +38,7 @@ sources/applicationpost.h \ sources/canbus/caninterface.h \ sources/canbus/frameinterface.h \ + sources/canbus/messageacknowmodel.h \ sources/canbus/messagebuilder.h \ sources/canbus/messagedispatcher.h \ sources/canbus/messageglobals.h \ @@ -65,6 +66,7 @@ sources/applicationpost.cpp \ sources/canbus/caninterface.cpp \ sources/canbus/frameinterface.cpp \ + sources/canbus/messageacknowmodel.cpp \ sources/canbus/messagebuilder.cpp \ sources/canbus/messagedispatcher.cpp \ sources/canbus/messageinterpreter.cpp \ Index: main.cpp =================================================================== diff -u -r8c69137f18382bdc55a5678e6ed44a7683fe4dea -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- main.cpp (.../main.cpp) (revision 8c69137f18382bdc55a5678e6ed44a7683fe4dea) +++ main.cpp (.../main.cpp) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -31,6 +31,7 @@ #include "maintimer.h" #include "caninterface.h" #include "frameinterface.h" +#include "messageacknowmodel.h" #include "messagedispatcher.h" #include "applicationcontroller.h" #include "guicontroller.h" @@ -108,6 +109,9 @@ //! - Initializing CanBus Message Handler _FrameInterface.init(Threads::_CanFrame_Thread); + //! - Initializing the CanBus Message Acknowledgment Model + _MessageAcknowModel.init(Threads::_CanAcknow_Thread); + //! - Initializing CanBus Message Dispatcher if (_MessageDispatcher.init(Threads::_CanMessage_Thread)) { _MessageDispatcher.enableConsoleOut(_consoleoutFrameInterface); Index: sources/canbus/messageacknowmodel.cpp =================================================================== diff -u --- sources/canbus/messageacknowmodel.cpp (revision 0) +++ sources/canbus/messageacknowmodel.cpp (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -0,0 +1,146 @@ +/*! + * + * 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 + * date 1/17/2020 + * author Behrouz NematiPour + * + */ +#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(); + + 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() +{ + quitThread(); +} + +/*! + * \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 QApplicaiton + * And to be destroyed there. + */ +void MessageAcknowModel::quitThread() +{ + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); +} + +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(); +} + +void MessageAcknowModel::onAcknowReceive(Sequence vSequence) +{ + _acknowList[vSequence]->deleteLater(); + _acknowList.remove(vSequence); +} + +void MessageAcknowModel::onFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) +{ + emit didFramesTransmit(vCan_Id, vSequence, vFrameList); +} + +void MessageAcknowModel::onFailedTransmit(Sequence vSequence) +{ + _acknowList[vSequence]->deleteLater(); + _acknowList.remove(vSequence); + emit didFailedTransmit(vSequence); +} Index: sources/canbus/messageacknowmodel.h =================================================================== diff -u --- sources/canbus/messageacknowmodel.h (revision 0) +++ sources/canbus/messageacknowmodel.h (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -0,0 +1,125 @@ +/*! + * + * 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.h + * date 1/17/2020 + * author Behrouz NematiPour + * + */ +#pragma once + +// Qt +#include + +// Project +#include "messageglobals.h" + +// Define +#define _MessageAcknowModel Can::MessageAcknowModel::I() + +// namespace +namespace Can { + +namespace Private { +/*! + * \brief The AcknowModel class + * \details This is the private class of the MessageAcknowModel + * but since Qt doesn't support nested meta objects, + * it has been moved out with a meaningful namespace. + */ +class AcknowModel : public QObject { // Private Model + + Q_OBJECT + + const int _interval = 1000; // in ms + int _timerId = 0; + quint8 _retry = 9; + + Can_Id _can_Id = Can_Id::eChlid_NONE; + Sequence _sequence = 0; + FrameList _frameList ; + explicit AcknowModel(QObject *parent = nullptr) : QObject (parent) { } + +public: + AcknowModel(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) : AcknowModel (nullptr) + { + _can_Id = vCan_Id ; + _sequence = vSequence ; + _frameList = vFrameList; + } + + void start() { + _timerId = startTimer(_interval); + } + +protected: + /*! + * \brief MessageAcknowModel::timerEvent + * \details This event handler has been overrode in here + * to receive timer events for the object + * for the timer which has been set to _interval + * emits the didFramesTransmit signal to retry transmitting the frames + * emits the didFailedTransmit signal if exceeds retry limit. + */ + void timerEvent(QTimerEvent *) override + { + if ( _retry -- ) { + emit didFramesTransmit(_can_Id, _sequence, _frameList); + } else { + killTimer(_timerId); + emit didFailedTransmit(_sequence); + } + } + +signals: + void didFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); // Retry + void didFailedTransmit( Sequence vSequence ); // Retry failed +}; + +} +class MessageAcknowModel : public QObject +{ + Q_OBJECT + + + typedef QHash AcknowList; + AcknowList _acknowList; + + QThread *_thread = nullptr; + bool _init = false; + +// Singleton +SINGLETON(MessageAcknowModel) + +public slots: + bool init(); + bool init(QThread &vThread); + +private slots: + void quit(); + +private: + void initConnections(); + + void initThread(QThread &vThread); + void quitThread(); + +signals: + void didFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); // Retry + void didFailedTransmit( Sequence vSequence ); // Retry failed + +private slots: + void onFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); // Retry + void onFailedTransmit( Sequence vSequence ); // Retry failed + + void onAcknowTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); // Add + void onAcknowReceive ( Sequence vSequence ); // Del + +}; + +} Index: sources/canbus/messagedispatcher.cpp =================================================================== diff -u -r0e87420e50dd94c37eb25f289ef3262e0e45d7f4 -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 0e87420e50dd94c37eb25f289ef3262e0e45d7f4) +++ sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -21,6 +21,7 @@ #include "logger.h" #include "applicationcontroller.h" #include "frameinterface.h" +#include "messageacknowmodel.h" #define DEBUG_ACKBACK_HD_TO_UI @@ -83,15 +84,20 @@ void MessageDispatcher::initConnections() { // From GUI - connect(&_ApplicationController, SIGNAL(didActionTransmit(GuiActionType, const QVariantList &)), - this , SLOT( onActionTransmit(GuiActionType, const QVariantList &))); + 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 &))); + connect(&_FrameInterface , SIGNAL(didFrameReceive (Can_Id , const QByteArray &)), + this , SLOT( onFrameReceive (Can_Id , const QByteArray &))); - connect(this ,SIGNAL(didFramesTransmit( Can_Id, const FrameList &)), - this , SLOT( onFramesTransmit( Can_Id, const FrameList &))); + + // + 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 ))); } /*! @@ -164,14 +170,22 @@ * \brief MessageDispatcher::onFramesTransmit * \details this slots calls the framesTransmit to emit the didFrameTransmit signal * to queue the frame(s) to be sent - * \param vCan_Id - CanBus channel + * \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, const FrameList &vFrameList) +void MessageDispatcher::onFramesTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList) { + Q_UNUSED(vSequence) framesTransmit(vCan_Id, vFrameList); } +void MessageDispatcher::onFailedTransmit(Sequence vSequence) +{ + Q_UNUSED(vSequence) + // may requires showing an alarm screen + // but we don't know yet. +} + /*! * \brief MessageDispatcher::onActionTransmit * \details This slot will be called by ApplicationController::didActionTransmit @@ -181,7 +195,7 @@ */ void MessageDispatcher::onActionTransmit(GuiActionType vActionId, const QVariantList &vData) { - actionTransmit(vActionId, vData, txCount()); + actionTransmit(vActionId, vData); } /*! @@ -194,6 +208,14 @@ */ void MessageDispatcher::actionTransmit(GuiActionType vActionId, const QVariantList &vData, Sequence vSequence) { + 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 function parameter as a local variable. + vSequence = _txSequence; + } + QByteArray mData; if (! _interpreter.interpretMessage(vActionId, vData, mData)) { LOG_ERROR(tr("Incorrect Message, can't be interpreted")); @@ -204,7 +226,13 @@ FrameList frameList; Sequence mSequence = vSequence; bool mNeedsAcknow = needsAcknow(vActionId); - if (mNeedsAcknow) mSequence = -mSequence; + if (mNeedsAcknow) { + mSequence = -mSequence; + LOG_EVENT(tr("UI Ack Req %1").arg(mSequence)); +#ifdef DEBUG_ACKBACK_HD_TO_UI + qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckReq : %1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence); +#endif + } if ( ! _builder.buildFrames(vActionId, mData, frameList, mSequence) ) { LOG_ERROR(tr("Incorrect Message can't be built")); @@ -216,7 +244,7 @@ // 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(vSequence, eChlid_UI_HD, frameList); + emit didAcknowTransmit(eChlid_UI_HD, vSequence, frameList); } framesTransmit(eChlid_UI_HD, frameList); } @@ -266,17 +294,26 @@ { bool ok = false; QVariantList mData; + Sequence mSequence = vMessage.sequence; if (_interpreter.interpretMessage(vMessage, mData)) { ok = true; GuiActionType mActionId = vMessage.actionId; switch (mActionId) { case GuiActionType::Acknow: - emit didAcknowReceive(vMessage.sequence); + LOG_EVENT(tr("HD Ack Bak %1").arg(mSequence)); + #ifdef DEBUG_ACKBACK_HD_TO_UI + qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckBak : %1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence); + #endif + emit didAcknowReceive(mSequence); break; default: - if (vMessage.sequence < 0) { - actionTransmit(GuiActionType::Acknow, {}, vMessage.sequence); - qDebug() << tr(" ~~~~~~~~~~ Ack Back : %1~~~~~~~~~~ ").arg(vMessage.sequence); + if (mSequence < 0) { + LOG_EVENT(tr("HD Ack Req %1").arg(mSequence)); + #ifdef DEBUG_ACKBACK_HD_TO_UI + qDebug() << tr(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckReq : %1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ").arg(mSequence); + #endif + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckBak is immediately handled at the same place. + actionTransmit(GuiActionType::Acknow, {}, -mSequence); } emit didActionReceive(mActionId, mData); break; @@ -327,18 +364,12 @@ { switch(vActionId) { case GuiActionType::Acknow: - // this is the Acknow itself - // since the actionTransmit will make any needsAcknow sequence to negative - // and the Ack Back should be in positive after receiving it in negative - // actually this make it positive and send it back. - return true; + return false; default: - // TEST : this code is for test. #ifdef DEBUG_ACKBACK_HD_TO_UI - return ( ! (_txSequence % 21) ); + return true; #else return false; #endif } - return false; } Index: sources/canbus/messagedispatcher.h =================================================================== diff -u -r0e87420e50dd94c37eb25f289ef3262e0e45d7f4 -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 0e87420e50dd94c37eb25f289ef3262e0e45d7f4) +++ sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -127,7 +127,6 @@ Sequence txCount(); Sequence rxCount(); - signals: /*! * \brief didActionReceive @@ -144,15 +143,15 @@ * \details Emits when a message requires * \param vData */ - void didActionReceive (const Message &vMessage); + void didActionReceive (const Message &vMessage); - /** - * @brief didAcknowReceive - * @details if the type the received message id is and Acknow this signal will be emitted - * @param vData - the data of the Acknow message which is the message Sequence + /*! + * \brief didAcknowReceive + * \details if the type the received message id is and Acknow this signal will be emitted + * \param vData - the data of the Acknow message which is the message Sequence * which we got the Ack for. */ - void didAcknowReceive (Sequence vSequence); + void didAcknowReceive (Sequence vSequence); /*! * \brief didAcknowTransmit @@ -161,30 +160,25 @@ * \param vFrameList - the frames which has been send * and will be used to be send on retries. */ - void didAcknowTransmit(Sequence vSequence, Can_Id vCan_Id, const FrameList &vFrameList); + void didAcknowTransmit(Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); /*! - * \brief didFramesTransmit - * \details when this signal is emitted frame(s) in the vFramesList - * will be queued to be sent. - * \param vFrameList - list of the frame(s) to be sent. - */ - void didFramesTransmit(Can_Id vCan_Id, const FrameList &vFrameList); - - /*! * \brief didFrameTransmit * \details When a message is requested to be transmitted this signal is emitted * on successful interpretation and building the message into frames * \param vCan_Id - Target channel of the CANBUS message * \param vPayload - The payload of the message to be sent */ - void didFrameTransmit (Can_Id vCan_Id, const QByteArray &vPayload); + void didFrameTransmit (Can_Id vCan_Id, const QByteArray &vPayload); private slots: // A Frame has been received from CanInterface - void onFrameReceive (Can_Id vCan_Id, const QByteArray &vPayload); - void onFramesTransmit (Can_Id vCan_Id, const FrameList &vFrameList); + void onFrameReceive (Can_Id vCan_Id, const QByteArray &vPayload); + // + void onFramesTransmit (Can_Id vCan_Id, Sequence vSequence, const FrameList &vFrameList); + void onFailedTransmit ( Sequence vSequence); + // An Action has been requested to be transmitted. void onActionTransmit (GuiActionType vActionId, const QVariantList &vData); Index: sources/canbus/messageinterpreter.cpp =================================================================== diff -u -r0e87420e50dd94c37eb25f289ef3262e0e45d7f4 -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 0e87420e50dd94c37eb25f289ef3262e0e45d7f4) +++ sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -160,6 +160,9 @@ LOG_DATUM(QString("Power Off (%1)").arg(mShowHide)); break; } + case Gui::GuiActionType::Acknow: + ok = true; + break; case Gui::GuiActionType::BloodFlow: ok = bloodFlowData (vMessage, vData); Index: sources/storage/usbwatcher.cpp =================================================================== diff -u -r8c69137f18382bdc55a5678e6ed44a7683fe4dea -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/storage/usbwatcher.cpp (.../usbwatcher.cpp) (revision 8c69137f18382bdc55a5678e6ed44a7683fe4dea) +++ sources/storage/usbwatcher.cpp (.../usbwatcher.cpp) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -30,7 +30,7 @@ using namespace Storage; /*! - * \brief USBWatcher::USBWatcher + * \brief USBWatcher::USBWatcher * \details Constructor * \param parent - QObject parent owner object. * Qt handles the children destruction by their parent objects life-cycle. @@ -49,7 +49,7 @@ // runs in USBWatcher thread initConnections(); - startTimer(_checkInterval); + startTimer(_interval); return true; } Index: sources/storage/usbwatcher.h =================================================================== diff -u -r415f3e16ff6e572c8ce7e7b3576e82ce8b44c6ce -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/storage/usbwatcher.h (.../usbwatcher.h) (revision 415f3e16ff6e572c8ce7e7b3576e82ce8b44c6ce) +++ sources/storage/usbwatcher.h (.../usbwatcher.h) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -35,14 +35,14 @@ { Q_OBJECT - bool _mounted = false; - bool _umounted = false; - bool _removed = false; - const char *_usbDrive = ""; - const int _checkInterval = 1000; // in ms + bool _mounted = false; + bool _umounted = false; + bool _removed = false; + const char *_usbDrive = ""; + const int _interval = 1000; // in ms - QThread *_thread = nullptr; - bool _init = false; + QThread *_thread = nullptr; + bool _init = false; // Singleton SINGLETON(USBWatcher) Index: sources/threads.cpp =================================================================== diff -u -rb9c5b0b3afc3b34d4980ecc4f023f498f80dafbc -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/threads.cpp (.../threads.cpp) (revision b9c5b0b3afc3b34d4980ecc4f023f498f80dafbc) +++ sources/threads.cpp (.../threads.cpp) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -28,11 +28,12 @@ * this has currently been done in main.cpp in main() after the qpp.exe() is done. */ namespace Threads { - QThread _CanFrame_Thread; - QThread _CanMessage_Thread; - QThread _USBWatcher_Thread; - QThread _Logger_Thread; - QThread _Application_Thread; + QThread _CanFrame_Thread ; + QThread _CanAcknow_Thread ; + QThread _CanMessage_Thread ; + QThread _USBWatcher_Thread ; + QThread _Logger_Thread ; + QThread _Application_Thread ; /*! * \brief registerTypes @@ -51,6 +52,12 @@ // FrameInterface : This is required for Signal/Slots in threading. qRegisterMetaType("Can_Id"); + + // MessageAcknowModel : This is required for Signal/Slots in threading. + qRegisterMetaType("Sequence"); + + // MessageAcknowModel : This is required for Signal/Slots in threading. + qRegisterMetaType("FrameList"); } /*! @@ -73,10 +80,11 @@ */ void quitThreads() { - quitThread(_CanFrame_Thread ); - quitThread(_CanMessage_Thread ); - quitThread(_USBWatcher_Thread ); - quitThread(_Logger_Thread ); - quitThread(_Application_Thread); + quitThread(_CanFrame_Thread ); + quitThread(_CanAcknow_Thread ); + quitThread(_CanMessage_Thread ); + quitThread(_USBWatcher_Thread ); + quitThread(_Logger_Thread ); + quitThread(_Application_Thread ); } } Index: sources/threads.h =================================================================== diff -u -rb9c5b0b3afc3b34d4980ecc4f023f498f80dafbc -r939d1bae9a394697d46ca913a2dc3442bf8ef82f --- sources/threads.h (.../threads.h) (revision b9c5b0b3afc3b34d4980ecc4f023f498f80dafbc) +++ sources/threads.h (.../threads.h) (revision 939d1bae9a394697d46ca913a2dc3442bf8ef82f) @@ -27,6 +27,7 @@ namespace Threads { extern QThread _CanFrame_Thread ; + extern QThread _CanAcknow_Thread ; extern QThread _CanMessage_Thread ; extern QThread _USBWatcher_Thread ; extern QThread _Logger_Thread ;