/*! * * 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) { } FrameList MessageBuilder::buildFrames(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; if (len % eLenCanFrame) ++frameCount; 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 != 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) { 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) { if (vData.length() > eLenMaxData) { len = eLenMaxData ; } else { len = vData.length(); } } 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) #ifdef QT_DEBUG return ePayload_Sync; #else return '\0'; #endif } // CRC is always next byte after Data bool MessageBuilder::checkCRC(const QByteArray &vData) { #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) return true; #endif } bool MessageBuilder::buildMessage(const QByteArray &vPayload, Message &vMessage) { QByteArray mPayload = vPayload; 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 { vMessage.data += vPayload.mid(0, vMessage.length - vMessage.data.length()); } if (vMessage.isComplete()) { if ( ! checkCRC(vMessage.data) ) { // CRC is always next byte after Data qDebug() << "ERROR :" << "CRC error"; return false; } } 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); } 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. 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, int vLen) { QByteArray mData; if (vLen <= eLenMaxHeaderData) { mData = vPayload.mid(0, vLen); } else { mData = vPayload; } return mData; }