/*! * * 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 messagehandler.cpp * date 10/26/2019 * author Behrouz NematiPour * */ #include "messagehandler.h" // Qt #include #include // Project #include "applicationcontroller.h" // namespace using namespace Can; // Singleton SINGLETON_INIT(MessageHandler) /*! * \brief MessageHandler Constructor * \param parent */ MessageHandler::MessageHandler(QObject *parent) : QObject(parent) { } /*! * \brief Message Handler initializer */ void MessageHandler::init() { connection(); checked_in(); //startTimer(1000); } /*! * \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 MessageHandler::connection() { // From GUI connect(_ApplicationController, SIGNAL(didActionRequest(GuiActionType)), this , SLOT( onActionRequest(GuiActionType))); // From GUI connect(_ApplicationController, SIGNAL(didActionPerform(GuiActionType,GuiActionData)), this , SLOT( onActionPerform(GuiActionType, GuiActionData))); // From HD/DG connect(_CanInterface , SIGNAL(didRead(QCanBusFrame)), this , SLOT( onRead(QCanBusFrame))); } void MessageHandler::checked_in() { QCanBusFrame mFrame; mFrame.setFrameId(eChlid_UI); mFrame.setPayload(buildMessage(GuiActions::Check_In)); emit didActionPerform(mFrame); } QByteArray MessageHandler::buildMessage(GuiActionType vAction, GuiActionData vData) { QByteArray mPayload ; addSyncByte (mPayload); addActionId (mPayload, vAction ); // Message ID addLegth (mPayload, vAction ); // Payload Length addData (mPayload, vData ); // Adding required Data addCRC (mPayload); // CRC addPadding (mPayload); // Padded to 8 byte frame return mPayload ; } void MessageHandler::addSyncByte(QByteArray &vPayload) { vPayload.append(ePayload_Sync); // Sync byte } void MessageHandler::addActionId(QByteArray &vPayload, GuiActionType vAction) { if (vAction != GuiActions::Unknown) { vPayload += (vAction >> 8) & 0xFF;//high byte vPayload += vAction & 0xFF;// low byte } } void MessageHandler::addLegth(QByteArray &vPayload, GuiActionType vAction) { vPayload.append( payloadLen[vAction]); } void MessageHandler::addData(QByteArray &vPayload, GuiActionData vData) { // if the payload is more than a remaining frame empty bytes // then it requires to be chopped. vPayload.append(vData); // Adding required Data } void MessageHandler::addPadding(QByteArray &vPayload) { vPayload = vPayload.leftJustified(eLenCanFrame, '\0'); } quint8 MessageHandler::calcCRC(const QByteArray &vData) { // 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) { quint8 mSyncByte = vPayload[0]; if (mSyncByte == ePayload_Sync) { vPayload = vPayload.mid(eLenSyncByte); return true; } return false; } GuiActionType MessageHandler::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 MessageHandler::getLength(QByteArray &vPayload) { quint8 mlen = vPayload[0]; vPayload = vPayload.mid(eLenLength); return mlen; } QByteArray MessageHandler::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; } void MessageHandler::addCRC(QByteArray &vPayload) { vPayload += calcCRC(vPayload); } /*! * \brief Process the requested action * \details Processes the requested action * \param vAction - User requested Action */ void MessageHandler::onActionRequest(GuiActionType vAction) { // TODO : Test Code QCanBusFrame mFrame; mFrame.setFrameId(eChlid_UI); mFrame.setPayload(buildMessage(vAction)); emit didActionRequest(mFrame); } /*! * \brief Process the performed action * \details An action which has been commanded by HD has been performed by GUI.\n * GUI notifies that the action has been performed * \param vAction * \param vData */ void MessageHandler::onActionPerform(GuiActionType vAction, GuiActionData vData) { // TODO : Test Code QCanBusFrame mFrame; mFrame.setFrameId(eChlid_UI); mFrame.setPayload(buildMessage(vAction, vData)); emit didActionPerform(mFrame); } /*! * \brief MessageHandler::onRead * \param vFrame */ void MessageHandler::onRead(const QCanBusFrame &vFrame) { bool isCommand = true ; bool isUnknown = false; bool isIgnored = false; //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: isIgnored = true; break; case eChlid_HD: break; default: break; } QByteArray mPayload = vFrame.payload(); //if (messages[mCanId].isEmpty()) { // messages[mCanId].append(Message()); //} //if (messages[mCanId].last().isComplete()) { // messages[mCanId].append(Message()); //} // //Message message = messages[mCanId].last(); 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 { qDebug() << "ERROR : incomplete message or corrupted without sync byte (without header)"; } //messages[mCanId].append(message); if (isUnknown || isIgnored) return; if (isCommand) { emit didActionCommand(message.actionId); } else { emit didActionConfirm(message.actionId, GuiActionData::Accepted); } } void MessageHandler::timerEvent(QTimerEvent *event) { QObject::timerEvent(event); }