// ************************************************************************** // // (C) Copyright 2009 Swiss SIMTEC AG // // ************************************************************************** // // $HeadURL$ // $LastChangedBy$ // $LastChangedDate$ // $LastChangedRevision$ // // ************************************************************************** #include "LogViewTelegram.hpp" #include #include #include #include #include "LogViewXdrParser.hpp" #include "LogViewXdrStruct.hpp" #include "LogViewXdrValue.hpp" #include "LogViewXdrType.hpp" #include "LogViewTetraTelegramsParser.hpp" #include "LogViewField.hpp" #include #include #include #include #include #include namespace N_LogView { // static member initialization const LogViewXdrParser* LogViewTelegram::m_Parser = nullptr; const uint16_t LogViewTelegram::START_OFFSET_CENTRAL = 12; const uint16_t LogViewTelegram::POS_CENTRAL_COUNTER = 4; const uint16_t LogViewTelegram::POS_CENTRAL_TELID = 8; const uint16_t LogViewTelegram::POS_CENTRAL_PARTICIPANTID = 12; const uint16_t LogViewTelegram::START_OFFSET_TETRA_REGISTER = 5; const uint16_t LogViewTelegram::START_OFFSET_TETRA_AIRLOAD = 5; const uint16_t LogViewTelegram::START_OFFSET_TETRA_DATA = 28; const uint16_t LogViewTelegram::START_OFFSET_TETRA_LOGIN = 27; const uint16_t LogViewTelegram::START_OFFSET_TETRA_FRAGMENT = 26; const uint16_t LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE = 4; // --------------------------------------------------------------- // Copy ctor // --------------------------------------------------------------- LogViewTelegram::LogViewTelegram(const LogViewTelegram &o) : m_Name(o.m_Name) , m_ToolTipText(o.m_ToolTipText) , m_WaitTime(o.m_WaitTime) , m_ParticipantId(o.m_ParticipantId) , m_ISSI(o.m_ISSI) , m_AllocatedSize(o.m_AllocatedSize) , m_ActOffset(o.m_ActOffset) , m_GpsFieldOffset(o.m_GpsFieldOffset) , m_TelId(o.m_TelId) , m_LastUnsignedValue(o.m_LastUnsignedValue) , m_MaxArraySize(o.m_MaxArraySize) , m_DynArraySizeMethod(o.m_DynArraySizeMethod) , m_Destination(o.m_Destination) , m_Validity(o.m_Validity) , m_Protocol(o.m_Protocol) , m_LogTime(o.m_LogTime) , m_logTimeText(o.m_logTimeText) , m_GpsTime(o.m_GpsTime) , m_data(o.m_data) , m_json(o.m_json) , m_TetraTelegram(nullptr) , m_logger(getLogger("LogViewTelegram")) { if (!m_data.isEmpty()) m_TetraTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(m_data); } // --------------------------------------------------------------- // Constructor for new telegrams (only receive central- // telegrams are allowed), which will be edited // --------------------------------------------------------------- LogViewTelegram::LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, int telegramId) : m_WaitTime(1000) , m_ParticipantId(0) , m_ISSI(0) , m_AllocatedSize(0) , m_ActOffset(0) , m_GpsFieldOffset(QVector()) , m_TelId(telegramId) , m_LastUnsignedValue(0) , m_MaxArraySize(0) , m_DynArraySizeMethod(LogViewXdrStandardType::e_DynArrayMsgLength) , m_Destination(a_destination) , m_Validity(e_NotYetEvaluated) , m_Protocol(static_cast(a_destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask)) , m_LogTime(0) , m_GpsTime(0) , m_TetraTelegram(nullptr) , m_logger(getLogger("LogViewTelegram")) { const uint32_t &waitTime = qgetenv("LogViewWaitTime").toUInt(); if (waitTime > 0) m_WaitTime = waitTime; m_ToolTipText.resize(e_ColMax); switch (m_Protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: { m_Name = jsonParser()->nameFromTelegramId(m_TelId); m_json[QStringLiteral("type")] = m_Name; m_json[QStringLiteral("typeId")] = m_TelId; break; } default: showMessageBox(QObject::tr("Nur Zentral-Telegramme sind erlaubt")); } } // --------------------------------------------------------------- // Constructor for existing telegrams // --------------------------------------------------------------- LogViewTelegram::LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, const quint64 a_unixTime, const QByteArray &a_telegramData) : m_WaitTime(1000) , m_ParticipantId(0) , m_ISSI(0) , m_AllocatedSize(0) , m_ActOffset(0) , m_GpsFieldOffset(QVector()) , m_TelId(0) , m_LastUnsignedValue(0) , m_MaxArraySize(0) , m_DynArraySizeMethod(LogViewXdrStandardType::e_DynArrayMsgLength) , m_Destination(a_destination) , m_Validity(e_NotYetEvaluated) , m_Protocol(static_cast(a_destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask)) , m_LogTime(a_unixTime) , m_GpsTime(0) , m_data(a_telegramData) , m_TetraTelegram(nullptr) , m_logger(getLogger("LogViewTelegram")) { const uint32_t &waitTime = qgetenv("LogViewWaitTime").toUInt(); if (waitTime > 0) m_WaitTime = waitTime; m_ToolTipText.resize(e_ColMax); // log-time switch (m_Protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { m_json = QJsonDocument::fromJson(a_telegramData).object(); m_TelId = m_json.value(QLatin1String("typeId")).toInt();//getUInt32(POS_CENTRAL_TELID); // INFO_LOG(m_logger) << "m_TelId=" << m_TelId; //m_Name = m_Parser[m_Protocol]->getTelegramName(getTelId()); m_Name = m_json.value(QLatin1String("type")).toString(); switch (getTelId()) { case TrainingAreaBase::TetraIcd::BESTAETIGUNG: break; default: // the participant-id can not be taken out of xyData.header.identitaet without knowing the exact Wrapper, // because in some (unclear) cases an unknown 4-byte value is on expected position (maybe some C++ alignment stuff) //m_ParticipantId = getUInt32(POS_CENTRAL_PARTICIPANTID); m_ParticipantId = m_json.value(QLatin1String("data")) .toObject().value(QLatin1String("header")) .toObject().value(QLatin1String("equipmentNumber")).toInt(); break; } break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { m_TetraTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(m_data); // NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, m_Data, m_Size); switch (m_TetraTelegram->getPDU_Type()) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: m_Name = QObject::tr("TETRA-Register-Indication"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: m_Name = QObject::tr("TETRA-Register-Response"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: { if (m_TetraTelegram->isLoginTelegram()) { m_Name = QObject::tr("TETRA-Login-Telegramm"); m_ParticipantId = m_TetraTelegram->getIdentity(); } else if (m_TetraTelegram->isNormalTelegram()) { // unfragmented telegram m_TelId = m_TetraTelegram->getTelID(); m_Name = tetraParser()->getTelegramName(m_TelId); m_ParticipantId = m_TetraTelegram->getIdentity(); // get the GPS-time if (getDirection() == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend) { // fixme: mache dies konfigurierbar uint16_t gpsTimeOffset = 2; // without telID switch (m_TelId) { case GEF_DEAKTIVIERUNG_EINZELMINE: gpsTimeOffset = 4; // without telID break; default: gpsTimeOffset = 2; // without telID } m_GpsTime = getUInt32(START_OFFSET_TETRA_DATA+gpsTimeOffset); } } else { // fragmented telegram switch (m_TetraTelegram->getFragmentStatus()) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: m_Name = QObject::tr("1. Fragment eines TETRA-Telegrammes"); m_ParticipantId = m_TetraTelegram->getIdentity(); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: m_Name = QObject::tr("%1.-letztes Fragment eines TETRA-Telegrammes").arg(m_TetraTelegram->getFragmentCounter()+1); // fixme: get participantid over ISSI break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: m_Name = QObject::tr("Letztes Fragment eines TETRA-Telegrammes"); // fixme: get participantid over ISSI break; default: m_Name = QObject::tr("TETRA-Telegramm mit Fragment-Status=%1 ist nicht implementiert").arg(m_TetraTelegram->getFragmentStatus()); break; } } // set the ISSI if ((m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask) == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive) { m_ISSI = m_TetraTelegram->getDestISSI(); } else { m_ISSI = m_TetraTelegram->getSrcISSI(); } break; } case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: m_Name = QObject::tr("Report-Indication/Request"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_GroupMonitorReq: m_Name = QObject::tr("Group monitoring Request"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: m_Name = QObject::tr("Status Indication/Request"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: m_Name = QObject::tr("AirInterfaceLoad-Request"); break; default: // Commented because of annoying message for Type 240 /* QMessageBox::warning(NULL, QObject::tr("Unknown PDU-Type"), QObject::tr("Handling for TETRA-Telegram mit PDU-Type=%1 is not implemented!").arg(m_TetraTelegram->getPDU_Type())); */ m_Name = QObject::tr("PDU-Type=%1").arg(m_TetraTelegram->getPDU_Type()); break; } } break; default: showMessageBox(QObject::tr("Unknown protocol %1!").arg(m_Protocol), QObject::tr("Unknown protocol")); m_Validity = e_Invalid; break; } } LogViewTelegram::~LogViewTelegram() { delete m_TetraTelegram; } // --------------------------------------------------------------- // Writes a_value with size a_size at actual position of // m_Data (given with m_ActOffset). m_ActOffset will be // updated after writing data. // If the size of m_Data is not big enough, it will be made // bigger. // --------------------------------------------------------------- void LogViewTelegram::setUIntX(const uint8_t a_size, quint64 a_value, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) { // check whether m_Data is big enough if (m_ActOffset + a_size > m_data.size()) m_data.resize(m_ActOffset + a_size); // write the data if (a_byteOrder == LogViewXdrStandardType::e_ByteOrderBigEndian) { for (int i = a_size - 1; i >= 0; i--) { setData(m_ActOffset+i, a_value & 0x000000FF); a_value = a_value >> 8; } } else { for (int i = 0; i < a_size; i++) { setData(m_ActOffset + i, a_value & 0x000000FF); a_value = a_value >> 8; } } m_ActOffset += a_size; } // --------------------------------------------------------------- // Returns true if a_data could be written. // Returns false if a_offset is outside of range and therefore // a_data could not be written. // --------------------------------------------------------------- bool LogViewTelegram::setData(const uint16_t a_offset, const uint8_t a_data) { if (a_offset < m_data.size()) { m_data[a_offset] = a_data; return true; } return false; } quint64 LogViewTelegram::getLogTimeMsec() const { const quint64 logTimeSec = m_LogTime >> 32; const quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; return (logTimeSec * 1000 + logTimeMicroSec / 1000); } // --------------------------------------------------------------- // Returns the log-time of the telegram as pretty formatted // text // --------------------------------------------------------------- QString LogViewTelegram::getLogTimeText() const { if (m_logTimeText.isEmpty()) { const QDateTime dt(QDateTime::fromMSecsSinceEpoch(getLogTimeMsec())); m_logTimeText = dt.toString(QLatin1String("ddd, MMM dd, yyyy hh:mm:ss.zzz")); } return m_logTimeText; } // --------------------------------------------------------------- QString LogViewTelegram::getDestinationText() const { auto protocol = static_cast (m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); auto dest = static_cast (m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); switch (protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return QLatin1String("C > P"); case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return QLatin1String("P > C"); default: break; } break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return QLatin1String("W > C"); case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return QLatin1String("C > W"); default: break; } break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return QLatin1String("P > T"); case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return QLatin1String("T > P"); default: break; } break; } default: break; } return QStringLiteral("<%1>").arg(m_Destination); } // --------------------------------------------------------------- // Returns the GPS-time of the telegram as pretty formatted // text. Only telegrams from TETRA to central have a GPS-time, // for all other telegrams an empty string will be returned. // --------------------------------------------------------------- QString LogViewTelegram::getGpsTimeText() const { if (m_GpsTime != 0) return QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL).toString(QLatin1String("hh:mm:ss")); return QString(); } // --------------------------------------------------------------- // Returns the difference between GPS-time and log-time in // seconds. Only telegrams from TETRA to central have a GPS- // time (and therefore only for this telegrams a time- // difference can be calculated), for all other telegrams 0 // will be returned. // --------------------------------------------------------------- int32_t LogViewTelegram::getDelay() const { if (m_GpsTime != 0) { quint64 logTimeSec = m_LogTime >> 32; return logTimeSec - m_GpsTime; } return 0; } // --------------------------------------------------------------- // Returns the tool-tip text for the with a_col defined column // for this telegram. Its content depends on the type and // subtype of telegram. // --------------------------------------------------------------- QString LogViewTelegram::getToolTipText(const E_Column a_col) { if (a_col < e_ColMax) { if(a_col == e_ColName && m_ToolTipText[e_ColName].isNull()) createToolTipTextForColName(); if(a_col == e_ColLogTime && m_ToolTipText[e_ColLogTime].isNull()) { quint64 logTimeSec = m_LogTime >> 32; quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; m_ToolTipText[e_ColLogTime] = QStringLiteral("%1.%2 s") .arg(logTimeSec) .arg(logTimeMicroSec); } if(a_col == e_ColGpsTime && m_ToolTipText[e_ColGpsTime].isNull()) { if(m_GpsTime == 0) { m_ToolTipText[e_ColGpsTime] = QLatin1String(""); // wichtig damit isNull() false ist! } else { const QDateTime dtGpsTime(QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL)); m_ToolTipText[e_ColGpsTime] = QStringLiteral("%1
Unixzeit: %2 0x%3") .arg(dtGpsTime.toString(QLatin1String("ddd, MMM dd, yyyy hh:mm:ss"))) .arg(m_GpsTime) .arg(m_GpsTime, 8, 16, QLatin1Char('0')); } } return m_ToolTipText[a_col]; } return QString(); } // --------------------------------------------------------------- void LogViewTelegram::createToolTipTextForColName() { switch (m_Protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { const QString jsonStr = QString::fromUtf8(QJsonDocument(m_json).toJson(QJsonDocument::JsonFormat::Indented)); // set the tool-tip-text m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Telegram Id"), getTelId()) + formatToolTipLine(QObject::tr("Counter"), getUInt32(POS_CENTRAL_COUNTER)) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + formatToolTipLine(QObject::tr("Json Data"), jsonStr, jsonStr.size()) + QLatin1String("
"); break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { switch (m_TetraTelegram->getPDU_Type()) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: // set the tool-tip-text m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Host ISSI"), m_TetraTelegram->getSrcISSI()) + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + QLatin1String("
"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Registration Status"), m_TetraTelegram->getRegistrationStatusAsText(), m_TetraTelegram->getRegistrationStatus()) + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + QLatin1String("
"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: { int frameSize = 1; if(m_TetraTelegram->getWithCrc()) frameSize += 2; m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Source ISSI"), m_TetraTelegram->getSrcISSI()) + formatToolTipLine(QObject::tr("Destination ISSI"), m_TetraTelegram->getDestISSI()) + formatToolTipLine(QObject::tr("Protocol Identifier"), m_TetraTelegram->getProtocolIdentifierAsText(), m_TetraTelegram->getProtocolIdentifier()) + formatToolTipLine(QObject::tr("Message Reference"), m_TetraTelegram->getMessageReference()) + formatToolTipLine(QObject::tr("Area Selection"), m_TetraTelegram->getAreaSelection()) + formatToolTipLine(QObject::tr("Validity Period"), m_TetraTelegram->getValidityPeriod()) + formatToolTipLine(QObject::tr("Forward Address"), m_TetraTelegram->getForwardAddress()) + formatToolTipLine(QObject::tr("Flags"), m_TetraTelegram->getFlagsAsText(), m_TetraTelegram->getFlags()) + formatToolTipLine(QObject::tr("Complete Payload in Bits"), m_TetraTelegram->getLengthInBits()) + formatToolTipLine(QObject::tr("Real Payload in Bytes"), m_TetraTelegram->getLengthInBytes() - frameSize) + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + QLatin1String("
"); break; } case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Source ISSI"), m_TetraTelegram->getSrcISSI()) + formatToolTipLine(QObject::tr("Destination ISSI"), m_TetraTelegram->getDestISSI()) + formatToolTipLine(QObject::tr("Protocol Identifier"), m_TetraTelegram->getProtocolIdentifierAsText(), m_TetraTelegram->getProtocolIdentifier()) + formatToolTipLine(QObject::tr("Message Reference"), m_TetraTelegram->getMessageReference()) + formatToolTipLine(QObject::tr("Area Selection"), m_TetraTelegram->getAreaSelection()) + formatToolTipLine(QObject::tr("Delivery"), m_TetraTelegram->getDeliveryAsText(), m_TetraTelegram->getDelivery()) + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + QLatin1String("
"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: default: m_ToolTipText[e_ColName] = QLatin1String("") + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + formatToolTipLine(QObject::tr("Size"), m_data.size()) + QLatin1String("
"); break; } break; } default: break; } } union convertHackDouble { quint64 i; double d; }; union convertHackFloat { uint32_t i; float f; }; double LogViewTelegram::xdrToDouble(quint64 in) { convertHackDouble c; c.i = in; return c.d; } float LogViewTelegram::xdrToFloat(uint32_t in) { convertHackFloat c; c.i = in; return c.f; } quint64 LogViewTelegram::doubleToXdr(double in) { convertHackDouble c; c.d = in; return c.i; } uint32_t LogViewTelegram::floatToXdr(float in) { convertHackFloat c; c.f = in; return c.i; } // --------------------------------------------------------------- void LogViewTelegram::resetOffset() { switch (m_Protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: m_ActOffset = START_OFFSET_CENTRAL; break; default: ERROR_LOG(m_logger) << "resetOffset is only for Central-Protocol implemented"; } } // --------------------------------------------------------------- LogViewField* LogViewTelegram::getFieldTree() { // INFO_LOG(m_logger) << "type=" << getStructName().toStdString(); switch (m_Protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { resetOffset(); const QString type = m_json.value(QStringLiteral("type")).toString(); QStringList objPath = {QStringLiteral("data")}; return getFieldTreeJson(m_json.value(QStringLiteral("data")), type, jsonParser()->structFromType(type), objPath); } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { QString structName; switch (m_TetraTelegram->getPDU_Type()) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: m_ActOffset = START_OFFSET_TETRA_REGISTER; structName = QLatin1String("TETRA_register_indication_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: m_ActOffset = START_OFFSET_TETRA_REGISTER; structName = QLatin1String("TETRA_register_response_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: if (m_TetraTelegram->isLoginTelegram()) { m_ActOffset = START_OFFSET_TETRA_LOGIN; structName = QLatin1String("TETRA_login_telegram_rt"); } else if (m_TetraTelegram->isNormalTelegram()) { structName = getStructName(); if (structName == QLatin1String("gef_automatic_conversion_rt")) { // use the central-structure for telegrams which information on tetra and central-side are identical auto centralTelegram = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(m_TetraTelegram); if (centralTelegram) { // create a temporary central-telegram for getting the field-tree LogViewTelegram* tmpCentralTelegram = new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, m_LogTime, centralTelegram->data()); LogViewField* fieldTree = tmpCentralTelegram->getFieldTree(); delete tmpCentralTelegram; delete centralTelegram; return fieldTree; } } else { // conversion to central-telegram was not successful => use tetra-structure m_ActOffset = START_OFFSET_TETRA_DATA; structName = getStructName(); } } else { // fragmented telegram switch (m_TetraTelegram->getFragmentStatus()) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: m_ActOffset = START_OFFSET_TETRA_FRAGMENT; structName = QLatin1String("TETRA_first_fragment_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: m_ActOffset = START_OFFSET_TETRA_FRAGMENT; structName = QLatin1String("TETRA_middle_fragment_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: m_ActOffset = START_OFFSET_TETRA_FRAGMENT; structName = QLatin1String("TETRA_last_fragment_rt"); break; default: break; } } break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_GroupMonitorReq: m_ActOffset = START_OFFSET_TETRA_REGISTER; structName = QLatin1String("TETRA_group_monitoring_ind_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: m_ActOffset = START_OFFSET_TETRA_REGISTER; structName = QLatin1String("TETRA_status_ind_req_rt"); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: m_ActOffset = START_OFFSET_TETRA_AIRLOAD; structName = QLatin1String("TETRA_air_interface_load_req_rt"); break; default: m_ActOffset = 0; // data begins at 0 structName = QLatin1String("TETRA_unknown_PDU_rt"); break; } return getFieldTree(structName, structName, 1); } default: break; } return nullptr; } static inline QStringList objectPath(const LogViewField *parent, const QString &name, const QString &nameOverride) { auto ret = parent->jsonPath(); if (!nameOverride.isEmpty()) ret += nameOverride; if (!name.isEmpty()) ret += name; return ret; } LogViewField *LogViewTelegram::getFieldTreeJson(const QJsonValue &data, const QString &name, const StructInformation &si, const QStringList &objectPathBase) { auto xdr = new LogViewXdrStruct(name, LogViewXdrElement::e_KindStructElement); LogViewField *f = new LogViewField(name, LogViewField::e_FieldKindBorder, xdr); f->setJsonPath(objectPathBase); f->setDeleteXdr(true); addFieldTreeStruct(data.toObject(), f, si, QString(), m_logger); return f; } void LogViewTelegram::addFieldTreeStruct(const QJsonObject &parentObject, LogViewField *parent, const StructInformation &si, const QString &objectNameArrayHint, NGL::INGLLogger &logger) { DEBUG_LOG(logger) << "getFieldTreeJson for struct " << si.type << " with #members: " << si.member.size(); auto parser = jsonParser(); for (const MemberInformation &mi : si.member) { if (!mi.isVisible) continue; const QJsonValue val = parentObject.value(mi.name); if (mi.isString || mi.isBinary) { addFieldTreeJsonString(val, parent, mi.name, mi.isBinary, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); continue; } if (mi.isPod) { addFieldTreeJsonPod(val, parent, mi.name, mi.type, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); continue; } if (mi.isEnum) { addFieldTreeJsonEnum(val, parent, mi.name, mi.type, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); continue; } if (mi.isStruct) { const StructInformation si = parser->structFromType(mi.type); auto xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindStructElement); LogViewField *f = new LogViewField(mi.name, LogViewField::e_FieldKindBorder, xdr); f->setJsonPath(objectPath(parent, mi.name, objectNameArrayHint)); f->setDeleteXdr(true); addFieldTreeStruct(val.toObject(), f, si, objectNameArrayHint, logger); parent->addChild(f); continue; } if (mi.isArray) { const QString innerType = LogViewTetraTelegramsParser::getInnerType(mi.type); const bool isPod = parser->isPod(innerType); const bool isEnum = isPod ? false : parser->isEnum(innerType); const bool isStruct = (isPod || isEnum) ? false : (parser->isStruct(mi.type) || parser->isStruct(innerType)); LogViewXdrElement *xdr; if (isStruct) { xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindStruct); } else if (isEnum) { xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindEnum, 16); } else // isPod { const PodInformation pod = jsonParser()->podFromType(innerType); auto stdType = LogViewXdrStandardType::e_Float; if (pod.isBoolean) stdType = LogViewXdrStandardType::e_Boolean; else if (pod.isIntegral) stdType = pod.isSigned ? LogViewXdrStandardType::e_Signed : LogViewXdrStandardType::e_Unsigned; xdr = new LogViewXdrStandardType(mi.name, pod.byteLen, pod.byteLen, stdType, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian); } LogViewField *f = new LogViewField(mi.name, isStruct ? LogViewField::e_FieldKindTab : LogViewField::e_FieldKindPodArray, xdr); const QString fieldName = isStruct ? QStringLiteral("array: ") + mi.name : mi.name; f->setJsonPath(objectPath(parent, fieldName, objectNameArrayHint)); f->setDeleteXdr(true); f->setMaxArraySize(200, true); f->setType(LogViewTetraTelegramsParser::getInnerType(mi.type)); const QJsonArray arr = val.toArray(); const QString path(QStringLiteral("index: %1")); if (isStruct) { auto si = parser->structFromType(mi.type); // custom struct if (si.type.isEmpty()) si = parser->structFromType(innerType); // pod? for (int i = 0; i < arr.size(); ++i) { LogViewField *tc = new LogViewField(mi.name + QStringLiteral("TabChild"), LogViewField::e_FieldKindTabChild, xdr); tc->setJsonPath(f->jsonPath()); f->addChild(tc); addFieldTreeStruct(arr.at(i).toObject(), tc, si, path.arg(i), logger); } } else if (isPod) { for (const auto &ele : arr) f->addValue(QString::number(ele.toInt())); } else if (isEnum) { for (const auto &ele : arr) addFieldTreeJsonEnum(ele, f, QString(), innerType, objectNameArrayHint, LogViewField::e_FieldKindPodArrayChild, logger); } else { // assume string for (int i = 0; i < arr.size(); ++i) addFieldTreeJsonString(arr.at(i), f, QString(), false, path.arg(i), LogViewField::e_FieldKindPodArrayChild, logger); } parent->addChild(f); } } } // --------------------------------------------------------------- void LogViewTelegram::addFieldTreeJsonString(const QJsonValue &val, LogViewField *parent, const QString &name, bool isBinary, const QString &objectNameArrayHint, LogViewField::E_FieldKind fieldKind, NGL::INGLLogger &logger) { DEBUG_LOG(logger) << "addFieldTreeJsonString for " << name << " and value: " << val.toString(); auto xdr = new LogViewXdrStandardType(name, 1, 1, isBinary ? LogViewXdrStandardType::e_Data : LogViewXdrStandardType::e_Character, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian); LogViewField *f = new LogViewField(name, fieldKind, xdr); f->setMaxArraySize(std::numeric_limits::max(), true); if (isBinary) f->addValueBinaryHex(val.toString()); else f->addValue(val.toString()); f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); f->setDeleteXdr(true); parent->addChild(f); } // --------------------------------------------------------------- void LogViewTelegram::addFieldTreeJsonPod(const QJsonValue &val, LogViewField *parent, const QString &name, const QString &type, const QString &objectNameArrayHint, LogViewField::E_FieldKind fieldKind, NGL::INGLLogger &logger) { DEBUG_LOG(logger) << "addFieldTreeJsonPod for " << name << " and value: " << val.toDouble() << ", type: " << type; const PodInformation pod = jsonParser()->podFromType(type); auto stdType = LogViewXdrStandardType::e_Float; if (pod.isBoolean) stdType = LogViewXdrStandardType::e_Boolean; else if (pod.isIntegral) stdType = pod.isSigned ? LogViewXdrStandardType::e_Signed : LogViewXdrStandardType::e_Unsigned; auto xdr = new LogViewXdrStandardType(name, pod.byteLen, pod.byteLen, stdType, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian); LogViewField *f = new LogViewField(name, fieldKind, xdr); if (pod.isBoolean) f->addValue(QString::number(val.toBool())); else if (pod.isIntegral) f->addValue(QString::number(qRound64(val.toDouble()))); else f->addValue(QStringLiteral("%1").arg(val.toDouble(), 0, 'f', 10)); f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); f->setDeleteXdr(true); parent->addChild(f); } // --------------------------------------------------------------- void LogViewTelegram::addFieldTreeJsonEnum(const QJsonValue &val, LogViewField *parent, const QString &name, const QString &type, const QString &objectNameArrayHint, LogViewField::E_FieldKind fieldKind, NGL::INGLLogger &logger) { DEBUG_LOG(logger) << "addFieldTreeJsonEnum for " << name << " and value: " << val.toDouble(); const EnumInformation ei = jsonParser()->enumFromType(type); if (ei.type.isEmpty()) { WARNING_LOG(logger) << "Can not find enum information for " << type; return; } const int enumVal = val.toInt(); auto xdr = new LogViewXdrStruct(name, LogViewXdrElement::e_KindEnum, 16); LogViewField *f = new LogViewField(name, fieldKind, xdr); bool bAddedDefault = false; for (const EnumValue &ev : ei.values) { xdr->addElement(ev.key, ev.value, LogViewXdrElement::e_KindEnumElement); if (ev.value == enumVal) { bAddedDefault = true; f->addValue(ev.key); } } if (!bAddedDefault) f->addValue(QStringLiteral("Unknown (%1)").arg(enumVal)); f->setMaxArraySize(0, false); f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); f->setDeleteXdr(true); parent->addChild(f); } // --------------------------------------------------------------- QString LogViewTelegram::typeFromStructInformation(const StructInformation &si, const QString &name) { return memberFromStructInformation(si, name).type; } // --------------------------------------------------------------- MemberInformation LogViewTelegram::memberFromStructInformation(const StructInformation &si, const QString &name) { for(const MemberInformation &mi : si.member) { if (mi.name == name) return mi; } return {}; } // --------------------------------------------------------------- LogViewField* LogViewTelegram::getFieldTree(const QString& a_type, const QString& a_name, uint16_t a_arraySize, const LogViewXdrType* a_parentElement, const bool a_hasContent) { DEBUG_LOG(m_logger) << "a_type=" << a_type << " a_name=" << a_name << " a_arraySize=" << a_arraySize; const LogViewXdrElement* xdrElement = tetraParser()->getElement(a_type); if (!xdrElement) return nullptr; // xdrElement->dump(); //INFO_LOG(m_logger) << "name=" << xdrElement->getName().toStdString() << " type=" << xdrElement->getType().toStdString() << " value=" << xdrElement->getValue() << " kind=" << xdrElement->getKind() << " hasChilds=" << xdrElement->hasChilds() << " arraySize=" << xdrElement->getArraySize(); uint16_t maxArraySize = 0; LogViewField* fieldTree = nullptr; switch (xdrElement->getKind()) { case LogViewXdrElement::e_KindStruct: { // add tab for arrays or border for normal structure if (a_arraySize == 1) { // border for normal structure fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindBorder, xdrElement); } else { // static or dynamic array of structures => make tabs fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindTab, xdrElement); if (0 != a_arraySize) { // static array of structures fieldTree->setMaxArraySize(0, false); } } // add the childs as struct-elements uint32_t i = 0; while (LogViewXdrType* child = static_cast(xdrElement)->getChildAsType(i++)) { bool isDynArray = false; int arraySize = child->getArraySize(); if (0 == arraySize && !isScalar(child)) { INFO_LOG(m_logger) << "dyn. array of struc"; arraySize = getDynArraySize(m_ActOffset); isDynArray = true; } else { // do not iterate scalar types if (isScalar(child)) { arraySize = 1; } m_MaxArraySize = child->getMaxArraySize(); } // INFO_LOG(m_logger) << "struct-element: name=" << child->getName().toStdString() << " arraySize=" << arraySize << " maxArraySize=" << m_DynArrayOffset; // handle specialcase: dyn. array of structures with actual count of 0 elements if (0 == arraySize) { LogViewField* field = getFieldTree(child->getType(), child->getName(), child->getArraySize(), child); field->setHasContent(false); if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true); // fixme: kommt weiter unten nochmals fieldTree->addChild(field); } // now the normal-case begins for (int k=0; kgetType(), /*childName*/child->getName(), child->getArraySize(), child); if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true); // fixme: kommt weiter oben auch schon fieldTree->addChild(field); } } break; } case LogViewXdrElement::e_KindTypedef: // get the size of the element (with iterating down until we get a standard-type) if (a_arraySize != 0) // fixme: dies wird nur bei dyn. arrays von skalaren typen funktionieren { // INFO_LOG(m_logger) << "typedef statisch"; a_arraySize = static_cast(xdrElement)->getArraySize(); } else { // fixme INFO_LOG(m_logger) << "typedef dynamisch"; } maxArraySize = static_cast(xdrElement)->getMaxArraySize(); // fixme: vielleicht funktioniert das nicht in allen Fällen, funktioniert für allgemeine_nachricht while (xdrElement->getKind() != LogViewXdrElement::e_KindStandardType) { xdrElement = tetraParser()->getElement(static_cast(xdrElement)->getType()); // xdrElement->dump(); // INFO_LOG(m_logger) << "====> typedef name=" << a_name.toStdString() << " type=" << a_type.toStdString() << " a_arraySize=" << a_arraySize << " xdr.name=" << xdrElement->getName().toStdString() << " xdr.isLeaf=" << xdrElement->isLeaf() << " kind=" << xdrElement->getKind(); if (LogViewXdrElement::e_KindEnum == xdrElement->getKind()) { return getFieldTree(xdrElement->getName(), a_name, a_arraySize); } } Q_FALLTHROUGH(); case LogViewXdrElement::e_KindStandardType: { //INFO_LOG(m_logger) << "standardtype: add edit-field a_name=" << a_name.toStdString() << " a_arraySize=" << a_arraySize << " maxArraySize=" << maxArraySize << " m_DynArrayOffset=" << m_DynArrayOffset << " <==========================="; if (a_hasContent) { fieldTree = getContent(static_cast(xdrElement), m_ActOffset, a_arraySize); fieldTree->setName(a_name); } else { fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement); fieldTree->setHasContent(false); // todo: mache test mit telegramm, welches ein dyn. array von strukture mit anzahl 0 enthält (z.B. statistik-nachforderung mit 0 teilnehmern) } // set the maximal size of array: static arrays => a_arraySize; dyn. arrays => maxArraySize if (0 == a_arraySize) { // dynamic array fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true); } else { // static array or no array (== [1]) fieldTree->setMaxArraySize(a_arraySize, false); } break; } case LogViewXdrElement::e_KindEnum: { // evaluate the size uint16_t size = static_cast(xdrElement)->getEnumSize(); uint16_t arraySize = a_arraySize; if (0 == arraySize) { arraySize = getDynArraySize(m_ActOffset); } QString tooltipText; bool isLast = true; if (1 == arraySize) { uint32_t enumValue = getUIntX(m_ActOffset, size); tooltipText = QStringLiteral("%1 0x%2 0b%3").arg(enumValue) .arg(enumValue, 2, 16, QLatin1Char('0')) .arg(enumValue, 8, 2, QLatin1Char('0')); // only for Tetra and not for arrays: mask out unneeded bits (used for different bitfields within one value) if (a_parentElement) { isLast = a_parentElement->maskValue(enumValue, size, tooltipText); } } // allocate a new field fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement); fieldTree->setToolTipText(tooltipText); // get the enums for (int i=0; imaskValue(enumValue, size, tmp); // get the enum-text QString enumText = QStringLiteral("<%1>").arg(enumValue); int j=0; while (LogViewXdrValue* child = (static_cast(xdrElement))->getChildAsValue(j++)) { //INFO_LOG(m_logger) << "child name=" << child->getName().toStdString() << " type=" << child->getType().toStdString() << " value=" << child->getValue(); if (child->getValue() == enumValue) { enumText = LogViewField::makeClean(child->getName()); break; } } // add the enum-array-element fieldTree->addValue(enumText); if (isLast) m_ActOffset += size; } // set the maximal size of array: static arrays => a_arraySize; dyn. arrays => maxArraySize if (0 == a_arraySize) { // dynamic array fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true); } else { // static array or no array (== [1]) fieldTree->setMaxArraySize(a_arraySize, false); } break; } default: break; } return fieldTree; } // --------------------------------------------------------------- void LogViewTelegram::dump() const { //INFO_LOG(m_logger) << "m_ActOffset=" << m_ActOffset; NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, m_data.data(), m_data.size()); } // --------------------------------------------------------------- QString LogViewTelegram::getStructName() const { return isJsonTelegram() ? jsonParser()->nameFromTelegramId(getTelId()) : tetraParser()->getStructName(getTelId());; } // --------------------------------------------------------------- uint16_t LogViewTelegram::getUInt16(const uint16_t a_offset) const { return (uint16_t)getUIntX(a_offset, 2); } // --------------------------------------------------------------- uint32_t LogViewTelegram::getUInt32(const uint16_t a_offset) const { return getUIntX(a_offset, 4); } // --------------------------------------------------------------- int32_t LogViewTelegram::getInt32(const uint16_t a_offset) const { return getUInt32(a_offset); } // --------------------------------------------------------------- quint64 LogViewTelegram::getUIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) const { quint64 factor = 1; // used for little endian quint64 value = getData(a_offset); for (int i=1; i(m_TetraTelegram->getData()[0]); if (magicNumber != 0xA5) { showMessageBox(QObject::tr("TETRA-Magic-Number is 0x%1 but must be 0xA5").arg(magicNumber, 2, 16, QLatin1Char('0'))); m_Validity = e_Invalid; return false; } // check telegram-length int length = m_TetraTelegram->getSize(); if (length != m_data.size()) { showMessageBox(QObject::tr("Telegram length is %1 but must be %2").arg(length+4).arg(m_data.size())); m_Validity = e_Invalid; return false; } m_Validity = e_Valid; return true; } default: m_Validity = e_Invalid; return false; } case e_Valid: return true; case e_Invalid: return false; } } // --------------------------------------------------------------- LogViewField* LogViewTelegram::getContent(const LogViewXdrStandardType* a_standardType, uint16_t& a_offset, const uint16_t a_arraySize) { // INFO_LOG(m_logger) << "name=" << a_standardType->getName() << " valueKind=" << a_standardType->getValueKind() << " valueSize=" << a_standardType->getValueSize() << " a_offset=" << a_offset << " a_arraySize=" << a_arraySize; // allocate a new field LogViewField* field = new LogViewField(QString(), LogViewField::e_FieldKindEdit, a_standardType); field->setIsRightAligned(false); // evaluate the size const int size = a_standardType->getValueSize(); field->setSize(size); uint16_t arraySize = a_arraySize; if (0 == arraySize) arraySize = getDynArraySize(a_offset); // INFO_LOG(m_logger) << "name=" << a_standardType->getName().toStdString() << " size=" << size << " arraySize=" << arraySize; switch (a_standardType->getValueKind()) { case LogViewXdrStandardType::e_Unsigned: // get the values { const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); uint32_t value = 0; for (int i = 0; i < arraySize; i++) { value = getUIntX(i*size+a_offset, size, byteOrder); field->addValue(QString::number(value)); } // generate the tool-tip-text if (arraySize <= 1) { if (a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndex || a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndexDiv8) { m_DynArraySizeMethod = a_standardType->getDynArraySizeMethod(); m_LastUnsignedValue = value; // used for dyn. array in TETRA-Protocol } } field->setIsRightAligned(true); } break; case LogViewXdrStandardType::e_Signed: // get the signed values { const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); for (int i = 0; i < arraySize; i++) { int32_t value = getSIntX(i*size+a_offset, size, byteOrder); field->addValue(QString::number(value)); } field->setIsRightAligned(true); } break; case LogViewXdrStandardType::e_Float: // get the floating-point value { const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); for (int i = 0; i < arraySize; i++) { const quint64 value = getUIntX(i*size+a_offset, size, byteOrder); if (8 == size) { field->addValue(QString::number(xdrToDouble(value))); INFO_LOG(m_logger) << "value=" << xdrToDouble(value); } else { field->addValue(QString::number(xdrToFloat(value))); INFO_LOG(m_logger) << "value=" << xdrToFloat(value); } } field->setIsRightAligned(true); // fixme: vielleicht wird isRightAligned gar nicht benötigt... } break; case LogViewXdrStandardType::e_Character: // generate the text { QByteArray text; for (int i = 0; i < arraySize; i++) { char theChar = getChar(a_offset+(i*size), size); if (0 == theChar) break; text += theChar; } field->addValue(QString::fromUtf8(text)); } break; case LogViewXdrStandardType::e_Data: // generate the data-field for (int i = 0; i < arraySize; i++) field->addValue(QString::number(getData(a_offset+i))); break; default: ERROR_LOG(m_logger) << "ValueKind " << a_standardType->getValueKind() << " not implemented!"; break; } uint16_t sizeOfContent = arraySize * size; a_offset += sizeOfContent; // dynamic arrays must have an overall size which is 4-byte aligned if (0 == a_arraySize) { uint16_t rest = sizeOfContent % 4; if (0 != rest) { a_offset += (4 - rest); // INFO_LOG(m_logger) << "align offset to " << a_offset << " because it was an dyn. array content."; } } return field; } // --------------------------------------------------------------- N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol LogViewTelegram::getDirection() const { return static_cast(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); } // --------------------------------------------------------------- void LogViewTelegram::setJsonValue(const QStringList &path, const QJsonValue &val) { m_data.clear(); updateJsonValue(path, val, m_json); if (path.size() && path.last() == QLatin1String("equipmentNumber")) m_ParticipantId = m_json.value(QLatin1String("data")) .toObject().value(QLatin1String("header")) .toObject().value(QLatin1String("equipmentNumber")).toInt(); } // --------------------------------------------------------------- void LogViewTelegram::updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonObject &obj) { if (path.isEmpty()) return; if (path.size() > 1) { QString key = path.first(); static const QLatin1String arrayMarker(QLatin1String("array: ")); const bool isArray = key.startsWith(arrayMarker); if (isArray) { key = key.mid(arrayMarker.size()); const QJsonValue val = obj.value(key); QJsonArray arr = val.toArray(); const QStringList subPath = path.mid(1); updateJsonValue(subPath, newVal, arr); obj[key] = arr; } else { const QJsonValue val = obj.value(key); QJsonObject child = val.toObject(); const QStringList subPath = path.mid(1); updateJsonValue(subPath, newVal, child); obj[key] = child; } } else { obj[path.first()] = newVal; } } // --------------------------------------------------------------- void LogViewTelegram::updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonArray &arr) { if (path.isEmpty()) return; const QString &key = path.first(); static const QLatin1String indexMarker(QLatin1String("index: ")); if (!key.startsWith(indexMarker)) return; const int arrayIdx = key.midRef(indexMarker.size()).toInt(); while (arr.size() <= arrayIdx) arr.append(QJsonValue()); QJsonValue childVal = arr.at(arrayIdx); if (childVal.isObject() || path.size() > 1) { QJsonObject child = childVal.toObject(); const QStringList subPath = path.mid(1); updateJsonValue(subPath, newVal, child); arr[arrayIdx] = child; } else { arr[arrayIdx] = newVal; } } // --------------------------------------------------------------- QIcon LogViewTelegram::getIcon() const { static const QIcon c2p(QLatin1String(":/image/C2P.png")); static const QIcon p2c(QLatin1String(":/image/P2C.png")); static const QIcon w2p(QLatin1String(":/image/W2P.png")); static const QIcon p2w(QLatin1String(":/image/P2W.png")); static const QIcon t2p(QLatin1String(":/image/T2P.png")); static const QIcon p2t(QLatin1String(":/image/P2T.png")); static const QIcon unk(QLatin1String(":/image/Unknown.png")); N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol protocol, dest; protocol =(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol)(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); dest = (N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol)(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); switch (protocol) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return c2p; case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return p2c; default: break; } break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return w2p; case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return p2w; default: break; } break; } case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { switch (dest) { case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: return p2t; case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: return t2p; default: break; } break; } default: break; } return unk; } // --------------------------------------------------------------- bool LogViewTelegram::isScalar(const LogViewXdrType* a_xdrType) const { const LogViewXdrElement* xdrElement = tetraParser()->getElement(a_xdrType->getType()); if (xdrElement) { switch (xdrElement->getKind()) { case LogViewXdrElement::e_KindStandardType: case LogViewXdrElement::e_KindEnum: return true; case LogViewXdrElement::e_KindStruct: return false; case LogViewXdrElement::e_KindTypedef: return isScalar(static_cast(xdrElement)); /* e_KindStructElement, e_KindEnumElement, e_KindDefine*/ default: ERROR_LOG(m_logger) << "name=" << xdrElement->getName().toStdString() << " kind=" << xdrElement->getKind() << " case not implemented!"; return false; } } return false; } // --------------------------------------------------------------- void LogViewTelegram::showMessageBox(const QString& a_errorText, const QString& a_title) const { quint64 logTimeSec = m_LogTime >> 32; quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; const QDateTime dt(QDateTime::fromMSecsSinceEpoch(logTimeSec * 1000 + logTimeMicroSec/1000)); const QString destStr((m_Destination&N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask)==N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend ? QLatin1String("gesendete") : QLatin1String("gelesene")); QMessageBox::warning(QApplication::topLevelWidgets()[0], a_title, QString::fromUtf8("Das %5 Telegramm mit Protokoll %6 von %1 (Unix-Zeit: %2) und Länge %3 ist fehlerhaft:

%4") .arg(dt.toString(Qt::SystemLocaleLongDate)).arg(logTimeSec).arg(m_data.size()).arg(a_errorText, destStr).arg(m_Protocol)); } // --------------------------------------------------------------- uint16_t LogViewTelegram::getDynArraySize(uint16_t& a_offset) const { uint16_t arraySize; if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra == m_Protocol) { switch (m_DynArraySizeMethod) { case LogViewXdrStandardType::e_DynArrayMsgLength: arraySize = m_data.size() - m_MaxArraySize; break; case LogViewXdrStandardType::e_DynArrayIndexDiv8: arraySize = (m_LastUnsignedValue+7)/8; break; default: arraySize = m_LastUnsignedValue; break; } } else { // dynamic array => get the next 4 bytes, which contain the lengths of the dynamic array arraySize = getUIntX(a_offset, SIZE_CENTRAL_DYN_ARRAY_SIZE); a_offset += SIZE_CENTRAL_DYN_ARRAY_SIZE; } return arraySize; } // --------------------------------------------------------------- QString LogViewTelegram::formatToolTipLine(const QString& a_name, const QString& a_text, const uint32_t a_value) { static const QString s1(QLatin1String("%1: %20x%30b%4")); static const QString s2(QLatin1String("%1")); QString num16 = s2.arg(a_value, 2, 16, QLatin1Char('0')); QString num2 = s2.arg(a_value, 8, 2, QLatin1Char('0')); QString ret = s1.arg(a_name, a_text, num16, num2); ret = ret.replace(QLatin1Char('\n'), QLatin1String("
")); return ret; } // --------------------------------------------------------------- const N_CoPrtCnv::CoPrtCnvRadioTelegram* LogViewTelegram::getTetraTelegram() const { return m_TetraTelegram; } // --------------------------------------------------------------- LogViewTetraTelegramsParser *LogViewTelegram::jsonParser() { static LogViewTetraTelegramsParser s_parser; return &s_parser; } // --------------------------------------------------------------- LogViewXdrParser *LogViewTelegram::tetraParser() { static LogViewXdrParser s_parser; return &s_parser; } // --------------------------------------------------------------- // returns the data-byte at a_offset. Returns 0 if a_offset is // outside of range. // --------------------------------------------------------------- uint8_t LogViewTelegram::getData(const uint16_t a_offset) const { if (a_offset < m_data.size()) return m_data.at(a_offset); return 0; } // --------------------------------------------------------------- QByteArray LogViewTelegram::getData(QJsonDocument::JsonFormat format) const { if (m_data.isEmpty() && !m_json.isEmpty()) return QJsonDocument(m_json).toJson(format); return m_data; } // --------------------------------------------------------------- void LogViewTelegram::setNextFieldAsGpsTimeField() { m_GpsFieldOffset.append(m_ActOffset); } // --------------------------------------------------------------- void LogViewTelegram::actualizeGpsTime() { if (m_GpsFieldOffset.size() > 0) { if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Protocol) { uint16_t savedOffset = m_ActOffset; for (QVector::const_iterator i = m_GpsFieldOffset.cbegin(); i < m_GpsFieldOffset.cend(); ++i) { m_ActOffset = *i; setUIntX(4, ::time(nullptr)); // todo nicht 4 sondern size des typs } m_ActOffset = savedOffset; } } if (!m_json.isEmpty()) { static const QString dataKey = QStringLiteral("data"); if (dataKey.contains(dataKey)) { auto data = m_json.value(dataKey).toObject(); static const QString hdrKey = QStringLiteral("header"); if (data.contains(hdrKey)) { auto hdr = data.value(hdrKey).toObject(); hdr[QStringLiteral("timeStamp")] = QDateTime::currentMSecsSinceEpoch(); data[hdrKey] = hdr; } m_json[dataKey] = data; } m_data.clear(); } } } // namespace N_LogView