1769 lines
53 KiB
C++
1769 lines
53 KiB
C++
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "LogViewTelegram.hpp"
|
|
|
|
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
|
|
#include <CoPrtCnv/CoPrtCnvCentralTelegram.hpp>
|
|
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
|
|
#include <CoPrtCnv/CoPrtCnvHexDumpHelper.hpp>
|
|
#include "LogViewXdrParser.hpp"
|
|
#include "LogViewXdrStruct.hpp"
|
|
#include "LogViewXdrValue.hpp"
|
|
#include "LogViewXdrType.hpp"
|
|
#include "LogViewTetraTelegramsParser.hpp"
|
|
|
|
#include "LogViewField.hpp"
|
|
#include <QDateTime>
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QMessageBox>
|
|
#include <QApplication>
|
|
#include <time.h>
|
|
|
|
|
|
namespace N_LogView
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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<uint16_t>())
|
|
, 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<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol>(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"));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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<uint16_t>())
|
|
, 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<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol>(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);
|
|
|
|
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();
|
|
|
|
|
|
m_Name = m_json.value(QLatin1String("type")).toString();
|
|
switch (getTelId())
|
|
{
|
|
case TrainingAreaBase::TetraIcd::BESTAETIGUNG:
|
|
break;
|
|
default:
|
|
|
|
|
|
|
|
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);
|
|
|
|
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())
|
|
{
|
|
|
|
m_TelId = m_TetraTelegram->getTelID();
|
|
m_Name = tetraParser()->getTelegramName(m_TelId);
|
|
m_ParticipantId = m_TetraTelegram->getIdentity();
|
|
|
|
if (getDirection() == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend)
|
|
{
|
|
|
|
uint16_t gpsTimeOffset = 2;
|
|
switch (m_TelId)
|
|
{
|
|
case GEF_DEAKTIVIERUNG_EINZELMINE:
|
|
gpsTimeOffset = 4;
|
|
break;
|
|
default:
|
|
gpsTimeOffset = 2;
|
|
}
|
|
m_GpsTime = getUInt32(START_OFFSET_TETRA_DATA+gpsTimeOffset);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
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);
|
|
|
|
break;
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment:
|
|
m_Name = QObject::tr("Letztes Fragment eines TETRA-Telegrammes");
|
|
|
|
break;
|
|
default:
|
|
m_Name = QObject::tr("TETRA-Telegramm mit Fragment-Status=%1 ist nicht implementiert").arg(m_TetraTelegram->getFragmentStatus());
|
|
break;
|
|
}
|
|
}
|
|
|
|
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:
|
|
|
|
|
|
|
|
m_Name = QObject::tr("PDU-Type=%1").arg(m_TetraTelegram->getPDU_Type());
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
showMessageBox(QObject::tr("Unknown protocol %1!</b>").arg(m_Protocol), QObject::tr("Unknown protocol"));
|
|
m_Validity = e_Invalid;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
LogViewTelegram::~LogViewTelegram()
|
|
{
|
|
delete m_TetraTelegram;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LogViewTelegram::setUIntX(const uint8_t a_size, quint64 a_value, const LogViewXdrStandardType::E_ByteOrder a_byteOrder)
|
|
{
|
|
|
|
if (m_ActOffset + a_size > m_data.size())
|
|
m_data.resize(m_ActOffset + a_size);
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol>
|
|
(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask);
|
|
auto dest = static_cast<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 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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString LogViewTelegram::getGpsTimeText() const
|
|
{
|
|
if (m_GpsTime != 0)
|
|
return QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL).toString(QLatin1String("hh:mm:ss"));
|
|
|
|
return QString();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t LogViewTelegram::getDelay() const
|
|
{
|
|
if (m_GpsTime != 0)
|
|
{
|
|
quint64 logTimeSec = m_LogTime >> 32;
|
|
return logTimeSec - m_GpsTime;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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("<nobr>%1.%2 s</nobr>")
|
|
.arg(logTimeSec)
|
|
.arg(logTimeMicroSec);
|
|
}
|
|
if(a_col == e_ColGpsTime && m_ToolTipText[e_ColGpsTime].isNull()) {
|
|
if(m_GpsTime == 0) {
|
|
m_ToolTipText[e_ColGpsTime] = QLatin1String("");
|
|
} else {
|
|
const QDateTime dtGpsTime(QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL));
|
|
m_ToolTipText[e_ColGpsTime] = QStringLiteral("%1<br><nobr>Unixzeit: %2 <b>0x%3</b></nobr>")
|
|
.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));
|
|
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ 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("</table>");
|
|
break;
|
|
}
|
|
|
|
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra:
|
|
{
|
|
switch (m_TetraTelegram->getPDU_Type())
|
|
{
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd:
|
|
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ formatToolTipLine(QObject::tr("Host ISSI"), m_TetraTelegram->getSrcISSI())
|
|
+ formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler())
|
|
+ formatToolTipLine(QObject::tr("Size"), m_data.size())
|
|
+ QLatin1String("</table>");
|
|
break;
|
|
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp:
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ 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("</table>");
|
|
break;
|
|
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: {
|
|
int frameSize = 1;
|
|
if(m_TetraTelegram->getWithCrc())
|
|
frameSize += 2;
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ 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("</table>");
|
|
break;
|
|
}
|
|
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq:
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ 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("</table>");
|
|
break;
|
|
|
|
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq:
|
|
default:
|
|
m_ToolTipText[e_ColName] = QLatin1String("<table>")
|
|
+ formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler())
|
|
+ formatToolTipLine(QObject::tr("Size"), m_data.size())
|
|
+ QLatin1String("</table>");
|
|
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()
|
|
{
|
|
|
|
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"))
|
|
{
|
|
|
|
auto centralTelegram = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(m_TetraTelegram);
|
|
if (centralTelegram)
|
|
{
|
|
|
|
LogViewTelegram* tmpCentralTelegram = new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral,
|
|
m_LogTime,
|
|
centralTelegram->data());
|
|
LogViewField* fieldTree = tmpCentralTelegram->getFieldTree();
|
|
delete tmpCentralTelegram;
|
|
delete centralTelegram;
|
|
return fieldTree;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
m_ActOffset = START_OFFSET_TETRA_DATA;
|
|
structName = getStructName();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
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;
|
|
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
|
|
{
|
|
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);
|
|
if (si.type.isEmpty())
|
|
si = parser->structFromType(innerType);
|
|
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
|
|
{
|
|
|
|
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<uint16_t>::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;
|
|
|
|
|
|
|
|
uint16_t maxArraySize = 0;
|
|
LogViewField* fieldTree = nullptr;
|
|
switch (xdrElement->getKind())
|
|
{
|
|
case LogViewXdrElement::e_KindStruct:
|
|
{
|
|
|
|
if (a_arraySize == 1)
|
|
{
|
|
|
|
fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindBorder, xdrElement);
|
|
}
|
|
else
|
|
{
|
|
|
|
fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindTab, xdrElement);
|
|
if (0 != a_arraySize)
|
|
{
|
|
|
|
fieldTree->setMaxArraySize(0, false);
|
|
}
|
|
}
|
|
|
|
|
|
uint32_t i = 0;
|
|
while (LogViewXdrType* child = static_cast<const LogViewXdrStruct*>(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
|
|
{
|
|
|
|
if (isScalar(child))
|
|
{
|
|
arraySize = 1;
|
|
}
|
|
m_MaxArraySize = child->getMaxArraySize();
|
|
}
|
|
|
|
|
|
|
|
if (0 == arraySize)
|
|
{
|
|
LogViewField* field = getFieldTree(child->getType(), child->getName(), child->getArraySize(), child);
|
|
field->setHasContent(false);
|
|
if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true);
|
|
fieldTree->addChild(field);
|
|
}
|
|
|
|
for (int k=0; k<arraySize; k++)
|
|
{
|
|
LogViewField* field = getFieldTree(child->getType(), child->getName(), child->getArraySize(), child);
|
|
if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true);
|
|
fieldTree->addChild(field);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LogViewXdrElement::e_KindTypedef:
|
|
|
|
if (a_arraySize != 0)
|
|
{
|
|
|
|
a_arraySize = static_cast<const LogViewXdrType*>(xdrElement)->getArraySize();
|
|
}
|
|
else
|
|
{
|
|
|
|
INFO_LOG(m_logger) << "typedef dynamisch";
|
|
}
|
|
maxArraySize = static_cast<const LogViewXdrType*>(xdrElement)->getMaxArraySize();
|
|
while (xdrElement->getKind() != LogViewXdrElement::e_KindStandardType)
|
|
{
|
|
xdrElement = tetraParser()->getElement(static_cast<const LogViewXdrType*>(xdrElement)->getType());
|
|
|
|
|
|
if (LogViewXdrElement::e_KindEnum == xdrElement->getKind())
|
|
{
|
|
return getFieldTree(xdrElement->getName(), a_name, a_arraySize);
|
|
}
|
|
}
|
|
Q_FALLTHROUGH();
|
|
case LogViewXdrElement::e_KindStandardType:
|
|
{
|
|
|
|
if (a_hasContent)
|
|
{
|
|
fieldTree = getContent(static_cast<const LogViewXdrStandardType*>(xdrElement), m_ActOffset, a_arraySize);
|
|
fieldTree->setName(a_name);
|
|
}
|
|
else
|
|
{
|
|
fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement);
|
|
fieldTree->setHasContent(false);
|
|
|
|
}
|
|
|
|
if (0 == a_arraySize)
|
|
{
|
|
|
|
fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true);
|
|
}
|
|
else
|
|
{
|
|
|
|
fieldTree->setMaxArraySize(a_arraySize, false);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LogViewXdrElement::e_KindEnum:
|
|
{
|
|
|
|
uint16_t size = static_cast<const LogViewXdrStruct*>(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("<b>%1 0x%2</b> 0b%3").arg(enumValue)
|
|
.arg(enumValue, 2, 16, QLatin1Char('0'))
|
|
.arg(enumValue, 8, 2, QLatin1Char('0'));
|
|
|
|
if (a_parentElement)
|
|
{
|
|
isLast = a_parentElement->maskValue(enumValue, size, tooltipText);
|
|
}
|
|
}
|
|
|
|
|
|
fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement);
|
|
fieldTree->setToolTipText(tooltipText);
|
|
|
|
|
|
for (int i=0; i<arraySize; i++)
|
|
{
|
|
uint32_t enumValue = getUIntX(m_ActOffset, size);
|
|
QString tmp;
|
|
if(a_parentElement)
|
|
a_parentElement->maskValue(enumValue, size, tmp);
|
|
|
|
QString enumText = QStringLiteral("<%1>").arg(enumValue);
|
|
int j=0;
|
|
while (LogViewXdrValue* child = (static_cast<const LogViewXdrStruct*>(xdrElement))->getChildAsValue(j++))
|
|
{
|
|
|
|
if (child->getValue() == enumValue)
|
|
{
|
|
enumText = LogViewField::makeClean(child->getName());
|
|
break;
|
|
}
|
|
}
|
|
|
|
fieldTree->addValue(enumText);
|
|
if (isLast) m_ActOffset += size;
|
|
}
|
|
|
|
|
|
|
|
if (0 == a_arraySize)
|
|
{
|
|
|
|
fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true);
|
|
}
|
|
else
|
|
{
|
|
|
|
fieldTree->setMaxArraySize(a_arraySize, false);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return fieldTree;
|
|
}
|
|
|
|
|
|
|
|
void LogViewTelegram::dump() const
|
|
{
|
|
|
|
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;
|
|
quint64 value = getData(a_offset);
|
|
for (int i=1; i<a_size; i++)
|
|
{
|
|
if (LogViewXdrStandardType::e_ByteOrderBigEndian == a_byteOrder)
|
|
{
|
|
value = value << 8;
|
|
value += getData(a_offset+i);
|
|
}
|
|
else
|
|
{
|
|
|
|
factor = factor << 8;
|
|
value += factor * getData(a_offset+i);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
|
|
int32_t LogViewTelegram::getSIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) const
|
|
{
|
|
uint32_t value = getUIntX(a_offset, a_size, a_byteOrder);
|
|
switch (a_size)
|
|
{
|
|
case 1:
|
|
if (value & 0x00000080) value = value | 0xFFFFFF00;
|
|
break;
|
|
case 2:
|
|
if (value & 0x00008000) value = value | 0xFFFF0000;
|
|
break;
|
|
case 3:
|
|
if (value & 0x00800000) value = value | 0xFF000000;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
|
|
char LogViewTelegram::getChar(const uint16_t a_offset, const uint8_t a_size) const
|
|
{
|
|
char theChar = getData(a_offset+a_size-1);
|
|
return theChar;
|
|
}
|
|
|
|
|
|
|
|
bool LogViewTelegram::isValid()
|
|
{
|
|
switch (m_Validity)
|
|
{
|
|
default:
|
|
switch (m_Protocol)
|
|
{
|
|
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral:
|
|
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls:
|
|
{
|
|
const QJsonValue typeId(m_json.value(QStringLiteral("typeId")));
|
|
const QJsonValue data(m_json.value(QStringLiteral("data")));
|
|
const QJsonValue type(m_json.value(QStringLiteral("type")));
|
|
if (!typeId.isDouble() || !data.isObject() || !type.isString())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra:
|
|
{
|
|
|
|
uint8_t magicNumber = static_cast<uint8_t>(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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
|
|
|
|
|
|
LogViewField* field = new LogViewField(QString(), LogViewField::e_FieldKindEdit, a_standardType);
|
|
field->setIsRightAligned(false);
|
|
|
|
|
|
const int size = a_standardType->getValueSize();
|
|
field->setSize(size);
|
|
uint16_t arraySize = a_arraySize;
|
|
if (0 == arraySize)
|
|
arraySize = getDynArraySize(a_offset);
|
|
|
|
|
|
switch (a_standardType->getValueKind())
|
|
{
|
|
case LogViewXdrStandardType::e_Unsigned:
|
|
|
|
{
|
|
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));
|
|
}
|
|
|
|
if (arraySize <= 1)
|
|
{
|
|
if (a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndex
|
|
|| a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndexDiv8)
|
|
{
|
|
m_DynArraySizeMethod = a_standardType->getDynArraySizeMethod();
|
|
m_LastUnsignedValue = value;
|
|
}
|
|
}
|
|
field->setIsRightAligned(true);
|
|
}
|
|
break;
|
|
|
|
case LogViewXdrStandardType::e_Signed:
|
|
|
|
{
|
|
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:
|
|
|
|
{
|
|
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);
|
|
}
|
|
break;
|
|
|
|
case LogViewXdrStandardType::e_Character:
|
|
|
|
{
|
|
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:
|
|
|
|
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;
|
|
|
|
if (0 == a_arraySize)
|
|
{
|
|
uint16_t rest = sizeOfContent % 4;
|
|
if (0 != rest)
|
|
{
|
|
a_offset += (4 - rest);
|
|
|
|
}
|
|
}
|
|
|
|
return field;
|
|
}
|
|
|
|
|
|
|
|
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol LogViewTelegram::getDirection() const
|
|
{
|
|
return static_cast<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol>(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<const LogViewXdrType*>(xdrElement));
|
|
|
|
|
|
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:<br><br><b>%4</b>")
|
|
.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
|
|
{
|
|
|
|
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("<tr><td><nobr>%1: </nobr></td><td align=right><b><nobr>%2</nobr></b></td><td align=right><nobr>0x%3</nobr></td><td align=right><nobr>0b%4</nobr></td></tr>"));
|
|
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("<br/>"));
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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<uint16_t>::const_iterator i = m_GpsFieldOffset.cbegin(); i < m_GpsFieldOffset.cend(); ++i)
|
|
{
|
|
m_ActOffset = *i;
|
|
setUIntX(4, ::time(nullptr));
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
|
|
}
|