Index: sources/canbus/messagebuilder.cpp =================================================================== diff -u -rfee7fabf49befb065c89248c19e15efc9ca194e4 -rc5389647e2259e67f8e6d923f3481d7d3f4eab68 --- sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision fee7fabf49befb065c89248c19e15efc9ca194e4) +++ sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision c5389647e2259e67f8e6d923f3481d7d3f4eab68) @@ -25,47 +25,94 @@ MessageBuilder::MessageBuilder(QObject *parent) : QObject(parent) { } -FrameList MessageBuilder::buildFrames(GuiActionType vAction, const QByteArray &vData) +/*! + * \brief MessageBuilder::buildFrames + * \details This method builds list of frames out of the vActions of type GuiActionType + * and vData of type QByteArray which has been requested to be sent by UI. + * The message will be chopped into 8 bytes frames to be able to be send + * by fixed length CANBUS protocol. + * \param vAction - The ActionID of the requested message. + * \param vData - The payload of the message. + * \param ok - Will be set if any error happens. + * This parameter has been defined as mandatory check + * so it has been passed and checked. + * \return list of frames of type FrameList + */ +bool MessageBuilder::buildFrames(GuiActionType vAction, const QByteArray &vData, FrameList &vFrameList) { - QList mFrames; QByteArray mPayload ; - addSyncByte (mPayload); // SyncByte - addActionId (mPayload, vAction); // Message ID - addData (mPayload, vAction, vData); // Regarding Payload Length, Adding required Data + addSyncByte (mPayload); // Sync Byte + if ( ! addActionId (mPayload, vAction) ) { // MessageID + return false; + } + if ( ! addData (mPayload, vAction, vData) ) { // Regarding Payload Length, Adding required Data + return false; + } addCRC (mPayload); // CRC quint16 len = mPayload.length(); if (len > eLenCanFrame) { quint8 frameCount = len / eLenCanFrame; if (len % eLenCanFrame) ++frameCount; for (quint8 i = 0; i < frameCount; i++) { - mFrames += mPayload.mid(i * eLenCanFrame, eLenCanFrame); + vFrameList += mPayload.mid(i * eLenCanFrame, eLenCanFrame); } } else { - mFrames += mPayload; + vFrameList += mPayload; } - addPadding (mFrames.last()); // Padded to 8 byte frame - return mFrames; + addPadding (vFrameList.last()); // Padded to 8 byte frame + return true; } +/*! + * \brief MessageBuilder::addSyncByte + * \details Adds the sync/start byte at the end of the Payload vPayload of type QByteArray + * \param vPayload - payload which is going to be constructed by appending byte + */ void MessageBuilder::addSyncByte(QByteArray &vPayload) { vPayload.append(ePayload_Sync); // Sync byte } -void MessageBuilder::addActionId(QByteArray &vPayload, GuiActionType vAction) +/*! + * \brief MessageBuilder::addActionId + * \details Adds the sync/start byte at the end of the Payload vPayload of type QByteArray + * \param vPayload - payload which is going to be constructed by appending byte + * \param vAction - The ActionID of the message which needs to be appended + * to the Payload vPayload + */ +bool MessageBuilder::addActionId(QByteArray &vPayload, GuiActionType vAction) { if (vAction != GuiActionType::Unknown) { quint16 mAction = static_cast(vAction); vPayload += (mAction >> 8) & 0xFF;//high byte vPayload += mAction & 0xFF;// low byte + } else { + QString mHexString = Format::toHexString(vAction, false, 3); + qDebug() << "ERROR :" << tr("Not enough data has been provided for the Message ID '%1'").arg(mHexString); + return false; } + return true; } -void MessageBuilder::addData(QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) +/*! + * \brief MessageBuilder::addData + * \details Regarding ActionID appends correct bytes amount of vData to the vPayload + * \param vPayload - payload which is going to be constructed by appending byte + * \param vAction - The ActionID of the message which needs to be appended + * \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) { quint8 len = payloadLen[vAction]; + if (vData.length() < len) { + QString mHexString = Format::toHexString(vAction, false, 3); + qDebug() << "ERROR :" << tr("Not enough data has been provided for the Message ID '%1'").arg(mHexString); + qDebug() << vData.toHex('.'); + return false; + } // 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) { @@ -77,47 +124,82 @@ } vPayload += len; vPayload += vData.mid(0, len); // Adding required Data + return true; } +/*! + * \brief MessageBuilder::addCRC + * \details Appends calculated crc8 (1 byte) of the vPayload at the end of the vPayload + * \param vPayload - The Payload which is going to be used for crc8 calculation + * \note The first byte will be excluded and is not part of the crc8 calculation. + * Since the first byte is the Sync and has always constant value of A5. + * SW/FW agreement. + */ void MessageBuilder::addCRC(QByteArray &vPayload) { - // sync byte should not be passed for crc calculation + // sync byte should not be Used for crc calculation vPayload += calcCRC(vPayload.mid(1)); } +/*! + * \brief MessageBuilder::addPadding + * \details This method is appending bytes containing 0x00 + * to keep the length of the frame 8 bytes. + * \param vPayload - The payload of the CANBUS message + */ void MessageBuilder::addPadding(QByteArray &vPayload) { vPayload = vPayload.leftJustified(eLenCanFrame, '\0'); } -// TODO : This section better to be in the MessageModel +/*! + * \brief MessageBuilder::calcCRC + * \details Calculates the crc8 + * \param vData - The data of type QByteArray to be used for crc8 calculation. + * \return returns a byte contains crc8 + */ quint8 MessageBuilder::calcCRC(const QByteArray &vData) +// TODO : This section better to be in the MessageModel { quint8 crc = crc8(vData); return crc; } // CRC is always next byte after Data +/*! + * \brief MessageBuilder::checkCRC + * \details This method checks the crc8 of the vData of type QByteArray + * by using the last byte as the crc8 of the rest of the data + * \param vData - The data of type QByteArray to be used for crc8 calculation. + * \return returns false if the crc8 is not correct or the data is empty. + */ +bool MessageBuilder::checkCRC(const QByteArray &vData, quint8 &vExpected, quint8 &vBeenRead) // TODO : This section better to be in the MessageModel -bool MessageBuilder::checkCRC(const QByteArray &vData) { #ifndef DISABLE_CRC int len = vData.length(); if ( ! len ) return false; - quint8 crc = vData.back(); - quint8 got = calcCRC(vData.mid(0, len - 1)); - bool ok = got == crc; + vBeenRead = vData.back(); + vExpected = calcCRC(vData.mid(0, len - 1)); + bool ok = vExpected == vBeenRead; // it's very good but I'm not sure if it's correct. //bool ok = calcCRC(vData) == 0; - if ( ! ok ) { - qDebug() << "ch crc :" << hex << got << crc << vData.toHex('.'); - } return ok; #else return true; #endif } +/*! + * \brief MessageBuilder::buildMessage + * \details Builds Message out of vPayload of type QByteArray + * by adding Sync byte, ActionID(MessageID), data length, data, CANBUS channel id for header + * and keeps collecting data from payload up until the specified length. + * \param vPayload - The payload of the CANBUS message + * \param vMessage - The Message variable which is going to be built + * \param vCan_Id - The CANBUS frame channel id + * \return false if the payload doesn't contain sync byte (Payload_Data::ePayload_Sync) + */ bool MessageBuilder::buildMessage(const QByteArray &vPayload, Message &vMessage, Can_Id vCan_Id) { QByteArray mPayload = vPayload; @@ -131,8 +213,8 @@ vMessage.data = getData (mPayload, vMessage.length); vMessage.initialized = true; } else { // Expected Header but got pure data - printPayload(vPayload, false ,vCan_Id); qDebug() << "ERROR :" << tr("Expected Header, got frame without Sync byte"); + printPayload(vPayload, false ,vCan_Id); return false; } } else { @@ -146,15 +228,28 @@ if (vMessage.isComplete()) { consoleOut("", false, Can_Id::eChlid_NONE); QByteArray crcData = vMessage.head + vMessage.data; - if ( ! checkCRC(crcData) ) { // CRC is always next byte after Data - qDebug() << "ERROR :" << tr("CRC error"); + quint8 mExpected = 0; + quint8 mBeenRead = 0; + if ( ! checkCRC(crcData, mExpected, mBeenRead ) ) { // CRC is always next byte after Data + qDebug() << "ERROR :" << tr("CRC error, expected %1 but got %2") + .arg(Format::toHexString(mExpected, true, 2)) + .arg(Format::toHexString(mBeenRead, true, 2)); return false; } } return true; } +/*! + * \brief MessageBuilder::hasSyncByte + * \details Checks for Sync byte and take it out of vPayload + * \param vPayload - The payload of type QByteArray + * \return true if the first byte of the vPayload is sync byte + * (Payload_Data::ePayload_Sync) + * \note Removes the first 1 byte of sync byte from vPayload + * It starts from the first byte. + */ bool MessageBuilder::hasSyncByte(QByteArray &vPayload) { quint8 mSyncByte = vPayload[0]; @@ -165,6 +260,20 @@ return false; } +/*! + * \brief MessageBuilder::getHeader + * \details Collect the 3 bytes (Frame_Data::eLenHeaderInfo) + * as header portion of the payload + * which is the MessageID (2 bytes) , data length (1 byte) + * It doesn't contain sync byte (Payload_Data::ePayload_Sync) + * as this value will be used for crc8 calculation + * and that doesn't include sync byte (Payload_Data::ePayload_Sync) + * \param vPayload - The payload of the CANBUS message + * \return Returns 3 byte of header data of type QByteArray + * \note As it's obvious from the function parameter it's not changing the vPayload + * Just has been mentioned to be consistent with the other methods of buildMessage. + * It starts from the first byte so the vPayload should not have the sync byte. + */ QByteArray MessageBuilder::getHeader(const QByteArray &vPayload) { QByteArray headInfo; @@ -174,18 +283,41 @@ return headInfo; } +/*! + * \brief MessageBuilder::getActionId + * \details Extracts the 2 bytes ActionID (Frame_Data::eLenActionId) + * out of the vPayload of type QByteArray + * \param vPayload - The payload of the CANBUS message + * \return Returns ActionId of type GuiActionType + * \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) { quint16 mActionId; mActionId = (vPayload[0] << 8) | vPayload[1]; - //TODO : It needs to be checked that the Action ID is Correct. + //TODO : It needs to be checked that the ActionID is Correct. //return GuiActionType::Unknown; vPayload = vPayload.mid(eLenActionId); return static_cast(mActionId); } +/*! + * \brief MessageBuilder::getLength + * \details Extracts the 1 byte data length out of the vPayload + * and removes the first 1 byte + * \param vPayload - The payload of the CANBUS message + * \return returns the length of the data which is added by 1 to include 1 byte crc + * \note the length of the data should not be more than 255 which requires 1 byte only + * so technically it doesn't need to return a value of type more than 1 byte + * But some room reserved for later huge buffer passing + * And also as 1 byte crc8 is included as part of data + * it make it 256 which is going to be more than a byte. + * \note Removes the 1 byte of data length from vPayload + * It starts from the first byte so that byte should be the first 1 byte. + */ int MessageBuilder::getLength(QByteArray &vPayload) { // on the line bellow it has to be cast to unsigned otherwise FF will be converted to -1 and + 1 becomes 0. @@ -194,7 +326,17 @@ return mlen; } -QByteArray MessageBuilder::getData(QByteArray &vPayload, int vLen) +/*! + * \brief MessageBuilder::getData + * \details Extract data from vPayload + * if vLen is less or equal to Frame_Data::eLenMaxHeaderData + * it gets data of first byte up to the len of vLen + * otherwise returns the whole vPayload as the data + * \param vPayload - The payload of the CANBUS message + * \param vLen - the length of the data + * \return The data to be returned + */ +QByteArray MessageBuilder::getData(const QByteArray &vPayload, int vLen) { QByteArray mData; if (vLen <= eLenMaxHeaderData) { @@ -205,6 +347,19 @@ return mData; } +/*! + * \brief MessageBuilder::printPayload + * \details Sends out formatted message to the console + * for debugging purposes. + * Since this method is only formatting the payload + * and doesn't extract the content of the payload + * it gets required information from outside through it's parameters. + * \param vPayload - The payload of the CANBUS message + * \param vIsHeader - Should be sent as true if this payload contains header data + * \param vCan_Id - CANBUS channel id + * \param vUseColor - Use coloring or just space formatted output + * if vUseColor passed true is uses different color for Sync byte, MessageID & data + */ void MessageBuilder::printPayload(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor) { if (vCan_Id == Can_Id::eChlid_NONE) { @@ -238,9 +393,15 @@ } } +/*! + * \brief MessageBuilder::consoleOut + * \details An overloaded method of the MessageBuilder::printPayload + * which is only printPayload if the console output is enabled + * by setting MessageBuilder::enableConsoleOut + * \note please refer to MessageBuilder::printPayload + */ void MessageBuilder::consoleOut(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor) { if ( ! _enableConsoleOut) return; printPayload(vPayload, vIsHeader, vCan_Id, vUseColor); - }