Index: denali.pro =================================================================== diff -u -r68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c --- denali.pro (.../denali.pro) (revision 68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b) +++ denali.pro (.../denali.pro) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -22,9 +22,10 @@ sources/applicationcontroller.h \ sources/applicationpost.h \ sources/canbus/caninterface.h \ + sources/canbus/messagebuilder.h \ + sources/canbus/messagedispatcher.h \ sources/canbus/messageglobals.h \ sources/canbus/messagehandler.h \ - sources/canbus/messagepartitioner.h \ sources/configuration/display.h \ sources/configuration/sound.h \ sources/gui/guiactions.h \ @@ -42,8 +43,9 @@ sources/applicationcontroller.cpp \ sources/applicationpost.cpp \ sources/canbus/caninterface.cpp \ + sources/canbus/messagebuilder.cpp \ + sources/canbus/messagedispatcher.cpp \ sources/canbus/messagehandler.cpp \ - sources/canbus/messagepartitioner.cpp \ sources/configuration/display.cpp \ sources/configuration/sound.cpp \ sources/gui/guiactions.cpp \ Index: sources/canbus/messagebuilder.cpp =================================================================== diff -u --- sources/canbus/messagebuilder.cpp (revision 0) +++ sources/canbus/messagebuilder.cpp (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -0,0 +1,175 @@ +/*! + * + * 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 messagebuilder.cpp + * date 12/6/2019 + * author Behrouz NematiPour + * + */ +#include "messagebuilder.h" + +// Qt +#include + +// Project +// namespace +using namespace Can; + +MessageBuilder::MessageBuilder(QObject *parent) : QObject(parent) { } + +QList MessageBuilder::buildMessage(GuiActionType vAction, const QByteArray &vData) +{ + QList mFrames; + QByteArray mPayload ; + addSyncByte (mPayload); // SyncByte + addActionId (mPayload, vAction); // Message ID + addData (mPayload, vAction, vData); // Regarding Payload Length, Adding required Data + addCRC (mPayload); // CRC + + quint16 len = mPayload.length(); + if (len > eLenCanFrame) { + quint8 frameCount = len / eLenCanFrame; + for (quint8 i = 0; i <= frameCount; i++) { + mFrames += mPayload.mid(i * eLenCanFrame, eLenCanFrame); + } + } else { + mFrames += mPayload; + } + + addPadding (mFrames.last()); // Padded to 8 byte frame + return mFrames; +} + +void MessageBuilder::addSyncByte(QByteArray &vPayload) +{ + vPayload.append(ePayload_Sync); // Sync byte +} + +void MessageBuilder::addActionId(QByteArray &vPayload, GuiActionType vAction) +{ + if (vAction != GuiActions::Unknown) { + vPayload += (vAction >> 8) & 0xFF;//high byte + vPayload += vAction & 0xFF;// low byte + } +} + +void MessageBuilder::addData(QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) +{ + quint8 len = payloadLen[vAction]; + // 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 ; + } + } + vPayload += len; + vPayload += vData.mid(0, len); // Adding required Data +} + +void MessageBuilder::addCRC(QByteArray &vPayload) +{ + vPayload += calcCRC(vPayload); +} + +void MessageBuilder::addPadding(QByteArray &vPayload) +{ + vPayload = vPayload.leftJustified(eLenCanFrame, '\0'); +} + +quint8 MessageBuilder::calcCRC(const QByteArray &vData) +{ + // TODO : calcCRC has not been used yet + Q_UNUSED(vData) + return '\0'; +} + +bool MessageBuilder::checkCRC(const QByteArray &vData, quint8 vCRC) +{ + //TODO : enable when the calcCRC implemented + Q_UNUSED(vData) + Q_UNUSED(vCRC ) + return true;//calcCRC(vData) == vCRC; +} + +bool MessageBuilder::stripMessage(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"; + return false; + } + } else { + qDebug() << "ERROR : incomplete message or corrupted without sync byte (without header)"; + return false; + } + + //messages[mCanId].append(message); + return true; +} + +bool MessageBuilder::hasSyncByte(QByteArray &vPayload) +{ + quint8 mSyncByte = vPayload[0]; + if (mSyncByte == ePayload_Sync) { + vPayload = vPayload.mid(eLenSyncByte); + return true; + } + return false; +} + +GuiActionType MessageBuilder::getActionId(QByteArray &vPayload) +{ + quint16 mActionId; + mActionId = (vPayload[0] << 8) | vPayload[1]; + + //TODO : It needs to be checked that the Action ID is Correct. + //return GuiActionType::Unknown; + + vPayload = vPayload.mid(eLenActionId); + return static_cast(mActionId); +} + +quint8 MessageBuilder::getLength(QByteArray &vPayload) +{ + quint8 mlen = vPayload[0]; + vPayload = vPayload.mid(eLenLength); + return mlen; +} + +QByteArray MessageBuilder::getData(QByteArray &vPayload, quint8 vLen, bool *ok) +{ + 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 + } + } else { + mData = vPayload; + } + return mData; +} Index: sources/canbus/messagebuilder.h =================================================================== diff -u --- sources/canbus/messagebuilder.h (revision 0) +++ sources/canbus/messagebuilder.h (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -0,0 +1,79 @@ +/*! + * + * 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 messagebuilder.h + * date 12/6/2019 + * author Behrouz NematiPour + * + */ +#pragma once + +// Qt +#include +#include + +// Project +#include "guiactions.h" +#include "messageglobals.h" + +using namespace Gui; +namespace Can { + +/*! + * + * \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) + * + */ +class MessageBuilder : public QObject +{ + Q_OBJECT + +public: + explicit MessageBuilder(QObject *parent = nullptr); + + // 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); + + // CRC tools + quint8 calcCRC (const QByteArray &vData); + bool checkCRC (const QByteArray &vData, quint8 vCRC); + + // 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); + +signals: + +public slots: +}; +} Index: sources/canbus/messagedispatcher.cpp =================================================================== diff -u --- sources/canbus/messagedispatcher.cpp (revision 0) +++ sources/canbus/messagedispatcher.cpp (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -0,0 +1,21 @@ +/*! + * + * 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 messagepacker.cpp + * date 12/9/2019 + * author Behrouz NematiPour + * + */ +#include "messagedispatcher.h" + +using namespace Can; + +MessageDispatcher::MessageDispatcher(QObject *parent) : QObject(parent) +{ + +} Index: sources/canbus/messagedispatcher.h =================================================================== diff -u --- sources/canbus/messagedispatcher.h (revision 0) +++ sources/canbus/messagedispatcher.h (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -0,0 +1,84 @@ +/*! + * + * 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 messagepacker.h + * date 12/9/2019 + * author Behrouz NematiPour + * + */ +#pragma once + +// Qt +#include + +// Project +#include + + +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. + * ---------------------------------------------------------------------------------------- + * + * Interpreter : message [ toHex , fromHex] + * + * Builder : message [ toFrame , fromFrame ] + * + * Dipatcher : signal->Handler( .. frame .. ) + * + * Handler : signal->Dispatcher( .. frame .. ) + * + * ---------------------------------------------------------------------------------------- + * + * *** UI <-> AppController <-> Dispatcher <-> Handler <-> HD *** + * + * ---------------------------------------------------------------------------------------- + * + * UI -> message -> + * AppController { + * signal->Dispatcher ( .. message .. ) + * } + * + * Dispatcher { + * .. + * messageList[ch][frameList] += Builder.toFrame ( Interpreter.toHex ( message ) ) + * .. + * signal->Handler( .. frame .. ) + * } + * + * ---------------------------------------------------------------------------------------- + * + * HD -> frame -> + * Handler { + * signal->Dispatcher ( .. frame .. ) + * } + * + * Dispatcher { + * messageList[ch][frameList] += Interpreter.fromHex( frame ) + * isComplete => Builder.fromFrame( frameList ) : singal->AppController + * } + * + * ---------------------------------------------------------------------------------------- + */ +class MessageDispatcher : public QObject +{ + Q_OBJECT + //QHash _messages; + +public: + explicit MessageDispatcher(QObject *parent = nullptr); + +signals: +public slots: +}; + +} Index: sources/canbus/messageglobals.h =================================================================== diff -u -r68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c --- sources/canbus/messageglobals.h (.../messageglobals.h) (revision 68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b) +++ sources/canbus/messageglobals.h (.../messageglobals.h) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -13,22 +13,36 @@ */ #pragma once +// Qt +#include + +// Project #include "guiactions.h" namespace Can { -namespace Message { +/*! + * \brief Payload Length + * \details List of each action acceptable data length in the whole message packet. + */ const QHash payloadLen { - {Gui::GuiActionType::PowerOff, 255}, + {Gui::GuiActionType::PowerOff, 1}, {Gui::GuiActionType::Check_In, 0} }; -// constants +/*! + * \brief The Payload_Data enum + * \details Global information for message packet. + */ enum Payload_Data : quint8 { ePayload_None = 0x00, ePayload_Sync = 0xA5, }; +/*! + * \brief The Frame_Data enum + * \details Global information for each message frame. + */ enum Frame_Data : quint8 { eLenCanFrame = 8, eLenMaxHeaderData = 3, @@ -39,7 +53,10 @@ eLenLength = 1, }; - +/*! + * \brief The Can_Id enum + * \details The Valid Can Bus Message Id of each frame + */ enum Can_Id : quint16 { // Broadcasts //// Alarm @@ -64,5 +81,20 @@ 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; + QByteArray data; + + bool isComplete() { return data.length() == length; } + bool isEmpty () { return data.length() == 0 ; } +}; +typedef QList MessageList; + } -} + Index: sources/canbus/messagehandler.cpp =================================================================== diff -u -r68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c --- sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision 68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b) +++ sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -66,14 +66,14 @@ void MessageHandler::checked_in() { - transmitFrame(Message::eChlid_UI, GuiActions::Check_In); + transmitFrame(eChlid_UI, GuiActions::Check_In); } -void MessageHandler::transmitFrame(Message::Can_Id vFrameId, GuiActionType vAction, const QByteArray &vData) +void MessageHandler::transmitFrame(Can_Id vFrameId, GuiActionType vAction, const QByteArray &vData) { QCanBusFrame mFrame; mFrame.setFrameId(vFrameId); - QList mFrames = _partitioner.buildMessage(vAction,vData); + QList mFrames = _builder.buildMessage(vAction,vData); for (auto frame : mFrames) { mFrame.setPayload(frame); //TODO : If it's necessary we can have a dispatcher @@ -85,13 +85,13 @@ bool MessageHandler::ignoreChannel(const QCanBusFrame &vFrame) { //TODO : There should be an easy way to find if the correct CAN ID has been received - Message::Can_Id mCanId = static_cast(vFrame.frameId()); + Can_Id mCanId = static_cast(vFrame.frameId()); switch (mCanId) { - case Message::eChlid_HD_DG: - case Message::eChlid_DG_HD: + case eChlid_HD_DG: + case eChlid_DG_HD: return true; break; - case Message::eChlid_HD: + case eChlid_HD: break; default: break; @@ -100,7 +100,7 @@ } -bool MessageHandler::interpretData(const MessagePartitioner::Packet &vMessage, GuiActionType &vActionId, GuiActionData &vData) +bool MessageHandler::interpretData(const Message &vMessage, GuiActionType &vActionId, GuiActionData &vData) { quint8 tmp; vActionId = vMessage.actionId; @@ -127,7 +127,7 @@ void MessageHandler::onActionTransmit(GuiActionType vAction, const QByteArray &vData) { qDebug() << vData; - transmitFrame(Message::eChlid_UI, vAction, vData); + transmitFrame(eChlid_UI, vAction, vData); } /*! @@ -140,15 +140,15 @@ return; } - MessagePartitioner::Packet mPacket; - if (! _partitioner.stripMessage(vFrame.payload(), mPacket)) { + Message mMessage; + if (! _builder.stripMessage(vFrame.payload(), mMessage)) { return; } // FIXME: Needs MessageInterpreter class for data in each action [Sprint 8] GuiActionType mActionId; GuiActionData mData; - if (! interpretData(mPacket, mActionId, mData)) { + if (! interpretData(mMessage, mActionId, mData)) { return; } Index: sources/canbus/messagehandler.h =================================================================== diff -u -r68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b -rb2ebb6f71cf9b0c2ba68a47776e5b220b165b21c --- sources/canbus/messagehandler.h (.../messagehandler.h) (revision 68fe14b0d2f0e79d03c95cc0dfff5b47948b6d5b) +++ sources/canbus/messagehandler.h (.../messagehandler.h) (revision b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c) @@ -25,7 +25,7 @@ // Project #include "main.h" #include "guiactions.h" -#include "messagepartitioner.h" +#include "messagebuilder.h" // Define #define _MessageHandler MessageHandler::I() @@ -47,7 +47,7 @@ // friends friend class ::unittests; - MessagePartitioner _partitioner; + MessageBuilder _builder; // Singleton SINGLETON_DECL(MessageHandler) @@ -58,13 +58,13 @@ void initConnections(); void checked_in(); - void transmitFrame(Message::Can_Id vCan_Id, GuiActionType vAction, const QByteArray &vData = 0); + void transmitFrame(Can_Id vCan_Id, GuiActionType vAction, const QByteArray &vData = 0); bool ignoreChannel(const QCanBusFrame &vFrame); // interpret the data into GUI understandable Actions/Data - bool interpretData(const MessagePartitioner::Packet &vMessage, GuiActionType &vActionId, GuiActionData &vData); + bool interpretData(const Message &vMessage, GuiActionType &vActionId, GuiActionData &vData); private slots: // Should be private for thread safety and is connected internally. void onActionTransmit(GuiActionType vAction, const QByteArray &vData); // UI => HD/DG Fisheye: Tag b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c refers to a dead (removed) revision in file `sources/canbus/messagepartitioner.cpp'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag b2ebb6f71cf9b0c2ba68a47776e5b220b165b21c refers to a dead (removed) revision in file `sources/canbus/messagepartitioner.h'. Fisheye: No comparison available. Pass `N' to diff?