Index: denali.pro =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- denali.pro (.../denali.pro) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ denali.pro (.../denali.pro) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -26,7 +26,7 @@ sources/canbus/messagedispatcher.h \ sources/canbus/messageglobals.h \ sources/canbus/messagehandler.h \ - sources/canbus/messageinterface.h \ + sources/canbus/messageinterpreter.h \ sources/configuration/display.h \ sources/configuration/sound.h \ sources/gui/guiglobals.h \ @@ -39,23 +39,23 @@ sources/storage/settings.h SOURCES += \ - main.cpp \ - sources/applicationcontroller.cpp \ - sources/applicationpost.cpp \ - sources/canbus/caninterface.cpp \ - sources/canbus/messagebuilder.cpp \ - sources/canbus/messagedispatcher.cpp \ - sources/canbus/messagehandler.cpp \ - sources/canbus/messageinterface.cpp \ - sources/configuration/display.cpp \ - sources/configuration/sound.cpp \ - sources/gui/guiglobals.cpp \ - sources/gui/guiview.cpp \ - sources/gui/guicontroller.cpp \ - sources/maintimer.cpp \ - sources/storage/filehandler.cpp \ - sources/storage/logger.cpp \ - sources/storage/settings.cpp + main.cpp \ + sources/applicationcontroller.cpp \ + sources/applicationpost.cpp \ + sources/canbus/caninterface.cpp \ + sources/canbus/messagebuilder.cpp \ + sources/canbus/messagedispatcher.cpp \ + sources/canbus/messagehandler.cpp \ + sources/canbus/messageinterpreter.cpp \ + sources/configuration/display.cpp \ + sources/configuration/sound.cpp \ + sources/gui/guiglobals.cpp \ + sources/gui/guiview.cpp \ + sources/gui/guicontroller.cpp \ + sources/maintimer.cpp \ + sources/storage/filehandler.cpp \ + sources/storage/logger.cpp \ + sources/storage/settings.cpp RESOURCES += \ denali.qrc Index: main.cpp =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- main.cpp (.../main.cpp) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ main.cpp (.../main.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -30,6 +30,7 @@ #include "maintimer.h" #include "caninterface.h" #include "messagehandler.h" +#include "messagedispatcher.h" #include "applicationcontroller.h" #include "guicontroller.h" @@ -78,6 +79,9 @@ //! - Initializing CanBus Message Handler _MessageHandler->init(); + //! - Initializing CanBus Message Dispatcher + _MessageDispatcher->init(); + //! - Initializing Application Controller _ApplicationController->init(); QObject::connect(_ApplicationController, &ApplicationController::quit, &app, [](int retcode) { Index: sources/applicationcontroller.cpp =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/applicationcontroller.cpp (.../applicationcontroller.cpp) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/applicationcontroller.cpp (.../applicationcontroller.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -18,7 +18,7 @@ // Project #include "guiglobals.h" #include "guicontroller.h" -#include "messagehandler.h" +#include "messagedispatcher.h" // Singleton SINGLETON_INIT(ApplicationController) @@ -54,8 +54,8 @@ connect(_GuiController , SIGNAL(didActionTransmit(GuiActionType, const QVariantList &)), this , SLOT( onActionTransmit(GuiActionType, const QVariantList &))); // From HD/DG - connect(_MessageHandler, SIGNAL(didActionReceive (GuiActionType, const QVariantList &)), - this , SLOT( onActionReceive (GuiActionType, const QVariantList &))); + connect(_MessageDispatcher, SIGNAL(didActionReceive(GuiActionType, const QVariantList &)), + this , SLOT( onActionReceive(GuiActionType, const QVariantList &))); } /*! Index: sources/canbus/caninterface.cpp =================================================================== diff -u -r4c53c7c62df7562a6c0915f0c5af7ea0ed884ca3 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision 4c53c7c62df7562a6c0915f0c5af7ea0ed884ca3) +++ sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -78,10 +78,14 @@ { if (_canDevice) { connect(_canDevice, SIGNAL( framesReceived()), - this , SLOT (onFrameReceive ())); + this , SLOT (onFrameReceive ())); connect(_canDevice, SIGNAL( errorOccurred(QCanBusDevice::CanBusError)), - this , SLOT (onError (QCanBusDevice::CanBusError))); + this , SLOT (onFrameError (QCanBusDevice::CanBusError))); + + connect(_canDevice, SIGNAL( framesWritten(qint64)), + this , SLOT (onFrameWrittern(qint64))); + } connect(_MessageHandler, SIGNAL(didFrameTransmit(QCanBusFrame)), this , SLOT( onFrameTransmit(QCanBusFrame))); @@ -116,14 +120,13 @@ * \details send a frame over the CAN Bus * \param vFrame CAN message frame */ -void CanInterface::transmit(const QCanBusFrame &vFrame) +bool CanInterface::transmit(const QCanBusFrame &vFrame) { if( !_canDevice ) - return; - _canDevice->writeFrame(vFrame); -} + return false; + return _canDevice->writeFrame(vFrame);} -void CanInterface::consoleout(const QCanBusFrame &vFrame, const QString &vView) +void CanInterface::consoleOut(const QCanBusFrame &vFrame, const QString &vView) { const QString time = QString::fromLatin1("%1.%2 ") .arg(vFrame.timeStamp().seconds(), 10, 10, QLatin1Char(' ')) @@ -173,7 +176,7 @@ * \details Can Bus error handler which sets the can status description * \param vError CanBus error */ -void CanInterface::onError(QCanBusDevice::CanBusError vError) +void CanInterface::onFrameError(QCanBusDevice::CanBusError vError) { switch (vError) { case QCanBusDevice::ReadError: @@ -186,10 +189,24 @@ default: break; } - emit didError(_canStatus); + emit didFrameError(_canStatus); } /*! + * \brief CanInterface::onFrameWrittern + * \details This is the slot connected to the signal + * which is emitted every time a payload of frames + * has been written to the CAN bus. + * \param vFramesCount The framesCount argument is set to the number of frames + * that were written in this payload. + */ +void CanInterface::onFrameWrittern(qint64 /*vFramesCount*/) +{ + //_numberFramesWritten = vFramesCount; + //qDebug() << "onFrameWrittern::FramesCount : " << vFramesCount; +} + +/*! * \brief CanInterface onRead * \details CanBus read handler */ @@ -201,17 +218,18 @@ while (_canDevice->framesAvailable()) { const QCanBusFrame frame = _canDevice->readFrame(); - QString view; - if (frame.frameType() == QCanBusFrame::ErrorFrame) { - view = _canDevice->interpretErrorFrame(frame); + if (_consoleOutEnabled) { + QString view; + if (frame.frameType() == QCanBusFrame::ErrorFrame) { + view = _canDevice->interpretErrorFrame(frame); + } + else { + view = frame.toString(); + } + consoleOut(frame, view); } - else { - view = frame.toString(); - } - //consoleout(frame, view); - - emit didRead(frame); + emit didFrameReceive(frame); } } @@ -223,6 +241,6 @@ */ void CanInterface::onFrameTransmit(const QCanBusFrame &vFrame) { - // TODO : Process Frame - transmit(vFrame); + bool ok = transmit(vFrame); + emit didFrameTransmit(ok); } Index: sources/canbus/caninterface.h =================================================================== diff -u -rf36dd9c29f633b54bf7f0232093ecaefa5452ca8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/caninterface.h (.../caninterface.h) (revision f36dd9c29f633b54bf7f0232093ecaefa5452ca8) +++ sources/canbus/caninterface.h (.../caninterface.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -49,35 +49,38 @@ const int _canBitRate = 250000; // member variables - QCanBusDevice *_canDevice = nullptr; + QCanBusDevice *_canDevice = nullptr; qint64 _numberFramesWritten = 0; - QString _canStatus = ""; - + QString _canStatus = ""; + bool _consoleOutEnabled = false; // Singleton SINGLETON_DECL(CanInterface) public: bool init(); void quit(); QString status() const; - + void consoleOutEnabled(bool vEnabled) { _consoleOutEnabled = vEnabled; } private: void initConnections(); void status (const QString &vDescription, QString vError = ""); - void transmit (const QCanBusFrame &vFrame); - void consoleout (const QCanBusFrame &vFrame, const QString &vView); + bool transmit (const QCanBusFrame &vFrame); + void consoleOut (const QCanBusFrame &vFrame, const QString &vView); static QString frameFlags(const QCanBusFrame &frame); signals: - void didRead (const QCanBusFrame &vFrame ); - void didError(const QString &vStatus); + void didFrameReceive (const QCanBusFrame &vFrame ); + void didFrameError (const QString &vStatus); + void didFrameTransmit(bool ok); public slots: private slots: - void onFrameTransmit(const QCanBusFrame &vFrame); - void onFrameReceive (); - void onError(QCanBusDevice::CanBusError vError); + void onFrameTransmit (const QCanBusFrame &vFrame); + void onFrameReceive (); + void onFrameError (QCanBusDevice::CanBusError vError); + void onFrameWrittern (qint64 vFramesCount); + }; } Index: sources/canbus/messagebuilder.cpp =================================================================== diff -u -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) +++ sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -22,7 +22,7 @@ MessageBuilder::MessageBuilder(QObject *parent) : QObject(parent) { } -QList MessageBuilder::buildMessage(GuiActionType vAction, const QByteArray &vData) +FrameList MessageBuilder::buildFrames(GuiActionType vAction, const QByteArray &vData) { QList mFrames; QByteArray mPayload ; @@ -34,7 +34,8 @@ quint16 len = mPayload.length(); if (len > eLenCanFrame) { quint8 frameCount = len / eLenCanFrame; - for (quint8 i = 0; i <= frameCount; i++) { + if (len % eLenCanFrame) ++frameCount; + for (quint8 i = 0; i < frameCount; i++) { mFrames += mPayload.mid(i * eLenCanFrame, eLenCanFrame); } } else { @@ -52,21 +53,24 @@ void MessageBuilder::addActionId(QByteArray &vPayload, GuiActionType vAction) { - if (vAction != GuiActions::Unknown) { - vPayload += (vAction >> 8) & 0xFF;//high byte - vPayload += vAction & 0xFF;// low byte + if (vAction != GuiActionType::Unknown) { + quint16 mAction = static_cast(vAction); + vPayload += (mAction >> 8) & 0xFF;//high byte + vPayload += mAction & 0xFF;// low byte } } void MessageBuilder::addData(QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) { - quint8 len = payloadLen[vAction]; + quint16 i = static_cast(vAction); + quint8 len = payloadLen[i]; // if len has been set to max(255) // it means it has no limit and can be as long as 255 bytes if (len == eLenMaxData) { - len = vData.length(); if (vData.length() > eLenMaxData) { len = eLenMaxData ; + } else { + len = vData.length(); } } vPayload += len; @@ -87,47 +91,55 @@ { // TODO : calcCRC has not been used yet Q_UNUSED(vData) +#ifdef QT_DEBUG + return ePayload_Sync; +#else return '\0'; +#endif } -bool MessageBuilder::checkCRC(const QByteArray &vData, quint8 vCRC) +// CRC is always next byte after Data +bool MessageBuilder::checkCRC(const QByteArray &vData) { - //TODO : enable when the calcCRC implemented +#ifdef QT_DEBUG + //qDebug() << "qChecksum(\"0\",1) : " << qChecksum("\0",1); + // TODO : If a Message ID has not data does it still have CRC ? + if ( ! vData.length()) return false; + quint8 crc = vData.back(); + bool ok = calcCRC(vData) == crc; + return ok; +#else Q_UNUSED(vData) - Q_UNUSED(vCRC ) - return true;//calcCRC(vData) == vCRC; + return true; +#endif + + } -bool MessageBuilder::stripMessage(const QByteArray &vPayload, Message &vMessage) +bool MessageBuilder::buildMessage(const QByteArray &vPayload, Message &vMessage) { QByteArray mPayload = vPayload; - //Can_Id mCanId = static_cast(vFrame.frameId()); - //if (messages[mCanId].isEmpty()) { - // messages[mCanId].append(Message()); - //} else { - // if (messages[mCanId].last().isComplete()) { - // messages[mCanId].append(Message()); - // } - //} - // - //Message message = messages[mCanId].last(); - - // when we are here the message is new or partial. - bool ok = false; - if (hasSyncByte(mPayload)) { - vMessage.actionId = getActionId(mPayload); - vMessage.length = getLength (mPayload); - vMessage.data = getData (mPayload, vMessage.length, &ok); - if (!ok) { - qDebug() << "ERROR : CRC error"; + if (vMessage.data.isEmpty()) { // message is empty so expected a header + if (hasSyncByte(mPayload)) { // Got header + vMessage.actionId = getActionId(mPayload); + vMessage.length = getLength (mPayload); + vMessage.data = getData (mPayload, vMessage.length); + vMessage.initialized = true; + } else { // Expected Header but got pure data + qDebug() << "ERROR :" << "Expected Header, got frame without Sync byte"; return false; } } else { - qDebug() << "ERROR : incomplete message or corrupted without sync byte (without header)"; - return false; + vMessage.data += vPayload.mid(0, vMessage.length - vMessage.data.length()); } - //messages[mCanId].append(message); + if (vMessage.isComplete()) { + if ( ! checkCRC(vMessage.data) ) { // CRC is always next byte after Data + qDebug() << "ERROR :" << "CRC error"; + return false; + } + } + return true; } @@ -153,23 +165,22 @@ return static_cast(mActionId); } -quint8 MessageBuilder::getLength(QByteArray &vPayload) +int MessageBuilder::getLength(QByteArray &vPayload) { - quint8 mlen = vPayload[0]; + // on the line bellow it has to be cast to unsigned otherwise FF will be converted to -1 and + 1 becomes 0. + int mlen = static_cast(vPayload[0]) + 1; // Add CRC to the length of data vPayload = vPayload.mid(eLenLength); return mlen; } -QByteArray MessageBuilder::getData(QByteArray &vPayload, quint8 vLen, bool *ok) +QByteArray MessageBuilder::getData(QByteArray &vPayload, int vLen) { QByteArray mData; if (vLen <= eLenMaxHeaderData) { - mData = vPayload.mid(0,vLen); - if (ok) { - *ok = checkCRC(mData,vPayload[vLen+1]); // CRC is always next byte after Data - } + mData = vPayload.mid(0, vLen); } else { mData = vPayload; } return mData; } + Index: sources/canbus/messagebuilder.h =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -28,52 +28,52 @@ * * \brief The Message Builder class * \details This class is handling the can message by building and striping it. - * - * // -- CAN PAYLOAD STRUCTURE -- - * #0 #1 #2 #3 #4 #5 #6 #7 - * +---+---+---+---+---+---+---+---+--.......--+ - * | A5| MsgId |Len| Data |CRC|..padding..| - * +---+---+---+---+---+---+---+---+--.......--+ - * - * Header Frame: - * 1 - CRC is last after payload - * Ex1 - If Len=0 then CRC is #4 - * Ex2 - If Len=1 then CRC is #5 and payload is #4 - * 2 - If CRC is not the last by in the frame - * then there is padding 0x00 to make the frame 8 byte fix - * - * Tail Frame: - * 3 - Partial frames only have Payload and CRC ( and padded) - * + * \n + * // -- CAN PAYLOAD STRUCTURE -- \n + * #0 #1 #2 #3 #4 #5 #6 #7 \n + * +---+---+---+---+---+---+---+---+--.......--+ \n + * | A5| MsgId |Len| Data |CRC|..padding..| \n + * +---+---+---+---+---+---+---+---+--.......--+ \n + * \n + * Header Frame: \n + * 1 - CRC is last after payload \n + * Ex1 - If Len=0 then CRC is #4 \n + * Ex2 - If Len=1 then CRC is #5 and payload is #4 \n + * 2 - If CRC is not the last by in the frame \n + * then there is padding 0x00 to make the frame 8 byte fix \n + * \n + * Tail Frame: \n + * 3 - Partial frames only have Payload and CRC ( and padded) \n + * \n */ class MessageBuilder : public QObject { Q_OBJECT -public: - explicit MessageBuilder(QObject *parent = nullptr); + void addSyncByte ( QByteArray &vPayload); + void addActionId ( QByteArray &vPayload, GuiActionType vAction); + void addData ( QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData); + void addCRC ( QByteArray &vPayload); + void addPadding ( QByteArray &vPayload); - // build message to be sent - QList buildMessage(GuiActionType vAction , const QByteArray &vData); - void addSyncByte (QByteArray &vPayload); - void addActionId (QByteArray &vPayload, GuiActionType vAction); - void addData (QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData); - void addCRC (QByteArray &vPayload); - void addPadding (QByteArray &vPayload); + quint8 calcCRC (const QByteArray &vData); + bool checkCRC (const QByteArray &vData); - // CRC tools - quint8 calcCRC (const QByteArray &vData); - bool checkCRC (const QByteArray &vData, quint8 vCRC); + bool hasSyncByte ( QByteArray &vPayload); + GuiActionType getActionId ( QByteArray &vPayload); + int getLength ( QByteArray &vPayload); + QByteArray getData ( QByteArray &vPayload, int vLen); - // strip message to its parts - bool stripMessage (const QByteArray &vPayload, Message &vMessage); - bool hasSyncByte ( QByteArray &vPayload); - GuiActionType getActionId ( QByteArray &vPayload); - quint8 getLength ( QByteArray &vPayload); - QByteArray getData ( QByteArray &vPayload, quint8 vLen, bool *ok = nullptr); +public: + explicit MessageBuilder(QObject *parent = nullptr); + // build message to be sent frame by frame + FrameList buildFrames ( GuiActionType vAction , const QByteArray &vData); + // build message from received frames + bool buildMessage (const QByteArray &vPayload, Message &vMessage); signals: public slots: }; + } Index: sources/canbus/messagedispatcher.cpp =================================================================== diff -u -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) +++ sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -13,9 +13,123 @@ */ #include "messagedispatcher.h" +// Qt + +// Project +#include "applicationcontroller.h" +#include "messagehandler.h" +#include "maintimer.h" + using namespace Can; -MessageDispatcher::MessageDispatcher(QObject *parent) : QObject(parent) +// Singleton +SINGLETON_INIT(MessageDispatcher) + +/*! + * \brief MessageDispatcher Constructor + * \param parent + */ +MessageDispatcher::MessageDispatcher(QObject *parent) : QObject(parent) { } + +/*! + * \brief Message Handler initializer + */ +void MessageDispatcher::init() { + initConnections(); +} +/*! + * \brief Message Handler connections definition + * \details Initializes the required signal/slot connection between this class and other objects\n + * to be able to communicate. + */ +void MessageDispatcher::initConnections() +{ + // From GUI + connect(_ApplicationController, SIGNAL(didActionTransmit(GuiActionType, const QVariantList &)), + this , SLOT( onActionTransmit(GuiActionType, const QVariantList &))); + + // From HD + connect(_MessageHandler , SIGNAL(didFrameReceive ( Can_Id, const QByteArray &)), + this , SLOT( onFrameReceive ( Can_Id, const QByteArray &))); + + // From GUI : Scheduled keep alive signal + connect(_MainTimer , SIGNAL( didTimeout()), + this , SLOT(onMainTimerTimeout())); } + +void MessageDispatcher::keepAlive() +{ +#ifndef QT_DEBUG + QVariantList mData; + mData += static_cast(GuiActionData::NoData); + actionTransmit(GuiActionType::KeepAlive, mData); +#endif +} + +void MessageDispatcher::onFrameReceive(Can_Id vCanId, const QByteArray &vPayload) +{ + // Append a message to the list + if (_messageList[vCanId].isEmpty() || _messageList[vCanId].last().isComplete()) { + _messageList[vCanId].append(Message()); + } + + + // build the message + if (! _builder.buildMessage(vPayload, _messageList[vCanId].last())) { + // Test + for (const auto &key : _messageList.keys()) { + for (const auto &item : _messageList[key]) { + qDebug() << "item :" << key << item.actionId << item.data; + } + } + qDebug() << ""; + _messageList[vCanId].removeLast(); + return; + } + Message mMessage = _messageList[vCanId].last(); + + // Test + for (const auto &key : _messageList.keys()) { + for (const auto &item : _messageList[key]) { + qDebug() << "item :" << key << item.actionId << item.data; + } + } + qDebug() << ""; + + // TODO : must be moved to a MessageModel class + if (mMessage.isComplete()) { + GuiActionType mActionId; + QVariantList mData; + if (_interpreter.interpretMessage(vCanId, mMessage, mActionId, mData)) { + emit didActionReceive(mActionId, mData); + } + _messageList[vCanId].removeLast(); + } +} + +void MessageDispatcher::onActionTransmit(GuiActionType vActionId, const QVariantList &vData) +{ + actionTransmit(vActionId, vData); +} + +void MessageDispatcher::actionTransmit(GuiActionType vActionId, const QVariantList &vData) +{ + QByteArray mData; + if (! _interpreter.interpretAction(vActionId, vData, mData)) { + qDebug() << "Error :" << "Incorrect Message"; + return; + } + + FrameList frameList = _builder.buildFrames(vActionId, mData); + for (const auto &frame : frameList) { + emit didFrameTransmit(eChlid_UI, frame); + } +} + +void MessageDispatcher::onMainTimerTimeout() +{ + //QMetaObject::invokeMethod(this, "checked_in"); + keepAlive(); +} Index: sources/canbus/messagedispatcher.h =================================================================== diff -u -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) +++ sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -17,23 +17,29 @@ #include // Project -#include +#include "main.h" +#include "messageglobals.h" +#include "messagebuilder.h" +#include "messageinterpreter.h" +// define +#define _MessageDispatcher MessageDispatcher::I() +using namespace Gui; namespace Can { /*! * \brief The MessageDispatcher class * \details Message Dispatcher is the class which is the mediator between CanBus Frames * and Application Messages. * The massages and frames need to be interpreted form/to hex - * and also need to be splitted into frames or constructer from frames to be a message. + * and also need to be split into frames or constructor from frames to be a message. * ---------------------------------------------------------------------------------------- * * Interpreter : message [ toHex , fromHex] * * Builder : message [ toFrame , fromFrame ] * - * Dipatcher : signal->Handler( .. frame .. ) + * Dispatcher : signal->Handler( .. frame .. ) * * Handler : signal->Dispatcher( .. frame .. ) * @@ -64,21 +70,44 @@ * * Dispatcher { * messageList[ch][frameList] += Interpreter.fromHex( frame ) - * isComplete => Builder.fromFrame( frameList ) : singal->AppController + * isComplete => Builder.fromFrame( frameList ) : signal->AppController * } * * ---------------------------------------------------------------------------------------- */ class MessageDispatcher : public QObject { Q_OBJECT - //QHash _messages; + QHash _messageList; + + MessageBuilder _builder; + MessageInterpreter _interpreter; + + // Singleton + SINGLETON_DECL(MessageDispatcher) public: - explicit MessageDispatcher(QObject *parent = nullptr); + void init(); +private: + void initConnections(); + void keepAlive(); + + void actionTransmit(GuiActionType vActionId, const QVariantList &vData); + signals: -public slots: + // When frames received and processed to action and are ready then notifies UI Action is ready + void didActionReceive(GuiActionType vAction , const QVariantList &vData); + 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); + + // An Action has been requested to be transmitted. + void onActionTransmit(GuiActionType vActionId, const QVariantList &vData); + + void onMainTimerTimeout(); }; } Index: sources/canbus/messageglobals.h =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messageglobals.h (.../messageglobals.h) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/canbus/messageglobals.h (.../messageglobals.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -19,15 +19,19 @@ // Project #include "guiglobals.h" +using namespace Gui; namespace Can { /*! * \brief Payload Length * \details List of each action acceptable data length in the whole message packet. */ -const QHash payloadLen { - {Gui::GuiActionType::PowerOff, 1}, - {Gui::GuiActionType::Check_In, 0} +const QHash payloadLen { +// {/*GuiActionType::PowerOff*/ 0x0100, 1}, +// {/*GuiActionType::Check_In*/ 0x0700, 0} + {static_cast(GuiActionType::PowerOff ), 1}, + {static_cast(GuiActionType::KeepAlive), 0}, + {static_cast(GuiActionType::String ), 255}, }; /*! @@ -53,6 +57,7 @@ eLenLength = 1, }; + /*! * \brief The Can_Id enum * \details The Valid Can Bus Message Id of each frame @@ -79,22 +84,23 @@ // UI lessens occasionally eChlid_DG_UI = eChlid_DG_Alarm, ///< No direct channel has been defined between DG&UI, May be required for logging eChlid_UI_DG = eChlid_UI_Sync , ///< No direct channel has been defined between DG&UI, May be required for logging - }; /*! * \brief The Message struct * \details The message structure after it's been glued together. */ -struct Message { - quint8 length; - Gui::GuiActionType actionId; +struct Message { // TODO : Should be converted to MessageModel + GuiActionType actionId = GuiActionType::Unknown; + int length = 0; QByteArray data; - - bool isComplete() { return data.length() == length; } - bool isEmpty () { return data.length() == 0 ; } + bool initialized = false; + bool isEmpty () { return !initialized || !data.length(); } + bool isComplete() { return !isEmpty() && data.length() == length; } }; + typedef QList MessageList; +typedef QList FrameList; } Index: sources/canbus/messagehandler.cpp =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -23,8 +23,8 @@ // Project #include "maintimer.h" -#include "applicationcontroller.h" -#include "guiglobals.h" +#include "messagedispatcher.h" +#include "caninterface.h" // namespace using namespace Can; @@ -54,90 +54,64 @@ void MessageHandler::initConnections() { // From GUI - connect(_ApplicationController, SIGNAL(didActionTransmit(GuiActionType, const QVariantList &)), - this , SLOT( onActionTransmit(GuiActionType, const QVariantList &))); + connect(_MessageDispatcher, SIGNAL(didFrameTransmit(Can_Id, const QByteArray &)), + this , SLOT( onFrameTransmit(Can_Id, const QByteArray &))); - // From HD/DG - connect(_CanInterface , SIGNAL( didRead(QCanBusFrame)), - this , SLOT(onFrameReceive (QCanBusFrame))); - - connect(_MainTimer , SIGNAL( didTimeout()), - this , SLOT(onMainTimerTimeout())); + // From CAN + connect(_CanInterface , SIGNAL( didFrameReceive( const QCanBusFrame &)), + this , SLOT( onFrameReceive( const QCanBusFrame &))); } -void MessageHandler::checked_in() +void MessageHandler::transmitFrame(Can_Id vFrameId, const QByteArray &vData) { - transmitFrame(eChlid_UI, GuiActions::Check_In); -} - -void MessageHandler::transmitFrame(Can_Id vFrameId, GuiActionType vAction, const QByteArray &vData) -{ QCanBusFrame mFrame; mFrame.setFrameId(vFrameId); - QList mFrames = _builder.buildMessage(vAction,vData); - for (auto frame : mFrames) { - mFrame.setPayload(frame); - //TODO : If it's necessary we can have a dispatcher - // to schedule and send messages in another thread. - emit didFrameTransmit(mFrame); + if (vData.length() > Can::eLenCanFrame) { + qDebug() << "Error :" << tr("Payload can't be larger than %1 bytes").arg(Can::eLenCanFrame); + return; } + mFrame.setPayload(vData); + emit didFrameTransmit(mFrame); } -bool MessageHandler::ignoreChannel(const QCanBusFrame &vFrame) +MessageHandler::ChannelGroup MessageHandler::checkChannel(quint32 vFrameId, bool *vOK) { - //TODO : There should be an easy way to find if the correct CAN ID has been received - Can_Id mCanId = static_cast(vFrame.frameId()); - switch (mCanId) { - case eChlid_HD_DG: - case eChlid_DG_HD: - return true; + bool ok = true; + MessageHandler::ChannelGroup channelGroup = ChannelGroup::eChannel_Unknown; + switch (vFrameId) { + case eChlid_HD_DG : + case eChlid_DG_HD : + channelGroup = ChannelGroup::eChannel_Ignores; break; - case eChlid_HD: + + case eChlid_HD : + case eChlid_HD_Alarm : + case eChlid_DG_Alarm : + case eChlid_HD_Sync : + case eChlid_DG_Sync : + //case eChlid_DG_UI : // has duplicate value as eChlid_DG_Alarm + //case eChlid_UI_DG : // has duplicate value as eChlid_UI_Sync + channelGroup = ChannelGroup::eChannel_Listens; break; - default: - break; - } - return false; -} -bool MessageHandler::interpretData(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) -{ - quint8 tmp; - quint8 l = vMessage.data.length(); - quint8 i = 0; - vActionId = vMessage.actionId; - vData.clear(); - switch (vActionId) { // notice we are in receive mode - case GuiActionType::PowerOff: - i = GuiActions::PowerOff_Show; - if (l >= i + 1) { - tmp = vMessage.data[GuiActions::PowerOff_Show]; - vData += static_cast(tmp); - } - //TODO: (MessageInterpreter) There should be an easy way to check if a correct data has been provided. + case eChlid_UI_Alarm : + case eChlid_UI_Sync : + case eChlid_UI : + channelGroup = ChannelGroup::eChannel_Outputs; break; - case GuiActionType::BloodFlow: - break; + default: - vData += GuiActionData::Command; + ok = false; break; } - return true; + + if (vOK) *vOK = ok; + return channelGroup; } -/*! - * \brief Process the requested action - * \details Processes the requested action - * \param vAction - User requested Action - */ -void MessageHandler::onActionTransmit(GuiActionType vAction, const QVariantList &vData) +void MessageHandler::onFrameTransmit(Can_Id vCan_ID, const QByteArray &vData) { - qDebug() << vData; - QByteArray mData; - for (auto data: vData) { - mData += fromVariant(data); - } - transmitFrame(eChlid_UI, vAction, mData); + transmitFrame(vCan_ID, vData); } /*! @@ -146,27 +120,19 @@ */ void MessageHandler::onFrameReceive(const QCanBusFrame &vFrame) { - if (ignoreChannel(vFrame)) { - return; - } + bool ok = false; + quint32 mFrameId = vFrame.frameId(); + ChannelGroup channelGroup = checkChannel(mFrameId, &ok); - Message mMessage; - if (! _builder.stripMessage(vFrame.payload(), mMessage)) { + if (!ok){ + qDebug() << "ERROR : " << "Unexpected Channel"; return; } - // FIXME: Needs MessageInterpreter class for data in each action [Sprint 8] - GuiActionType mActionId; - QVariantList mData; - if (! interpretData(mMessage, mActionId, mData)) { + if ( channelGroup != ChannelGroup::eChannel_Listens) { return; } - emit didActionReceive (mActionId, mData); + Can_Id mCanId = static_cast(mFrameId); + emit didFrameReceive(mCanId, vFrame.payload()); } - -void MessageHandler::onMainTimerTimeout() -{ - //QMetaObject::invokeMethod(this, "checked_in"); - checked_in(); -} Index: sources/canbus/messagehandler.h =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/canbus/messagehandler.h (.../messagehandler.h) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/canbus/messagehandler.h (.../messagehandler.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -26,6 +26,7 @@ #include "main.h" #include "guiglobals.h" #include "messagebuilder.h" +#include "messageinterpreter.h" // Define #define _MessageHandler MessageHandler::I() @@ -44,32 +45,31 @@ // friends friend class ::unittests; - MessageBuilder _builder; + enum class ChannelGroup { + eChannel_Unknown, + eChannel_Ignores, + eChannel_Listens, + eChannel_Outputs, + }; // Singleton SINGLETON_DECL(MessageHandler) public: - void init(); + void init(); private: void initConnections(); - void checked_in(); - void transmitFrame(Can_Id vCan_Id, GuiActionType vAction, const QByteArray &vData = 0); + void transmitFrame(Can_Id vCan_Id, const QByteArray &vData = 0); - bool ignoreChannel(const QCanBusFrame &vFrame); + ChannelGroup checkChannel(quint32 vFrameId, bool *vOK = nullptr); - // interpret the data into GUI understandable Actions/Data - bool interpretData(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); - private slots: // Should be private for thread safety and is connected internally. - void onActionTransmit(GuiActionType vAction, const QVariantList &vData); // UI => HD/DG - void onFrameReceive (const QCanBusFrame &vFrame ); // UI <= HD/DG + void onFrameTransmit(Can_Id vCan_ID, const QByteArray &vData ); // GUI => CAN + void onFrameReceive ( const QCanBusFrame &vFrame ); // GUI <= CAN - void onMainTimerTimeout(); - signals: - void didActionReceive (GuiActionType vAction, const QVariantList &vData); // UI <= HD/DG - void didFrameTransmit (const QCanBusFrame &vFrame ); // UI => HD/DG + void didFrameReceive (Can_Id vCan_ID, const QByteArray &vPayload); // GUI <= CAN + void didFrameTransmit( const QCanBusFrame &vFrame ); // GUI => CAN }; } Fisheye: Tag 1732e83d2a0308b9c706f37d6d7724a364bbff2a refers to a dead (removed) revision in file `sources/canbus/messageinterface.cpp'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1732e83d2a0308b9c706f37d6d7724a364bbff2a refers to a dead (removed) revision in file `sources/canbus/messageinterface.h'. Fisheye: No comparison available. Pass `N' to diff? Index: sources/canbus/messageinterpreter.cpp =================================================================== diff -u --- sources/canbus/messageinterpreter.cpp (revision 0) +++ sources/canbus/messageinterpreter.cpp (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -0,0 +1,113 @@ +/*! + * + * 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 messageinterpreter.cpp + * date 12/11/2019 + * author Behrouz NematiPour + * + */ +#include "messageinterpreter.h" + +using namespace Can; + +MessageInterpreter::MessageInterpreter(QObject *parent) : QObject(parent) { } + +bool MessageInterpreter::interpretMessage(const Can_Id vCan_Id, const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +{ + bool ok = false; + switch (vCan_Id) { + case eChlid_HD: + case eChlid_HD_Alarm: + case eChlid_HD_Sync: + ok = interpretMessage_HD(vMessage, vActionId, vData); + default: + + break; + } + return ok; +} + +bool MessageInterpreter::interpretAction(const 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); + if (l >= ix + 1) { + quint8 tmp = vData[ix].toUInt(); + vPayload += tmp; + } + break; + case GuiActionType::KeepAlive: + break; + + case GuiActionType::String: + vPayload = fromVariant(vData[0]); + break; + + default: + qDebug() << "ERROR :" << "Unknown Message ID"; + ok = false; + break; + } + return ok; +} + +QByteArray MessageInterpreter::fromVariant(const QVariant &vData) +{ + QByteArray mData; + if(vData.type() == QVariant::String) { + mData += vData.toByteArray(); + } else { + mData += vData.toUInt(); + } + return mData; +} + +bool MessageInterpreter::interpretMessage_HD(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +{ + bool ok = true; + int l = vMessage.data.length(); + quint8 ix = 0; + quint16 id = static_cast(vActionId); + vActionId = vMessage.actionId; + vData.clear(); + + switch (vActionId) { // notice we are in receive mode + case GuiActionType::PowerOff: + ix = static_cast(GuiActionIndx::PowerOff_ShowHide); + if (l >= ix + 1) { + quint8 tmp = vMessage.data[ix]; + vData += tmp; + } else { + qDebug() << "ERROR :" << tr("Incorrect data for MessageId %1").arg(id); + ok = false; + } + break; + case GuiActionType::BloodFlow: + ok = false; + break; + default: + qDebug() << "ERROR :" << "Unknown Message ID"; + ok = false; + break; + } + return ok; +} + +bool MessageInterpreter::interpretMessage_DG(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) +{ + Q_UNUSED(vMessage ); + Q_UNUSED(vActionId); + Q_UNUSED(vData ); + // No data have been interpreted from GD yet + return false; +} Index: sources/canbus/messageinterpreter.h =================================================================== diff -u --- sources/canbus/messageinterpreter.h (revision 0) +++ sources/canbus/messageinterpreter.h (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -0,0 +1,46 @@ +/*! + * + * 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 messageinterpreter.h + * date 12/11/2019 + * author Behrouz NematiPour + * + */ +#pragma once + +// Qt +#include + +// Project +#include "guiglobals.h" +#include "messageglobals.h" + +using namespace Gui; +namespace Can { + +class MessageInterpreter : public QObject +{ + Q_OBJECT + + QByteArray fromVariant(const QVariant &vData); + + bool interpretMessage_HD(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); + bool interpretMessage_DG(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); +public: + 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); + bool interpretAction (const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload); + +signals: + +public slots: +}; + +} Index: sources/gui/guiglobals.cpp =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -22,18 +22,6 @@ namespace Gui { QQuickView *_viewer = nullptr; - - QByteArray fromVariant(const QVariant &vData) - { - QByteArray mData; - if(vData.type() == QVariant::String) { - mData += vData.toByteArray(); - } else { - mData += vData.toUInt(); - } - return mData; - } - /*! * \brief registerTypes * \details registering meta types @@ -51,7 +39,7 @@ */ void registerQmlTypes() { - qmlRegisterType ("Gui.View", 0, 1, "GuiView"); + qmlRegisterType ("Gui.View" , 0, 1, "GuiView"); qmlRegisterUncreatableType ("Gui.Actions", 0, 1, "GuiActions", QStringLiteral("Used only for enumerations no need to have an object")); } Index: sources/gui/guiglobals.h =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/gui/guiglobals.h (.../guiglobals.h) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/gui/guiglobals.h (.../guiglobals.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -27,18 +27,21 @@ Q_GADGET explicit GuiActions(); public: - enum GuiActionsType_Enum /*: quint16 QML doesn't support*/ { + enum class GuiActionsType_Enum /*: quint16 QML doesn't support*/ { Unknown = 0x0000, PowerOff = 0x0100, - Check_In = 0x0700, + KeepAlive = 0x0700, BloodFlow = 0x0500, + + String = 0xFFFF, }; - enum GuiActionsIndx_Enum { - PowerOff_Show = 0, + enum class GuiActionsIndx_Enum { + PowerOff_ShowHide = 0, + PowerOff_Response = 0, }; - enum GuiActionsData_Enum /*: quint8 QML doesn't support*/ { + enum class GuiActionsData_Enum /*: quint8 QML doesn't support*/ { NoData = 0x00, Command = 0x00, // HD=>UI : should be handled in receive @@ -63,8 +66,6 @@ typedef GuiActions::GuiActionsData_Enum GuiActionData; typedef GuiActions::GuiActionsIndx_Enum GuiActionIndx; - QByteArray fromVariant(const QVariant &vData); - void registerTypes(); void registerQmlTypes(); Index: sources/gui/qml/main.qml =================================================================== diff -u -r272bb81655222b2bf0c3c7099523c0b658eb9cb8 -r1732e83d2a0308b9c706f37d6d7724a364bbff2a --- sources/gui/qml/main.qml (.../main.qml) (revision 272bb81655222b2bf0c3c7099523c0b658eb9cb8) +++ sources/gui/qml/main.qml (.../main.qml) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) @@ -39,9 +39,9 @@ onDidActionReceive: { switch(vAction) { case GuiActions.PowerOff: - if (vData[GuiActions.PowerOff_Show] === GuiActions.Command) + if (vData[GuiActions.PowerOff_ShowHide] === GuiActions.Command) _powerOffDialog.open() - if (vData[GuiActions.PowerOff_Show] === GuiActions.Timeout) + if (vData[GuiActions.PowerOff_ShowHide] === GuiActions.Timeout) _powerOffDialog.close() break; }