Index: sources/canbus/messagehandler.cpp =================================================================== diff -u -rd6c7d6c382fe56e19d132f6ba0bcbbc1e6b2060f -r212de04bcfd9c0ec4c13faca1d4227a8ae30e978 --- sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision d6c7d6c382fe56e19d132f6ba0bcbbc1e6b2060f) +++ sources/canbus/messagehandler.cpp (.../messagehandler.cpp) (revision 212de04bcfd9c0ec4c13faca1d4227a8ae30e978) @@ -81,8 +81,8 @@ addSyncByte (mPayload); addActionId (mPayload, vAction ); // Message ID addLegth (mPayload, vAction ); // Payload Length - addPayload (mPayload); // Adding required Data - addChecksum (mPayload); // Checksum + addData (mPayload, vData ); // Adding required Data + addCRC (mPayload); // CRC addPadding (mPayload); // Padded to 8 byte frame return mPayload ; } @@ -105,7 +105,7 @@ vPayload.append( payloadLen[vAction]); } -void MessageHandler::addPayload(QByteArray &vPayload, GuiActionData vData) +void MessageHandler::addData(QByteArray &vPayload, GuiActionData vData) { // if the payload is more than a remaining frame empty bytes // then it requires to be chopped. @@ -114,44 +114,73 @@ void MessageHandler::addPadding(QByteArray &vPayload) { - vPayload.rightJustified(eCanFrameLen,'\0'); + vPayload = vPayload.rightJustified(eLenCanFrame, '\0'); } -quint8 MessageHandler::checksum(QByteArray &vBytes) +quint8 MessageHandler::calcCRC(const QByteArray &vData) { - // TODO : has not been used yet + // TODO : calcCRC has not been used yet + Q_UNUSED(vData) return '\0'; } +bool MessageHandler::checkCRC(const QByteArray &vData, quint8 vCRC) +{ + //TODO : enable when the calcCRC implemented + Q_UNUSED(vData) + Q_UNUSED(vCRC ) + return true;//calcCRC(vData) == vCRC; +} + bool MessageHandler::hasSyncByte(QByteArray &vPayload) { - if (vPayload.left(eLenSync) == ePayload_Sync) { - vPayload = vPayload.right(eLenSync); + quint8 mSyncByte = vPayload[0]; + if (mSyncByte == ePayload_Sync) { + vPayload = vPayload.mid(eLenSyncByte); return true; } return false; } GuiActionType MessageHandler::getActionId(QByteArray &vPayload) { - GuiActionType mActionId = vPayload.left(eLenActionId); - vPayload = vPayload.right(eLenActionId); - return mActionId; + 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 MessageHandler::getLength(QByteArray &vPayload) { - quint8 mPayloadLength = vPayload.left(eLenPayload); - vPayload = vPayload.right(eLenPayload); - return mPayloadLength; + quint8 mlen = vPayload[0]; + vPayload = vPayload.mid(eLenLength); + return mlen; } -void MessageHandler::addChecksum(QByteArray &vPayload) +QByteArray MessageHandler::getData(QByteArray &vPayload, quint8 vLen, bool *ok) { - vPayload += checksum(vPayload); + 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; } +void MessageHandler::addCRC(QByteArray &vPayload) +{ + vPayload += calcCRC(vPayload); +} + /*! * \brief Process the requested action * \details Processes the requested action @@ -188,18 +217,12 @@ */ void MessageHandler::onRead(const QCanBusFrame &vFrame) { - // TODO : Test Code bool isCommand = true ; bool isUnknown = false; bool isIgnored = false; - //// TODO : For test - //QString cmd = " 020 [8] A5 01"; - //if (vFrame.toString().left(cmd.length()) != cmd) { - // isUnknown = true; - //} - - Can_Id mCanId = vFrame.frameId(); + //TODO : There should be a 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: @@ -212,43 +235,39 @@ } QByteArray mPayload = vFrame.payload(); - Message message; - if (messages[mCanId].isEmpty()) { - // there is no message in the message list for this channel - // so we expect to have a new message which starts with Sync - // and we are striping out the payload and add to the list - if (hasSyncByte(mPayload)) { - message.actionId = getActionId(mPayload); - message.length = getLength(mPayload); - if (message.length <= eMaxHeaderData) { // payload can be fitted in one frame so we have all the payload - message.data = getPayload(mPayload); - } else { + //if (messages[mCanId].isEmpty()) { + // messages[mCanId].append(Message()); + //} + //if (messages[mCanId].last().isComplete()) { + // messages[mCanId].append(Message()); + //} + // + //Message message = messages[mCanId].last(); - } - - if (checksum(message.data) != getChecksum(mPayload)) { - // ERROR : Checksum error - } - messages[mCanId].append(message); - } else { - // ERROR : incomplete message or corrupted without sync byte (without header) + Message message; + // when we are here the message is new or partial. + bool ok = false; + if (hasSyncByte(mPayload)) { + message.actionId = getActionId(mPayload); + message.length = getLength (mPayload); + message.data = getData (mPayload, message.length, &ok); + if (!ok) { + qDebug() << "ERROR : CRC error"; } } else { - if (!messages[mCanId].last().isFull()) { - - } + qDebug() << "ERROR : incomplete message or corrupted without sync byte (without header)"; } + //messages[mCanId].append(message); if (isUnknown || isIgnored) return; if (isCommand) { - emit didActionCommand(GuiActions::PowerOff); + emit didActionCommand(message.actionId); + } else { + emit didActionConfirm(message.actionId, GuiActionData::Accepted); } - else { - emit didActionConfirm(GuiActions::PowerOff,GuiActions::Accepted); - } } void MessageHandler::timerEvent(QTimerEvent *event) Index: sources/canbus/messagehandler.h =================================================================== diff -u -rd6c7d6c382fe56e19d132f6ba0bcbbc1e6b2060f -r212de04bcfd9c0ec4c13faca1d4227a8ae30e978 --- sources/canbus/messagehandler.h (.../messagehandler.h) (revision d6c7d6c382fe56e19d132f6ba0bcbbc1e6b2060f) +++ sources/canbus/messagehandler.h (.../messagehandler.h) (revision 212de04bcfd9c0ec4c13faca1d4227a8ae30e978) @@ -44,14 +44,14 @@ * \brief The MessageHandler class * \details This class is handling the can message by building and striping it. * // -- CAN MESSAGE STRUCTURE -- - * #1 #2 #3 #4 #5 #6 #7 #8 - * +---+---+---+---+---+---+---+---+...........+ + * #0 #1 #2 #3 #4 #5 #6 #7 + * +---+---+---+---+---+---+---+---+--.......--+ * | A5| MsgId |Len| Payload |CRC|..padding..| - * +---+---+---+---+---+---+---+---+...........+ + * +---+---+---+---+---+---+---+---+--.......--+ * Header Frame: * 1 - CRC is last after payload - * Ex1 - If Len=0 then CRC is #5 - * Ex2 - If Len=1 then CRC is #6 and payload is #5 + * 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: @@ -65,37 +65,24 @@ // friends friend class ::unittests; - struct Message { - quInt8 length; - GuiActionType actionId; - QByteArray data; - bool isFull() { - return length == data.length(); - } + const QHash payloadLen { + {GuiActionType::PowerOff, 0x01}, + {GuiActionType::Check_In, 0x00} }; - typedef QList MessageList; - QHash messages; - - const QMap payloadLen { - {GuiActions::PowerOff, 0x01}, - {GuiActions::Check_In, 0x00} - }; - // constants enum Payload_Data : quint8 { ePayload_None = 0x00, ePayload_Sync = 0xA5, }; enum Frame_Data : quint8 { - eCanFrameLen = 8, - eMaxHeaderData = 3, + eLenCanFrame = 8, + eLenMaxHeaderData = 3, - eLenSync = 1, - eLenActionId = 2, - eLenPayload = 1, - eLenChecksum = 1, + eLenSyncByte = 1, + eLenActionId = 2, + eLenLength = 1, }; @@ -122,46 +109,53 @@ 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 + }; + struct Message { // Private Data Class + quint8 length; + GuiActionType actionId; + QByteArray data; + bool isComplete() { return data.length() == length; } + bool isEmpty () { return data.length() == 0 ; } }; + typedef QList MessageList; + QHash messages; // Singleton SINGLETON_DECL(MessageHandler) -public: - void init(); + public: + void init(); private: void connection(); void checked_in(); // TODO : needs to be renamed and called from the main timer to tell HD, UI is alive // build message to be sent QByteArray buildMessage (GuiActionType vAction , GuiActionData vData = GuiActionData::NoData); - void addSyncByte ( QByteArray &vPayload ); - void addActionId ( QByteArray &vPayload , GuiActionType vAction); - void addLegth ( QByteArray &vPayload , GuiActionType vAction); - void addPayload ( QByteArray &vPayload , GuiActionData vData = GuiActionData::NoData); - void addChecksum ( QByteArray &vPayload ); - void addPadding ( QByteArray &vPayload ); + void addSyncByte (QByteArray &vPayload ); + void addActionId (QByteArray &vPayload , GuiActionType vAction); + void addLegth (QByteArray &vPayload , GuiActionType vAction); + void addData (QByteArray &vPayload , GuiActionData vData = GuiActionData::NoData); + void addCRC (QByteArray &vPayload ); + void addPadding (QByteArray &vPayload ); - quint8 checksum ( QByteArray &vBytes ); + quint8 calcCRC (const QByteArray &vData ); + bool checkCRC (const QByteArray &vData , quint8 vCRC); // strip message to its parts - QByteArray stripMessage ( const QCanBusFrame &vFrame ); - bool hasSyncByte ( QByteArray &vPayload ); - GuiActionType getActionId ( QByteArray &vPayload ); - quint8 getLength ( QByteArray &vPayload ); - QByteArray getPayload ( QByteArray &vPayload ); - bool getChecksum ( QByteArray &vPayload ); + QByteArray stripMessage (const QCanBusFrame &vFrame ); + bool hasSyncByte (QByteArray &vPayload ); + GuiActionType getActionId (QByteArray &vPayload ); + quint8 getLength (QByteArray &vPayload ); + QByteArray getData (QByteArray &vPayload , quint8 vLen , bool *ok = nullptr ); + // 0 - command definition // 0.0- Can ID // 0.1- command id // 0.2- command payload length - // 1 - create, frame, schedule, send - - // 2 - read, categorize, buffer, act private slots: // Should be private for thread safety and is connected internally.