Index: cppcheck.err =================================================================== diff -u -r4244de5f994d6bf155752ec78c54b8e08edccb03 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- cppcheck.err (.../cppcheck.err) (revision 4244de5f994d6bf155752ec78c54b8e08edccb03) +++ cppcheck.err (.../cppcheck.err) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -1,8 +1,6 @@ -[sources/gui/guiview.cpp:106]: (style) The function 'alarmIDName' is never used. -[sources/gui/guiview.cpp:97]: (style) The function 'alarmPriorityName' is never used. +[sources/gui/guiview.cpp:171]: (style) The function 'alarmIDName' is never used. +[sources/gui/guiview.cpp:153]: (style) The function 'alarmPriorityName' is never used. [sources/utility/types.cpp:20]: (style) The function 'floatCompare' is never used. -[sources/storage/usbwatcher.cpp:55]: (style) The function 'isMounted' is never used. -[sources/storage/usbwatcher.cpp:60]: (style) The function 'isUmounted' is never used. -[sources/storage/filehandler.cpp:88]: (style) The function 'onRead' is never used. -[sources/maintimer.cpp:39]: (style) The function 'timerEvent' is never used. +[sources/storage/filehandler.cpp:61]: (style) The function 'read' is never used. +[sources/maintimer.cpp:52]: (style) The function 'timerEvent' is never used. (information) Cppcheck cannot find all the include files. Cppcheck can check the code without the include files found. But the results will probably be more accurate if all the include files are found. Please check your project's include directories and add all of them as include directories for Cppcheck. To see what files Cppcheck cannot find use --check-config. Index: cppcheck.log =================================================================== diff -u -r4244de5f994d6bf155752ec78c54b8e08edccb03 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- cppcheck.log (.../cppcheck.log) (revision 4244de5f994d6bf155752ec78c54b8e08edccb03) +++ cppcheck.log (.../cppcheck.log) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,88 +14,88 @@ Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 3/23 files checked 13% done -Checking sources/canbus/alarminterpreter.cpp ... +Checking sources/canbus/caninterface.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 4/23 files checked 17% done -Checking sources/canbus/caninterface.cpp ... +Checking sources/canbus/frameinterface.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 5/23 files checked 21% done -Checking sources/canbus/frameinterface.cpp ... +Checking sources/canbus/messagebuilder.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native +Checking sources/canbus/messagebuilder.cpp: DISABLE_CRC... 6/23 files checked 26% done -Checking sources/canbus/messagebuilder.cpp ... +Checking sources/canbus/messagedispatcher.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native -Checking sources/canbus/messagebuilder.cpp: DISABLE_CRC... 7/23 files checked 30% done -Checking sources/canbus/messagedispatcher.cpp ... +Checking sources/canbus/messageinterpreter.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 8/23 files checked 34% done -Checking sources/canbus/messageinterpreter.cpp ... +Checking sources/configuration/display.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 9/23 files checked 39% done -Checking sources/configuration/display.cpp ... +Checking sources/configuration/sound.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 10/23 files checked 43% done -Checking sources/configuration/sound.cpp ... +Checking sources/gui/guicontroller.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 11/23 files checked 47% done -Checking sources/gui/guicontroller.cpp ... +Checking sources/gui/guiglobals.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 12/23 files checked 52% done -Checking sources/gui/guiglobals.cpp ... +Checking sources/gui/guiview.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 13/23 files checked 56% done -Checking sources/gui/guiview.cpp ... +Checking sources/maintimer.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 14/23 files checked 60% done -Checking sources/maintimer.cpp ... +Checking sources/storage/filehandler.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 15/23 files checked 65% done -Checking sources/storage/filehandler.cpp ... +Checking sources/storage/logger.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 16/23 files checked 69% done -Checking sources/storage/logger.cpp ... +Checking sources/storage/settings.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 17/23 files checked 73% done -Checking sources/storage/settings.cpp ... +Checking sources/storage/storageglobals.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 18/23 files checked 78% done -Checking sources/storage/storageglobals.cpp ... +Checking sources/storage/usbwatcher.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native 19/23 files checked 82% done -Checking sources/storage/usbwatcher.cpp ... +Checking sources/threads.cpp ... Defines: Includes: -I.//sources/ -I.//sources/gui/ -I.//sources/storage/ -I.//sources/configuration/ -I.//sources/canbus/ Platform:Native Index: denali.pro =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- denali.pro (.../denali.pro) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ denali.pro (.../denali.pro) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -36,7 +36,6 @@ HEADERS += \ sources/applicationcontroller.h \ sources/applicationpost.h \ - sources/canbus/alarminterpreter.h \ sources/canbus/caninterface.h \ sources/canbus/frameinterface.h \ sources/canbus/messagebuilder.h \ @@ -55,6 +54,7 @@ sources/storage/settings.h \ sources/storage/storageglobals.h \ sources/storage/usbwatcher.h \ + sources/threads.h \ sources/utility/crc.h \ sources/utility/format.h \ sources/utility/types.h @@ -63,12 +63,10 @@ main.cpp \ sources/applicationcontroller.cpp \ sources/applicationpost.cpp \ - sources/canbus/alarminterpreter.cpp \ sources/canbus/caninterface.cpp \ sources/canbus/frameinterface.cpp \ sources/canbus/messagebuilder.cpp \ sources/canbus/messagedispatcher.cpp \ - sources/canbus/messageglobals.cpp \ sources/canbus/messageinterpreter.cpp \ sources/configuration/display.cpp \ sources/configuration/sound.cpp \ @@ -81,6 +79,7 @@ sources/storage/settings.cpp \ sources/storage/storageglobals.cpp \ sources/storage/usbwatcher.cpp \ + sources/threads.cpp \ sources/utility/crc.cpp \ sources/utility/format.cpp \ sources/utility/types.cpp Index: main.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- main.cpp (.../main.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ main.cpp (.../main.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -26,7 +26,6 @@ #include #include #include -#include // Project #include "maintimer.h" @@ -37,6 +36,7 @@ #include "guicontroller.h" #include "logger.h" #include "usbwatcher.h" +#include "threads.h" #ifdef UNIT_TEST #include TEST_CLASS_INCLUDE @@ -91,38 +91,35 @@ app.installTranslator(&translator); } + //! - Initializing required thread types + Threads::registerTypes(); + //! - Initializing Logger _Logger.init(); LOG_EVENT(QObject::tr("Application Started")); //! - Initializing USB Watcher - _USBWatcher.init(); + _USBWatcher.init(Threads::_USBWatcher_Thread); //! - Initializing CanBus Interface - if (_CanInterface.init()) { + if (_CanInterface.init(Threads::_CanFrame_Thread)) { _CanInterface.enableConsoleOut(_consoleoutCanInterface); } //! - Initializing CanBus Message Handler - _FrameInterface.init(); + _FrameInterface.init(Threads::_CanFrame_Thread); //! - Initializing CanBus Message Dispatcher - _MessageDispatcher.init(); - _MessageDispatcher.enableConsoleOut(_consoleoutFrameInterface); + if (_MessageDispatcher.init(Threads::_CanMessage_Thread)) { + _MessageDispatcher.enableConsoleOut(_consoleoutFrameInterface); + } //! - Initializing Application Controller - _ApplicationController.init(); - QObject::connect(&app, &QApplication::aboutToQuit, []() { - emit _ApplicationController.quit(); - }); - QObject::connect(&_ApplicationController, &ApplicationController::quit, &app, [](int retcode) { - QCoreApplication::exit(retcode); - qDebug() << QObject::tr("Application Terminated: %1").arg(retcode); - }, Qt::QueuedConnection); + _ApplicationController.init(Threads::_Application_Thread); ////! - Initializing GUI Controller - _GuiController.init(); + _GuiController.init(Threads::_Application_Thread); //! - Initializing Main Timer _MainTimer.init(); @@ -132,6 +129,13 @@ int app_exec = app.exec(); + // Due to Qt Error the CAN Device cannot be disable/enable from withing another thread + // (other than main thread which is the owner of the CanDevice owner). + // So it needs to be done here in main thread. + _CanInterface.quitDevice(); + + Threads::quitThreads(); + return app_exec; } #endif Index: sources/applicationcontroller.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/applicationcontroller.cpp (.../applicationcontroller.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/applicationcontroller.cpp (.../applicationcontroller.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -38,14 +38,47 @@ */ bool ApplicationController::init() { - if (!_applicationPost->init()) return false; + if ( _init ) return false; + _init = true; + initConnections(); + if (!_applicationPost->init()) return false; + + LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); + return true; } /*! - * \brief GUI Controller connections definition + * \brief ApplicationController::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 ApplicationController::init(QThread &vThread) +{ + if ( init() ) return false; + initThread(vThread); + return true; +} + +/*! + * \brief ApplicationController::quit + * \details quits the class + * Calls quitThread + */ +void ApplicationController::quit() +{ + quitThread(); +} + +/*! + * \brief ApplicationController::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + */ void ApplicationController::initConnections() { @@ -72,6 +105,37 @@ } /*! + * \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 ApplicationController::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 ApplicationController::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * And to be destroyed there. + */ +void ApplicationController::quitThread() +{ + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); +} + +/*! * \brief Process the requested action * \details Processes the requested action * \param vAction - User requested Action @@ -103,25 +167,46 @@ keepAlive(); } +/*! + * \brief ApplicationController::onUSBDriveMount + * \details This is the slot which connects to the _USBWatcher didUSBDriveMount signal + * and notifies the other classes (GuiController) by emitting its signal didUSBDriveMount + */ void ApplicationController::onUSBDriveMount () { emit didUSBDriveMount(); } +/*! + * \brief ApplicationController::onUSBDriveRemove + * \details This is the slot which connects to the _GuiController didUSBDriveUmount signal + * and notifies the other classes (USBWatcher) by emitting its signal didUSBDriveUmount + */ void ApplicationController::onUSBDriveUmount() { emit didUSBDriveUmount(); } +/*! + * \brief ApplicationController::onUSBDriveRemove + * \details This is the slot which connects to the _USBWatcher didUSBDriveRemove signal + * and notifies the other classes (GuiController) by emitting its signal didUSBDriveRemove + */ void ApplicationController::onUSBDriveRemove() { emit didUSBDriveRemove(); } +/*! + * \brief ApplicationController::onExportLog + * \details the slot which will be called by UI to so the log export. + */ void ApplicationController::onExportLog() { Storage::FileHandler fh; - fh.exportLog(); + fh.concurrentExportLog(); + //TODO : it needs to change in a way that we can have an actual export finish time and then emit signal. + // this is not accurate. emit didExportLog(); } Index: sources/applicationcontroller.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/applicationcontroller.h (.../applicationcontroller.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/applicationcontroller.h (.../applicationcontroller.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -15,36 +15,43 @@ // Qt #include -#include // Project #include "main.h" #include "guiglobals.h" #include "applicationpost.h" -#include "caninterface.h" - // define #define _ApplicationController ApplicationController::I() // namespace using namespace Gui; -using namespace Can; class ApplicationController : public QObject { Q_OBJECT ApplicationPost *_applicationPost = nullptr; + QThread *_thread = nullptr; + bool _init = false; + // Singleton SINGLETON(ApplicationController) -public: +public slots: bool init(); + bool init(QThread &vThread); +private slots: + void quit(); + private: void initConnections(); + + void initThread(QThread &vThread); + void quitThread(); + void keepAlive(); private slots: // Should be private for thread safety and is connected internally. @@ -68,8 +75,5 @@ void didUSBDriveRemove(); void didExportLog(); - - void quit(int retcode=0); - }; Fisheye: Tag 56d00a82669a7a2c00ab90109a89dbec8db27527 refers to a dead (removed) revision in file `sources/canbus/alarminterpreter.cpp'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 56d00a82669a7a2c00ab90109a89dbec8db27527 refers to a dead (removed) revision in file `sources/canbus/alarminterpreter.h'. Fisheye: No comparison available. Pass `N' to diff? Index: sources/canbus/caninterface.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,13 +14,13 @@ #include "caninterface.h" // Qt -#include +#include #include // Project #include "logger.h" -#include "frameinterface.h" #include "messageglobals.h" +#include "frameinterface.h" // namespace using namespace Can; @@ -38,44 +38,45 @@ */ bool CanInterface::init() { + if ( _init ) return false; + _init = true; - // This is required for Signal/Slots in threading. - qRegisterMetaType("QCanBusFrame"); + if ( ! initDevice() ) return false; + if ( ! testDevice() ) return false; - // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , "_CanInterface::init", "The Class initialization must be done in Main Thread" ); - _CanFrame_Thread.setObjectName("CAN Frame Thread"); - connect(qApp, &QApplication::aboutToQuit, this, &CanInterface::quit); - _CanFrame_Thread.start(); - moveToThread(&_CanFrame_Thread); - - if ( ! createDevice() ) return false; - if ( ! checkDevice () ) return false; - _numberFramesWritten = 0; initConnections(); status(tr("Connected")); - LOG_EVENT(QObject::tr("CanInterface Initialized")); LOG_EVENT(status()); + LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); + return true; } /*! + * \brief CanInterface::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 CanInterface::init(QThread &vThread) +{ + if ( ! init() ) return false; + initThread(vThread); + return true; +} + +/*! * \brief CanInterface quit - * \details Quit the CANBUS Interface by disconnecting the bus and device. + * \details quits the class + * Calls quitThread */ void CanInterface::quit() { - deleteDevice(); - - // runs in Logger thread - moveToThread(qApp->thread()); - - // runs in main thread - _CanFrame_Thread.quit(); - _CanFrame_Thread.wait(); - + quitThread(); } /*! @@ -104,18 +105,48 @@ connect(_canDevice, SIGNAL( framesWritten(qint64)), this , SLOT (onFrameWrittern(qint64))); - } connect(&_FrameInterface, SIGNAL(didFrameTransmit(QCanBusFrame)), this , SLOT( onFrameTransmit(QCanBusFrame))); } /*! + * \brief CanInterface::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 CanInterface::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 CanInterface::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * And to be destroyed there. + */ +void CanInterface::quitThread() +{ + if (! _thread) return; + + // runs in thread + moveToThread(qApp->thread()); +} + +/*! * \brief CanInterface::createDevice * \details Creates the CANBus device * \return false if can't create the device */ -bool CanInterface::createDevice() +bool CanInterface::initDevice() { QString mError; _canDevice = QCanBus::instance()->createDevice(_canType, _canInterface, &mError); @@ -132,7 +163,7 @@ * \details Checks if the device has been connected. * \return */ -bool CanInterface::checkDevice() +bool CanInterface::testDevice() { if (!_canDevice->connectDevice()) { status(tr("Connection")); @@ -148,7 +179,7 @@ * \brief CanInterface::deleteDevice * \details Disconnect the CANBus device and deletes the pointer */ -void CanInterface::deleteDevice() +void CanInterface::quitDevice() { if (!_canDevice) return; Index: sources/canbus/caninterface.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/caninterface.h (.../caninterface.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/caninterface.h (.../caninterface.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -21,7 +21,7 @@ #include "main.h" // Define -#define _CanInterface CanInterface::I() +#define _CanInterface Can::CanInterface::I() // forward declarations class tst_canbus; @@ -56,22 +56,33 @@ QString _canStatus = ""; bool _enableConsoleOut = false; - // Singleton - SINGLETON(CanInterface) + QThread *_thread = nullptr; + bool _init = false; -public: +// Singleton +SINGLETON(CanInterface) + +public slots: bool init(); + bool init(QThread &vThread); + +private slots: void quit(); +public: QString status() const; void enableConsoleOut(bool vEnabled) { _enableConsoleOut = vEnabled; } + + void quitDevice(); private: void initConnections(); - bool createDevice(); - bool checkDevice (); - void deleteDevice(); + void initThread(QThread &vThread); + void quitThread(); + bool initDevice(); + bool testDevice(); + void status (const QString &vDescription, QString vError = ""); bool transmit (const QCanBusFrame &vFrame); void consoleOut (const QCanBusFrame &vFrame); Index: sources/canbus/frameinterface.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/frameinterface.cpp (.../frameinterface.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/frameinterface.cpp (.../frameinterface.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,16 +14,13 @@ #include "frameinterface.h" // Qt -#include -#include +#include #include // Project #include "logger.h" -#include "maintimer.h" #include "messagedispatcher.h" #include "caninterface.h" -#include "format.h" // namespace using namespace Can; @@ -39,32 +36,39 @@ */ bool FrameInterface::init() { - // This is required for Signal/Slots in threading. - qRegisterMetaType("Can_Id"); + if ( _init ) return false; + _init = true; - // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , "_FrameInterface::init", "The Class initialization must be done in Main Thread" ); - _CanFrame_Thread.setObjectName("Can Frame Thread"); - connect(qApp, &QApplication::aboutToQuit, this, &FrameInterface::quit); - _CanFrame_Thread.start(); - moveToThread(&_CanFrame_Thread); - - // runs in USB Watcher thread initConnections(); - LOG_EVENT(QObject::tr("FrameInterface Initialized")); + LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); return true; } -void FrameInterface::quit() +/*! + * \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) { - // runs in Logger thread - moveToThread(qApp->thread()); + if ( init() ) return false; + initThread(vThread); + return true; +} - // runs in main thread - _CanFrame_Thread.quit(); - _CanFrame_Thread.wait(); +/*! + * \brief FrameInterface::quit + * \details quits the class + * Calls quitThread + */ +void FrameInterface::quit() +{ + quitThread(); } /*! @@ -84,6 +88,37 @@ } /*! + * \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 Index: sources/canbus/frameinterface.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/frameinterface.h (.../frameinterface.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/frameinterface.h (.../frameinterface.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -16,22 +16,18 @@ // Qt #include #include -#include // Project #include "main.h" -#include "guiglobals.h" -#include "messagebuilder.h" -#include "messageinterpreter.h" +#include "messageglobals.h" // Define -#define _FrameInterface FrameInterface::I() +#define _FrameInterface Can::FrameInterface::I() // forward declarations class tst_canbus; // namespace -using namespace Gui; namespace Can { /*! @@ -59,14 +55,25 @@ eChannel_Outputs, ///< The Channels that are related to UI frames out. }; - // Singleton - SINGLETON(FrameInterface) -public: + QThread *_thread = nullptr; + bool _init = false; + +// Singleton +SINGLETON(FrameInterface) + +public slots: bool init(); + bool init(QThread &vThread); + +private slots: void quit(); private: void initConnections(); + + void initThread(QThread &vThread); + void quitThread(); + void transmitFrame(Can_Id vCan_Id, const QByteArray &vData = 0); ChannelGroup checkChannel(quint32 vFrameId, bool *vOK = nullptr); Index: sources/canbus/messagebuilder.cpp =================================================================== diff -u -rfeb3423b373dc2a2c4267ef9fcb4d924d738423d -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision feb3423b373dc2a2c4267ef9fcb4d924d738423d) +++ sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,7 +14,6 @@ #include "messagebuilder.h" // Qt -#include // Project #include "logger.h" @@ -39,7 +38,7 @@ * so it has been passed and checked. * \return list of frames of type FrameList */ -bool MessageBuilder::buildFrames(GuiActionType vAction, const QByteArray &vData, FrameList &vFrameList) +bool MessageBuilder::buildFrames(Gui::GuiActionType vAction, const QByteArray &vData, FrameList &vFrameList) { QByteArray mPayload ; addSyncByte (mPayload); // Sync Byte @@ -83,9 +82,9 @@ * \param vAction - The ActionID of the message which needs to be appended * to the Payload vPayload */ -bool MessageBuilder::addActionId(QByteArray &vPayload, GuiActionType vAction) +bool MessageBuilder::addActionId(QByteArray &vPayload, Gui::GuiActionType vAction) { - if (vAction != GuiActionType::Unknown) { + if (vAction != Gui::GuiActionType::Unknown) { quint16 mAction = static_cast(vAction); vPayload += (mAction >> 8) & 0xFF; // high byte vPayload += mAction & 0xFF; // low byte @@ -105,7 +104,7 @@ * \param vData - The data which is going to be message payload. * \return false if the vData of type QByteArray is not sufficient regarding vAction */ -bool MessageBuilder::addData(QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) +bool MessageBuilder::addData(QByteArray &vPayload, Gui::GuiActionType vAction, const QByteArray &vData) { quint8 len = payloadLen[vAction]; // if len has been set to max(255) @@ -293,7 +292,7 @@ * \note Removes the 2 bytes of ActionID from vPayload * It starts from the first byte so those 2 bytes should be the first 2 bytes. */ -GuiActionType MessageBuilder::getActionId(QByteArray &vPayload) +Gui::GuiActionType MessageBuilder::getActionId(QByteArray &vPayload) { quint16 mActionId; mActionId = (vPayload[0] << 8) | vPayload[1]; @@ -302,7 +301,7 @@ //return GuiActionType::Unknown; vPayload = vPayload.mid(eLenActionId); - return static_cast(mActionId); + return static_cast(mActionId); } /*! Index: sources/canbus/messagebuilder.h =================================================================== diff -u -rc5389647e2259e67f8e6d923f3481d7d3f4eab68 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision c5389647e2259e67f8e6d923f3481d7d3f4eab68) +++ sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -15,13 +15,12 @@ // Qt #include -#include +//#include // Project #include "guiglobals.h" #include "messageglobals.h" -using namespace Gui; namespace Can { /*! @@ -50,31 +49,31 @@ { Q_OBJECT - bool _enableConsoleOut = false; + bool _enableConsoleOut = false; - void addSyncByte ( QByteArray &vPayload); - bool addActionId ( QByteArray &vPayload, GuiActionType vAction) __attribute_warn_unused_result__; - bool addData ( QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) __attribute_warn_unused_result__; - void addCRC ( QByteArray &vPayload); - void addPadding ( QByteArray &vPayload); + void addSyncByte ( QByteArray &vPayload); + bool addActionId ( QByteArray &vPayload, Gui::GuiActionType vAction) __attribute_warn_unused_result__; + bool addData ( QByteArray &vPayload, Gui::GuiActionType vAction, const QByteArray &vData) __attribute_warn_unused_result__; + void addCRC ( QByteArray &vPayload); + void addPadding ( QByteArray &vPayload); - quint8 calcCRC (const QByteArray &vData ); - bool checkCRC (const QByteArray &vData , quint8 &vExpected, quint8 &vBeenRead); + quint8 calcCRC (const QByteArray &vData ); + bool checkCRC (const QByteArray &vData , quint8 &vExpected, quint8 &vBeenRead); - bool hasSyncByte ( QByteArray &vPayload); - QByteArray getHeader (const QByteArray &vPayload); - GuiActionType getActionId ( QByteArray &vPayload); - int getLength ( QByteArray &vPayload); - QByteArray getData (const QByteArray &vPayload, int vLen); + bool hasSyncByte ( QByteArray &vPayload); + QByteArray getHeader (const QByteArray &vPayload); + Gui::GuiActionType getActionId ( QByteArray &vPayload); + int getLength ( QByteArray &vPayload); + QByteArray getData (const QByteArray &vPayload, int vLen); - void printPayload(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); - void consoleOut (const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); + void printPayload(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); + void consoleOut (const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); public: explicit MessageBuilder(QObject *parent = nullptr); // build message to be sent frame by frame - bool buildFrames(GuiActionType vAction , const QByteArray &vData, FrameList &vFrameList) __attribute_warn_unused_result__; + bool buildFrames(Gui::GuiActionType vAction , const QByteArray &vData, FrameList &vFrameList) __attribute_warn_unused_result__; // build message from received frames bool buildMessage(const QByteArray &vPayload, Message &vMessage, Can_Id vCan_Id) __attribute_warn_unused_result__; Index: sources/canbus/messagedispatcher.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,6 +14,7 @@ #include "messagedispatcher.h" // Qt +#include #include // Project @@ -34,33 +35,40 @@ */ bool MessageDispatcher::init() { - // This is required for Signal/Slots in threading. - qRegisterMetaType("Can_Id"); + if ( _init ) return false; + _init = true; - // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , "_MessageDispatcher::init", "The Class initialization must be done in Main Thread" ); - _CanMessage_Thread.setObjectName("Can Message Thread"); - connect(qApp, &QApplication::aboutToQuit, this, &MessageDispatcher::quit); - _CanMessage_Thread.start(); - moveToThread(&_CanMessage_Thread); - - // runs in USBWatcher thread initConnections(); - LOG_EVENT(QObject::tr("MessageDispatcher Initialized")); + LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); return true; } -void MessageDispatcher::quit() +/*! + * \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) { - // runs in Logger thread - moveToThread(qApp->thread()); + if ( init() ) return false; + initThread(vThread); + return true; +} - // runs in main thread - _CanMessage_Thread.quit(); - _CanMessage_Thread.wait(); +/*! + * \brief MessageDispatcher::quit + * \details quits the class + * Calls quitThread + */ +void MessageDispatcher::quit() +{ + quitThread(); } /*! @@ -80,6 +88,37 @@ } /*! + * \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 Index: sources/canbus/messagedispatcher.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -18,17 +18,18 @@ // Project #include "main.h" -#include "messageglobals.h" #include "messagebuilder.h" #include "messageinterpreter.h" // define -#define _MessageDispatcher MessageDispatcher::I() +#define _MessageDispatcher Can::MessageDispatcher::I() // forward declarations class tst_canbus; -using namespace Gui; +// since this class is the interface between GUI and Can +// it needs to use Gui namespace otherwise it makes code hard to read. +using namespace Gui; namespace Can { /*! * \brief The MessageDispatcher class \n @@ -82,24 +83,36 @@ { Q_OBJECT + // friends + friend class ::tst_canbus; + QHash _messageList; MessageBuilder _builder; MessageInterpreter _interpreter; - // friends - friend class ::tst_canbus; + QThread *_thread = nullptr; + bool _init = false; - // Singleton - SINGLETON(MessageDispatcher) -public: +// Singleton +SINGLETON(MessageDispatcher) + +public slots: bool init(); + bool init(QThread &vThread); + +private slots: void quit(); + +public: void enableConsoleOut(bool vEnable) { _builder.enableConsoleOut(vEnable); } private: void initConnections(); + void initThread(QThread &vThread); + void quitThread(); + void actionTransmit(GuiActionType vActionId, const QVariantList &vData); signals: @@ -119,11 +132,11 @@ * \param vCanId - Target channel of the CANBUS message * \param vPayload - The payload of the message to be sent */ - void didFrameTransmit(Can_Id vCanId , const QByteArray &vPayload); + void didFrameTransmit(Can_Id vCanId , const QByteArray &vPayload); private slots: // A Frame has been received from CanInterface - void onFrameReceive (Can_Id vCanId , const QByteArray &vPayload); + void onFrameReceive (Can_Id vCanId , const QByteArray &vPayload); // An Action has been requested to be transmitted. void onActionTransmit(GuiActionType vActionId, const QVariantList &vData); Fisheye: Tag 56d00a82669a7a2c00ab90109a89dbec8db27527 refers to a dead (removed) revision in file `sources/canbus/messageglobals.cpp'. Fisheye: No comparison available. Pass `N' to diff? Index: sources/canbus/messageglobals.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messageglobals.h (.../messageglobals.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/canbus/messageglobals.h (.../messageglobals.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -15,29 +15,23 @@ // Qt #include -#include // Project #include "guiglobals.h" -using namespace Gui; namespace Can { -extern QThread _CanFrame_Thread; -extern QThread _CanMessage_Thread; - - /*! * \brief Payload Length * \details List of each ActionID required data (in byte) length in the message. * So the data collector has to collect this amount of bytes as payload of a message. */ -const QHash payloadLen { - {GuiActionType::PowerOff , 1 }, - {GuiActionType::KeepAlive , 0 }, - {GuiActionType::BloodFlow , 7 * 4 } , // 7 parameters each 4bytes - {GuiActionType::DialysateFlow , 7 * 4 } , // 7 parameters each 4bytes - {GuiActionType::String , 255 }, +const QHash payloadLen { + {Gui::GuiActionType::PowerOff , 1 }, + {Gui::GuiActionType::KeepAlive , 0 }, + {Gui::GuiActionType::BloodFlow , 7 * 4 } , // 7 parameters each 4bytes + {Gui::GuiActionType::DialysateFlow , 7 * 4 } , // 7 parameters each 4bytes + {Gui::GuiActionType::String , 255 }, }; /*! @@ -103,12 +97,13 @@ * \details The message structure after it's been converted form hex bytes to meaningful struct for UI. */ struct Message { // TODO : Should be converted to MessageModel class // no time left for now !!! - Can_Id can_id; - GuiActionType actionId = GuiActionType::Unknown; - int length = 0; - QByteArray head; - QByteArray data; - bool initialized = false; + Can_Id can_id; + Gui::GuiActionType actionId = Gui::GuiActionType::Unknown; + int length = 0; + QByteArray head; + QByteArray data; + bool initialized = false; + bool isEmpty () { return !initialized || !data.length(); } bool isComplete() { return !isEmpty() && data.length() == length; } }; Index: sources/canbus/messageinterpreter.cpp =================================================================== diff -u -rfeb3423b373dc2a2c4267ef9fcb4d924d738423d -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision feb3423b373dc2a2c4267ef9fcb4d924d738423d) +++ sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -16,9 +16,8 @@ // Qt // Project -#include "types.h" -#include "format.h" #include "logger.h" +#include "format.h" using namespace Can; @@ -41,15 +40,15 @@ * \return true if the vActionId is valid. * This return value will be used later for error handling. */ -bool MessageInterpreter::interpretMessage(const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) +bool MessageInterpreter::interpretMessage(const Gui::GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) { bool ok = true; vPayload.clear(); int l = vData.length(); quint8 ix = 0; switch (vActionId) { // notice we are in transmit mode - case GuiActionType::PowerOff: - ix = static_cast(GuiActionIndx::PowerOff_Response); + case Gui::GuiActionType::PowerOff: + ix = static_cast(Gui::GuiActionIndx::PowerOff_Response); if (l >= ix + 1) { quint8 tmp = vData[ix].toUInt(); vPayload += tmp; @@ -59,13 +58,13 @@ ok = false; } break; - case GuiActionType::KeepAlive: + case Gui::GuiActionType::KeepAlive: // Nothing needs to be done. // KeepAlive has No data. // Mentioned in the switch/case to be registered as a valid message. break; - case GuiActionType::String: + case Gui::GuiActionType::String: vPayload = Format::fromVariant(vData[0]); break; @@ -91,7 +90,7 @@ * \return true if the message channel is in the range which can be interpreted, false otherwise. * This return value will be used later to emit MessageDispatcher::didActionReceive signal or not */ -bool MessageInterpreter::interpretMessage(const Can_Id vCan_Id, const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +bool MessageInterpreter::interpretMessage(const Can_Id vCan_Id, const Message &vMessage, Gui::GuiActionType &vActionId, QVariantList &vData) { bool ok = false; switch (vCan_Id) { @@ -134,14 +133,14 @@ * \return true if the message CANBUS channel is in the range which can be interpreted, false otherwise. * This return value will be used later to emit MessageDispatcher::didActionReceive signal or not */ -bool MessageInterpreter::interpretMessage_HD(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +bool MessageInterpreter::interpretMessage_HD(const Message &vMessage, Gui::GuiActionType &vActionId, QVariantList &vData) { bool ok = true; vActionId = vMessage.actionId; vData.clear(); switch (vActionId) { // notice we are in receive mode - case GuiActionType::PowerOff: { + case Gui::GuiActionType::PowerOff: { quint8 mShowHide; ok = getPowerOffData(vMessage, mShowHide); if (ok) { @@ -151,23 +150,23 @@ break; } - case GuiActionType::BloodFlow: + case Gui::GuiActionType::BloodFlow: ok = bloodFlowData (vMessage, vData); break; - case GuiActionType::DialysateFlow: + case Gui::GuiActionType::DialysateFlow: ok = dialysateFlowData (vMessage, vData); break; - case GuiActionType::AlarmStatus: + case Gui::GuiActionType::AlarmStatus: ok = alarmStatus (vMessage, vData); break; - case GuiActionType::AlarmTriggered: + case Gui::GuiActionType::AlarmTriggered: printUnhandled (vMessage); break; - case GuiActionType::AlarmCleared: + case Gui::GuiActionType::AlarmCleared: printUnhandled (vMessage); break; @@ -191,7 +190,7 @@ * \return true if the message CANBUS channel is in the range which can be interpreted, false otherwise. * This return value will be used later to emit MessageDispatcher::didActionReceive signal or not */ -bool MessageInterpreter::interpretMessage_DG(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +bool MessageInterpreter::interpretMessage_DG(const Message &vMessage, Gui::GuiActionType &vActionId, QVariantList &vData) { Q_UNUSED(vMessage ); Q_UNUSED(vActionId); @@ -214,7 +213,7 @@ { bool ok = true; int l = vMessage.data.length(); - quint8 ix = static_cast(GuiActionIndx::PowerOff_ShowHide); + quint8 ix = static_cast(Gui::GuiActionIndx::PowerOff_ShowHide); if (l >= ix + 1) { quint8 tmp = vMessage.data[ix]; vShowHide = tmp; @@ -246,10 +245,10 @@ Types::F32 &vMeasuredFlow , Types::F32 &vRotorSpeed , Types::F32 &vMotorSpeed, Types::F32 &vMotorCtlSpeed , Types::F32 &vMotorCtlCurrent , Types::F32 &vPWMDtCycle) { - if ( vMessage.actionId != GuiActionType::BloodFlow ) { + if ( vMessage.actionId != Gui::GuiActionType::BloodFlow ) { return false; } - if ( vMessage.data.length() < payloadLen[GuiActionType::BloodFlow] ) { + if ( vMessage.data.length() < payloadLen[Gui::GuiActionType::BloodFlow] ) { QString mActionIdHexString = Format::toHexString(vMessage.actionId); LOG_ERROR(tr("Incorrect data for Message ID (HD) '%1'").arg(mActionIdHexString)); return false; @@ -267,6 +266,15 @@ return true; } +/*! + * \brief MessageInterpreter::bloodFlowData + * \details Used the getBloodFlowData method and converts each parameter + * in vData of type QVaranitList, to be used in the GUI + * Also logs the data + * \param vMessage - The message + * \param vData - the output data + * \return return value of the method getBloodFlowData + */ bool MessageInterpreter::bloodFlowData(const Message &vMessage, QVariantList &vData) { bool ok; @@ -327,10 +335,10 @@ Types::F32 &vMotorCtlSpeed , Types::F32 &vMotorCtlCurrent , Types::F32 &vPWMDtCycle) { - if ( vMessage.actionId != GuiActionType::DialysateFlow ) { + if ( vMessage.actionId != Gui::GuiActionType::DialysateFlow ) { return false; } - if ( vMessage.data.length() < payloadLen[GuiActionType::DialysateFlow] ) { + if ( vMessage.data.length() < payloadLen[Gui::GuiActionType::DialysateFlow] ) { QString mActionIdHexString = Format::toHexString(vMessage.actionId); LOG_ERROR(tr("Incorrect data for Message ID (HD) '%1'").arg(mActionIdHexString)); return false; @@ -348,6 +356,15 @@ return true; } +/*! + * \brief MessageInterpreter::dialysateFlowData + * \details Used the getDialysateFlowData method and converts each parameter + * in vData of type QVaranitList, to be used in the GUI + * Also logs the data + * \param vMessage - The message + * \param vData - the output data + * \return return value of the method getDialysateFlowData + */ bool MessageInterpreter::dialysateFlowData(const Message &vMessage, QVariantList &vData) { bool ok; @@ -405,10 +422,10 @@ Types::U32 &vMuteTimeout, Types::U32 &vEscalatesIn, Types::Flags &vFlags) { - if ( vMessage.actionId != GuiActionType::AlarmStatus ) { + if ( vMessage.actionId != Gui::GuiActionType::AlarmStatus ) { return false; } - if ( vMessage.data.length() < payloadLen[GuiActionType::AlarmStatus] ) { + if ( vMessage.data.length() < payloadLen[Gui::GuiActionType::AlarmStatus] ) { QString mActionIdHexString = Format::toHexString(vMessage.actionId); LOG_ERROR(tr("Incorrect data for Message ID (HD) '%1'").arg(mActionIdHexString)); return false; @@ -423,6 +440,15 @@ return true; } +/*! + * \brief MessageInterpreter::alarmStatus + * \details Used the getAlarmStatus method and converts each parameter + * in vData of type QVaranitList, to be used in the GUI + * Also logs the data + * \param vMessage - The message + * \param vData - the output data + * \return return value of the method getAlarmStatus + */ bool MessageInterpreter::alarmStatus(const Message &vMessage, QVariantList &vData) { bool ok; Index: sources/canbus/messageinterpreter.h =================================================================== diff -u -rfeb3423b373dc2a2c4267ef9fcb4d924d738423d -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/canbus/messageinterpreter.h (.../messageinterpreter.h) (revision feb3423b373dc2a2c4267ef9fcb4d924d738423d) +++ sources/canbus/messageinterpreter.h (.../messageinterpreter.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -17,11 +17,9 @@ #include // Project -#include "guiglobals.h" #include "messageglobals.h" #include "types.h" -using namespace Gui; namespace Can { /*! @@ -37,8 +35,8 @@ void printUnhandled (const Message &vMessage); - bool interpretMessage_HD (const Message &vMessage , GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; - bool interpretMessage_DG (const Message &vMessage , GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; + bool interpretMessage_HD (const Message &vMessage , Gui::GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; + bool interpretMessage_DG (const Message &vMessage , Gui::GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; bool getPowerOffData (const Message &vMessage , quint8 &vShowHide) __attribute_warn_unused_result__; @@ -69,8 +67,8 @@ explicit MessageInterpreter(QObject *parent = nullptr); // interpret the data into GUI understandable Actions/Data - bool interpretMessage(const Can_Id vCan_Id, const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; - bool interpretMessage(const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) __attribute_warn_unused_result__; + bool interpretMessage(const Can_Id vCan_Id, const Message &vMessage, Gui::GuiActionType &vActionId, QVariantList &vData) __attribute_warn_unused_result__; + bool interpretMessage(const Gui::GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) __attribute_warn_unused_result__; signals: Index: sources/gui/guicontroller.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/gui/guicontroller.cpp (.../guicontroller.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/gui/guicontroller.cpp (.../guicontroller.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -14,11 +14,12 @@ #include "guicontroller.h" // Qt -#include +#include +#include // Project -#include "applicationcontroller.h" #include "logger.h" +#include "applicationcontroller.h" // namespace using namespace Gui; @@ -30,8 +31,35 @@ GuiController::GuiController(QObject *parent) : QObject(parent) {} /*! - * \brief GuiController connections definition + * \brief GuiController::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 GuiController::init(QThread &vThread) +{ + if ( init() ) return false; + initThread(vThread); + return true; +} + +/*! + * \brief GuiController::quit + * \details quits the class + * Calls quitThread + */ +void GuiController::quit() +{ + quitThread(); +} + +/*! + * \brief GuiController::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + */ void GuiController::initConnections() { // From HD/DG @@ -46,12 +74,49 @@ } /*! + * \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 GuiController::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 GuiController::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * And to be destroyed there. + */ +void GuiController::quitThread() +{ + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); +} + +/*! * \brief GuiController initializer */ -void GuiController::init() +bool GuiController::init() { + if ( _init ) return false; + _init = true; + initConnections(); - LOG_EVENT(QObject::tr("Gui Controller Initialized")); + + LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); + + return true; } /*! @@ -70,29 +135,41 @@ } } -bool GuiController::handleTransmit(GuiActionType, const QVariantList &) +/*! + * \brief GuiController::handleTransmit + * \details If an action request from Gui can be handled in Gui Controller + * without passing to HD, then can be handled here. + * \param vAction - the Requested action + * \param vData - Data of the action + * \return if handled returns true to not to pass to the lower level (Application Controller) + * to not to send to HD then. + */ +bool GuiController::handleTransmit(GuiActionType vAction, const QVariantList &vData) { + Q_UNUSED(vAction) + Q_UNUSED(vData) + // This is an example implementation of how to handle // which does not require HD approval in GuiController - /* // Process the GuiView Request. // It can be processed in GuiController take action and notify GuiView switch (vAction) { case GuiActionType::PowerOff: + //qApp->quit(); + // GUI Controller decides (loop back) - if (vData == GuiActionData::NoData){ - // PowerOff noData is a request - emit didActionReceive (vAction, GuiActionData::Accepted); - return true; - } + //if (vData == GuiActionData::NoData){ + // // PowerOff noData is a request + // emit didActionReceive (vAction, GuiActionData::Accepted); + // return true; + //} break; //case Another_Command_Which_Doesn't_Require_HD_Approval: //return true; //break; default: break; } - */ return false; } @@ -109,22 +186,43 @@ emit didActionReceive (vAction, vData); } +/*! + * \brief GuiController::onUSBDriveMount + * \details emits didUSBDriveMount signal to notify other classes (GuiView) + * , the USB drive has been mounted. + */ void GuiController::onUSBDriveMount() { emit didUSBDriveMount(); } +/*! + * \brief GuiController::doUSBDriveUmount + * \details emits didUSBDriveUmount signal to notify other classes (GuiView) + * , the USB drive has been unmounted. + */ void GuiController::doUSBDriveUmount() { emit didUSBDriveUmount(); } -void GuiController::doExportLog() +/*! + * \brief GuiController::onUSBDriveRemove + * \details emits didUSBDriveRemove signal to notify other classes (GuiView) + * , the USB drive has been removed. + */ +void GuiController::onUSBDriveRemove() { - emit didExportLog(); + emit didUSBDriveRemove(); } -void GuiController::onUSBDriveRemove() +/*! + * \brief GuiController::doExportLog + * \details emits didExportLog signal to notify other classes (ApplicationController) + * , the User requested to export the log. + */ +void GuiController::doExportLog() { - emit didUSBDriveRemove(); + emit didExportLog(); } + Index: sources/gui/guicontroller.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/gui/guicontroller.h (.../guicontroller.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/gui/guicontroller.h (.../guicontroller.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -30,13 +30,25 @@ { Q_OBJECT + QThread *_thread = nullptr; + bool _init = false; + +// singleton SINGLETON(GuiController) -public: - void init(); +public slots: + bool init(); + bool init(QThread &vThread); + +private slots: + void quit(); + private: void initConnections(); + void initThread(QThread &vThread); + void quitThread(); + bool handleTransmit(GuiActionType vAction, const QVariantList &vData); public slots: Index: sources/gui/guiview.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/gui/guiview.cpp (.../guiview.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/gui/guiview.cpp (.../guiview.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -30,6 +30,11 @@ initConnections(); } +/*! + * \brief GuiView::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + */ void GuiView::initConnections() { connect(&_GuiController, SIGNAL(didActionReceive (GuiActionType, const QVariantList &)), @@ -55,45 +60,96 @@ &_GuiController, SLOT( doExportLog())); } +/*! + * \brief GuiView::onActionReceive + * \details emits didActionReceive signal to notify other classes (Gui) + * , an action has been received. + * \param vAction - the action + * \param vData - the action data + */ void GuiView::onActionReceive (GuiActionType vAction, const QVariantList &vData) { // process the evaluation and notify GUI // process ... emit didActionReceive (vAction, vData); } -void GuiView::doUSBDriveMount () -{ - emit didUSBDriveMount (); -} - -void GuiView::doUSBDriveRemove() -{ - emit didUSBDriveRemove(); -} - +/*! + * \brief GuiView::doActionTransmit + * \details emits didActionTransmit signal to notify other classes (GuiController) + * , an action has been required to be transmitted. + * \param vAction - the action + * \param vData - the action data + */ void GuiView::doActionTransmit(GuiActionType vAction, const QVariantList &vData) { emit didActionTransmit(vAction, vData); } +/*! + * \brief GuiView::doActionTransmit + * \details emits didActionTransmit signal to notify other classes (GuiController) + * , an action has been required to be transmitted. + * \note The overloaded method with only one data parameter, for easier use in qml. + * \param vAction - the action + * \param vData - the action data + */ + void GuiView::doActionTransmit(GuiActionType vAction, const QVariant &vData) { QVariantList mData; mData += vData; emit didActionTransmit(vAction, mData); } +/*! + * \brief GuiView::doUSBDriveMount + * \details emits didUSBDriveMount signal to notify other classes (GuiController) + * , the USB drive has been mounted. + */ +void GuiView::doUSBDriveMount () +{ + emit didUSBDriveMount (); +} + +/*! + * \brief GuiView::doUSBDriveUmount + * \details emits didUSBDriveRemove signal to notify other classes (GuiController) + * , the USB drive has been removed. + */ void GuiView::doUSBDriveUmount() { emit didUSBDriveUmount(); } +/*! + * \brief GuiView::doUSBDriveRemove + * \details emits didUSBDriveRemove signal to notify other classes (GuiController) + * , the USB drive has been removed. + */ +void GuiView::doUSBDriveRemove() +{ + emit didUSBDriveRemove(); +} + +/*! + * \brief GuiView::doExportLog + * \details emits didExportLog signal to notify other classes (GuiController) + * , the User requested to export the log. + */ void GuiView::doExportLog() { emit didExportLog(); } +/*! + * \brief GuiView::alarmPriorityName + * \details this code is the place holder for the alarms description mapping + * since it is another feature + * it returns the enum name for now + * \param vEnum - The Alarm priority + * \return String representation of the Alarm priority Enum name + */ QString GuiView::alarmPriorityName(GuiAlarmPriority vEnum) { // this code is the place holder for the alarms description mapping @@ -103,6 +159,15 @@ int enumIdx = mo->indexOfEnumerator(qt_getEnumName(vEnum)); return mo->enumerator(enumIdx).valueToKey(vEnum); } + +/*! + * \brief GuiView::alarmIDName + * \details this code is the place holder for the alarms description mapping + * since it is another feature + * it returns the enum name for now + * \param vEnum - The Alarm ID + * \return String representation of the Alarm Id Enum name + */ QString GuiView::alarmIDName(GuiAlarmID vEnum) { // this code is the place holder for the alarms description mapping Index: sources/main.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/main.h (.../main.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/main.h (.../main.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -19,7 +19,6 @@ // Qt #include -#include // Project @@ -30,7 +29,6 @@ // - We still need to work on threading on other classes // - We need to have a singleton parent class // - Some code has been added to debug can interface (We still have swap frames) -// - Thread Objects need to be gathered all together in one place to be handled easily. #define SINGLETON(vCLASS) \ private: \ explicit vCLASS(QObject *parent = nullptr); \ @@ -42,6 +40,3 @@ static vCLASS _instance; \ return _instance; \ } - - -#define PRINT_THREAD_NAME //qDebug() << __func__ << QThread::currentThread()->objectName() Index: sources/maintimer.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/maintimer.cpp (.../maintimer.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/maintimer.cpp (.../maintimer.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -24,15 +24,31 @@ */ MainTimer::MainTimer(QObject *parent) : QObject(parent) { } +/*! + * \brief MainTimer::init + * \details starts the timer ans sets the timer interval + * \return + */ bool MainTimer::init() { startTimer(_interval); LOG_EVENT(QObject::tr("Main Timer Initialized")); return true; } +/*! + * \brief MainTimer::quit + * \details Does nothing for now + */ void MainTimer::quit() { } +/*! + * \brief MainTimer::timerEvent + * \details This event handler has been re-implemented in here + * to receive timer events for the object + * for the timer which has been set to _checkInterval + * Emits the didTimeout signal on each interval. + */ void MainTimer::timerEvent(QTimerEvent *) { emit didTimeout(); Index: sources/storage/filehandler.cpp =================================================================== diff -u -r5e78f0799b46963feb5756decb1a27b952cd19b3 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/filehandler.cpp (.../filehandler.cpp) (revision 5e78f0799b46963feb5756decb1a27b952cd19b3) +++ sources/storage/filehandler.cpp (.../filehandler.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -22,10 +22,19 @@ // Project #include "storageglobals.h" #include "logger.h" +#include "threads.h" // namespace using namespace Storage; +/*! + * \brief FileHandler::write + * \details Writes the content of vContent into the file vFileName. + * \param vFileName - Source file name + * \param vContent - The content which is going to be written in the file. + * \param vAppend - if set to true the content will be appended at the end of the file. + * \return false if file can't be opened. + */ bool FileHandler::write(const QString &vFileName, const QString &vContent, bool vAppend) { QFile file(vFileName); @@ -42,6 +51,13 @@ return true; } +/*! + * \brief FileHandler::read + * \details reads file vFilename content into vContent variable. + * \param vFileName - Source file name + * \param vContent - The content of the file which will be set when done. + * \return false if file can't be opened. + */ bool FileHandler::read(const QString &vFileName, QString &vContent) { QFile file(vFileName); @@ -54,22 +70,38 @@ return true; } +/*! + * \brief FileHandler::copyFolder + * \details Copies all the file and folders recursively. + * \param vSource - The source folder + * \param vDestination - The destination folder + * \return Tue on successful execution. + * \note This method uses the Linux "cp -r vSource vDestination" command + * Not a Thread-Safe method so made private to be called by export log + * QtConcurrent::run. + * + */ int FileHandler::copyFolder(const QString &vSource, const QString &vDestination ) { - PRINT_THREAD_NAME; - QString cp = "cp"; QStringList arguments; arguments << "-r" << vSource << vDestination; return QProcess::execute(cp, arguments); } -bool FileHandler::exportLog() +/*! + * \brief FileHandler::concurrentExportLog + * \details Exports the log files from log folder (Storage::Log_Base_Path_Name_Location) + * into USB drive folder (Storage::USB_Mount_Point) + * \return always returns true for now. + * \note This method uses QtConcurrent run to execute the copyFolder method. + */ +bool FileHandler::concurrentExportLog() { QString mSource = Storage::Log_Base_Path_Name_Location; QString mDestination = Storage::USB_Mount_Point; //QFuture future = QtConcurrent::run(this, &FileHandler::copyFolder, mSource, mDestination); //return future.result(); - return 0; + return true; } Index: sources/storage/filehandler.h =================================================================== diff -u -r5e78f0799b46963feb5756decb1a27b952cd19b3 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/filehandler.h (.../filehandler.h) (revision 5e78f0799b46963feb5756decb1a27b952cd19b3) +++ sources/storage/filehandler.h (.../filehandler.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -21,13 +21,14 @@ class FileHandler { +private: int copyFolder(const QString &vSource, const QString &vDestination); public: static bool write(const QString &vFileName, const QString &vContent, bool vAppend = true); static bool read (const QString &vFileName, QString &vContent); - bool exportLog (); + bool concurrentExportLog (); }; } Index: sources/storage/logger.cpp =================================================================== diff -u -r5e78f0799b46963feb5756decb1a27b952cd19b3 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/logger.cpp (.../logger.cpp) (revision 5e78f0799b46963feb5756decb1a27b952cd19b3) +++ sources/storage/logger.cpp (.../logger.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -24,31 +24,53 @@ // Project #include "storageglobals.h" #include "filehandler.h" +#include "threads.h" using namespace Storage; Logger::Logger(QObject *parent) : QObject(parent) { } +/*! + * \brief Logger::init + * \details Initializes the Class. + * \return False if it has been called before. + */ bool Logger::init() { + if ( _init ) return false; + _init = true; + // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , "_Logger::init", "The Class initialization must be done in Main Thread" ); + Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread" ); - // runs in Logger thread + // runs in thread checkLogPath(); - qRegisterMetaType("LogType"); initConnections(); return true; } +/*! + * \brief Logger::quit + * \details Does nothing for now + */ void Logger::quit() { } +/*! + * \brief Logger::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + * \note No connection has been defined yet. + */ void Logger::initConnections() { } +/*! + * \brief Logger::checkLogPath + * \details Sets the log paths and creates them if didn't exist. + */ void Logger::checkLogPath() { setLogBasePath(); // try to use /media/sd_card on device @@ -58,6 +80,13 @@ } } +/*! + * \brief Logger::setLogBasePath + * \details Tries to the set the log path to the default log path (Log_Base_Path_Name) + * Will set the application folder as the base log path if can't set the log path to the default. + * Will log the event in that case. + * \param vUseApplicationDirPath + */ void Logger::setLogBasePath(bool vUseApplicationDirPath) { if (vUseApplicationDirPath) { @@ -68,6 +97,11 @@ } } +/*! + * \brief Logger::setLogPath + * \details set the log path for each of the Datum, Event, Error log types + * \return False if can not st the log paths. + */ bool Logger::setLogPath() { bool ok = true; @@ -77,6 +111,13 @@ return ok; } +/*! + * \brief Logger::setLogPath + * \details Sets the log path for the log type vLogType + * Creates the folder if not exists. + * \param vLogType - log type + * \return returns false if the path doesn't exist and folder can't be created. + */ bool Logger::setLogPath(LogType vLogType) { _logPathNames[vLogType] = _dir.path() + "/" + _logBasePathNames[vLogType]; @@ -92,10 +133,16 @@ return true; } +/*! + * \brief Logger::log + * \details Logs the content vContent in log type of vLogType. + * \param vContent - Log content + * \param vLogType - Log type + * \note This method is not thread-safe so is private and needs to be called by concurrentLog + * Which uses QtConcurrent::run to run in thread and thread-safe. + */ void Logger::log(const QString &vContent, Logger::LogType vLogType) { - PRINT_THREAD_NAME; - QString date = QDate::currentDate().toString(_dateFormat); QString mContent; @@ -118,9 +165,15 @@ } } +/*! + * \brief Logger::concurrentLog + * \details The thread safe of calling the log method in a separate thread. + * This method uses the QtConcurrent::run to call the log in separate thread and thread-safe. + * \param vContent - the content to be logged + * \param vLogType - The log type + */ void Logger::concurrentLog(const QString &vContent, LogType vLogType) { - PRINT_THREAD_NAME; // QFuture future = QtConcurrent::run(this,&Logger::log, vContent, vLogType); // qDebug() << future.result(); Index: sources/storage/logger.h =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/logger.h (.../logger.h) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/storage/logger.h (.../logger.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -19,6 +19,7 @@ // Project #include "main.h" +#include "storageglobals.h" // Define @@ -71,6 +72,7 @@ const char *_dateSeparator = "_" ; const char *_timeSeparator = " , "; + bool _init = false; // Singleton SINGLETON(Logger) Index: sources/storage/storageglobals.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/storageglobals.cpp (.../storageglobals.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/storage/storageglobals.cpp (.../storageglobals.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -16,8 +16,6 @@ namespace Storage { - QThread _USBWatcher_Thread; - // USB const char *USB_Mount_Point = "/media/usb/"; const char *USB_File_System = "vfat"; Index: sources/storage/storageglobals.h =================================================================== diff -u -r5e78f0799b46963feb5756decb1a27b952cd19b3 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/storageglobals.h (.../storageglobals.h) (revision 5e78f0799b46963feb5756decb1a27b952cd19b3) +++ sources/storage/storageglobals.h (.../storageglobals.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -13,14 +13,8 @@ */ #pragma once -#include - namespace Storage { - // Threading - //extern QThread _Logger_Thread; - extern QThread _USBWatcher_Thread; - // USB extern const char *USB_Mount_Point; extern const char *USB_File_System; Index: sources/storage/usbwatcher.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/usbwatcher.cpp (.../usbwatcher.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ sources/storage/usbwatcher.cpp (.../usbwatcher.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -29,54 +29,101 @@ // namespace using namespace Storage; -USBWatcher::USBWatcher(QObject *parent) : QObject(parent) { - startTimer(_checkInterval); -} +USBWatcher::USBWatcher(QObject *parent) : QObject(parent) { } +/*! + * \brief USBWatcher::init + * \details Initializes the class by setting the connections and starting the timer + * \return False if it has been called before. + */ bool USBWatcher::init() { - // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , "_USBWatcher::init", "The Class initialization must be done in Main Thread" ); - _USBWatcher_Thread.setObjectName("USB Watcher Thread"); - connect(qApp, &QApplication::aboutToQuit, this, &USBWatcher::quit); - _USBWatcher_Thread.start(); - moveToThread(&_USBWatcher_Thread); + if ( _init ) return false; + _init = true; - // runs in USBWatcher thread initConnections(); + startTimer(_checkInterval); return true; } -void USBWatcher::quit() +/*! + * \brief USBWatcher::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 USBWatcher::init(QThread &vThread) { - // runs in Logger thread - moveToThread(qApp->thread()); + if ( init() ) return false; + initThread(vThread); + return true; +} - // runs in main thread - _USBWatcher_Thread.quit(); - _USBWatcher_Thread.wait(); +/*! + * \brief USBWatcher::quit + * \details quits the class + * Calls quitThread + */ +void USBWatcher::quit() +{ + quitThread(); } +/*! + * \brief USBWatcher::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + */ void USBWatcher::initConnections() { connect(&_ApplicationController, SIGNAL(didUSBDriveUmount()), this , SLOT( onUSBDriveUmount())); } -bool USBWatcher::isMounted() const +/*! + * \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 USBWatcher::initThread(QThread &vThread) { - return _mounted; + // 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); } -bool USBWatcher::isUmounted() const +/*! + * \brief USBWatcher::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * And to be destroyed there. + */ +void USBWatcher::quitThread() { - return _umounted; + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); } +/*! + * \brief USBWatcher::usbSeek + * \details Tries to look for the available USB devices + * Starts from sda1 to sdz1. + * \note will only look for the first partition if there is any + * \param vDevice - Found device (/dev/sda1) + * \return true if a device found + */ bool USBWatcher::usbSeek(QString &vDevice) { - PRINT_THREAD_NAME; QString device = ""; for (char a = 'a'; a <= 'z'; a++) { device = QString("/dev/sd%1%2").arg(a).arg('1'); @@ -89,15 +136,25 @@ return false; } +/*! + * \brief USBWatcher::timerEvent + * \details This event handler has been re-implemented in here + * to receive timer events for the object + * for the timer which has been set to _checkInterval + * Runs the usbCheck on interval + */ void USBWatcher::timerEvent(QTimerEvent *) { - PRINT_THREAD_NAME; usbcheck(); } +/*! + * \brief USBWatcher::usbcheck + * \details Runs usbSeek to mount or umount or remove it + * regarding the state it's in. + */ void USBWatcher::usbcheck() { - PRINT_THREAD_NAME; QString device = ""; if (usbSeek(device)) { if (! _umounted ) { @@ -112,6 +169,14 @@ } } +/*! + * \brief USBWatcher::usbError + * \details Logs any error which has been happened + * On USB device vDevice + * \note When this method has been called error number will be read from errno variable, + * Which has been set by umount or mount. + * \param vDevice + */ void USBWatcher::usbError(const QString &vDevice) { QString error; @@ -131,17 +196,28 @@ } } +/*! + * \brief USBWatcher::onUSBDriveUmount + * \details This is the slot connected to the _ApplicationController's didUSBDriveUmount SIGNAL, + * To notify the USB drive detach. + */ void USBWatcher::onUSBDriveUmount() { _umounted = true; } +/*! + * \brief USBWatcher::usbMount + * \details Mounts the USB device vDevice + * \note Emits didUSBDriveMount signal + * \param vDevice - USB device to be mounted (eg. /dev/sda1) + * \return true on successful mount + */ bool USBWatcher::usbMount(const QString &vDevice) { - PRINT_THREAD_NAME; bool ok; _usbDrive = vDevice.toLatin1().constData(); - ok = mount(_usbDrive, USB_Mount_Point, USB_File_System, 0, "") == 0; + ok = ::mount(_usbDrive, USB_Mount_Point, USB_File_System, 0, "") == 0; if (ok) { _mounted = true; _removed = false; @@ -153,9 +229,15 @@ return ok; } +/*! + * \brief USBWatcher::usbUmount + * \details Unmounts the USB device vDevice + * \note Emits didUSBDriveUmount signal + * \param vDevice - USB device to be unmounted (eg. /dev/sda1) + * \return true on successful unmount + */ bool USBWatcher::usbUmount(const QString &vDevice) { - PRINT_THREAD_NAME; bool ok; ok = umount(vDevice.toLatin1().constData()) == 0; if (ok) { @@ -169,9 +251,14 @@ return ok; } +/*! + * \brief USBWatcher::usbRemove + * \details Removed the USB mount point + * So next time it is not mounted as next device. + * \note Emits didUSBDriveRemove signal + */ void USBWatcher::usbRemove() { - PRINT_THREAD_NAME; usbUmount(USB_Mount_Point); _umounted = false; _removed = true; Index: sources/storage/usbwatcher.h =================================================================== diff -u -r5e78f0799b46963feb5756decb1a27b952cd19b3 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- sources/storage/usbwatcher.h (.../usbwatcher.h) (revision 5e78f0799b46963feb5756decb1a27b952cd19b3) +++ sources/storage/usbwatcher.h (.../usbwatcher.h) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -18,6 +18,7 @@ // Project #include "main.h" +#include "threads.h" // Define #define _USBWatcher Storage::USBWatcher::I() @@ -34,25 +35,30 @@ const char *_usbDrive = ""; const int _checkInterval = 1000; // in ms + QThread *_thread = nullptr; + bool _init = false; + // Singleton SINGLETON(USBWatcher) -public: +public slots: bool init(); + bool init(QThread &vThread); + +private slots: void quit(); - protected: void timerEvent(QTimerEvent *) override; private: void initConnections(); + void initThread(QThread &vThread); + void quitThread(); + bool usbSeek(QString &vDevice); - bool isMounted () const; - bool isUmounted() const; - signals: void didUSBDriveMount (); void didUSBDriveUmount(); Index: sources/threads.cpp =================================================================== diff -u --- sources/threads.cpp (revision 0) +++ sources/threads.cpp (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -0,0 +1,80 @@ +/*! + * + * 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 threads.cpp + * date 1/6/2020 + * author Behrouz NematiPour + * + */ +#include "threads.h" + +// Qt +#include +#include + +// Application +#include "messageglobals.h" +#include "logger.h" + +/*! + * \details All the Thread has been and shall be defined in here + * And will be assigned to a required class from main thread. + * \note quitThreads() needs to be called when the application execution event loop is done + * 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 _Application_Thread; + + /*! + * \brief registerTypes + * \details this method has to be called before any class which uses these types + * and also is handled by threads + * It seems qt is using the meta objects for threading signal/slots + * and it requires any type which has been used in this context to be registered. + */ + void registerTypes() + { + // Logger : This is required for Signal/Slots in threading. + qRegisterMetaType("LogType"); + + // CanInterface : This is required for Signal/Slots in threading. + qRegisterMetaType("QCanBusFrame"); + + // FrameInterface : This is required for Signal/Slots in threading. + qRegisterMetaType("Can_Id"); + } + + /*! + * \brief quitThread + * \details quits the thread vThread and wait for it to be destroyed. + * \param vThread - the thread + */ + void quitThread(QThread &vThread) + { + // runs in main thread + vThread.quit(); + vThread.wait(); + } + + /*! + * \brief quitThreads + * \details quits the list of the threads which has been defined + * int the Threads namespace + * \note It requires to be updated by developer if any more thread has been added + */ + void quitThreads() + { + quitThread(_CanFrame_Thread ); + quitThread(_CanMessage_Thread ); + quitThread(_USBWatcher_Thread ); + quitThread(_Application_Thread); + } +} Index: sources/threads.h =================================================================== diff -u --- sources/threads.h (revision 0) +++ sources/threads.h (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -0,0 +1,39 @@ +/*! + * + * 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 threads.h + * date 1/6/2020 + * author Behrouz NematiPour + * + */ +#pragma once + +// Qt +#include +#include + +// Application +#define PRINT_THREAD_NAME_ENABLE 1 +#if (PRINT_THREAD_NAME_ENABLE) + #define PRINT_THREAD_NAME qDebug() << __func__ << QThread::currentThread()->objectName() +#else + #define PRINT_THREAD_NAME +#endif + +namespace Threads { + extern QThread _CanFrame_Thread ; + extern QThread _CanMessage_Thread ; + extern QThread _USBWatcher_Thread ; + extern QThread _Application_Thread; + + void registerTypes(); + void quitThread (QThread &vThread); + void quitThreads(); + +} + Index: unittests/tst_canbus.cpp =================================================================== diff -u -re1605219ac2baf49ef21d0889f845ac53d59c3c1 -r56d00a82669a7a2c00ab90109a89dbec8db27527 --- unittests/tst_canbus.cpp (.../tst_canbus.cpp) (revision e1605219ac2baf49ef21d0889f845ac53d59c3c1) +++ unittests/tst_canbus.cpp (.../tst_canbus.cpp) (revision 56d00a82669a7a2c00ab90109a89dbec8db27527) @@ -13,17 +13,13 @@ */ #include "tst_canbus.h" -//using namespace Can; // Project -#include "guiglobals.h" #include "caninterface.h" #include "frameinterface.h" #include "messagedispatcher.h" -#include "applicationcontroller.h" -#include "guicontroller.h" -#include "maintimer.h" -#include "format.h" +using namespace Can; + tst_canbus::tst_canbus(QObject *parent) : QObject(parent) { } void tst_canbus::initTestCase() @@ -41,35 +37,37 @@ void tst_canbus::tst_CanInterface_Connect_Error_Interface() { - QString mTr = tr("Error: Connection"); - Can::_CanInterface ._canInterface = "can1"; - Can::_CanInterface .init(); - Can::_CanInterface .enableConsoleOut(false); - QCOMPARE(Can::_CanInterface.status().left(mTr.length()), mTr); + QString mTr = tr("Connection"); + _CanInterface._canInterface = "can1"; + _CanInterface._init = false; + _CanInterface.init(); + _CanInterface.enableConsoleOut(false); + QCOMPARE(_CanInterface.status().left(mTr.length()), mTr); } void tst_canbus::tst_CanInterface_Connect_NoError() { - Can::_CanInterface._canInterface = "can0"; - Can::_CanInterface.init(); - Can::_CanInterface.enableConsoleOut(true); + _CanInterface._canInterface = "can0"; + _CanInterface._init = false; + _CanInterface.init(); + _CanInterface.enableConsoleOut(true); QString mTr = tr("Connected"); - QCOMPARE(Can::_CanInterface.status().left(mTr.length()), mTr); + QCOMPARE(_CanInterface.status().left(mTr.length()), mTr); - Can::_CanInterface.onFrameReceive (); + _CanInterface.onFrameReceive (); } void tst_canbus::tst_FrameInterface_Init() { - Can::_FrameInterface .init(); - Can::_MessageDispatcher .init(); - Can::_MessageDispatcher .enableConsoleOut(true); + _FrameInterface .init(); + _MessageDispatcher .init(); + _MessageDispatcher .enableConsoleOut(true); - connect(Can::_MessageDispatcher, &Can::MessageDispatcher::didFrameTransmit, [=](Can_Id vCanId , const QByteArray &vPayload) { + connect(&_MessageDispatcher, &MessageDispatcher::didFrameTransmit, [=](Can::Can_Id vCanId , const QByteArray &vPayload) { _emited = true; QCOMPARE(Format::toHexString(vPayload), _expected); }); - connect(Can::_MessageDispatcher, &Can::MessageDispatcher::didActionReceive, [=](GuiActionType vAction , const QVariantList &vData ) { + connect(&_MessageDispatcher, &MessageDispatcher::didActionReceive, [=](Gui::GuiActionType vAction , const QVariantList &vData ) { _emited = true; QVERIFY(vAction == _action); for (int i = 0; i < vData.length(); i++) { @@ -145,10 +143,10 @@ _data = {0}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD); + mFrame.setFrameId(Can_Id::eChlid_HD); mPayload = "A5.01.00.01.00.6F.00.00"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QVERIFY(_emited); } @@ -158,10 +156,10 @@ _data = {1}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD); + mFrame.setFrameId(Can_Id::eChlid_HD); mPayload = "A5.01.00.01.01.5E.00.00"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QVERIFY(_emited); } @@ -171,10 +169,10 @@ _data = {1}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD_DG); + mFrame.setFrameId(Can_Id::eChlid_HD_DG); mPayload = "A5.01.00.01.01.5E.00.00"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QCOMPARE(_emited, false); // should not be emitted due to not listening channel } @@ -187,7 +185,7 @@ mFrame.setFrameId(0x999); mPayload = "A5.01.00.01.01.5E.00.00"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QCOMPARE(_emited, false); // should not be emitted due to not listening channel } @@ -197,10 +195,10 @@ _data = {0}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD); + mFrame.setFrameId(Can_Id::eChlid_HD); mPayload = "A5.01.00.01.00.66.00.00"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QCOMPARE(_emited, false); // Should not emit due to crc error } @@ -210,10 +208,10 @@ _data = {0}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD); + mFrame.setFrameId(Can_Id::eChlid_HD); mPayload = "A5.01.00.01.00.6F"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QVERIFY(_emited); // Should not emit due to crc error } @@ -223,10 +221,10 @@ _data = {0}; QCanBusFrame mFrame; QString mPayload; - mFrame.setFrameId(Can::Can_Id::eChlid_HD); + mFrame.setFrameId(Can_Id::eChlid_HD); mPayload = "A5.01.00.01.00.6F.FF.FF.FF"; mFrame.setPayload(QByteArray::fromHex(mPayload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); QVERIFY(_emited); // Should not emit due to crc error } @@ -235,7 +233,7 @@ _action = Gui::GuiActionType::BloodFlow; _data = { -400, -397.50f, -26.20f, -2000.00f, -2002.50f, 648.75f, 62.50f }; QCanBusFrame mFrame; - mFrame.setFrameId(Can::Can_Id::eChlid_HD_Sync); + mFrame.setFrameId(Can_Id::eChlid_HD_Sync); QStringList mPayloadList { "a5.05.00.1c.70.fe.ff.ff" , "00.c0.c6.c3.9a.99.d1.c1" , @@ -245,7 +243,7 @@ }; for ( QString payload : mPayloadList ) { mFrame.setPayload(QByteArray::fromHex(payload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); } QVERIFY(_emited); // Should not emit due to crc error } @@ -255,7 +253,7 @@ _action = Gui::GuiActionType::BloodFlow; _data = { -400, -397.50f, -26.20f, -2000.00f, -2002.50f, 648.75f, 62.50f }; QCanBusFrame mFrame; - mFrame.setFrameId(Can::Can_Id::eChlid_HD_Sync); + mFrame.setFrameId(Can_Id::eChlid_HD_Sync); QStringList mPayloadList { "a5.05.00.1c.70.fe.ff.ff" , "00.c0.c6.c3.9a.99.d1.c1" , @@ -264,23 +262,18 @@ }; for ( QString payload : mPayloadList ) { mFrame.setPayload(QByteArray::fromHex(payload.remove(QLatin1Char('.')).toLatin1())); - emit Can::_CanInterface.didFrameReceive(mFrame); + emit _CanInterface.didFrameReceive(mFrame); } QCOMPARE(_emited, false); // Should not emit due to - ERROR : "Incorrect data for Message ID (HD) '0x0500'" } void tst_canbus::cleanup() { - //disconnect(Can::_FrameInterface ); - //disconnect(Can::_MessageDispatcher ); - //Can::_CanInterface ->initConnections(); - //Can::_FrameInterface ->initConnections(); - //Can::_MessageDispatcher ->initConnections(); } void tst_canbus::cleanupTestCase() { - Can::_CanInterface.quit(); + _CanInterface.quitDevice(); QString mTr = tr("Disconnected"); - QCOMPARE(Can::_CanInterface.status().left(mTr.length()), mTr); + QCOMPARE(_CanInterface.status().left(mTr.length()), mTr); }