/*! * * Copyright (c) 2020-2024 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 MessageGlobals.h * \author (last) Dara Navaei * \date (last) 08-May-2024 * \author (original) Behrouz NematiPour * \date (original) 26-Aug-2020 * */ #pragma once // Qt #include #include #include // Project #include "types.h" namespace Can { /*! * \brief Sequence * \details the messages sequence type */ using Sequence = qint16; using Sequence_Bytes = Types::S16; #define SEQUENCE_MAX INT16_MAX /*! * \brief MsgId * \details the messages message ID type */ using MsgId = quint16; using MsgId_Bytes = Types::U16; #define MSGID_MAX UINT16_MAX /*! * \brief FrameCount * \details The maximum unsigned integer value to be used as the frame count */ using FrameCount = quint64; /*! * \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, ///< The length of each can frame. Should be padded by 0x00 if is less. eLenHeaderInfo = 5, ///< The Header length witch is included in CRC after Sync byte (it's the sum of eLenSequence + eLenActionId + eLenLength) eLenMaxHeaderData = 3, ///< Maximum data byte can be in one frame as header data portion eLenMaxData = 255, ///< Maximum data length in a Can Message since data length value kept in one byte eLenSyncByte = 1, ///< The length of Sync byte at the beginning of each header frame eLenSequence = 2, ///< The length of Sequence number bytes (2) at the beginning of each header frame after sync eLenActionId = 2, ///< The length of MessageID bytes eLenLength = 1, ///< The length of data length value byte at the beginning of each header frame after MessageID eLenCRCDigits = 2, ///< The length of CRC value byte in each Denali message eLenChannelDigits = 3, ///< The length of channel value byte in each Denali message eLenMessageIDDigits = 4, ///< The length of message id value byte in each Denali message }; /*! * \brief The Can_Id enum * \details The Valid CANBus MessageID of each frame */ enum CanId : quint16 { eChlid_LOWEST = 0x7FF, eChlid_NONE = 0x7FF, // Broadcasts //// Alarm eChlid_TD_Alarm = 0x001, ///< TD alarm broadcast eChlid_DD_Alarm = 0x002, ///< DD alarm broadcast eChlid_FP_Alarm = 0x003, ///< FP alarm broadcast eChlid_UI_Alarm = 0x004, ///< UI alarm broadcast [Out] //// Sync eChlid_TD_Sync = 0x100, ///< HD sync broadcast eChlid_DD_Sync = 0x101, ///< DD sync broadcast eChlid_FP_Sync = 0x102, ///< DD sync broadcast eChlid_UI_Sync = 0x103, ///< UI sync broadcast [Out] // UI not listening eChlid_TD_DD = 0x010, ///< TD => DD eChlid_DD_TD = 0x011, ///< DD => TD eChlid_DD_FP = 0x021, ///< DD => FP eChlid_FP_DD = 0x020, ///< FP => DD // UI is listening eChlid_TD_UI = 0x040, ///< TD => UI eChlid_UI_TD = 0x041, ///< UI => TD [Out] // UI listens occasionally eChlid_DD_UI = eChlid_DD_Sync , ///< DD => UI eChlid_FP_UI = eChlid_FP_Sync , ///< FP => UI eChlid_UI_DD = eChlid_UI_Sync , ///< UI => DD [Out] // Dialing channel has been requested by V&V team for CANBus testing // and clarify the source of the unexpected channel message // UI still does not do anything with the messages on these channels. eDialin_TD = 0x400, ///< dialin => TD eTD_Dialin = 0x401, ///< TD => dialin eDialin_DD = 0x402, ///< dialin => DD eDD_Dialin = 0x403, ///< DD => dialin eDialin_FP = 0x404, ///< dialin => FP eFP_Dialin = 0x405, ///< FP => dialin eDialin_UI = 0x406, ///< dialin => UI eUI_Dialin = 0x407, ///< UI => dialin }; /*! * \brief The Can_Source enum * \details The allowable sources of the CANBus messages. */ enum Can_Source { eCan_Unknown = -1, eCan_TD = 0, eCan_DD = 1, eCan_FP = 2, eCan_DI = 3, }; /*! * \brief The Message struct * \details The message structure after it's been converted form hex bytes to meaningful struct for UI. */ struct Message { // TODO : Should be converted to MessageModel class // no time left for now !!! CanId canId = eChlid_NONE; Sequence sequence = 0; // seq 0 is invalid MsgId msgId = 0; quint8 length = 0; QByteArray head; QByteArray data; bool initialized = false; void clear() { canId = eChlid_NONE; sequence = 0; msgId = 0; length = 0; head = QByteArray(); data = QByteArray(); initialized = false; } void dump() const { qDebug().noquote() << "Message {"; qDebug().noquote() << QString(" canId = 0x%1").arg(QString("%1").arg(canId, 3, 16, QChar('0')).toUpper()); qDebug().noquote() << QString(" sequence = %1").arg(sequence); qDebug().noquote() << QString(" msgId = 0x%1").arg(QString("%1").arg(msgId, 4, 16, QChar('0')).toUpper()); qDebug().noquote() << QString(" length = %1").arg(length); QString header; for (int i = 0; i < head.size(); i++) { header.append(QString(" 0x%1").arg(QString("%1").arg(quint8(head[i]), 2, 16, QChar('0')).toUpper())); } qDebug().noquote() << QString(" header(%1) =%2").arg(head.length(), 2, 10, QChar('0')).arg(header); QString payload; for (int i = 0; i < data.size(); i++) { payload.append(QString(" 0x%1").arg(QString("%1").arg(quint8(data[i]), 2, 16, QChar('0')).toUpper())); } qDebug().noquote() << QString(" data(%1) =%2").arg(data.length(), 2, 10, QChar('0')).arg(payload); qDebug().noquote() << "}"; } bool isComplete() { // Since the crc is part of the data and there is no message without crc // then a message would never be empty. // It is preferred to keep it as is so that the initialization is independent of data. return !isEmpty() && data.length() == length; } bool isEmpty () { // Since the crc is part of the data and there is no message without crc // initialized flag and data.length() == 0 became the same. // It is preferred to keep it as is so that the initialization is independent of data. return !initialized || !data.length(); } }; using MessageList = QList; using FrameList = QList; } // namespace Can