Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
#
# $Id$
# $HeadURL$
# $Author$
#
ADD_SUBDIRECTORY(CoPrtCnv)
ADD_SUBDIRECTORY(LogView)
ADD_SUBDIRECTORY(PrtCnv)
+30
View File
@@ -0,0 +1,30 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(my_SRCS
tetra_telegram_ids.h
CoPrtCnvCentralTelegram.cpp
CoPrtCnvCentralTelegram.hpp
CoPrtCnvHexDumpHelper.cpp
CoPrtCnvHexDumpHelper.hpp
CoPrtCnvInjectionHeader.hpp
CoPrtCnvLogHeader.hpp
CoPrtCnvRadioTelegram.cpp
CoPrtCnvRadioTelegram.hpp
CoPrtCnvTelegramConverter.hpp
CoPrtCnvTelegramConverterNewIcd.cpp
)
NGL_ADD_LIBRARY2(AAR SV CoPrtCnv SHARED ${my_SRCS} ${my_HDRS})
NGL_TARGET_LINK_LIBRARIES(CoPrtCnv
PUBLIC
NGLLogger
tabTelegrams
)
NGL_TARGET_INCLUDE_DIRECTORIES(CoPrtCnv
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
@@ -0,0 +1,87 @@
/**
* Thin wrapper around json telegram data
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-22
*/
#include "CoPrtCnvCentralTelegram.hpp"
#include <QJsonDocument>
namespace N_CoPrtCnv
{
void CoPrtCnvCentralTelegram::setData(const QByteArray &data)
{
m_data = data;
m_json = QJsonObject();
}
QByteArray CoPrtCnvCentralTelegram::data()
{
ensureByteArray();
return m_data;
}
QJsonObject CoPrtCnvCentralTelegram::json()
{
ensureJson();
return m_json;
}
QJsonObject CoPrtCnvCentralTelegram::jsonData()
{
return json()[QStringLiteral("data")].toObject();
}
TrainingAreaBase::TetraIcd::TelegramId CoPrtCnvCentralTelegram::telegramId()
{
if (m_telegramId != TrainingAreaBase::TetraIcd::UNKNOWN)
return m_telegramId;
ensureJson();
m_telegramId = static_cast<TrainingAreaBase::TetraIcd::TelegramId>(m_json[QStringLiteral("typeId")].toInt());
return m_telegramId;
}
void CoPrtCnvCentralTelegram::setCounter(qint32 counter)
{
if (m_json.isEmpty())
m_json = QJsonDocument::fromJson(m_data).object();
m_json[QStringLiteral("counter")] = counter;
m_data.clear();
}
qint32 CoPrtCnvCentralTelegram::counter()
{
ensureJson();
const QString key(QStringLiteral("counter"));
const QJsonValue sendCounter(m_json[key]);
if (!sendCounter.isDouble())
throw TrainingAreaBase::TetraIcd::JsonException(m_json, key);
return sendCounter.toInt(-1);
}
void CoPrtCnvCentralTelegram::ensureJson()
{
if (m_json.isEmpty())
{
if (m_data.isEmpty())
return;
m_json = QJsonDocument::fromJson(m_data).object();
}
}
void CoPrtCnvCentralTelegram::ensureByteArray()
{
if (m_data.isEmpty())
{
if (m_json.isEmpty())
return;
m_data = QJsonDocument(m_json).toJson(QJsonDocument::Compact);
}
}
} // namespace N_CoPrtCnv
@@ -0,0 +1,68 @@
/**
* Thin wrapper around json telegram data
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-22
*/
#pragma once
#include <QJsonObject>
#include <QByteArray>
#include <CoPrtCnv/coprtcnv_export.h>
#include <TrainingAreaBase/training_area_telegrams.h>
namespace N_CoPrtCnv
{
/**
* The central-telegram, an subclass of XDR_Wrapper_it used for creation of
* telegrams with telegramId. It also contains the deletion of dynamic allocated
* space within central-telegrams.
*/
class COPRTCNV_EXPORT CoPrtCnvCentralTelegram final
{
public:
explicit CoPrtCnvCentralTelegram(TrainingAreaBase::TetraIcd::TelegramId telegramId)
: m_telegramId(telegramId)
{}
explicit CoPrtCnvCentralTelegram(const QByteArray &data)
: m_data(data)
, m_telegramId(TrainingAreaBase::TetraIcd::UNKNOWN)
{}
CoPrtCnvCentralTelegram(const QByteArray &data, TrainingAreaBase::TetraIcd::TelegramId telegramId)
: m_data(data)
, m_telegramId(telegramId)
{}
CoPrtCnvCentralTelegram(const QByteArray &data, const QJsonObject &json, TrainingAreaBase::TetraIcd::TelegramId telegramId)
: m_data(data)
, m_json(json)
, m_telegramId(telegramId)
{}
explicit CoPrtCnvCentralTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram &tele)
: m_telegramId(tele.id())
{
m_json[QStringLiteral("type")] = tele.type();
m_json[QStringLiteral("typeId")] = tele.id();
m_json[QStringLiteral("data")] = tele.toJson();
}
void setData(const QByteArray &data);
QByteArray data();
QJsonObject json(); // complete json
QJsonObject jsonData(); // json()["data"]
TrainingAreaBase::TetraIcd::TelegramId telegramId();
void setCounter(qint32 counter);
qint32 counter();
private:
void ensureJson();
void ensureByteArray();
private:
QByteArray m_data;
QJsonObject m_json;
TrainingAreaBase::TetraIcd::TelegramId m_telegramId;
};
}
+240
View File
@@ -0,0 +1,240 @@
// **************************************************************************
//
// @RDE_HEADER@
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// Helper to dump the data in hex
// **************************************************************************
#include "CoPrtCnvHexDumpHelper.hpp"
#include "CoPrtCnvRadioTelegram.hpp"
#include <QtCore/QByteArray>
#include <NGLLogger/NGLLoggerBootstrap.h>
static std::string dumpSammeldeaktivierung(const N_CoPrtCnv::CoPrtCnvRadioTelegram* sammelTelegram)
{
const int ANZAHL_POS = 5;
const int SIZE_POS = sammelTelegram->getTelID() == GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN ? 2 : 1;
std::stringstream sstream;
unsigned int cnt = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS, SIZE_POS); // anzahl
for (unsigned int i = 0; i < cnt; ++i) {
uint16_t telId = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS + SIZE_POS + 2 * i, 2); // add kennung
sstream << telId << " ";
}
return sstream.str();
}
QByteArray telegramId2String(gef_telegramm_id_et telId)
{
const char *str = nullptr;
switch (telId)
{
case GEF_BESTAETIGUNG: str = "GEF_BESTAETIGUNG"; break;
case GEF_INIT: str = "GEF_INIT"; break;
case GEF_MANIPULATIONSMELDUNG: str = "GEF_MANIPULATIONSMELDUNG"; break;
case GEF_UMGEBUNGS_MELDUNG2: str = "GEF_UMGEBUNGS_MELDUNG2"; break;
case GEF_AUFFORDERUNG_BITE_MELDUNG: str = "GEF_AUFFORDERUNG_BITE_MELDUNG"; break;
case GEF_BITE_MELDUNG2: str = "GEF_BITE_MELDUNG2"; break;
case GEF_LIZENSIERUNG_TNE: str = "GEF_LIZENSIERUNG_TNE"; break;
case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: str = "GEF_BETRIEBSZUSTAND_AUSSTATTUNG"; break;
case GEF_KONFIGURATION_WIRKMODELL: str = "GEF_KONFIGURATION_WIRKMODELL"; break;
case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: str = "GEF_ANFORDERUNG_KONFIGURATIONSDATEN"; break;
case GEF_KONFIGURATIONSMELDUNG: str = "GEF_KONFIGURATIONSMELDUNG"; break;
case GEF_FEHLERMELDUNG_GFD: str = "GEF_FEHLERMELDUNG_GFD"; break;
case GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT: str = "GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT"; break;
case GEF_POSITIONS_MELDUNG: str = "GEF_POSITIONS_MELDUNG"; break;
case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: str = "GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER"; break;
case GEF_POSITIONS_MELDUNG_LFZ: str = "GEF_POSITIONS_MELDUNG_LFZ"; break;
case GEF_IPS_POSITIONSDATEN: str = "GEF_IPS_POSITIONSDATEN"; break;
case GEF_SCHIEDSRICHTERKOMMANDO: str = "GEF_SCHIEDSRICHTERKOMMANDO"; break;
case GEF_WIRKFELD_EINZELGESCHOSS: str = "GEF_WIRKFELD_EINZELGESCHOSS"; break;
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER"; break;
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP"; break;
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN"; break;
case GEF_WIRKFELD_MINENSPERRE: str = "GEF_WIRKFELD_MINENSPERRE"; break;
case GEF_WIRKFELD_STATUS_MINENSPERRE: str = "GEF_WIRKFELD_STATUS_MINENSPERRE"; break;
case GEF_WIRKFELD_A_KAMPFMITTEL: str = "GEF_WIRKFELD_A_KAMPFMITTEL"; break;
case GEF_WIRKFELD_C_KAMPFMITTEL: str = "GEF_WIRKFELD_C_KAMPFMITTEL"; break;
case GEF_DEAKTIVIERUNG_WIRKFELD: str = "GEF_DEAKTIVIERUNG_WIRKFELD"; break;
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: str = "GEF_WIRKFELD_AENDERUNG_BEZEICHNER"; break;
case GEF_DEAKTIVIERUNG_EINZELMINE: str = "GEF_DEAKTIVIERUNG_EINZELMINE"; break;
case GEF_REAKTIVIERUNG_DUS_MINE: str = "GEF_REAKTIVIERUNG_DUS_MINE"; break;
case GEF_DEFINITION_IED: str = "GEF_DEFINITION_IED"; break;
case GEF_ZUSTAND_IED: str = "GEF_ZUSTAND_IED"; break;
case GEF_STATUS_EINZELMINENSIMULATOR: str = "GEF_STATUS_EINZELMINENSIMULATOR"; break;
case GEF_WIRKFELD_EINZELMINENSIMULATOR: str = "GEF_WIRKFELD_EINZELMINENSIMULATOR"; break;
case GEF_TREFFER_EREIGNIS_DUS: str = "GEF_TREFFER_EREIGNIS_DUS"; break;
case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION"; break;
case GEF_TREFFER_AUSLOESUNG: str = "GEF_TREFFER_AUSLOESUNG"; break;
case GEF_SCHIEDSRICHTEREINGRIFF: str = "GEF_SCHIEDSRICHTEREINGRIFF"; break;
case GEF_SELEKTIVE_AUFMUNITIONIERUNG: str = "GEF_SELEKTIVE_AUFMUNITIONIERUNG"; break;
case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: str = "GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG"; break;
case GEF_TREFFER_EREIGNIS_DUS_IPS: str = "GEF_TREFFER_EREIGNIS_DUS_IPS"; break;
case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS"; break;
case GEF_TAKTISCHER_STATUS: str = "GEF_TAKTISCHER_STATUS"; break;
case GEF_FUNKTIONSRAUM: str = "GEF_FUNKTIONSRAUM"; break;
case GEF_EINTRETEN_FUNKTIONSRAUM: str = "GEF_EINTRETEN_FUNKTIONSRAUM"; break;
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: str = "GEF_DEAKTIVIEREN_FUNKTIONSRAUM"; break;
case GEF_DATENVERKEHR_SRT_TDS: str = "GEF_DATENVERKEHR_SRT_TDS"; break;
case GEF_DATENVERKEHR_TDS_SRT: str = "GEF_DATENVERKEHR_TDS_SRT"; break;
case GEF_DATENVERKEHR_DMF_TDS: str = "GEF_DATENVERKEHR_DMF_TDS"; break;
case GEF_DATENVERKEHR_TDS_DMF: str = "GEF_DATENVERKEHR_TDS_DMF"; break;
case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: str = "GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME"; break;
case GEF_NOP: str = "GEF_NOP"; break;
case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: str = "GEF_SONDERSENSORIK_BETRIEBSZUSTAND"; break;
case GEF_SONDERSENSORIK_FAHRSPUR: str = "GEF_SONDERSENSORIK_FAHRSPUR"; break;
case GEF_SONDERSENSORIK_DATEN: str = "GEF_SONDERSENSORIK_DATEN"; break;
case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN"; break;
case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN"; break;
case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION"; break;
case GEF_SPRACHAUSWAHL: str = "GEF_SPRACHAUSWAHL"; break;
case GEF_ALLGEMEINE_NACHRICHT: str = "GEF_ALLGEMEINE_NACHRICHT"; break;
case GEF_ECHO_ON_OFF: str = "GEF_ECHO_ON_OFF"; break;
case GEF_ESW_MELDUNG: str = "GEF_ESW_MELDUNG"; break;
case GEF_WF_SAMMELDEAKTIVIERUNG: str = "GEF_WF_SAMMELDEAKTIVIERUNG"; break;
case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: str = "GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN"; break;
case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: str = "GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM"; break;
case GEF_DATENVERKEHR_GEOP_TDS: str = "GEF_DATENVERKEHR_GEOP_TDS"; break;
case GEF_DATENVERKEHR_TDS_GEOP: str = "GEF_DATENVERKEHR_TDS_GEOP"; break;
case GEF_DATENVERKEHR_TGTC_TDS: str = "GEF_DATENVERKEHR_TGTC_TDS"; break;
case GEF_DATENVERKEHR_TDS_TGTC: str = "GEF_DATENVERKEHR_TDS_TGTC"; break;
case GEF_GERAETEEREIGNIS: str = "GEF_GERAETEEREIGNIS"; break;
case GEF_WAFFENZUORDNUNG: str = "GEF_WAFFENZUORDNUNG"; break;
case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: str = "GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE"; break;
case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: str = "GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG"; break;
case GEF_AUSLOESUNG_DUS_TREFFER: str = "GEF_AUSLOESUNG_DUS_TREFFER"; break;
case GEF_ANFORDERUNG_SW_VERSION: str = "GEF_ANFORDERUNG_SW_VERSION"; break;
case GEF_SW_VERSIONSMELDUNG: str = "GEF_SW_VERSIONSMELDUNG"; break;
case GEF_TECHNIK_FUNKTIONSRAUM: str = "GEF_TECHNIK_FUNKTIONSRAUM"; break;
case GEF_TEILNEHMERMODE_SETZEN: str = "GEF_TEILNEHMERMODE_SETZEN"; break;
case GEF_TEILNEHMERMODE_MELDUNG: str = "GEF_TEILNEHMERMODE_MELDUNG"; break;
case GEF_TEILNEHMERMODE_ANFORDERN: str = "GEF_TEILNEHMERMODE_ANFORDERN"; break;
case GEF_TEILNEHMER_KONFIG_ANTWORT: str = "GEF_TEILNEHMER_KONFIG_ANTWORT"; break;
case GEF_TEILNEHMER_KONFIG_SETZEN: str = "GEF_TEILNEHMER_KONFIG_SETZEN"; break;
case GEF_TEILNEHMER_KONFIG_ANFORDERN: str = "GEF_TEILNEHMER_KONFIG_ANFORDERN"; break;
case GEF_SANITAETSDIENST_INSTANDSETZUNG: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG"; break;
case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN"; break;
case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: str = "GEF_BESTANDSMELDUNG_SANITAETSMATERIAL"; break;
case GEF_GEFECHTSFELDTELEGRAMM: str = "GEF_GEFECHTSFELDTELEGRAMM"; break;
}
Q_ASSERT(str);
if (!str)
str = "Unknown";
return str + QByteArray(" (") + QByteArray::number(int(telId)) + ")";
}
QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp)
{
switch(wirkfeldTyp)
{
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea:
return QLatin1String("MINENSPERRE");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea:
return QLatin1String("FLAECHENFEUER");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle:
return QLatin1String("EINZELFEUER");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination:
return QLatin1String("A_KAMPF");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination:
return QLatin1String("C_KAMPF");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea:
return QLatin1String("FUNKTIONS_RAUM");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::TechnicalArea:
return QLatin1String("FUNKTIONS_RAUM_TECHNIK");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::GasPipeDetonation:
return QLatin1String("GAS_PIPE_DETONATION");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::SpecialArea:
return QLatin1String("SPECIAL_AREA");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::Unknown:
return QLatin1String("DUS");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator:
return QLatin1String("DUS_SINGLE_MINE_SIMULATOR");
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::BeStillWarning:
return QLatin1String("BE_STILL_WARNING");
}
return QStringLiteral("Unknown Wirkfeldtyp <%1>").arg(static_cast<int>(wirkfeldTyp));
}
static inline QString wirkfeldTyp2Str(int typ)
{
return wirkfeldTyp2Str(static_cast<TrainingAreaBase::TetraIcd::AreaEffectSimulationType>(typ));
}
void dumpTelegram(NGL::INGLLogger &m_logger, int id, N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const char *prefix)
{
if(!m_logger.isDebugEnabled())
return;
if (!prefix)
prefix = "";
const QByteArray commonLog(prefix + QByteArray("BC: ") + QByteArray::number(id) +
", " + telegramId2String(a_radioTelegram->getTelID()));
switch (a_radioTelegram->getTelID())
{
case GEF_DEAKTIVIERUNG_WIRKFELD:
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER:
{
uint8_t wirkfeldTyp = a_radioTelegram->getPayloadDataUInt32(5, 1);
uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2);
DEBUG_LOG(m_logger) << commonLog
<< ", type: " << wirkfeldTyp2Str(wirkfeldTyp) << ", kennung: "
<< wirkfeldKennung;
break;
}
case GEF_DEAKTIVIERUNG_EINZELMINE: {
uint32_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(9, 2);
uint32_t minenKennung = a_radioTelegram->getPayloadDataUInt32(11, 2);
DEBUG_LOG(m_logger) << commonLog
<< ", kennung: " << wirkfeldKennung << ", mineId: " << minenKennung;
break;
}
case GEF_WIRKFELD_STATUS_MINENSPERRE:
case GEF_WIRKFELD_A_KAMPFMITTEL:
case GEF_WIRKFELD_MINENSPERRE:
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER:
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
case GEF_FUNKTIONSRAUM:
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM:
{
uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
DEBUG_LOG(m_logger) << commonLog << ", kennung: " << wirkfeldKennung;
break;
}
case GEF_TECHNIK_FUNKTIONSRAUM:
{
uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
uint8_t funktionsraumtyp = a_radioTelegram->getPayloadDataUInt32(7, 1);
DEBUG_LOG(m_logger) << commonLog
<< ", kennung: " << funktionsraumkennung
<< " type: " << int(funktionsraumtyp);
break;
}
case GEF_WF_SAMMELDEAKTIVIERUNG:
case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN:
case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM:
DEBUG_LOG(m_logger) << commonLog << ", Ids: " << dumpSammeldeaktivierung(a_radioTelegram);
break;
case GEF_NOP:
{
uint16_t bcFrom = a_radioTelegram->getPayloadDataUInt32(3, 2);
uint16_t bcTo = a_radioTelegram->getPayloadDataUInt32(5, 2);
DEBUG_LOG(m_logger) << prefix
<< commonLog
<< ", from BC " << bcFrom << " to " << bcTo;
break;
}
default:
DEBUG_LOG(m_logger) << commonLog;
break;
}
}
@@ -0,0 +1,32 @@
// **************************************************************************
//
// @RDE_HEADER@
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// Helper to dump the data in hex
// **************************************************************************
#pragma once
#include <QtCore/QString>
#include <NGLLogger/INGLLogger.h>
#include <TrainingAreaBase/training_area_telegrams.h>
#include <CoPrtCnv/coprtcnv_export.h>
#include "tetra_telegram_ids.h"
namespace N_CoPrtCnv
{
class CoPrtCnvRadioTelegram;
}
COPRTCNV_EXPORT QByteArray telegramId2String(gef_telegramm_id_et telId);
COPRTCNV_EXPORT void dumpTelegram(NGL::INGLLogger &m_logger,
int id,
N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram,
const char *prefix = nullptr);
COPRTCNV_EXPORT QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp);
@@ -0,0 +1,64 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <stdint.h>
namespace N_CoPrtCnv
{
/**
* The header used for injection-data
*
* @author alois.wismer
* @version 1.0
* @created 06-Aug-2010 10:27:55
*/
struct CoPrtCnvInjectionHeader
{
/**
* The m_Id1 and m_Id2 are used to detect rubish data.
*/
uint32_t m_Id1;
/**
* The m_Id1 and m_Id2 are used to detect rubish data.
*/
uint32_t m_Id2;
/**
* 0 => unknown
* 1 => central-telegram
* 2 => radio-telegram
* all others: unknown
*/
enum Destination
{
eUnknown = 0,
eCentral = 1,
eRadio = 2
} m_Kind;
/**
* The size of following data
*/
uint16_t m_Size;
CoPrtCnvInjectionHeader()
: m_Id1(0x12345678),
m_Id2(0x78236239),
m_Kind(eUnknown),
m_Size(0)
{}
bool isIdCorrect() const { return (m_Id1 == 0x12345678 && m_Id2 == 0x78236239); }
};
}
+63
View File
@@ -0,0 +1,63 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <stdint.h>
namespace N_CoPrtCnv
{
/**
* @author alois.wismer
* @version 1.0
* @created 12-Mrz-2010 16:07:19
*/
struct CoPrtCnvLogHeader
{
/**
* @author alois.wismer
* @version 1.0
* @created 12-Mrz-2010 16:04:42
*/
enum E_CoPrtCnvProtocol
{
e_DestProtocolCentral = 0,
e_DestProtocolWls = 1,
e_DestProtocolTetra = 5,
e_DestProtocolMax = 6,
e_DestProtocolMask = 0x0000000F,
e_DestDirectionMask = 0xC0000000,
e_DestReceive = 0x40000000,
e_DestSend = 0xC0000000
};
/**
* length of data, including length of this header
*/
short m_Length = 0;
short m_Version = 0;
int m_Priority = 0;
/**
* We do not use E_CoPrtCnvProtocol here, because we want a size of 4 bytes
*/
int m_Protocol = 0;
/**
* needed for correct alignment when compiling on 64-bit systems
*/
int m_Reserved = 0;
/**
* Upper 4 bytes => seconds
* Lower 4 byte => microseconds
*/
uint64_t m_Time = 0;
};
}
File diff suppressed because it is too large. Load diff
+882
View File
@@ -0,0 +1,882 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <set>
#include <map>
#include <memory>
#include <vector>
#include <QByteArray>
#include <CoPrtCnv/coprtcnv_export.h>
#include "tetra_telegram_ids.h"
namespace NGL
{
class INGLLogger;
}
namespace N_CoPrtCnv
{
/**
* used for telegram "LizenzierungTNE" to Radio
*/
enum class E_LicensingKind
{
/**
* Anmeldung erfolgreich
*/
Success = 0,
/**
* Anmeldung abgelehnt
*/
Rejected = 1,
/**
* Abmeldung
*/
Unlicense = 2
};
/**
* used for telegram "LizenzierungTNE" to Radio
*/
enum class E_LicensingErrorCode
{
Ok = 0,
Selftest = 1,
Battery = 2,
Configuration = 3,
Unlicense = 4,
IdentityDenied = 5
};
/**
* The radio-telegram, holds the data of telegram and additiional data for filling
* and sending as braodcast.
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:37:23
*/
class COPRTCNV_EXPORT CoPrtCnvRadioTelegram
{
public:
/**
* The radio-telegram flags
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
enum E_Flags
{
e_FlagsNone = 0x00,
e_StorageAllowed = 0x10,
e_GroupServiceOrOnlyStandardReportAllowed = 0x20,
e_ReceivedConfirmationRequested = 0x40,
e_ConsumedConfirmationRequested = 0x80
};
/**
* The transmission-protocoll to be used for radio-telegram
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
enum E_ProtocolIdentifier
{
e_SimpleTextMessagingWithoutSDS_TL = 0x02,
e_SimpleGPS_WithoutSDS_TL = 0x03,
e_TDSMessageWithoutSDS_TL = 0x50, // 80dec
e_UsingSDS_TL = 0x80,
e_SimpleTextMessagingUsingSDS_TL = 0x82,
e_SimpleGPS_UsingSDS_TL = 0x83,
e_LoginTest = 0x1D
};
/**
* The telegram-type:
* Fragmented, normal or login-telegram.
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
enum E_FragmentStatus
{
e_NotFragmented = 0x00,
e_FirstFragment = 0x40,
e_MiddleFragment = 0xC0,
e_LastFragment = 0x80,
e_FragmentStatusMask = 0xC0,
e_Checksum = 0x20,
e_CounterMask = 0x0F,
e_NormalTelegram = 0x00,
e_LoginTelegram = 0x02,
e_DgpsTelegram = 0x03
};
/**
* The header of a radio-telegram
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
struct PrtCnvRadioGwHeader
{
/**
* The first byte must be the magic number A5
*/
uint8_t m_MagicNumber;
/**
* The telegram-counter
*/
uint8_t m_Counter;
/**
* length of the following message in bytes
*/
uint16_t m_Length;
};
/**
* The PDU-type of radio-telegram
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
enum E_PDU_Type
{
e_RegisterInd = 0,
e_RegisterRsp = 1,
e_DataIndReq = 2,
e_ReportIndReq = 3,
e_StatusIndReq = 4,
e_GroupMonitorReq = 6,
e_AirInterfaceLoadReq = 8,
e_AirLoadHyterra = 19
};
/**
* @author alois.wismer
* @version 1.0
* @created 17-Mrz-2010 13:06:40
*/
enum E_RegistrationStatus
{
e_IssiSuccessfulRegistered = 0,
e_DuplicateISSI = 1,
e_InvalidISSI = 2,
e_InvalidIpAddress = 3
};
/**
* The delivery-status (only for SDS-TL)
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:39:54
*/
enum E_DeliveryStatusForTL_Report
{
e_SDS_ReceiptAcknowledgedByDestination = 0x00,
e_SDS_ConsumedByDestination = 0x02,
e_SourceIsNotAuthorizedForSDS = 0x43,
e_DestinationIsNotAuthorizedForSDS = 0x44,
e_UnknownDestinationAddress = 0x45,
e_DeliveryFailed = 0x4A,
e_DestinationNotRegisteredOnSystem = 0x4B,
e_DestinationQueueFull = 0x4C,
e_MessageTooLong = 0x4D,
e_DestinationHostPC_NotConnected = 0x4F,
e_ProtocolNotSupported = 0x50,
e_DataCodingSchemeNotSupported = 0x51,
e_DestinationNotReachable = 0x5A
};
/**
* The status of the login-telegram
*
* @author wia
* @version 1.0
* @created 12-Mrz-2010 16:41:22
*/
enum E_LoginStatus
{
e_LoginRequest = 0x40,
e_LoginAccept = 0x80,
e_LoginReject = 0xC0,
e_LoginStatusMask = 0xC0,
e_LoginMastering = 0x20,
// Bits 2 & 3
e_LoginNoExerciseAssignment = 0x00, // none set
e_LoginOtherEqId = 0x02, // bit2 set
e_LoginOtherISSI = 0x04, // bit3 set
e_LoginOtherExercise = 0x06, // bit2+3 set
};
/**
* The first byte of the radio-telegram. Must be A5
*/
static constexpr uint8_t MAGIC_NUMBER = 0xA5;
/**
* length of a data-ind/req-telegram-header with TL and without the 4-byte frame-
* header.
* It contains PDUtype, SourceISSI, DestinationISSI, ProtocolIdentifier,
* LengthInBits and LengthInBytes. Payload-status is not included.
*/
static constexpr uint16_t DATA_IND_REQ_WITH_TL_HEADER_LENGTH = 22;
/**
* frameheader (4) + tetra-header (22) + payloadheader (1)
*/
static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH = 27;
/**
* frameheader (4) + tetra-header (22)
*/
static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER = DATA_IND_REQ_HEADER_LENGTH -1;
/**
* length of a data-ind/req-telegram-header without TL and without the 4-byte
* frame-header.
* It contains PDUtype, SourceISSI, DestinationISSI, ProtocolIdentifier,
* LengthInBits and LengthInBytes.
*/
static constexpr uint16_t DATA_IND_REQ_NO_TL_HEADER_LENGTH = 14;
/**
* the maximum length of payload-data (including payload-status-byte) of a radio-
* telegram. If payload-data is larger, fragmentation must be made.
*/
static constexpr uint16_t MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH = 249; // 256: 1 Byte Protokoll-ID + 255 Byte Daten
/**
* frameheader (4) + tetra-header (22) + payloadheader (1)
*/
static constexpr uint16_t PAYLOAD_STATUS_LENGTH = 1;
/**
* The protocol allows a max of 16 fragments, but due to definitions in file
* zsksxdit.x it could be less.
*/
static constexpr uint8_t MAX_NBR_OF_FRAGMENTS = 16;
/**
* constructor for a Register-Ind telegram
*
* @param a_sourceISSI
*/
explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI);
/**
* constructor for a Group-Monitoring-Ind telegram
*
* @param a_sourceISSI
*/
explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const std::set<uint32_t> &groups);
/**
* constructor for a Report-Ind telegram
*
* @param a_sourceISSI
* @param a_delivery
*/
explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const E_DeliveryStatusForTL_Report a_delivery);
/**
* Constructor for received telegrams (Data-Ind/Req, PDU type = 2)
*
* @param a_data
*/
explicit CoPrtCnvRadioTelegram(const QByteArray &a_data);
/**
* the telegraminformation will be set
*
* @param a_telegramId
* @param a_payloadSize inclusive 3 byte telegraminformation
* @param a_identity
*/
explicit CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity);
/**
* for login-telegram
*
* @param a_loginTelegramStatus
* @param a_identity
* @param a_issi
*/
explicit CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi);
// set this issis for a login repsone e_LoginReject | e_LoginOtherExercise
void setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2);
/**
* for generating fragmented telegrams.
* a_error will be true, if the fragmented telegrams cannot be generated.
*
* @param a_bigTelegram
* @param a_fragmentIndex
* @param a_error
*/
explicit CoPrtCnvRadioTelegram(const std::shared_ptr<CoPrtCnvRadioTelegram> &a_bigTelegram,
const uint8_t a_fragmentIndex, bool &a_error);
virtual ~CoPrtCnvRadioTelegram();
/**
* ETS Hack due to +/-1 telegram id on tetra ...
*/
void fixupTelegramIdForEts(bool convertToEtsId);
static void setEtsMode(bool bIsEtsMode);
/**
* Sets the paylaod-data.
*
* @param a_value
* @param a_size
*/
void setPayload1Byte(uint8_t a_value);
void setPayload2Byte(uint16_t a_value);
void setPayload3Byte(uint32_t a_value);
void setPayload4Byte(uint32_t a_value);
void setPayloadData(uint32_t a_value, const uint8_t a_size);
/**
* Sets the paylaod-data.
*
* @param a_value
*/
void setPayloadData(const uint8_t a_value) { return setPayload1Byte(a_value); }
/**
* Sets the paylaod-data.
*
* @param a_data
* @param a_size
*/
void setPayloadData(const uint8_t *a_data, const uint16_t a_size);
/**
* Returns a pointer to data of radio-telegram.
*/
const char *getData() const { return m_data.data(); }
char *getData() { return m_data.data(); }
QByteArray data() const { return m_data; }
/**
* the overall size of telegram, including all headers
*/
int getSize() const { return m_data.size(); }
/**
* Returns the telegramId of radio-telegram.
*/
gef_telegramm_id_et getTelID() const;
/**
* Returns the counter.
*/
uint8_t zaehler() const;
/**
* Sets the counter.
*
* @param a_counter
*/
void setZaehler(const uint8_t a_counter);
/**
* Returns a paylaod-value. Its size depends on a_size.
*
* @param a_offset
* @param a_size
*/
uint32_t getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const;
/**
* Returns a 1-byte paylaod-value.
*
* @param a_offset
*/
uint8_t getPayloadDataUInt8(size_t a_offset) const;
/**
* Returns the destISSI of radio-telegram.
*/
uint32_t getDestISSI() const;
/**
* Returns the identiy of radio-telegram.
*/
uint16_t getIdentity() const;
/**
* Sets the srcISSI.
*
* @param a_ISSI
*/
void setSrcISSI(const uint32_t a_ISSI);
/**
* Returns true if it is broadcast-telegram, which has not yet set a broadcast-
* index.
*/
bool mustBroadcastBeSet() const;
/**
* Sets the broadcast-index.
*
* @param a_broadcastIndex
*/
void setBroadcastIndex(const uint16_t a_broadcastIndex);
/**
* Set the dstISSI.
*
* @param a_ISSI
*/
void setDestISSI(const uint32_t a_ISSI);
/**
* Returns the PDU-type of radio-telegram.
*/
CoPrtCnvRadioTelegram::E_PDU_Type getPDU_Type() const;
/**
* Returns the fragment-status of radio-telegram.
*/
CoPrtCnvRadioTelegram::E_FragmentStatus getFragmentStatus() const;
/**
* Returns the fragment-counter of radio-telegram.
*/
uint8_t getFragmentCounter() const;
/**
* If CRC-bit is set, it checks the CRC and removes CRC-stuff from telegram.
* If CRC-bit is not set, simply true will be returned
*/
bool isCrcOk() const;
/**
* Returns the srcISSI of radio-telegram.
*/
uint32_t getSrcISSI() const;
/**
* returns true if the it is a special login telegram
*/
bool isLoginTelegram() const;
/**
* returns true if the it is a special login telegram
*/
bool mustBeFragmented() const;
/**
* Returns a pointer to payload-data on a certain position of radio-telegram.
*
* @param a_offset
*/
const uint8_t *getPayloadDataPtr(uint16_t a_offset) const;
uint8_t *getPayloadDataPtr(uint16_t a_offset);
/**
* the size of payload-data without payload-status-header
*/
virtual uint16_t getPayloadSize() const;
/**
* Converts the list of fragmented telegrams into 1 big radio-telegram.
* The function allocates a block of data. The caller is responsible to delete
* this block of data, when no longer used.
* If conversion fails NULL will be returned
*
* @param a_fragTelegramList
*/
static QByteArray getUnfragmentedData(const std::multimap<uint16_t, CoPrtCnvRadioTelegram *> &a_fragTelegramList);
/**
* length without frame-header (4 byte)
*
* @param a_lengthWithoutFrame
*/
static bool isTelegramLengthOk(const uint16_t a_lengthWithoutFrame);
/**
* returns true if the it is a normal, unfragmented telegram (but not a login-
* telegram)
*/
bool isNormalTelegram() const;
/**
* Returns the priority of radio-telegram.
*/
uint8_t getPriority() const;
/**
* Returns the broadcast-index of radio-telegram.
*/
uint16_t getBroadcastIndex() const;
/**
* Sets the paylaod-data based on a_index with size a_size.
*
* @param a_index the payload-based position where the byte should be written
* @param a_value
* @param a_size
*/
void setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size);
/**
* Sets the complete paylaod-data.
*
* @param a_data
* @param a_length
*/
void setPayloadDataComplete(const QByteArray &payload);
/**
* ATTENTION with use of this function, because it is a (little) dirty trick to
* resize the sammel-telegrams without memory-allocation.
* It is the responsibity of the user to not overwrite memory!!!
*
* @param a_newPayloadSize
*/
void resetPayloadSize(const uint16_t a_newPayloadSize);
/**
* Set the identity.
*
* @param a_identity
*/
void setIdentity(const uint16_t a_identity);
/**
* Sets the protocol-identifier.
*
* @param a_ProtocolIdentifier
*/
void setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier);
/**
* Sets the message-reference.
*
* @param a_MessageReference
*/
void setMessageReference(const uint8_t a_MessageReference);
/**
* returns true if the it is a SDS/TL telegram
*/
bool isSDSTL() const;
/**
* Returns the registration-status of TETRA-header of SdsGw-Register-Rsp telegram
*/
CoPrtCnvRadioTelegram::E_RegistrationStatus getRegistrationStatus() const;
/**
* Returns the registration-status of TETRA-header of SdsGw-Register-Rsp telegram
* in text-form
*/
std::string getRegistrationStatusAsText() const;
/**
* Returns the protocolIdentifier of radio-telegram.
*/
CoPrtCnvRadioTelegram::E_ProtocolIdentifier getProtocolIdentifier() const;
/**
* Returns the protocolIdentifier of radio-telegram in text-form
*/
std::string getProtocolIdentifierAsText() const;
/**
* Returns the message-reference of radio-telegram.
*/
uint8_t getMessageReference() const;
/**
* Returns the area selection of TETRA-Header
*/
uint8_t getAreaSelection() const;
/**
* Returns the validity period of radio-telegram.
*/
uint8_t getValidityPeriod() const;
/**
* Returns the forward-address of TETRA-Header
*/
uint32_t getForwardAddress() const;
/**
* Returns the flags of TETRA-Header
*/
CoPrtCnvRadioTelegram::E_Flags getFlags() const;
/**
* Returns the flags of TETRA-Header as text
*/
std::string getFlagsAsText() const;
/**
* Returns the length in bits-field of TETRA-Header
*/
uint16_t getLengthInBits() const;
/**
* Returns the length in bytes-field of TETRA-Header
*/
uint16_t getLengthInBytes() const;
/**
* Returns true when the Telegram has a crc checksum.
*/
bool getWithCrc() const;
/**
* Returns the delivery-field of TETRA-Header of SdsGw-Report-Ind/Req telegrams.
*/
CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report getDelivery() const;
/**
* Returns the delivery-field of TETRA-Header of SdsGw-Report-Ind/Req telegrams as
* text.
*/
std::string getDeliveryAsText() const;
/**
* Converts a signed 3-byte value into a signed 4-byte-value. I.e. used for
* positions (north and east).
*
* @param a_offset
*/
int32_t getPayloadDataSInt24(uint16_t a_offset) const;
/**
* Returns true if the telegram needs licensing.
*/
bool needsLicensing() const;
/**
* returns true when the telegram has an expiry-date and is expired.
* Returns false if the telegram has no expiry-date
*/
bool hasExpired() const;
/**
* Returns the expire-time of the telegram.
* Returns 0 if the telegram has not expire-time.
*/
uint32_t getExpireTime() const;
/**
* checks whether the content of telegram is valid, but only a few data will be
* checked, i.e. the kennung of wirkfeld and funktionsraum.
* Returns true if content of telegram is vaild (or will not be checked)
*/
bool isContentValid();
/**
* returns true if it is time to send this telegram as normal broadcast.
*
* @param a_currentTime
* @param a_wasLastBroadcast
* @param a_updateBroadcastCounter
*/
bool mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter = true);
/**
* Set the delay-times for 2nd and 3rd broadcast.
*
* @param a_2ndDelay
* @param a_3rdDelay
*/
static void setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay);
/**
* Set the max count of how often a Broadcasttelegram will be send (0 is ignored, the telegram is send at least one time.
*
* @brief setMaxBroadcastSendCnt
* @param a_maxSendCnt
*/
static void setMaxBroadcastSendCnt(int a_maxSendCnt);
/**
* returns true if it is a broadcast-telegram and it is moved to broadcast-list
*/
bool isMovedToBroadcastList() const;
/**
* Sets the broadcast-only-flag.
*
* @param a_doSet
*/
void setBroadcastOnly(const bool a_doSet = true);
/**
* Returns the broadcast-only-flag.
*/
bool isBroadcastOnly() const;
/**
* Defines the telegram which will be sent as normal broadcast instead a
* Sammeltelegram.
*
* @param a_radioTelegram
*/
void setBroadcastonlyTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram);
/**
* Returns the telegram which will be sent as normal broadcast instead a
* Sammeltelegram.
*/
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> getBroadcastonlyTelegram() const;
/**
* nbr of times already sent this normal broadcast (only used for broadcast-
* telegrams)
*/
uint16_t getBroadcastCounter() const;
//begin_public_{ACFD8558-E5A4-4877-B503-41FCB730B678}
//end_public_{ACFD8558-E5A4-4877-B503-41FCB730B678}
protected:
/**
* The telegram-data, including header
*/
QByteArray m_data;
/**
* The internal index for filling telegram with setPayloadData()
*/
uint16_t m_PayloadIndex;
/**
* nbr of times already sent this normal broadcast (only used for broadcast-
* telegrams)
*/
uint16_t m_BroadcastCounter;
/**
* time when sending next normal broadcast (only used for broadcast-telegrams)
*/
time_t m_NextSendTime;
/**
* The delay between 1st and 2nd normal broadcast
*/
static int s_2ndDelay;
/**
* The delay between 2nd and 3rd normal broadcast
*/
static int s_3rdDelay;
/**
* The delay between 2nd and 3rd normal broadcast
*/
static int s_maxBroadcastSendCnt;
/**
* True if the telegram is used only as normal broadcast, not as nachforderung
*/
bool m_IsBroadcastOnly;
/**
* Contains the normal broadcast-telegram, which will be sent instead of
* sammeltelegram for Nachfoderung
*/
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> m_BroadcastOnlyTelegram;
/**
* For ETS - there al telgram ids are +1, therefore we have to remove 1 to be able
* to work with our ids.
*/
static bool s_etsMode;
/**
* checks the payload-length of telegram. Returns true if the length is ok.
* Logs an error if length not ok.
*/
bool isPayloadLengthOk(uint16_t a_minLength,
const uint16_t a_dataAmountOffset,
const uint8_t a_variableDataElementSize) const;
bool isPayloadLengthOk(uint16_t a_minLength,
uint16_t a_maxLength) const;
bool isPayloadLengthOk(uint16_t a_length) const;
bool isPayloadLengthOk(const std::vector<uint16_t> &a_lengths) const;
/**
* Set a 1-byte value at offset a_offset.
*/
static void set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value);
/**
* Set a 2-byte value at offset a_offset.
*/
static void set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value);
/**
* Set a 4-byte value at offset a_offset.
*/
static void set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value);
uint8_t getUInt8(const uint16_t a_offset) const { return static_cast<uint8_t>(m_data.at(a_offset)); }
uint16_t getUInt16(const uint16_t a_offset) const;
uint32_t getUInt32(const uint16_t a_offset) const;
/**
* Sets the header with magic-number and size. The length will be 0.
*
* @param a_data
* @param a_size The overall-size including all headers
*/
static void setHeader(QByteArray &data, E_PDU_Type pduType);
/**
* Fills the header with SrcISSI, DstISSI, length in bits and length in bytes. PDU
* will be set for DataIndicationRequest.
* ProtocolIdentifier, message reference, area selection, forward address, flags
* will be filled with default-values.
*
* @param a_data
*/
static void fillDataIndReqHeader(QByteArray &a_data);
/**
* Internal function to set the srcISSI.
*
* @param a_data
* @param a_ISSI
*/
static void setSrcISSI_Internal(QByteArray &data, const uint32_t issi);
/**
* Internal function to set the dstISSI.
*
* @param a_data
* @param a_ISSI
*/
static void setDestISSI_Internal(QByteArray &data, const uint32_t issi);
private:
/**
* The logger object
*/
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,72 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <CoPrtCnv/coprtcnv_export.h>
namespace TrainingAreaBase
{
namespace TetraIcd
{
struct TrainingAreaTelegram;
}
}
namespace N_CoPrtCnv
{
class CoPrtCnvRadioTelegram;
class CoPrtCnvCentralTelegram;
/**
* This class is responsible to convert radio-telegrams into central-telegrams and
* vice versa.
* @author alois.wismer
* @version 1.0
* @created 19-Mrz-2010 13:32:40
*/
namespace CoPrtCnvTelegramConverter
{
/**
* Converts central-telegrams to radio-telegrams.
* Returns NULL if conversion was failed.
*
* @param a_telegram
*/
COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(CoPrtCnvCentralTelegram *a_telegram);
COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *a_telegram);
/**
* converts a radiotelegram into a central.
* returns nullptr if conversion failed
*
* @param a_radioTelegram
*/
COPRTCNV_EXPORT CoPrtCnvCentralTelegram *convertToCentral(const CoPrtCnvRadioTelegram *a_radioTelegram);
COPRTCNV_EXPORT TrainingAreaBase::TetraIcd::TrainingAreaTelegram *convertToTabTele(const CoPrtCnvRadioTelegram *a_radioTelegram);
/**
* Set the text codec to use for string send to/received from tetra
*/
COPRTCNV_EXPORT void setTetraTextCodec(const char *codecName);
/**
* Set to trueif single fire (WIRKFELD_EINZELGESCHOSS) has two bytes for diameter, otherwise only one byte is used
*/
COPRTCNV_EXPORT void setUse2BytesForSingleFireDiameter(bool bUse);
COPRTCNV_EXPORT void setUsePvSan(bool bUse);
}
}
File diff suppressed because it is too large. Load diff
+121
View File
@@ -0,0 +1,121 @@
/**
* Telegram IDs used in ICD52
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-11-14
*/
#pragma once
enum gef_telegramm_id_et
{
GEF_BESTAETIGUNG = 0,
GEF_INIT = 1,
GEF_MANIPULATIONSMELDUNG = 2,
GEF_UMGEBUNGS_MELDUNG2 = 203,
GEF_AUFFORDERUNG_BITE_MELDUNG = 4,
GEF_BITE_MELDUNG2 = 205,
GEF_LIZENSIERUNG_TNE = 6,
GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7,
GEF_KONFIGURATION_WIRKMODELL = 9,
GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10,
GEF_KONFIGURATIONSMELDUNG = 11,
GEF_FEHLERMELDUNG_GFD = 12,
GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT = 13,
GEF_POSITIONS_MELDUNG = 21,
GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22,
GEF_POSITIONS_MELDUNG_LFZ = 23,
GEF_IPS_POSITIONSDATEN = 201,
GEF_SCHIEDSRICHTERKOMMANDO = 25,
GEF_WIRKFELD_EINZELGESCHOSS = 31,
GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32,
GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33,
GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34,
GEF_WIRKFELD_MINENSPERRE = 35,
GEF_WIRKFELD_STATUS_MINENSPERRE = 36,
GEF_WIRKFELD_A_KAMPFMITTEL = 37,
GEF_WIRKFELD_C_KAMPFMITTEL = 38,
GEF_DEAKTIVIERUNG_WIRKFELD = 39,
GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40,
GEF_DEAKTIVIERUNG_EINZELMINE = 41,
GEF_REAKTIVIERUNG_DUS_MINE = 42,
GEF_DEFINITION_IED = 43,
GEF_ZUSTAND_IED = 44,
GEF_STATUS_EINZELMINENSIMULATOR = 45,
GEF_WIRKFELD_EINZELMINENSIMULATOR = 46,
GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56,
GEF_TREFFER_EREIGNIS_DUS = 52,
GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53,
GEF_TREFFER_AUSLOESUNG = 54,
GEF_SCHIEDSRICHTEREINGRIFF = 55,
GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218,
GEF_TREFFER_EREIGNIS_DUS_IPS = 228,
GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229,
GEF_TAKTISCHER_STATUS = 61,
GEF_FUNKTIONSRAUM = 62,
GEF_EINTRETEN_FUNKTIONSRAUM = 63,
GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64,
GEF_DATENVERKEHR_SRT_TDS = 71,
GEF_DATENVERKEHR_TDS_SRT = 72,
GEF_DATENVERKEHR_DMF_TDS = 73,
GEF_DATENVERKEHR_TDS_DMF = 74,
GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82,
GEF_NOP = 83,
GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91,
GEF_SONDERSENSORIK_FAHRSPUR = 92,
GEF_SONDERSENSORIK_DATEN = 93,
GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95,
GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96,
GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97,
GEF_SPRACHAUSWAHL = 101,
GEF_ALLGEMEINE_NACHRICHT = 102,
GEF_ECHO_ON_OFF = 103,
GEF_ESW_MELDUNG = 104,
GEF_WF_SAMMELDEAKTIVIERUNG = 105,
GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106,
GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107,
GEF_DATENVERKEHR_GEOP_TDS = 181,
GEF_DATENVERKEHR_TDS_GEOP = 182,
GEF_DATENVERKEHR_TGTC_TDS = 183,
GEF_DATENVERKEHR_TDS_TGTC = 184,
GEF_GERAETEEREIGNIS = 185,
GEF_WAFFENZUORDNUNG = 200,
GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202,
GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210,
GEF_AUSLOESUNG_DUS_TREFFER = 211,
GEF_ANFORDERUNG_SW_VERSION = 212,
GEF_SW_VERSIONSMELDUNG = 213,
GEF_TECHNIK_FUNKTIONSRAUM = 219,
GEF_TEILNEHMERMODE_SETZEN = 230,
GEF_TEILNEHMERMODE_MELDUNG = 231,
GEF_TEILNEHMERMODE_ANFORDERN = 232,
GEF_TEILNEHMER_KONFIG_ANTWORT = 233,
GEF_TEILNEHMER_KONFIG_SETZEN = 234,
GEF_TEILNEHMER_KONFIG_ANFORDERN = 235,
GEF_SANITAETSDIENST_INSTANDSETZUNG = 240,
GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241,
GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242,
GEF_LASER_TARGET_DESIGNATOR_UPDATE = 214,
GEF_GEFECHTSFELDTELEGRAMM = 300
};
+104
View File
@@ -0,0 +1,104 @@
#
# $Id$
# $HeadURL$
# $Author$
#
ADD_SUBDIRECTORY(Console)
SET(my_SRCS
IntegerCalculator.cpp
IntegerCalculator.hpp
logger.cpp
logger.h
LogViewBooleanEdit.cpp
LogViewBooleanEdit.hpp
LogViewDateTimeEdit.cpp
LogViewDateTimeEdit.hpp
LogViewEnumEdit.cpp
LogViewEnumEdit.hpp
LogViewField.cpp
LogViewField.hpp
LogViewGui.cpp
LogViewGui.hpp
LogViewInjectionThread.cpp
LogViewInjectionThread.hpp
LogViewMain.cpp
LogViewModels.cpp
LogViewModels.hpp
LogViewOptionDialog.cpp
LogViewOptionDialog.hpp
LogViewSpinBox.cpp
LogViewSpinBox.hpp
LogViewTableWidget.cpp
LogViewTableWidget.hpp
LogViewTabWidget.cpp
LogViewTabWidget.hpp
LogViewTelegram.cpp
LogViewTelegramDialog.cpp
LogViewTelegramDialog.hpp
LogViewTelegramEdit.cpp
LogViewTelegramEdit.hpp
LogViewTelegramEditModel.cpp
LogViewTelegramEditModel.hpp
LogViewTelegram.hpp
LogViewTelegramSelectionDialog.cpp
LogViewTelegramSelectionDialog.hpp
LogViewTetraTelegramsParser.cpp
LogViewTetraTelegramsParser.hpp
LogViewTextEdit.cpp
LogViewTextEdit.hpp
LogViewValueEdit.cpp
LogViewValueEdit.hpp
LogViewWidget.cpp
LogViewWidget.hpp
LogViewXdrElement.cpp
LogViewXdrElement.hpp
LogViewXdrParser.cpp
LogViewXdrParser.hpp
LogViewXdrStandardType.cpp
LogViewXdrStandardType.hpp
LogViewXdrStruct.cpp
LogViewXdrStruct.hpp
LogViewXdrType.cpp
LogViewXdrType.hpp
LogViewXdrValue.cpp
LogViewXdrValue.hpp
zsksxd_tetraForLogView.x
)
QT5_ADD_RESOURCES(my_SRCS LogViewResources.qrc)
NGL_ADD_TOOL_ICON(my_SRCS)
NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION LogView ${my_SRCS})
NGL_TARGET_LINK_LIBRARIES(LogView
Qt5::Core
Qt5::Gui
Qt5::Network
CoPrtCnv
nglwidgets
NGLLogger
nglapplication
ngltools
)
NGL_INSTALL_TARGET(LogView)
NGL_INSTALL(AAR SV FILES LogView_log4cxx.props DESTINATION bin)
# install on RPM build and copy for local builds so that LogView automatically finds the zsksxd_tetraForLogView.x file
if (BUILD_RPM)
add_custom_target(zsksxd_tetraForLogView.x_bin) # empty target so that LogView still builds on RPM build
NGL_INSTALL(AAR SV FILES zsksxd_tetraForLogView.x DESTINATION bin)
else()
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x
COMMENT "[Local build] Copy zsksxd_tetraForLogView.x for LogView into bin/"
)
add_custom_target(zsksxd_tetraForLogView.x_bin DEPENDS ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x)
endif()
if (TARGET LogView)
add_dependencies(LogView zsksxd_tetraForLogView.x_bin training_area_telegrams.h_bin)
endif()
+17
View File
@@ -0,0 +1,17 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(console_SRCS
main.cpp
)
NGL_ADD_TOOL_ICON(console_SRCS)
NGL_ADD_EXECUTABLE(AAR SV LogView_console ${console_SRCS})
NGL_INSTALL_TARGET(LogView_console)
NGL_TARGET_LINK_LIBRARIES(LogView_console
CoPrtCnv
NGLLogger
)
+204
View File
@@ -0,0 +1,204 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include <QCoreApplication>
#include <QStringList>
#include <QFile>
#include <QByteArray>
#include <QDateTime>
#include <QBuffer>
#include <QSet>
#include <CoPrtCnv/CoPrtCnvLogHeader.hpp>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <TrainingAreaBase/training_area_telegrams.h>
static QSet<int> s_eqIds;
template <typename T>
bool validEqId(const T &tele)
{
if (!s_eqIds.isEmpty() && !s_eqIds.contains(tele.header.equipmentNumber))
return false;
return true;
}
QByteArray formatTime(quint64 t)
{
const quint64 secs = t >> 32;
const quint64 usecs = t & 0xFFFFFFFF;
const quint64 msecs = usecs / 1000;
return QDateTime::fromMSecsSinceEpoch(secs * 1000 + msecs).toString(QLatin1String("yy-MM-dd hh:mm:ss.zzz")).toUtf8();
}
int main(int argc, char **argv)
{
using namespace TrainingAreaBase::TetraIcd;
QCoreApplication app(argc, argv);
// Check alle 30 Sekunden
NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false);
NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger());
if (app.arguments().count() < 3)
{
ERROR_LOG(logger) << "Usage: " << app.arguments().at(0)
<< " <logfile> <telId> <equipId>";
return 1;
}
QFile telegramFile(app.arguments().at(1));
if (!telegramFile.open(QIODevice::ReadOnly))
{
ERROR_LOG(logger) << "Error opening " << telegramFile.fileName()
<< " for reading: " << telegramFile.errorString();
return 2;
}
bool bOk;
int telIdToSearch = app.arguments().at(2).toUShort(&bOk);
if (!bOk)
{
ERROR_LOG(logger) << "Error reading telId - not a (valid) number: "
<< app.arguments().at(2);
return 3;
}
s_eqIds.clear();
for (int i = 3; i < app.arguments().size(); ++i)
{
int eqId = app.arguments().at(i).toUShort(&bOk);
if (!bOk)
{
ERROR_LOG(logger) << "Error reading equipId - not a (valid) number: "
<< app.arguments().at(i);
return 4;
}
s_eqIds += eqId;
}
//fprintf(stdout, "Counter;EqID;TelID;TelTime;LogTime;Diff\n");
while (true)
{
// read the header of telegram-entry
N_CoPrtCnv::CoPrtCnvLogHeader lh;
if (sizeof(lh) == telegramFile.read((char *)&lh, sizeof(lh)))
{
if (lh.m_Version == 3)
{
// read the telegram itself
qint64 telegramLength = lh.m_Length - sizeof(lh);
QByteArray telegramData(telegramLength, Qt::Uninitialized);
if (telegramLength == telegramFile.read(telegramData.data(), telegramLength))
{
// add the telegram to telegram-list
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol dest = (N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol)
(lh.m_Protocol & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask);
switch (dest)
{
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral:
{
const QJsonObject obj = QJsonDocument::fromJson(telegramData).object();
int telId = obj.value(QStringLiteral("typeId")).toInt();
if (telIdToSearch != telId)
continue;
const QJsonObject objData = obj.value(QStringLiteral("data")).toObject();
const QByteArray tBA = formatTime(lh.m_Time);
const char *timeStr = tBA.constData();
switch (telId)
{
case Constraints<CreateFunctionalArea>::id():
{
const CreateFunctionalArea tele(CreateFunctionalArea::fromJson(objData));
if (!validEqId(tele))
break;
fprintf(stdout, "%s, FUNKTIONSRAUM: '%s', %d, %d\n",
timeStr,
tele.name.c_str(),
tele.aesDdsId,
tele.header.equipmentNumber
);
break;
}
case Constraints<DeactivateEffectSimulation>::id():
{
const DeactivateEffectSimulation tele(DeactivateEffectSimulation::fromJson(objData));
fprintf(stdout, "%s, DEAKTIVIERUNG_WIRKFELD: typ: %d - kennung: %d\n",
timeStr,
int(tele.aesType),
tele.aesDdsId
);
break;
}
case Constraints<PositionReport>::id():
{
const PositionReport tele(PositionReport::fromJson(objData));
if (!validEqId(tele))
break;
if (tele.opsPosition.opsId == 0)
break;
fprintf(stdout, "%s, IPS_POSITIONSDATEN: %d - OPS: %d\n",
timeStr,
tele.header.equipmentNumber,
tele.opsPosition.opsId
);
break;
}
case BESTAETIGUNG:
case UMGEBUNGS_MELDUNG2:
break;
default:
fprintf(stderr, "Printing telegram with id %d not implemented\n", telId);
break;
}
break;
}
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra:
{
N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(telegramData);
gef_telegramm_id_et telId = radioTelegram.getTelID();
if (telId == GEF_UMGEBUNGS_MELDUNG2)
{
const QByteArray tBA = formatTime(lh.m_Time);
const char *timeStr = tBA.constData();
static uint16_t bci = 0xFFFF;
if (bci != radioTelegram.getBroadcastIndex())
{
if (bci > radioTelegram.getBroadcastIndex() && bci != 0xFFFF)
{
fprintf(stdout, "BCI reset in %s at %s!\n",
qPrintable(telegramFile.fileName()),
timeStr);
}
fprintf(stdout, "BCI: %d\n", radioTelegram.getBroadcastIndex());
bci = radioTelegram.getBroadcastIndex();
}
}
break;
}
default:
break;
}
}
}
else
{
ERROR_LOG(logger) << "Wrong LogHeader version: " << lh.m_Version;
return 4;
}
}
else
break;
}
return 0;
}
+497
View File
@@ -0,0 +1,497 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "IntegerCalculator.hpp"
#include <sstream>
#include <iomanip>
namespace N_SST
{
IntegerCalculator::IntegerCalculator()
: m_OperationList({{"*", 6},{"/", 6},{"%", 6},{"+", 5},{"-", 5},{"<<", 4},{">>", 4}})
, m_AdditionalErrorText()
, m_ParanthesisCount(0)
, m_Error(IntegerCalculator::e_Ok)
{
}
// ---------------------------------------------------------------
// Converts the expressen in a_calcText into a signed value.
// Returns whether an error happend in the variable a_error.
// If an error happend, the variable a_addErrorText can
// contain more informaition about the error (see E_Error for
// more information about errors).
// ---------------------------------------------------------------
int64_t IntegerCalculator::calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText)
{
std::string calcText = a_calcText;
// separate operations from variables
for (auto iter = m_OperationList.begin(); iter != m_OperationList.end(); ++iter)
replace(calcText, iter->first, " "+iter->first+" ");
// separate paranthesis from variables
replace(calcText, "(", " ( ");
replace(calcText, ")", " ) ");
// now calculate the expression
m_ParanthesisCount = 0;
m_Error = e_Ok;
m_AdditionalErrorText = "";
size_t pos = 0;
bool dummy;
int64_t value = calc(calcText, pos, dummy, "", 0, "+"); // todo: use member-variable m_CalcText
//M_INFO("calc: " << calcText << " value: " << value);
// check the paranthesis
if (m_Error == e_Ok)
{
if (m_ParanthesisCount > 0)
{
m_Error = e_MissingRightParanthesis;
}
else if (m_ParanthesisCount < 0)
{
m_Error = e_MissingLeftParanthesis;
}
else if (pos != calcText.length())
{
m_Error = e_UnknownError;
}
}
// actions if a failure happens
a_error = m_Error;
if (a_error != e_Ok)
{
value = 0;
if (a_addErrorText)
{
*a_addErrorText = m_AdditionalErrorText;
}
}
return value;
}
// ---------------------------------------------------------------
// Adds or changes a case-sensitive variable to the calculator.
// ---------------------------------------------------------------
void IntegerCalculator::addVariable(const std::string& a_name, const int64_t a_value)
{
std::map<std::string, int64_t>::iterator iter = m_VariableList.find(a_name);
if (iter != m_VariableList.end())
removeVariable(a_name);
m_VariableList.insert(std::make_pair(a_name, a_value));
}
// ---------------------------------------------------------------
// Removes a case-sensitive variable from the calculator.
// ---------------------------------------------------------------
void IntegerCalculator::removeVariable(const std::string& a_name)
{
std::map<std::string, int64_t>::iterator iter = m_VariableList.find(a_name);
if (iter != m_VariableList.end())
m_VariableList.erase(iter);
}
// ---------------------------------------------------------------
// Calculates the expression (recursive)
// ---------------------------------------------------------------
int64_t IntegerCalculator::calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis,
const std::string& a_prevOp, const int64_t a_prevValue,
const std::string& a_initOp)
{
std::string operation = a_initOp;
int64_t value1 = a_prevValue;
bool isNegative = false;
std::string calcText = a_calcText;
a_IsEndParanthesis = false;
while (a_pos < calcText.length())
{
if (' ' == calcText[a_pos])
{
a_pos++;
}
else if ('(' == calcText[a_pos])
{
m_ParanthesisCount++;
bool dummy;
int64_t value2 = calcSign(calc(calcText, ++a_pos, dummy), isNegative);
value1 = doOperation(value1, operation, value2);
// get next operation to check priority of operation
size_t tmpPos = a_pos; // do not change the position, we only pre-read
std::string nextOp = getToken(a_calcText, tmpPos);
if (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp))
{
// end of higher priority operation
return value1;
}
operation = "";
}
else if (')' == calcText[a_pos])
{
m_ParanthesisCount--;
a_pos++;
a_IsEndParanthesis = true;
return value1;
}
else if (isDigit(calcText[a_pos]))
{
// value
// -----
int64_t value2 = calcSign(convertValue(calcText, a_pos), isNegative);
if (calcWithPriority(calcText, a_pos, value1, operation, value2, a_prevOp)) return value1;
}
else
{
// operation or variable
// ---------------------
std::string oldOperation = operation;
operation = getToken(calcText, a_pos);
// is it a variable?
if (!isOperation(operation))
{
int64_t value2 = 0;
if (getVariableValue(operation, value2))
{
value2 = calcSign(value2, isNegative);
if (calcWithPriority(calcText, a_pos, value1, oldOperation, value2, a_prevOp)) return value1;
operation = "";
}
else
{
// error
m_Error = e_UnknownOperationOrVariable;
m_AdditionalErrorText = operation;
}
}
else
{
// do we have a sign?
if (oldOperation != "")
{
if (operation == "+")
{
operation = oldOperation;
}
else if (operation == "-")
{
isNegative = !isNegative;
operation = oldOperation;
}
else
{
m_Error = e_NoOperandBetweenOperators;
m_AdditionalErrorText = oldOperation + " " + operation;
return 0;
}
}
}
}
}
return value1;
}
// ---------------------------------------------------------------
// Calculates an operation with respecting the priority of
// operations. This will be done with recursion.
// ---------------------------------------------------------------
bool IntegerCalculator::calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, std::string& a_operation, int64_t a_value2, const std::string& a_prevOp)
{
bool isParaEnd = false;
// get next operation to check priority of operation
size_t tmpPos = a_pos; // only pre-read
std::string nextOp = getToken(a_calcText, tmpPos);
if (isOperation(a_operation) && isOperation(nextOp) && isOperationPriorityHigher(nextOp, a_operation))
{
// next operation has higher priority => calc the next operation first
a_value2 = calc(a_calcText, a_pos, isParaEnd, a_operation, a_value2);
}
a_value1 = doOperation(a_value1, a_operation, a_value2);
if (isParaEnd || (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp)))
{
// end of higher priority operation
return true;
}
a_operation = "";
return false;
}
// ---------------------------------------------------------------
// Returns the inverted a_value if a_isNegative is true.
// a_isNegative will be false after calling this function.
// If a_isNegative is true, the NOT inverted a_value will be
// returned.
// ---------------------------------------------------------------
int64_t IntegerCalculator::calcSign(const int64_t a_value, bool& a_isNegative)
{
if (a_isNegative)
{
a_isNegative = false;
return -a_value;
}
return a_value;
}
// ---------------------------------------------------------------
// Converts the value in form of text to a number. The Text
// can be decimal, hex (0x) or binary (0b).
// ---------------------------------------------------------------
int64_t IntegerCalculator::convertValue(const std::string &a_valueText, size_t& a_pos)
{
std::string valueText = a_valueText.substr(a_pos);
int base = 10;
size_t startpos = 0;
// hex- and binary-stuff
bool isHex = (0 == valueText.find("0X")) || (0 == valueText.find("0x"));
bool isBin = (0 == valueText.find("0B")) || (0 == valueText.find("0b"));
if (isHex)
{
base = 16;
startpos = 2;
}
else if (isBin)
{
base = 2;
startpos = 2;
}
// search end of value
size_t i;
for (i=startpos; i<valueText.length(); i++)
{
if (!isDigit(valueText[i], isHex, isBin))
{
break;
}
}
// check the next char, it must be a space
if (valueText.length() > i && valueText[i] != ' ')
{
m_Error = e_InvalidOperand;
int spacePos = valueText.find(' ');
m_AdditionalErrorText = valueText.substr(0, spacePos);
}
a_pos += i;
int64_t value = 0;
std::stringstream stream;
stream.str(valueText.substr(startpos, i-startpos));
if (2 == base)
{
// our stl is not able to read in binary-values, therefore we have to implement it ourself
const std::string binValueAsText = stream.str();
for (const char c : binValueAsText)
{
value = value << 1;
if (c == '1')
value += 1;
}
}
else
{
stream << std::setbase(base);
stream >> value;
}
return value;
}
// ---------------------------------------------------------------
// Returns the next token (with space as separator). Heading
// spaces will be ignored.
// ---------------------------------------------------------------
std::string IntegerCalculator::getToken(const std::string &a_calcText, size_t& a_pos)
{
// skip spaces at begin
while (a_pos < a_calcText.length())
{
if (a_calcText[a_pos] == ' ') a_pos++;
else break;
}
// search until next space (or end)
size_t startPos = a_pos;
while (a_pos < a_calcText.length())
{
if (' ' == a_calcText[a_pos]) break;
a_pos++;
}
return a_calcText.substr(startPos, a_pos-startPos);
}
// ---------------------------------------------------------------
// returns true if a_operation is a known operation.
// ---------------------------------------------------------------
bool IntegerCalculator::isOperation(const std::string& a_operation) const
{
std::map<std::string, int>::const_iterator iter = m_OperationList.find(a_operation);
return (iter != m_OperationList.end());
}
// ---------------------------------------------------------------
// Calculates the opeation a_operations with a_value1 as first
// and a_value2 as second operand.
// ---------------------------------------------------------------
int64_t IntegerCalculator::doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2)
{
// M_INFO("" << a_value1 << " " << a_operation << " " << a_value2);
if (("+" == a_operation) || a_operation.empty())
{
return a_value1 + a_value2;
}
else if ("-" == a_operation)
{
return a_value1 - a_value2;
}
else if ("*" == a_operation)
{
return a_value1 * a_value2;
}
else if ("/" == a_operation)
{
if (0 == a_value2)
{
m_Error = e_DivisionByZero;
}
else
{
return a_value1 / a_value2;
}
}
else if ("%" == a_operation)
{
if (0 == a_value2)
{
m_Error = e_DivisionByZero;
}
else
{
return a_value1 % a_value2;
}
}
else if ("<<" == a_operation)
{
return a_value1 << a_value2;
}
else if (">>" == a_operation)
{
return a_value1 >> a_value2;
}
else
{
m_Error = e_UnknownOperationOrVariable;
m_AdditionalErrorText = a_operation;
}
return 0;
}
// ---------------------------------------------------------------
// returns true if priority of a_opeation1 is higher than
// priority of a_operation2.
// ---------------------------------------------------------------
bool IntegerCalculator::isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const
{
return (getPriority(a_operation1) > getPriority(a_operation2));
}
// ---------------------------------------------------------------
// Returns true if the variable named a_variableName is known
// and a_value will be filled with its value. If the variable
// is not found false will be returned.
// Overload this virtual function if you want to implement
// your own variable-list.
// ---------------------------------------------------------------
bool IntegerCalculator::getVariableValue(const std::string& a_variableName, int64_t& a_value) const
{
auto iter = m_VariableList.find(a_variableName);
if (iter != m_VariableList.end())
{
a_value = iter->second;
return true;
}
// error
return false;
}
// ---------------------------------------------------------------
// Returns true if a_char is a digit. When a_isHex is true,
// also the charactes a-f will be accepted as digits. When
// a_isBin is true, only 0 and 1 will be treated as digit.
// ---------------------------------------------------------------
bool IntegerCalculator::isDigit(const char a_char, const bool a_isHex, const bool a_isBin)
{
if (a_isHex)
{
// for hex-values also A..F are 'digits'
return (a_char >= '0' && a_char <= '9') || (a_char >= 'A' && a_char <= 'F') || (a_char >= 'a' && a_char <= 'f');
}
else if (a_isBin)
{
// for binary-values only 0 and 1 are allowed
return (a_char >= '0' && a_char <= '1');
}
// normal digits
return (a_char >= '0' && a_char <= '9');
}
// ---------------------------------------------------------------
// Returns the priority of the operation. A higher value means
// more priority.
// ---------------------------------------------------------------
int16_t IntegerCalculator::getPriority(const std::string& a_operation) const
{
std::map<std::string, int>::const_iterator iter = m_OperationList.find(a_operation);
if (iter != m_OperationList.end())
return iter->second;
return -1;
}
// ---------------------------------------------------------------
// replaces in a_haystack all a_searchText with a_replaceText
// (not greedy).
// ---------------------------------------------------------------
void IntegerCalculator::replace(std::string& a_haystack, const std::string &a_searchText, const std::string &a_replaceText)
{
std::string::size_type searchSize = a_searchText.length();
std::string::size_type replaceSize = a_replaceText.length();
std::string::size_type pos = a_haystack.find(a_searchText, 0);
while (std::string::npos != pos)
{
a_haystack.replace(pos, searchSize, a_replaceText);
pos += replaceSize;
pos = a_haystack.find(a_searchText, pos);
}
}
} // namespace N_SST
+257
View File
@@ -0,0 +1,257 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <string>
#include <map>
namespace N_SST
{
/**
* This class calculates algebraic texts with integer values and returns its
* result as a signed value. It handles the operations - +, -, *, /, %, <<, >>. It
* understands the paranthesis and priorities of operations, like * before -. It
* also computes with variables, which names are case-sensitive. The values can be
* decimal, hexadecimal (0x) or binary (0b). The variable-system implemented
* virtual, so you can implement your own variable system (see getVariableValue()).
*
*
* @author alois.wismer
* @version 1.0
* @created 12-Mai-2010 16:26:43
*/
class IntegerCalculator
{
public:
/**
* Describes the error happend while calculation of an expression
*
* @author alois.wismer
* @version 1.0
* @created 17-Mai-2010 16:38:24
*/
enum E_Error
{
/**
* No error happend
*/
e_Ok,
/**
* The divisor is 0
*/
e_DivisionByZero,
/**
* The operation/variable is not known. a_addErrorText will contain the unknown
* operation/variable.
*/
e_UnknownOperationOrVariable,
/**
* Between to operators no variable/operand exists. a_addErrorText contains the 2
* operations.
*/
e_NoOperandBetweenOperators,
/**
* The operand contains invalid characters. a_addErrorText contains the invalid
* operand.
*/
e_InvalidOperand,
/**
* There are more ) than (
*/
e_MissingLeftParanthesis,
/**
* There are more ) than (
*/
e_MissingRightParanthesis,
/**
* Something else went wrong
*/
e_UnknownError
};
IntegerCalculator();
virtual ~IntegerCalculator() = default;
/**
* Converts the expressen in a_calcText into a signed value. Returns whether an
* error happend in the variable a_error. If an error happend, the variable
* a_addErrorText can contain more informaition about the error (see E_Error for
* more information about errors).
*
* @param a_calcText
* @param a_error
* @param a_addErrorText
*/
int64_t calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText = nullptr);
/**
* Adds or changes a case-sensitive variable to the calculator.
*
* @param a_name
* @param a_value
*/
void addVariable(const std::string& a_name, const int64_t a_value);
/**
* Removes a case-sensitive variable from the calculator.
*
* @param a_name
*/
void removeVariable(const std::string& a_name);
protected:
/**
* Contains all supported operations
*/
const std::map<std::string, int> m_OperationList;
/**
* Contains all variables
*/
std::map<std::string, int64_t> m_VariableList;
/**
* The additional text for errors
*/
std::string m_AdditionalErrorText;
/**
* The number of open paranthesis
*/
int32_t m_ParanthesisCount;
E_Error m_Error;
/**
* Calculates the expression (recursive)
*
* @param a_calcText
* @param a_pos
* @param a_IsEndParanthesis
* @param a_prevOp
* @param a_prevValue
* @param a_initOp
*/
int64_t calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis,
const std::string& a_prevOp = std::string(), const int64_t a_prevValue = 0,
const std::string& a_initOp = std::string());
/**
* Calculates an operation with respecting the priority of operations. This will
* be done with recursion.
*
* @param a_calcText
* @param a_pos
* @param a_value1
* @param a_operation
* @param a_value2
* @param a_prevOp
*/
bool calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1,
std::string& a_operation, int64_t a_value2, const std::string& a_prevOp);
/**
* Returns the inverted a_value if a_isNegative is true. a_isNegative will be
* false after calling this function.
* If a_isNegative is true, the NOT inverted a_value will be returned.
*
* @param a_value
* @param a_isNegative
*/
static int64_t calcSign(const int64_t a_value, bool& a_isNegative);
/**
* Converts the value in form of text to a number. The Text can be decimal, hex
* (0x) or binary (0b).
*
* @param a_valueText
* @param a_pos
*/
int64_t convertValue(const std::string& a_valueText, size_t& a_pos);
/**
* Returns the next token (with space as separator). Heading spaces will be
* ignored.
*
* @param a_calcText
* @param a_pos
*/
static std::string getToken(const std::string& a_calcText, size_t& a_pos);
/**
* returns true if a_operation is a known operation.
*
* @param a_operation
*/
bool isOperation(const std::string& a_operation) const;
/**
* Calculates the opeation a_operations with a_value1 as first and a_value2 as
* second operand.
*
* @param a_value1
* @param a_operation
* @param a_value2
*/
int64_t doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2);
/**
* returns true if priority of a_opeation1 is higher than priority of a_operation2.
*
*
* @param a_operation1
* @param a_operation2
*/
bool isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const;
/**
* Returns true if the variable named a_variableName is known and a_value will be
* filled with its value. If the variable is not found false will be returned.
* Overload this virtual function if you want to implement your own variable-list.
*
* @param a_variableName
* @param a_value
*/
virtual bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const;
/**
* Returns true if a_char is a digit. When a_isHex is true, also the charactes a-f
* will be accepted as digits. When a_isBin is true, only 0 and 1 will be treated
* as digit.
*
* @param a_char
* @param a_isHex
* @param a_isBin
*/
static bool isDigit(const char a_char, const bool a_isHex = false, const bool a_isBin = false);
/**
* Returns the priority of the operation. A higher value means more priority.
*
* @param a_operation
*/
int16_t getPriority(const std::string& a_operation) const;
/**
* replaces in a_haystack all a_searchText with a_replaceText (not greedy).
*
* @param a_haystack
* @param a_searchText
* @param a_replaceText
*/
static void replace(std::string& a_haystack, const std::string& a_searchText, const std::string& a_replaceText);
};
}
+41
View File
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Edit boolean values
* $Id$
* $HeadURL$
* $Author$
*/
#include "LogViewBooleanEdit.hpp"
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewBooleanEdit::LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly)
: QCheckBox (a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
{
const QString valueText = a_field->value(0);
setChecked(valueText.toInt() == 1);
setEnabled(!a_readonly);
}
// ---------------------------------------------------------------
bool LogViewBooleanEdit::saveContent(LogViewTelegram* a_telegram)
{
if (m_Valid)
{
if (a_telegram->isJsonTelegram())
a_telegram->setJsonValue(m_Field->jsonPath(), isChecked());
else
a_telegram->setUIntX(getSize(), isChecked());
return true;
}
return false;
}
} // namespace N_LogView
+24
View File
@@ -0,0 +1,24 @@
/**
* @RDE_HEADER@
* Edit boolean values
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "LogViewWidget.hpp"
#include <QCheckBox>
namespace N_LogView
{
class LogViewBooleanEdit : public QCheckBox, public LogViewWidget
{
Q_OBJECT
public:
LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly);
bool saveContent(LogViewTelegram* a_telegram) override;
};
}
+86
View File
@@ -0,0 +1,86 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewDateTimeEdit.hpp"
#include <time.h>
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewDateTimeEdit::LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly)
: QDateTimeEdit(a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
{
if (a_readonly)
{
setReadOnly(true);
setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft);
}
// date-time-field
qint64 unixTime = 0;
if (a_field->hasContent())
{
if (a_field->isMSecsField())
unixTime = a_field->value(0, true).toLongLong();
else
unixTime = a_field->value(0, true).toInt() * 1000LL;
}
// take actual date and time if time is 0
if (0 == unixTime && !a_readonly)
unixTime = ::time(nullptr) * 1000LL;
//valueWidget = new QDateTimeEdit(dateTime);
setDateTime(QDateTime::fromMSecsSinceEpoch(unixTime));
setDisplayFormat(QLatin1String("dd MMM yyyy hh:mm:ss"));
setCalendarPopup(true);
updateToolTip(QString::number(unixTime));
//setToolTip(a_field->getToolTipText());
// checkAndOvertakeContent();
connect(this, &LogViewDateTimeEdit::editingFinished,
this, &LogViewDateTimeEdit::checkAndOvertakeContent);
}
// ---------------------------------------------------------------
void LogViewDateTimeEdit::checkAndOvertakeContent()
{
updateToolTip(QString::number(dateTime().toMSecsSinceEpoch() / 1000));
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewDateTimeEdit::saveContent(LogViewTelegram* a_telegram)
{
if (a_telegram->isJsonTelegram())
{
a_telegram->setJsonValue(m_Field->jsonPath(), dateTime().toMSecsSinceEpoch());
}
else
{
a_telegram->setNextFieldAsGpsTimeField(); // fixme: muss noch der feldname auf GPS Zeit geprüft werden?
a_telegram->setUIntX(getSize(), dateTime().toMSecsSinceEpoch() / 1000);
}
return true;
}
} // namespace N_LogView
+53
View File
@@ -0,0 +1,53 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewWidget.hpp"
#include <QDateTimeEdit>
namespace N_LogView
{
/**
* Used for date & time
*
* @author alois.wismer
* @version 1.0
* @created 20-Mai-2010 17:41:28
*/
class LogViewDateTimeEdit : public QDateTimeEdit, public LogViewWidget
{
Q_OBJECT
public:
/**
*
* @param a_field
* @param a_parent
* @param a_readonly
*/
LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly);
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
public slots:
void checkAndOvertakeContent();
};
}
+105
View File
@@ -0,0 +1,105 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewEnumEdit.hpp"
#include "LogViewXdrStruct.hpp"
#include "LogViewXdrValue.hpp"
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewEnumEdit::LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index)
: QComboBox(a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
{
QString value = a_field->value(a_index);
// show the tool-tip with special-case for TETRA bitfields
setToolTip(a_field->toolTipText());
// fill combobox
bool bCurrentIndexSet = false;
int i = 0;
while (LogViewXdrValue* child = (static_cast<const LogViewXdrStruct*>(a_field->xdrElement()))->getChildAsValue(i++))
{
QString enumText = LogViewField::makeClean(child->getName());
if (!a_readonly || enumText == value)
{
addItem(QStringLiteral("%1 (%2)").arg(enumText).arg(child->getValue()), QVariant::fromValue(child->getValue()));
if (a_readonly)
bCurrentIndexSet = true;
}
if (enumText == value)
{
setCurrentIndex(a_readonly ? 0 : i - 1);
bCurrentIndexSet = true;
if (!a_readonly || (0 != a_index))
updateToolTip(itemData(currentIndex()).toString());
}
}
if (!bCurrentIndexSet)
{
addItem(value);
setCurrentIndex(findText(value));
}
// connect signals
connect(this, QOverload<int>::of(&LogViewEnumEdit::currentIndexChanged),
this, &LogViewEnumEdit::checkAndOvertakeContent);
}
// ---------------------------------------------------------------
uint16_t LogViewEnumEdit::getSize() const
{
// todo: check ob wirklich ein struct
const LogViewXdrStruct* xdrStruct = static_cast<const LogViewXdrStruct*>(m_Field->xdrElement());
return xdrStruct->getEnumSize();
}
// ---------------------------------------------------------------
void LogViewEnumEdit::checkAndOvertakeContent()
{
updateToolTip(itemData(currentIndex()).toString());
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewEnumEdit::saveContent(LogViewTelegram* a_telegram)
{
bool ok;
int value = itemData(currentIndex()).toInt(&ok);
if (ok)
{
if (a_telegram->isJsonTelegram())
a_telegram->setJsonValue(m_Field->jsonPath(), value);
else
a_telegram->setUIntX(getSize(), value);
return true;
}
return false; // failure while conversion
}
} // namespace N_LogView
+57
View File
@@ -0,0 +1,57 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewWidget.hpp"
#include <QComboBox>
namespace N_LogView
{
/**
* Used for enums
*
* @author alois.wismer
* @version 1.0
* @created 21-Mai-2010 09:31:16
*/
class LogViewEnumEdit : public QComboBox, public LogViewWidget
{
Q_OBJECT
public:
/**
*
* @param a_field
* @param a_parent
* @param a_readonly
* @param a_index the array-index
*/
LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index);
uint16_t getSize() const override;
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
protected slots:
void checkAndOvertakeContent();
};
}
+275
View File
@@ -0,0 +1,275 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewField.hpp"
#include <QtCore/QDateTime>
#include "LogViewXdrElement.hpp"
#include "LogViewXdrStandardType.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewField::LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement)
: m_Name(a_name),
m_IsRightAligned(false),
m_Offset(0),
m_Size(0),
m_MaxArraySize(0),
m_IsDynamicArray(false),
m_HasContent(true),
m_bDeleteXdr(false),
m_Kind(a_kind),
m_XdrElement(a_xdrElement),
m_logger(getLogger("LogViewField"))
{
}
// ---------------------------------------------------------------
LogViewField::~LogViewField()
{
for (LogViewField *f : qAsConst(m_Child))
delete f;
if (m_bDeleteXdr)
delete m_XdrElement;
}
LogViewField *LogViewField::clone(int arrayIdx) const
{
LogViewField *f = new LogViewField(*this);
f->m_Child.clear();
f->m_bDeleteXdr = false;
for (auto * c : m_Child)
{
auto *clonedChild = c->clone(-1);
if (arrayIdx >= 0)
{
QStringList sl = clonedChild->jsonPath();
if (sl.size() > 1 && sl.at(sl.size() - 2).startsWith(QStringLiteral("index: ")))
{
sl[sl.size() - 2] = QStringLiteral("index: %1").arg(arrayIdx);
clonedChild->setJsonPath(sl);
}
}
f->addChild(clonedChild);
}
for (auto &val : f->m_ValueList)
val.clear();
return f;
}
// ---------------------------------------------------------------
void LogViewField::addChild(LogViewField* a_child)
{
if (a_child)
m_Child.push_back(a_child);
}
// ---------------------------------------------------------------
void LogViewField::removeLastChild()
{
if (m_Child.empty())
return;
delete m_Child.takeLast();
}
// ---------------------------------------------------------------
LogViewField* LogViewField::child(int arrayIdx)
{
if (m_Child.size() > arrayIdx)
return m_Child.at(arrayIdx);
return nullptr;
}
// ---------------------------------------------------------------
void LogViewField::addValue(const QString &value)
{
m_ValueList.append(value);
}
// ---------------------------------------------------------------
void LogViewField::addValueBinaryHex(const QString &value)
{
const QByteArray ba = QByteArray::fromHex(value.toLatin1());
for (const char c : ba)
m_ValueList.append(QString::number(static_cast<unsigned char>(c)));
}
// ---------------------------------------------------------------
// Returns the value at position a_index converted to a string.
// If the field is a date-time-field, the returned value is
// converted to a string containing date and time, execpt when
// a_doNotMakeSpecialConversions is set to true, the unix-time
// will be returned as value.
// ---------------------------------------------------------------
QString LogViewField::value(int arrayIdx, const bool a_doNotMakeSpecialConversions) const
{
if (m_ValueList.size() > arrayIdx)
{
const QString &ret = m_ValueList.at(arrayIdx);
if (!a_doNotMakeSpecialConversions)
{
if (isDateTimeField())
return QDateTime::fromMSecsSinceEpoch(ret.toLongLong() * 1000).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz"));
if (isMSecsField())
return QDateTime::fromMSecsSinceEpoch(ret.toLongLong()).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz"));
}
return ret;
}
return QString();
}
// ---------------------------------------------------------------
int64_t LogViewField::getHighestValue() const
{
switch (m_XdrElement->getKind())
{
case LogViewXdrElement::e_KindStandardType:
{
int64_t highest = 1;
//const LogViewXdrStandardType* xdrStandardType = static_cast<const LogViewXdrStandardType*>(m_XdrElement);
uint16_t bitSize = 8*static_cast<const LogViewXdrStandardType*>(m_XdrElement)->getEditSize();
// fixme: mache configurierbar
if ((0 == m_Name.compare(QLatin1String("utm nordwert"), Qt::CaseInsensitive)) ||
(0 == m_Name.compare(QLatin1String("utm ostwert"), Qt::CaseInsensitive)))
bitSize -= 8;
switch (static_cast<const LogViewXdrStandardType*>(m_XdrElement)->getValueKind()) {
case LogViewXdrStandardType::e_Boolean:
return 1;
case LogViewXdrStandardType::e_Signed:
bitSize--;
Q_FALLTHROUGH();
case LogViewXdrStandardType::e_Unsigned:
case LogViewXdrStandardType::e_Data:
highest = highest << bitSize;
highest--;
break;
default:
highest = 0;
break;
}
return highest;
}
default:
ERROR_LOG(m_logger) << "Case not implemented";
}
return 0;
}
// ---------------------------------------------------------------
int64_t LogViewField::getLowestValue() const
{
switch (m_XdrElement->getKind())
{
case LogViewXdrElement::e_KindStandardType:
{
int64_t lowest = 0;
//const LogViewXdrStandardType* xdrStandardType = static_cast<const LogViewXdrStandardType*>(a_field->getXdrElement());
switch (static_cast<const LogViewXdrStandardType*>(m_XdrElement)->getValueKind()) {
case LogViewXdrStandardType::e_Boolean:
return 0;
case LogViewXdrStandardType::e_Signed:
lowest = getHighestValue() + 1;
lowest = -lowest;
break;
default:
break;
}
return lowest;
}
default:
ERROR_LOG(m_logger) << "Case not implemented";
break;
}
return 0;
}
// ---------------------------------------------------------------
void LogViewField::dump(const QString &a_indent) const
{
INFO_LOG(m_logger) << a_indent << "[";
INFO_LOG(m_logger) << a_indent << "Field[" << m_Name << "]: m_Kind=" << m_Kind << " m_Offset=" << m_Offset << " m_Size=" << m_Size << " m_MaxArraySize=" << m_MaxArraySize << " m_IsRightAligned=" << m_IsRightAligned << " m_IsDynamicArray=" << m_IsDynamicArray << " m_ToolTipText=" << m_ToolTipText;
// m_XdrElement->dump();
for (int i=0; i<m_ValueList.size(); i++)
INFO_LOG(m_logger) << a_indent << "m_Value[" << i << "]=" << m_ValueList[i];
for (auto *c : m_Child)
c->dump(a_indent + QLatin1Char(' '));
INFO_LOG(m_logger) << a_indent << "]";
}
// ---------------------------------------------------------------
// Makes the text <a_uncleanText> pretty for human readable.
// It does following:
// - generates umlaute (ä, ö, ü)
// - removes _rt at end
// - replaces _ with space
// - uppercase of every word
// ---------------------------------------------------------------
QString LogViewField::makeClean(const QString &text)
{
QString a_uncleanText = text;
// remove _rt at end
if (a_uncleanText.endsWith(QLatin1String("_rt")))
a_uncleanText = a_uncleanText.left(a_uncleanText.length() - 3);
// replace _ with space
a_uncleanText = a_uncleanText.replace(QLatin1Char('_'), QLatin1Char(' '));
// first character of every word must be uppercase
int pos = 0;
while (a_uncleanText.length() > pos)
{
a_uncleanText[pos] = a_uncleanText[pos].toUpper();
pos = a_uncleanText.indexOf(QLatin1Char(' '), pos + 1);
if (-1 == pos)
break;
pos++;
}
return a_uncleanText;
}
// ---------------------------------------------------------------
// returns true if the field is a date-time
// ---------------------------------------------------------------
bool LogViewField::isDateTimeField() const
{
QString name = m_Name.toLower();
return name == QLatin1String("gps_zeit");
}
bool LogViewField::isMSecsField() const
{
QString name = m_Name.toLower();
return (name == QLatin1String("timestamp")) || (name == QLatin1String("effectstart"));
}
// ---------------------------------------------------------------
void LogViewField::setMaxArraySize(uint16_t newVal, const bool a_isDynamic)
{
m_MaxArraySize = newVal;
m_IsDynamicArray = a_isDynamic;
}
} // namespace N_LogView
+162
View File
@@ -0,0 +1,162 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QStringList>
#include <QVector>
#include "logger.h"
namespace N_LogView
{
class LogViewXdrElement;
class LogViewField
{
public:
enum E_FieldKind
{
e_FieldKindBorder,
e_FieldKindEdit,
e_FieldKindTab,
e_FieldKindTabChild,
e_FieldKindPodArray,
e_FieldKindPodArrayChild
};
LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement);
virtual ~LogViewField();
LogViewField *clone(int arrayIdx) const;
QString cleanName() const { return makeClean(m_Name); }
QString name() const { return m_Name; }
void setName(const QString &newVal) { m_Name = newVal; }
void addChild(LogViewField* a_child);
void removeLastChild();
LogViewField *child(int arrayIdx);
int childCount() const { return m_Child.size(); }
QString type() const { return m_type; }
void setType(const QString &type) { m_type = type; }
LogViewField::E_FieldKind kind() const { return m_Kind; }
void addValue(const QString &value);
void addValueBinaryHex(const QString &value);
/**
* Returns the value at position a_index converted to a string. If the field is a
* date-time-field, the returned value is converted to a string containing date
* and time, execpt when a_doNotMakeSpecialConversions is set to true, the unix-
* time will be returned as value.
*
* @param a_index
* @param a_doNotMakeSpecialConversions
*/
QString value(int arrayIdx, const bool a_doNotMakeSpecialConversions = false) const;
int valueListSize() const { return m_ValueList.size(); }
bool isRightAligned() const { return m_IsRightAligned; }
void setIsRightAligned(bool newVal) { m_IsRightAligned = newVal; }
QString toolTipText() const { return m_ToolTipText; }
void setToolTipText(const QString &newVal) { m_ToolTipText = newVal; }
int64_t getHighestValue() const;
int64_t getLowestValue() const;
/**
*
* @param a_indent
*/
void dump(const QString &a_indent = QString()) const;
/**
* Makes the text <a_uncleanText> pretty for human readable. It does following:
* - generates umlaute (ä, ö, ü)
* - removes _rt at end
* - replaces _ with space
* - uppercase of every word
*
* @param a_uncleanText
*/
static QString makeClean(const QString &text);
int size() const { return m_Size; }
void setSize(int newVal) { m_Size = newVal; }
const LogViewXdrElement* xdrElement() const { return m_XdrElement; }
/**
* returns true if the field is a date-time
*/
bool isDateTimeField() const;
bool isMSecsField() const;
uint16_t maxArraySize() const { return m_MaxArraySize; }
void setMaxArraySize(uint16_t newVal, const bool a_isDynamic);
/**
* True if the array is dynamic.
*/
bool isDynamicArray() const { return m_IsDynamicArray; }
bool hasContent() const { return m_HasContent; }
void setHasContent(bool newVal) { m_HasContent = newVal; }
void setDeleteXdr(bool bDelete) { m_bDeleteXdr = bDelete; }
void setJsonPath(const QStringList &path) { m_jsonPath = path; }
QStringList jsonPath() const { return m_jsonPath; }
protected:
QString m_Name;
QString m_type;
QStringList m_ValueList;
QStringList m_jsonPath;
bool m_IsRightAligned;
QString m_ToolTipText;
uint16_t m_Offset;
int m_Size;
uint16_t m_MaxArraySize;
/**
* True if the array is dynamic.
*/
bool m_IsDynamicArray;
bool m_HasContent;
bool m_bDeleteXdr;
QVector<LogViewField*> m_Child;
E_FieldKind m_Kind;
const LogViewXdrElement *m_XdrElement;
private:
/**
* The logger object
*/
NGL::INGLLogger &m_logger;
};
}
File diff suppressed because it is too large. Load diff
+200
View File
@@ -0,0 +1,200 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QMainWindow>
#include <QtCore/QMap>
#include "LogViewModels.hpp"
#include "LogViewTelegramEditModel.hpp"
#include <set>
#include <QMenu>
#include "logger.h"
namespace N_LogView
{
class LogViewTelegram;
}
class QTableView;
class QGroupBox;
class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QSplitter;
class QToolBox;
namespace N_LogView
{
class LogViewInjectionThread;
class TelegramEdit;
/**
* @author alois.wismer
* @version 1.0
* @created 03-Feb-2010 16:44:53
*/
class LogViewGui : public QMainWindow
{
Q_OBJECT
public:
explicit LogViewGui(QWidget* a_parent);
static const QLatin1String WINDOW_GROUP;
static const QLatin1String SCREEN;
protected:
const QSize RADIO_BUTTON_ICON_SIZE;
static const QLatin1String SIZE;
static const QLatin1String POS;
static const QLatin1String SPLITTPOS;
static const QLatin1String TOOLBOXINDEX;
// Central
QGroupBox *m_CentralSelectionGroup;
std::set<int> m_CentralTelegramFilterList;
QCheckBox* m_SentCentralTelCheckBox;
QCheckBox* m_ReceivedCentralTelCheckBox;
QCheckBox* m_PosCentralTelCheckBox;
QCheckBox* m_ackCentralTelCheckBox;
// Tetra
QGroupBox *m_TetraSelectionGroup;
std::set<int> m_TetraTelegramFilterList;
QCheckBox* m_SentTetraTelCheckBox;
QCheckBox* m_ReceivedTetraTelCheckBox;
QCheckBox* m_PosTetraTelCheckBox;
QCheckBox* m_LoginTetraTelCheckBox;
QCheckBox* m_RegisterTetraTelCheckBox;
QCheckBox* m_ReportTetraTelCheckBox;
QCheckBox* m_FragmentedTetraTelCheckBox;
QCheckBox* m_AirInterfaceLoadTetraTelCheckBox;
// Wls
QGroupBox *m_WlsSelectionGroup;
std::set<int> m_WlsTelegramFilterList;
QCheckBox* m_SentWlsTelCheckBox;
QCheckBox* m_ReceivedWlsTelCheckBox;
QCheckBox* m_PosWlsTelCheckBox;
QCheckBox* m_ackWlsTelCheckBox;
QString m_ActualLogfile;
qint64 m_LogfileSize;
bool m_DoReload;
QToolBox* m_ToolBox;
QTableView *m_ParticipantTableView;
ParticipantModel *m_participantModel;
QSortFilterProxyModel *m_participantProxyModel;
QTableView *m_logTelegramView;
TelegramModel *m_telegramModel;
TelegramProxyModel *m_telegramProxyModel;
QLabel *m_TelegramStatus;
QLabel *m_ParticipantStatus;
QGroupBox *m_ParticipantSelectionGroup;
TelegramEdit *m_EditTelegramController;
QTimer *m_TailTimer;
QSplitter *m_Splitter;
LogViewInjectionThread *m_InjectionThread;
QLabel *m_InjectionStatus;
// ausstg, telcount
QHash<int, int> m_participantListTelCount;
// ausstg, issi
QHash<int, int> m_participantListIssi;
QAction *m_reloadAction;
QTimer *m_replayTimer;
int m_currentReplayRow;
NGL::INGLLogger &m_logger;
protected:
void readTelegramsFromLogFile(const QString& a_fileName, const qint64 a_filePos = 0);
/**
* returns true if the participant was added to the list
*/
void addToParticipantList(const QSharedPointer<LogViewTelegram> &a_telegram);
void syncParticipantList();
QCheckBox* createRadioButton(const QString& a_buttonName, const QString& a_iconName);
/**
* starts the thread, which trys to connect to the injection-server of PrtCnv
*/
void startInjectionThread();
void closeEvent(QCloseEvent* a_closeEvent) override;
void createCentralSelectionWidget();
void createTetraSelectionWidget();
void createWlsSelectionWidget();
protected slots:
void addTelegramToEdit();
void showHexData();
void exportAsCsv();
void exportAsJson();
void onStartLogReplay();
void onReplayTimerTimeout();
void loadSpecificationFiles();
void newTelegramFile();
void loadTelegramFile();
/**
* Checks whether the size of actual logfile has changed. If yes, the new log-
* entries will be read and shown within table.
*/
void updateLogfile();
void selectedParticipantChanged();
void showTelegramTable();
//SLOT for creating the ContextMenu
void customMenuRequested(const QPoint &pos);
void changeSettings();
/**
* Toggles whether the logfile must be periodically checked for changes
*/
void reloadOnOff();
/**
*
* @param a_picName
* @param a_toopTipText
*/
void updateInjectionStatus(const QString& a_picName, const QString& a_toopTipText);
void onLogTelegramViewDoubleClicked(const QModelIndex &index);
private slots:
void onSettingsChanged(uint32_t changedFlags);
};
}
+143
View File
@@ -0,0 +1,143 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewInjectionThread.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewOptionDialog.hpp"
#include <CoPrtCnv/CoPrtCnvInjectionHeader.hpp>
#include <QtNetwork/QTcpSocket>
#include <QtCore/QTimer>
#include <QtCore/QSettings>
namespace N_LogView
{
LogViewInjectionThread::LogViewInjectionThread()
: m_DoStartConnection(false)
, m_SendingPossible(false)
, m_Socket(nullptr)
, m_Timer(nullptr)
, m_logger(getLogger("LogViewInjectionThread"))
{
// load the settings (and write default-values if not defined)
QSettings settings;
settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP);
m_Hostname = settings.value(LogViewOptionDialog::INJECTION_HOSTNAME).toString();
if (m_Hostname.isEmpty())
{
// set default-hostname if nothing was set
m_Hostname = QLatin1String("localhost");
settings.setValue(LogViewOptionDialog::INJECTION_HOSTNAME, m_Hostname);
}
m_Port = settings.value(LogViewOptionDialog::INJECTION_PORT).toInt();
if (0 == m_Port || m_Port > 65535)
{
m_Port = 46666;
settings.setValue(LogViewOptionDialog::INJECTION_PORT, m_Port);
}
}
// ---------------------------------------------------------------
void LogViewInjectionThread::run()
{
emit updateStatus(QLatin1String(":/image/RedLamp.png"),
tr("LogView ist nicht mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port));
QTimer::singleShot(100, this, &LogViewInjectionThread::tryToConnect);
exec();
}
// ---------------------------------------------------------------
void LogViewInjectionThread::setPort(uint16_t port)
{
m_Port = port;
QSettings settings;
settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP);
settings.setValue(LogViewOptionDialog::INJECTION_PORT, m_Port);
}
// ---------------------------------------------------------------
bool LogViewInjectionThread::isSendingPossible() const
{
return m_SendingPossible;
}
// ---------------------------------------------------------------
void LogViewInjectionThread::tryToConnect()
{
//m_Timer->setInterval(3000);
if (!m_Socket)
{
m_Socket = new QTcpSocket(this);
connect(m_Socket, &QTcpSocket::connected, this, &LogViewInjectionThread::doConnect);
connect(m_Socket, &QTcpSocket::disconnected, this, &LogViewInjectionThread::doDisconnect);
}
// we need a timer for retrying connection
if (!m_Timer)
{
m_Timer = new QTimer(this);
connect(m_Timer, &QTimer::timeout, this, &LogViewInjectionThread::tryToConnect);
}
m_Timer->setInterval(3000);
m_Timer->start();
INFO_LOG(m_logger) << "Try to connect to injection-server of TETRA-If (" << m_Hostname << ":" << m_Port << ")";
m_Socket->connectToHost(m_Hostname, m_Port);
}
// ---------------------------------------------------------------
void LogViewInjectionThread::doConnect()
{
INFO_LOG(m_logger) << "LogView has successful connected to injection-server of TETRA-If";
m_SendingPossible = true;
m_Timer->stop();
emit updateStatus(QLatin1String(":/image/GreenLamp.png"),
tr("LogView ist mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port));
}
// ---------------------------------------------------------------
void LogViewInjectionThread::doDisconnect()
{
INFO_LOG(m_logger) << "LogView was disconnected from injection-server of TETRA-If";
m_SendingPossible = false;
emit updateStatus(QLatin1String(":/image/RedLamp.png"),
tr("LogView ist nicht mehr mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port));
tryToConnect();
}
// ---------------------------------------------------------------
void LogViewInjectionThread::sendTelegram(LogViewTelegram* a_telegram, const bool a_doSendAsCentralTelegram)
{
INFO_LOG(m_logger) << "inject " << (a_doSendAsCentralTelegram ? "central" : "Tetra") << " telegram";
if (!m_Socket || m_Socket->state() != QAbstractSocket::ConnectedState)
{
ERROR_LOG(m_logger) << "Try to write a telegramm but we are not connected";
return;
}
N_CoPrtCnv::CoPrtCnvInjectionHeader injectionHeader;
injectionHeader.m_Kind = a_doSendAsCentralTelegram ? N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral : N_CoPrtCnv::CoPrtCnvInjectionHeader::eRadio;
const QByteArray &data = a_telegram->getData();
injectionHeader.m_Size = data.size();
m_Socket->write((char*)(&injectionHeader), sizeof(injectionHeader));
m_Socket->write(data);
}
} // namespace N_LogView
@@ -0,0 +1,89 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QtCore/QThread>
#include "logger.h"
class QTcpSocket;
class QTimer;
namespace N_LogView
{
class LogViewTelegram;
/**
* @author alois.wismer
* @version 1.0
* @created 05-Aug-2010 16:02:15
*/
class LogViewInjectionThread : public QThread
{
Q_OBJECT
public:
LogViewInjectionThread();
void run();
void setPort(uint16_t port);
bool isSendingPossible() const;
/**
*
* @param a_telegram
* @param a_doSendAsCentralTelegram
*/
void sendTelegram(LogViewTelegram* a_telegram, const bool a_doSendAsCentralTelegram);
protected:
bool m_DoStartConnection;
bool m_SendingPossible;
QString m_Hostname;
int m_Port;
QTcpSocket *m_Socket;
QTimer *m_Timer;
private:
/**
* The logger object
*/
NGL::INGLLogger &m_logger;
protected:
protected slots:
void tryToConnect();
void doConnect();
void doDisconnect();
public:
signals:
/**
*
* @param a_picName
* @param a_toolTipText
*/
void updateStatus(const QString& a_picName, const QString& a_toolTipText);
};
}
+57
View File
@@ -0,0 +1,57 @@
#include <nglapplication/nglapplication.h>
#include <QDesktopWidget>
#include <QtCore/QSettings>
#include <QNetworkProxy>
#ifndef WIN32
#include <unistd.h>
#endif
#include "LogViewGui.hpp"
#include "logger.h"
int main(int argc, char *argv[])
{
std::string logConfigFileName;
std::string dir;
#ifdef WIN32
dir = argv[0];
#else
std::stringstream s;
s << "/proc/" << getpid() << "/exe";
char buf[1024];
ssize_t len = readlink(s.str().c_str(), buf, 1024);
if(len > 0) {
buf[len] = '\0';
dir = buf;
} else {
// fallback
dir = argv[0];
}
#endif
std::string::size_type pos = dir.find_last_of('/');
if (std::string::npos != pos)
logConfigFileName += dir.substr(0, pos + 1);;
logConfigFileName += "LogView_log4cxx.props";
qputenv("TDS_DEVEL", QByteArray::number(1));
NGLApplication app(argc, argv);
QNetworkProxy::setApplicationProxy(QNetworkProxy());
app.createLogger("LogView", logConfigFileName.c_str());
QCoreApplication::setOrganizationName(QLatin1String("RME"));
QCoreApplication::setApplicationName(QLatin1String("LogView"));
QSettings settings;
settings.beginGroup(N_LogView::LogViewGui::WINDOW_GROUP);
int screenNbr = settings.value(N_LogView::LogViewGui::SCREEN, 0).toInt();
settings.endGroup();
N_LogView::LogViewGui* logViewGui = new N_LogView::LogViewGui(QApplication::desktop()->screen(screenNbr));
logViewGui->show();
int ret = app.exec();
delete logViewGui;
return ret;
}
+553
View File
@@ -0,0 +1,553 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#include "LogViewModels.hpp"
#include <QtGui/QFont>
#include <QtGui/QPalette>
#include <QtGui/QGuiApplication>
namespace N_LogView
{
// ---------------------------------------------------------------
// ---------------------------------------------------------------
int ParticipantModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_particpants.size();
}
// ---------------------------------------------------------------
int ParticipantModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 3;
}
// ---------------------------------------------------------------
QVariant ParticipantModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && index.row() < m_particpants.size())
{
const auto &p = m_particpants.at(index.row());
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case 0:
return p.first;
case 1:
return p.second;
case 2:
return m_particpantMap.value(p.first);
default:
break;
}
}
if (role == Qt::ToolTipRole)
{
switch (index.column())
{
case 0:
return tr("hex: 0x%1").arg(p.first, 4, 16, QLatin1Char('0'));
case 1:
return tr("hex: 0x%1").arg(p.second, 4, 16, QLatin1Char('0'));
default:
break;
}
}
if (role == Qt::BackgroundColorRole)
{
if (p.first == 0)
return QVariant(); // 0 aussen vor lassen
if (m_participantHeatmap.isEmpty())
updateHeatMap();
return m_participantHeatmap.value(p.first);
}
}
return QVariant();
}
// ---------------------------------------------------------------
QVariant ParticipantModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case 0:
return tr("Equip. No.");
case 1:
return tr("ISSI");
case 2:
return tr("#");
default:
break;
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
// ---------------------------------------------------------------
void ParticipantModel::clearParticipants()
{
beginResetModel();
m_particpantMap.clear();
m_particpants.clear();
m_participantHeatmap.clear();
endResetModel();
}
// ---------------------------------------------------------------
bool ParticipantModel::addUpdateParticipants(const QVector<int> &eqIds,
const QVector<int> &issis,
const QVector<int> &numberOfTelegrams)
{
QVector<QPair<int, int> > newParticpants;
for (int i = 0; i < eqIds.size(); ++i)
{
const int eqId = eqIds.at(i);
const int issi = issis.at(i);
const int cntTelegrams = numberOfTelegrams.at(i);
auto it = m_particpantMap.find(eqId);
if (it != m_particpantMap.end())
{
it.value() = cntTelegrams;
continue;
}
newParticpants.push_back(qMakePair(eqId, issi));
m_particpantMap[eqId] = cntTelegrams;
}
if (!newParticpants.isEmpty())
{
beginInsertRows(QModelIndex(), m_particpants.size(), m_particpants.size() + newParticpants.size() - 1);
m_particpants.append(newParticpants);
endInsertRows();
}
m_participantHeatmap.clear();
return true;
}
// ---------------------------------------------------------------
void ParticipantModel::updateHeatMap() const
{
int maxNumberOfTelegrams = 0;
for (auto it = m_particpantMap.begin(); it != m_particpantMap.end(); ++it)
{
if (it.key() == 0) // EqId 0 aussen vor lassen
continue;
maxNumberOfTelegrams = std::max(it.value(), maxNumberOfTelegrams);
}
const QColor backgroundColor = QGuiApplication::palette().base().color();
const QColor redColor = Qt::red;
for (auto it = m_particpantMap.begin(); it != m_particpantMap.end(); ++it)
{
const int eqId = it.key();
if (eqId == 0) // EqId 0 aussen vor lassen
continue;
const int nbrTelegrams = it.value();
QColor curColor;
double percent = static_cast<double>(nbrTelegrams) / maxNumberOfTelegrams;
curColor.setRed(backgroundColor.red() - ((backgroundColor.red() - redColor.red()) * percent));
curColor.setGreen(backgroundColor.green() - ((backgroundColor.green() - redColor.green()) * percent));
curColor.setBlue(backgroundColor.blue() - ((backgroundColor.blue() - redColor.blue()) * percent));
m_participantHeatmap[eqId] = curColor;
}
}
// ---------------------------------------------------------------
// ---------------------------------------------------------------
int TelegramModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_telegrams.size();
}
// ---------------------------------------------------------------
int TelegramModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 6;
}
// ---------------------------------------------------------------
QVariant TelegramModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && index.row() < m_telegrams.size())
{
if (role == Qt::DisplayRole)
{
const QSharedPointer<LogViewTelegram> &telegram = m_telegrams.at(index.row());
switch (index.column())
{
case 0:
return telegram->getDestinationText();
case 1:
return telegram->getName();
case 2:
return telegram->getParticipantId();
case 3:
return telegram->getLogTimeText();
case 4:
return telegram->getGpsTimeText();
case 5:
return telegram->getDelay();
}
}
if (role == Qt::DecorationRole)
{
const QSharedPointer<LogViewTelegram> telegram = m_telegrams.at(index.row());
switch (index.column())
{
case 0:
return telegram->getIcon();
default:
break;
}
}
if (role == Qt::ToolTipRole)
{
const QSharedPointer<LogViewTelegram> telegram = m_telegrams.at(index.row());
switch (index.column())
{
case 1:
return telegram->getToolTipText(LogViewTelegram::e_ColName);
case 3:
return telegram->getToolTipText(LogViewTelegram::e_ColLogTime);
case 4:
return telegram->getToolTipText(LogViewTelegram::e_ColGpsTime);
default:
break;
}
}
}
return QVariant();
}
// ---------------------------------------------------------------
QVariant TelegramModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal)
{
if (role == Qt::DisplayRole)
{
switch (section)
{
case 0:
return tr("Dest.");
case 1:
return tr("Description");
case 2:
return tr("Equip. No.");
case 3:
return tr("Send/Recieve time");
case 4:
return tr("GPS time");
case 5:
return tr("Delay");
default:
break;
}
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
// ---------------------------------------------------------------
void TelegramModel::clearTelegrams()
{
beginResetModel();
m_telegrams.clear();
endResetModel();
}
// ---------------------------------------------------------------
void TelegramModel::appendTelegrams(const QVector<QSharedPointer<LogViewTelegram> > &telegrams)
{
if (telegrams.isEmpty())
return;
beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size() + telegrams.size() - 1);
m_telegrams += telegrams;
endInsertRows();
}
// ---------------------------------------------------------------
void TelegramModel::appendTelegram(const QSharedPointer<LogViewTelegram> &telegram)
{
beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size());
m_telegrams.push_back(telegram);
endInsertRows();
}
// ---------------------------------------------------------------
QSharedPointer<LogViewTelegram> TelegramModel::telegram(int row) const
{
if (row >= 0 && row < m_telegrams.size())
return m_telegrams.at(row);
return QSharedPointer<LogViewTelegram>();
}
// ---------------------------------------------------------------
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterByEquipmentIds(bool bFilterByEquipmentIds)
{
if (m_bFilterByEquipmentIds == bFilterByEquipmentIds)
return;
m_bFilterByEquipmentIds = bFilterByEquipmentIds;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setAllowedEquipmentIds(const std::set<int> &allowedEquipmentIds)
{
if (m_allowedEquipmentIds == allowedEquipmentIds)
return;
m_allowedEquipmentIds = allowedEquipmentIds;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilteredCentralTelegramIds(const std::set<int> &filteredCentralTelegramIds)
{
if (m_filteredCentralTelegramIds == filteredCentralTelegramIds)
return;
m_filteredCentralTelegramIds = filteredCentralTelegramIds;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilteredTetraTelegramIds(const std::set<int> &filteredTetraTelegramIds)
{
if (m_filteredTetraTelegramIds == filteredTetraTelegramIds)
return;
m_filteredTetraTelegramIds = filteredTetraTelegramIds;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilteredWlsTelegramIds(const std::set<int> &filteredWlsTelegramIds)
{
if (m_filteredWlsTelegramIds == filteredWlsTelegramIds)
return;
m_filteredWlsTelegramIds = filteredWlsTelegramIds;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction,
bool bFilter)
{
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> curFilter = m_filterCentralTelegrams;
if (bFilter)
curFilter.insert(direction);
else
curFilter.erase(direction);
if (curFilter == m_filterCentralTelegrams)
return;
m_filterCentralTelegrams = curFilter;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction,
bool bFilter)
{
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> curFilter = m_filterTetraTelegrams;
if (bFilter)
curFilter.insert(direction);
else
curFilter.erase(direction);
if (curFilter == m_filterTetraTelegrams)
return;
m_filterTetraTelegrams = curFilter;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType,
bool bFilter)
{
std::set<N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type> curFilter = m_filterTetraPDU;
if (bFilter)
curFilter.insert(pduType);
else
curFilter.erase(pduType);
if (curFilter == m_filterTetraPDU)
return;
m_filterTetraPDU = curFilter;
invalidateFilter();
}
void TelegramProxyModel::setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction,
bool bFilter)
{
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> curFilter = m_filterWlsTelegrams;
if (bFilter)
curFilter.insert(direction);
else
curFilter.erase(direction);
if (curFilter == m_filterWlsTelegrams)
return;
m_filterWlsTelegrams = curFilter;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterTetraLogin(bool bFilter)
{
if (m_bFilterLoginTelegrams == bFilter)
return;
m_bFilterLoginTelegrams = bFilter;
invalidateFilter();
}
// ---------------------------------------------------------------
void TelegramProxyModel::setFilterTetraFragmented(bool bFilter)
{
if (m_bFilterFragmentedTelegrams == bFilter)
return;
m_bFilterFragmentedTelegrams = bFilter;
invalidateFilter();
}
// ---------------------------------------------------------------
QSharedPointer<LogViewTelegram> TelegramProxyModel::telegram(int row) const
{
const TelegramModel *tm = qobject_cast<TelegramModel *>(sourceModel());
if (!tm)
return {};
const int srcRow = mapToSource(index(row, 0)).row();
return tm->telegram(srcRow);
}
// ---------------------------------------------------------------
bool TelegramProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
if (left.column() != right.column())
return QSortFilterProxyModel::lessThan(left, right);
const TelegramModel *tm = qobject_cast<TelegramModel *>(sourceModel());
if (!tm)
return QSortFilterProxyModel::lessThan(left, right);
QSharedPointer<LogViewTelegram> teleLeft = tm->telegram(left.row());
QSharedPointer<LogViewTelegram> teleRight = tm->telegram(right.row());
if (!teleLeft || !teleRight)
return QSortFilterProxyModel::lessThan(left, right);
switch (left.column())
{
case 0:
return teleLeft->getDestination() < teleRight->getDestination();
case 1:
return teleLeft->getName() < teleRight->getName();
case 2:
return teleLeft->getParticipantId() < teleRight->getParticipantId();
case 3:
return teleLeft->getLogTime() < teleRight->getLogTime();
case 4:
return teleLeft->getGpsTime() < teleRight->getGpsTime();
case 5:
return teleLeft->getDelay() < teleRight->getDelay();
}
return QSortFilterProxyModel::lessThan(left, right);
}
// ---------------------------------------------------------------
bool TelegramProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
// TODO: optimize
const TelegramModel *tm = qobject_cast<TelegramModel *>(sourceModel());
if (!tm)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
QSharedPointer<LogViewTelegram> tele = tm->telegram(source_row);
if (!tele)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
if (m_bFilterByEquipmentIds)
{
int equipId = tele->getParticipantId();
if (m_allowedEquipmentIds.find(equipId) == m_allowedEquipmentIds.end())
return false;
}
switch (tele->getProtocol())
{
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral:
if (!m_filteredCentralTelegramIds.empty())
{
const int telegramId = tele->getTelId();
if (m_filteredCentralTelegramIds.find(telegramId) != m_filteredCentralTelegramIds.end())
return false;
}
if (!m_filterCentralTelegrams.empty())
{
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection();
if (m_filterCentralTelegrams.find(direction) != m_filterCentralTelegrams.end())
return false;
}
break;
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra:
{
if (!m_filteredTetraTelegramIds.empty())
{
const int telegramId = tele->getTelId();
if (m_filteredTetraTelegramIds.find(telegramId) != m_filteredTetraTelegramIds.end())
return false;
}
if (!m_filterTetraTelegrams.empty())
{
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection();
if (m_filterTetraTelegrams.find(direction) != m_filterTetraTelegrams.end())
return false;
}
const N_CoPrtCnv::CoPrtCnvRadioTelegram *tetraTelegram = tele->getTetraTelegram();
if (tetraTelegram)
{
if (!m_filterTetraPDU.empty())
{
N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType = tetraTelegram->getPDU_Type();
if (m_filterTetraPDU.find(pduType) != m_filterTetraPDU.end())
return false;
}
if (m_bFilterLoginTelegrams)
{
if (tetraTelegram->isLoginTelegram())
return false;
}
if (m_bFilterFragmentedTelegrams)
{
if (!tetraTelegram->isLoginTelegram() && !tetraTelegram->isNormalTelegram())
return false;
}
}
break;
}
case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls:
if (!m_filteredWlsTelegramIds.empty())
{
const int telegramId = tele->getTelId();
if (m_filteredWlsTelegramIds.find(telegramId) != m_filteredWlsTelegramIds.end())
return false;
}
if (!m_filterWlsTelegrams.empty())
{
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection();
if (m_filterWlsTelegrams.find(direction) != m_filterWlsTelegrams.end())
return false;
}
break;
default:
break;
}
return true;
}
} // namespace N_LogView;
+114
View File
@@ -0,0 +1,114 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QAbstractTableModel>
#include <QtCore/QSharedPointer>
#include <QSortFilterProxyModel>
#include <set>
#include <CoPrtCnv/CoPrtCnvLogHeader.hpp>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include "LogViewTelegram.hpp"
namespace N_LogView
{
class ParticipantModel final : public QAbstractTableModel
{
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
void clearParticipants();
bool addUpdateParticipants(const QVector<int> &eqIds,
const QVector<int> &issis,
const QVector<int> &numberOfTelegrams);
protected:
void updateHeatMap() const;
protected:
// eqId , issi
QVector<QPair<int, int> > m_particpants;
// eqid, count telegrams
QHash<int, int> m_particpantMap;
// eqId, QColor for heatmap
mutable QHash<int, QColor> m_participantHeatmap;
};
class TelegramModel final : public QAbstractTableModel
{
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
void clearTelegrams();
void appendTelegrams(const QVector<QSharedPointer<LogViewTelegram> > &telegrams);
void appendTelegram(const QSharedPointer<LogViewTelegram> &telegram);
QSharedPointer<LogViewTelegram> telegram(int row) const;
protected:
QVector<QSharedPointer<LogViewTelegram> > m_telegrams;
};
class TelegramProxyModel final : public QSortFilterProxyModel
{
Q_OBJECT
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
void setFilterByEquipmentIds(bool bFilterByEquipmentIds);
void setAllowedEquipmentIds(const std::set<int> &allowedEquipmentIds);
void setFilteredCentralTelegramIds(const std::set<int> &filteredCentralTelegramIds);
void setFilteredTetraTelegramIds(const std::set<int> &filteredTetraTelegramIds);
void setFilteredWlsTelegramIds(const std::set<int> &filteredWlsTelegramIds);
void setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter);
void setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter);
void setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType, bool bFilter);
void setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter);
void setFilterTetraLogin(bool bFilter);
void setFilterTetraFragmented(bool bFilter);
QSharedPointer<LogViewTelegram> telegram(int row) const;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
protected:
std::set<int> m_allowedEquipmentIds;
std::set<int> m_filteredCentralTelegramIds;
std::set<int> m_filteredTetraTelegramIds;
std::set<int> m_filteredWlsTelegramIds;
bool m_bFilterByEquipmentIds = false;
bool m_bFilterLoginTelegrams = false;
bool m_bFilterFragmentedTelegrams = false;
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> m_filterCentralTelegrams;
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> m_filterTetraTelegrams;
std::set<N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol> m_filterWlsTelegrams;
std::set<N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type> m_filterTetraPDU;
};
} // namespace N_LogView
+182
View File
@@ -0,0 +1,182 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewOptionDialog.hpp"
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QDir>
#include <QGridLayout>
#include <QGroupBox>
#include <QFileDialog>
#include <QIntValidator>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
namespace N_LogView
{
// static member initialization
const QString LogViewOptionDialog::SPEC_FILES = tr("Spezifikations-Dateien (*.x)");
const QString LogViewOptionDialog::KRLOG_FILES = tr("Log-Dateien (*.krlog)");
const QLatin1String LogViewOptionDialog::SPEC_FILES_GROUP("SpecFiles");
const QLatin1String LogViewOptionDialog::DIR("Dir");
const QLatin1String LogViewOptionDialog::P0_FILENAME("Central2PrtCnv");
const QLatin1String LogViewOptionDialog::P5_FILENAME("PrtCnv2TETRA");
const QLatin1String LogViewOptionDialog::SERVER_GROUP("ServerPorts");
const QLatin1String LogViewOptionDialog::CENTRAL_PORT("Central");
const QLatin1String LogViewOptionDialog::TETRA_PORT("Tetra");
const QLatin1String LogViewOptionDialog::LOG_FILENAME("LogFilename");
const QLatin1String LogViewOptionDialog::INJECTION_GROUP("InjectionServer");
const QLatin1String LogViewOptionDialog::INJECTION_HOSTNAME("InjectionHostname");
const QLatin1String LogViewOptionDialog::INJECTION_PORT("InjectionPort");
// ---------------------------------------------------------------
LogViewOptionDialog::LogViewOptionDialog(QWidget* a_parent)
: QDialog(a_parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
// telegram specification files
m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP);
QGroupBox* groupBox = new QGroupBox(tr("Telegramm-Spezifikations-Dateien"), this);
layout->addWidget(groupBox);
QGridLayout* groupLayout = new QGridLayout();
QLabel* p0Label = new QLabel(tr("&Zentrale - Protokollkonverter"), this);
groupLayout->addWidget(p0Label, 0, 0, 1, 2);
QString defString = QCoreApplication::applicationDirPath() + QLatin1String("/training_area_telegrams.h");
m_P0Edit = new QLineEdit(m_Settings.value(P0_FILENAME, defString).toString(), this);
m_P0Edit->setMinimumWidth(400);
groupLayout->addWidget(m_P0Edit);
QPushButton* p0Browse = new QPushButton(tr("Browse"), this);
p0Label->setBuddy(p0Browse);
connect(p0Browse, &QPushButton::clicked, this, &LogViewOptionDialog::browseP0File);
groupLayout->addWidget(p0Browse, 1, 1);
QLabel* p5Label = new QLabel(tr("Protokollkonverter - &TETRA"), this);
groupLayout->addWidget(p5Label, 2, 0, 1, 2);
defString = QCoreApplication::applicationDirPath() + QLatin1String("/zsksxd_tetraForLogView.x");
m_P5Edit = new QLineEdit(m_Settings.value(P5_FILENAME, defString).toString(), this);
groupLayout->addWidget(m_P5Edit);
QPushButton* p5Browse = new QPushButton(tr("Browse"), this);
p5Label->setBuddy(p5Browse);
connect(p5Browse, &QPushButton::clicked, this, &LogViewOptionDialog::browseP5File);
groupLayout->addWidget(p5Browse, 3, 1);
groupBox->setLayout(groupLayout);
m_Settings.endGroup();
// injection
m_Settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP);
groupBox = new QGroupBox(tr("Telegram Injection Server"), this);
layout->addWidget(groupBox);
QGridLayout* injectLayout = new QGridLayout();
QLabel* injectPortLabel = new QLabel(tr("Port"), this);
injectLayout->addWidget(injectPortLabel, 1, 0);
m_InjectPortEdit = new QLineEdit(m_Settings.value(INJECTION_PORT).toString(), this);
QIntValidator* validator = new QIntValidator(1024, 65535, this);
m_InjectPortEdit->setValidator(validator);
injectLayout->addWidget(m_InjectPortEdit, 1, 1);
QLabel* injectHostnameLabel = new QLabel(tr("Hostname"), this);
injectLayout->addWidget(injectHostnameLabel, 0, 0);
m_InjectHostnameEdit = new QLineEdit(m_Settings.value(INJECTION_HOSTNAME).toString(), this);
injectLayout->addWidget(m_InjectHostnameEdit, 0, 1);
groupBox->setLayout(injectLayout);
m_Settings.endGroup();
// buttons
layout->addStretch();
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &LogViewOptionDialog::save);
connect(buttonBox, &QDialogButtonBox::rejected, this, &LogViewOptionDialog::reject);
layout->addWidget(buttonBox);
//setLayout(layout);
}
// ---------------------------------------------------------------
void LogViewOptionDialog::browseP0File()
{
QString newFilename = QFileDialog::getOpenFileName(this,
tr("Zentrale - Protokollkonverter Spezifikations-Datei"),
m_Settings.value(DIR).toString(),
tr("TrainingArea Telegram Headerdatei (training_area_telegrams.h)"));
if (!newFilename.isEmpty())
{
m_P0Edit->setText(newFilename);
QDir dir;
m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP);
m_Settings.setValue(DIR, dir.filePath(newFilename));
m_Settings.endGroup();
}
}
// ---------------------------------------------------------------
void LogViewOptionDialog::browseP5File()
{
QString newFilename = QFileDialog::getOpenFileName(this, tr("Protokollkonverter - TETRA Spezifikations-Datei"), m_Settings.value(DIR).toString(), SPEC_FILES);
if (!newFilename.isEmpty())
{
m_P5Edit->setText(newFilename);
QDir dir;
m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP);
m_Settings.setValue(DIR, dir.filePath(newFilename));
m_Settings.endGroup();
}
}
// ---------------------------------------------------------------
void LogViewOptionDialog::save()
{
uint32_t changedFlags = 0;
// check group wise for changes
// specification files
m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP);
QString string = m_Settings.value(P0_FILENAME).toString();
if ((string != m_P0Edit->text()) ||
(m_Settings.value(P5_FILENAME).toString() != m_P5Edit->text()))
{
m_Settings.setValue(P0_FILENAME, m_P0Edit->text());
m_Settings.setValue(P5_FILENAME, m_P5Edit->text());
changedFlags |= SpecFilesGroup;
}
m_Settings.endGroup();
// injection settings
m_Settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP);
if ((m_Settings.value(INJECTION_HOSTNAME).toString() != m_InjectHostnameEdit->text()) ||
(m_Settings.value(INJECTION_PORT).toString() != m_InjectPortEdit->text()))
{
m_Settings.setValue(INJECTION_HOSTNAME, m_InjectHostnameEdit->text());
m_Settings.setValue(INJECTION_PORT, m_InjectPortEdit->text());
changedFlags |= InjectionGroup;
}
m_Settings.endGroup();
emit settingsChanged(changedFlags);
accept();
}
} // namespace N_LogView
+84
View File
@@ -0,0 +1,84 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QDialog>
#include <QtCore/QSettings>
class QLineEdit;
namespace N_LogView
{
/**
* This class lets the user view and change the settings of the application
*
* @author alois.wismer
* @version 1.0
* @created 09-Mrz-2010 14:49:40
*/
class LogViewOptionDialog : public QDialog
{
Q_OBJECT
public:
enum SettingsChangedFlag {
SpecFilesGroup = 0x01,
ServerGroup = 0x02,
InjectionGroup = 0x04
};
static const QString KRLOG_FILES;
static const QLatin1String SPEC_FILES_GROUP;
static const QLatin1String P0_FILENAME;
static const QLatin1String P5_FILENAME;
static const QLatin1String SERVER_GROUP;
static const QLatin1String CENTRAL_PORT;
static const QLatin1String TETRA_PORT;
static const QLatin1String SIZE;
static const QLatin1String POS;
static const QLatin1String CENTRAL_IS_SERVER;
static const QLatin1String CENTRAL_HOSTNAME;
static const QLatin1String LOG_FILENAME;
static const QLatin1String INJECTION_GROUP;
static const QLatin1String INJECTION_HOSTNAME;
static const QLatin1String INJECTION_PORT;
/**
*
* @param a_parent a_parent
*/
explicit LogViewOptionDialog(QWidget* a_parent);
signals:
void settingsChanged(uint32_t changed); // bitfield of SettingsChangedFlag enum
protected:
static const QString SPEC_FILES;
static const QLatin1String DIR;
bool m_IsServer;
QLineEdit *m_P0Edit;
QLineEdit *m_P5Edit;
QSettings m_Settings;
QLineEdit *m_InjectHostnameEdit;
QLineEdit *m_InjectPortEdit;
protected slots:
void browseP0File();
void browseP5File();
void save();
};
}
+18
View File
@@ -0,0 +1,18 @@
<RCC>
<qresource prefix="/" >
<file>image/P2C.png</file>
<file>image/C2P.png</file>
<file>image/P2W.png</file>
<file>image/W2P.png</file>
<file>image/P2T.png</file>
<file>image/T2P.png</file>
<file>image/Central.png</file>
<file>image/Tetra.png</file>
<file>image/TNE.png</file>
<file>image/GreenLamp.png</file>
<file>image/RedLamp.png</file>
<file>image/YellowLamp.png</file>
<file>image/ShowSend.png</file>
<file>image/Wls.png</file>
</qresource>
</RCC>
+59
View File
@@ -0,0 +1,59 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewSpinBox.hpp"
#include "LogViewField.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewSpinBox::LogViewSpinBox(LogViewField* a_field, QWidget* a_parent, const int a_value)
: QSpinBox(a_parent)
, LogViewWidget(a_field, this, a_parent, false)
{
// set range
uint16_t maxArraySize = a_field->maxArraySize();
setRange(0, maxArraySize);
// set the actual value
setValue(a_value);
// set tooltip-text
setToolTip(tr("<nobr>Wertebereich: 0..%1</nobr>").arg(maxArraySize));
// connect
connect(this, &LogViewSpinBox::editingFinished,
this, &LogViewSpinBox::finishEditing);
}
// ---------------------------------------------------------------
void LogViewSpinBox::finishEditing()
{
emit valueEditingFinished(text().toInt());
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewSpinBox::saveContent(LogViewTelegram* a_telegram)
{
Q_UNUSED(a_telegram);
// not yet implemented
return false;
}
} // namespace N_LogView
+60
View File
@@ -0,0 +1,60 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QSpinBox>
#include "LogViewWidget.hpp"
namespace N_LogView
{
/**
* Used for changing size of dyn. arrays.
*
* @author alois.wismer
* @version 1.0
* @created 25-Mai-2010 10:39:45
*/
class LogViewSpinBox : public QSpinBox, public LogViewWidget
{
Q_OBJECT
public:
/**
*
* @param a_field
* @param a_parent
* @param a_value
*/
LogViewSpinBox(LogViewField* a_field, QWidget* a_parent, const int a_value);
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
protected slots:
void finishEditing();
signals:
/**
*
* @param a_newValue
*/
void valueEditingFinished(int a_newValue);
};
}
+139
View File
@@ -0,0 +1,139 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewTabWidget.hpp"
#include <QFrame>
#include <QGridLayout>
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewTelegramDialog.hpp"
#include "LogViewSpinBox.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewTetraTelegramsParser.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewTabWidget::LogViewTabWidget(LogViewField* a_field, LogViewTelegramDialog* a_parent, LogViewSpinBox* a_spinBox)
: QTabWidget(a_parent)
, LogViewWidget(a_field, this, a_parent, false)
, m_TelegramDialog(a_parent)
, m_SpinBox(a_spinBox)
{
setVisible(false);
}
// ---------------------------------------------------------------
void LogViewTabWidget::changeSize(const int a_newSize)
{
// add new tabs
for (int i = count(); i < a_newSize; i++)
addTab(m_Field, true, i);
// remove old tabs
while (count() > a_newSize)
{
QStringList path = m_Field->jsonPath();
path += QStringLiteral("index: %1").arg(count() - 1);
m_TelegramDialog->removeItemsFromEditInfoList(path);
removeTab(count() - 1);
}
while (m_Field->childCount() > a_newSize)
m_Field->removeLastChild();
setVisible(a_newSize > 0);
m_TelegramDialog->makePretty(); // fixme: funktioniert so nicht, muss als signal realisiert werden
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewTabWidget::saveContent(LogViewTelegram* a_telegram)
{
if (a_telegram->isJsonTelegram())
return true;
// if m_SpinBox is NULL, we have a static array => no size has to be stored
if (m_SpinBox)
{
if (!isValid())
return false;
a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, count());
}
return true;
}
// ---------------------------------------------------------------
void LogViewTabWidget::addTab(LogViewField* a_field, const bool a_isEmpty, int arrayIdx)
{
if (arrayIdx < 0)
{
WARNING_LOG(m_logger) << "Invalid array index given: " << arrayIdx;
return;
}
QFrame *frame = new QFrame;
QGridLayout *box = new QGridLayout(frame);
QTabWidget::addTab(frame, QStringLiteral("%1 %2").arg(a_field->cleanName()).arg(count()+1));
if (a_isEmpty)
a_field->setHasContent(false);
auto *childTree = a_field->child(arrayIdx);
while (!childTree)
{
const auto *first = a_field->child(0);
if (first)
{
LogViewField *fNew = first->clone(arrayIdx);
a_field->addChild(fNew);
childTree = a_field->child(arrayIdx);
}
else
{
LogViewTetraTelegramsParser *p = LogViewTelegram::jsonParser();
const StructInformation si = p->structFromType(a_field->type());
if (si.type != a_field->type())
{
WARNING_LOG(m_logger) << "Could not find type '" << a_field->type() << "' - can not add substructure";
return;
}
LogViewField *tc = new LogViewField(a_field->name() + QStringLiteral("TabChild"), LogViewField::e_FieldKindTabChild, a_field->xdrElement());
tc->setJsonPath(a_field->jsonPath());
a_field->addChild(tc);
const QString path(QStringLiteral("index: %1"));
LogViewTelegram::addFieldTreeStruct(QJsonObject(), tc, si, path.arg(arrayIdx), m_logger);
childTree = a_field->child(arrayIdx);
}
}
m_TelegramDialog->showTree(childTree, box);
// todo: sind nach dem dyn. array noch weitere Felder, so wird addTab nicht richtig funktionieren, weil die
// neuen Felder des Tabs am Ende von m_EditInfoList hinzugefügt werden => diese müssen mittendrin (an der richtigen
// position) eingefügt werden.
// update spinbox
if (m_SpinBox)
{
int spinValue = m_SpinBox->value();
if (spinValue < count())
m_SpinBox->setValue(count());
}
setVisible(true);
}
} // namespace N_LogView
+56
View File
@@ -0,0 +1,56 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QTabWidget>
#include "LogViewWidget.hpp"
namespace N_LogView
{
class LogViewTelegramDialog;
class LogViewSpinBox;
/**
* Used for arrays of structures
*
* @author alois.wismer
* @version 1.0
* @created 26-Mai-2010 17:12:30
*/
class LogViewTabWidget : public QTabWidget, public LogViewWidget
{
Q_OBJECT
public:
LogViewTabWidget(LogViewField* a_field, LogViewTelegramDialog* a_parent, LogViewSpinBox* a_spinBox);
bool saveContent(LogViewTelegram* a_telegram) override;
void addTab(LogViewField* a_field, const bool a_isEmpty, int arrayIdx);
public slots:
/**
*
* @param a_newSize
*/
void changeSize(const int a_newSize);
protected:
LogViewTelegramDialog* m_TelegramDialog;
LogViewSpinBox* m_SpinBox;
};
}
+311
View File
@@ -0,0 +1,311 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewTableWidget.hpp"
#include "LogViewField.hpp"
#include <QHeaderView>
#include <QJsonArray>
#include "LogViewXdrStandardType.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewEnumEdit.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewTableWidget::LogViewTableWidget(LogViewField* a_field, QWidget* a_parent, const bool a_readonly)
: QTableWidget(0, 2, a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
, m_IsFloat(false)
, m_IsEnum(false)
{
switch (m_Field->xdrElement()->getKind())
{
case LogViewXdrElement::e_KindEnum:
m_IsEnum = true;
break;
default:
m_IsFloat = LogViewXdrStandardType::e_Float == static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement())->getValueKind();
}
if (!m_IsFloat)
setColumnCount(3);
if (m_IsEnum)
setColumnCount(1);
setHorizontalHeaderItem(0, new QTableWidgetItem(m_IsEnum ? tr("Enum") : tr("Dez")));
if (!m_IsEnum)
{
setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Hex")));
if (!m_IsFloat)
{
setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Bin")));
}
}
setAlternatingRowColors(true);
// make pretty
// horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);
updateToolTip();
// for debugging only
// INFO_LOG(m_logger) << "type=" << static_cast<const LogViewXdrStandardType*>(a_field->getXdrElement())->getValueKind();
// INFO_LOG(m_logger) << "name=" << static_cast<const LogViewXdrStandardType*>(a_field->getXdrElement())->getName().toStdString();
// a_field->getXdrElement()->dump();
// fill in the values
// fixme: implementiere den Fall isHasContent() false
int nbrOfRows = a_field->valueListSize();
setRowCount(nbrOfRows);
for (int i = 0; i < nbrOfRows; i++)
changeRow(i, a_field->value(i));
makePretty();
// connect signals
connect(this, &LogViewTableWidget::itemChanged,
this, &LogViewTableWidget::checkAndOvertakeContent);
}
// ---------------------------------------------------------------
void LogViewTableWidget::changeSize(const int a_newSize)
{
setRowCount(a_newSize);
disconnect(this, &LogViewTableWidget::itemChanged,
this, &LogViewTableWidget::checkAndOvertakeContent);
// check and set the new fields
for (int i = 0; i < a_newSize; i++)
changeRow(i, QLatin1String("0"));
connect(this, &LogViewTableWidget::itemChanged,
this, &LogViewTableWidget::checkAndOvertakeContent);
makePretty();
m_Valid = true;
}
// ---------------------------------------------------------------
void LogViewTableWidget::changeRow(const int a_rowIndex, const QString& a_value)
{
// INFO_LOG(m_logger) << "a_rowIndex=" << a_rowIndex << " a_value=" << a_value.toStdString();
if (m_IsEnum)
{
// enum
QWidget* enumItem = cellWidget(a_rowIndex, 0);
if (!enumItem)
setCellWidget(a_rowIndex, 0, new LogViewEnumEdit(m_Field, this, m_Readonly, a_rowIndex));
}
else
{
QFont font;
font.setStyleHint(QFont::TypeWriter);
font.setFamily(QString());
// decimal
QTableWidgetItem* decItem = item(a_rowIndex, 0);
if (!decItem)
{
decItem = new QTableWidgetItem();
//decItem->setData(Qt::DisplayRole, 0);
decItem->setText(a_value);
decItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
if (!m_Readonly)
{
decItem->setFlags(decItem->flags() | Qt::ItemIsEditable);
}
decItem->setFont(font);
decItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(a_rowIndex, 0, decItem);
}
// hexadecimal
QTableWidgetItem* hexItem = item(a_rowIndex, 1);
if (!hexItem)
{
hexItem = new QTableWidgetItem();
hexItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
hexItem->setFont(font);
hexItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(a_rowIndex, 1, hexItem);
}
// binary
if (!m_IsFloat)
{
QTableWidgetItem* binItem = item(a_rowIndex, 2);
if (!binItem)
{
binItem = new QTableWidgetItem();
binItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
binItem->setFont(font);
binItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(a_rowIndex, 2, binItem);
}
}
// set the values
checkAndOvertakeContent(decItem);
makePretty();
}
}
// ---------------------------------------------------------------
void LogViewTableWidget::checkAndOvertakeContent(QTableWidgetItem* a_changedItem)
{
if (a_changedItem->column() != 0) return;
int row = a_changedItem->row();
QString text = a_changedItem->text();
bool ok;
int64_t intValue = 0;
double floatValue = 0.0;
// get the calculated and checked value
if (m_IsFloat)
floatValue = getFloat(text, (uint64_t&)intValue, ok, true);
else
intValue = getInteger(text, ok);
// handle errors
if (!ok)
{
setFocus();
// selectAll();
setCurrentCell(row, 0); // todo: funktioniert nicht
return;
}
// set the decimal value
QTableWidgetItem* decField = item(row, 0);
if (decField) decField->setText(QString::number(m_IsFloat ? floatValue : intValue));
// set the hex value
QTableWidgetItem* hexField = item(row, 1);
if (hexField) hexField->setText(toHex(intValue));
// set the binary value
if (!m_IsFloat)
{
QTableWidgetItem* binField = item(row, 2);
if (binField) binField->setText(toBin(intValue));
}
}
// ---------------------------------------------------------------
void LogViewTableWidget::makePretty()
{
//horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);
resizeColumnsToContents();
resizeRowsToContents();
// set the height of table-widget
//// QWidget* cellWdg = tableWidget->cellWidget(0, 0);
// int showRows = 7;
// if (m_Field->getValueListSize() < (showRows-1))
// {
// showRows = m_Field->getValueListSize()+1;
// setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// }
// else
// {
// setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
// }
// setFixedHeight(showRows*tableWidget->rowHeight(0));
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewTableWidget::saveContent(LogViewTelegram* a_telegram)
{
if (!isValid())
return false;
if (a_telegram->isJsonTelegram())
{
if (m_Field->kind() == LogViewField::e_FieldKindPodArray)
{
QJsonArray arr;
for (int i = 0; i < rowCount(); ++i)
arr += item(i, 0)->text().toInt();
a_telegram->setJsonValue(m_Field->jsonPath(), arr);
}
else
{
QString value;
value.reserve(rowCount() * 2);
for (int i = 0; i < rowCount(); ++i)
{
int val = item(i, 0)->text().toInt();
value += QStringLiteral("%1").arg(val, 2, 16, QLatin1Char('0'));
}
a_telegram->setJsonValue(m_Field->jsonPath(), value);
}
return true;
}
uint16_t arraySize;
if (m_Field->isDynamicArray())
{
arraySize = rowCount();
a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, arraySize);
// fixme: bei vielen Telegrammen muss Länge auf die Länge des Textes gesetzt werden. Dies kann nicht automatisch gemacht werden. Aber vielleicht kann man schauen, ob vor dem dyn. Array ein Feld Länge vorkommt, oder hartcodieren, oder konfigurierbaren
}
else
{
// todo: teste mit opaque[]
arraySize = m_Field->maxArraySize();
}
// copy the data
INFO_LOG(m_logger) << "arraySize=" << arraySize;
for (int i = 0; i < arraySize; i++)
{
if (m_IsEnum)
{
LogViewEnumEdit *enumEdit = dynamic_cast<LogViewEnumEdit*>(cellWidget(i,0));
enumEdit->saveContent(a_telegram);
}
else
{
uint16_t size = getSize();
QString text = item(i, 0)->text();
if (!m_IsFloat)
{
a_telegram->setUIntX(size, text.toULong());
}
else
{
const LogViewXdrStandardType *stdType = static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement());
LogViewXdrStandardType::E_ByteOrder byteOrder = stdType->getByteOrder();
uint64_t hex;
getFloat(text, hex, m_Valid);
a_telegram->setUIntX(size, hex, byteOrder);
}
}
}
return true;
}
} // namespace N_LogView
+55
View File
@@ -0,0 +1,55 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QTableWidget>
#include "LogViewWidget.hpp"
namespace N_LogView
{
/**
* Used for arrays of data (opaque)
*
* @author alois.wismer
* @version 1.0
* @created 25-Mai-2010 09:34:24
*/
class LogViewTableWidget : public QTableWidget, public LogViewWidget
{
Q_OBJECT
public:
LogViewTableWidget(LogViewField* a_field, QWidget* a_parent, const bool a_readonly);
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
public slots:
void changeSize(const int a_newSize);
protected:
void changeRow(const int a_rowIndex, const QString& a_value);
void makePretty();
protected slots:
void checkAndOvertakeContent(QTableWidgetItem* a_changedItem);
private:
bool m_IsFloat;
bool m_IsEnum;
};
}
File diff suppressed because it is too large. Load diff
+487
View File
@@ -0,0 +1,487 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewXdrStandardType.hpp"
#include "LogViewField.hpp"
#include <CoPrtCnv/CoPrtCnvLogHeader.hpp>
#include <QIcon>
#include <QJsonObject>
#include <QJsonDocument>
namespace N_CoPrtCnv
{
class CoPrtCnvRadioTelegram;
}
namespace N_LogView
{
struct StructInformation;
struct MemberInformation;
class LogViewTetraTelegramsParser;
class LogViewXdrParser;
class LogViewXdrType;
/**
* The header and the data of a logged or a edited telegram.
*
* Writing telegrams:
* 1. allocate a telegram with the constructor LogViewTelegram(N_CoPrtCnv::
* CoPrtCnvLogHeader::e_DestProtocolCentral, telegramId)
* 2. prepare with resetOffset()
* 3. write data with setUIntX()
* 4. finish with setNewSize();
*
* @author alois.wismer
* @version 1.0
* @created 04-Feb-2010 13:15:43
*/
class LogViewTelegram final
{
public:
/**
* @author alois.wismer
* @version 1.0
* @created 12-Mrz-2010 11:04:14
*/
enum E_Validity
{
e_NotYetEvaluated,
e_Valid,
e_Invalid
};
/**
* @author alois.wismer
* @version 1.0
* @created 05-Mai-2010 09:07:22
*/
enum E_Column
{
e_ColName,
e_ColGpsTime,
e_ColLogTime,
e_ColJsonData,
e_ColMax
};
~LogViewTelegram();
/**
* The size of the field which defines the size of the dyn. array for central-
* telegrams
*/
static const uint16_t SIZE_CENTRAL_DYN_ARRAY_SIZE;
/**
* Copy ctor
*/
LogViewTelegram(const LogViewTelegram &o);
// no assignment (needed)
LogViewTelegram &operator=(const LogViewTelegram &o) = delete;
/**
* Constructor for new telegrams (only receive central-telegrams are allowd),
* which will be edited
*
* @param a_destination
* @param a_telId
*/
LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination,
int telegramId);
/**
* Constructor for existing telegrams
*
* @param a_destination
* @param a_unixTime
* @param a_telegramData
* @param a_telegramSize
*/
LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination,
const quint64 a_unixTime,
const QByteArray &a_telegramData);
/**
* 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.
*
* @param a_size
* @param a_value
* @param a_byteOrder
*/
void setUIntX(const uint8_t a_size,
quint64 a_value,
const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian);
/**
* 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.
*
* @param a_offset
* @param a_data
*/
bool setData(const uint16_t a_offset, const uint8_t a_data);
/**
* Returns the log-time of the telegram
*/
quint64 getLogTime() const { return m_LogTime; }
quint64 getLogTimeMsec() const;
/**
* Returns the log-time of the telegram as pretty formatted text
*/
QString getLogTimeText() const;
QString getDestinationText() const;
/**
* Returns the gps-time of the telegram
*/
quint64 getGpsTime() const { return m_GpsTime; }
/**
* 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 getGpsTimeText() const;
uint32_t getISSI() const { return m_ISSI; }
int getParticipantId() const { return m_ParticipantId; }
/**
* 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 getDelay() const;
/**
* 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.
*
* @param a_col
*/
QString getToolTipText(const E_Column a_col);
void resetOffset();
LogViewField* getFieldTree();
void dump() const;
QString getStructName() const;
bool isValid();
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getDestination() const { return m_Destination; }
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getDirection() const;
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getProtocol() const { return m_Protocol; }
int getTelId() const { return m_TelId; }
QIcon getIcon() const;
bool isJsonTelegram() const { return N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Protocol; }
void clearJsonData() { m_json.remove(QStringLiteral("data")); }
void rebuildJsonString() { if (!m_json.isEmpty()) m_data.clear(); }
void setJsonValue(const QStringList &path, const QJsonValue &val);
QJsonObject jsonData() const { return m_json; }
void updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonObject &obj);
void updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonArray &arr);
const N_CoPrtCnv::CoPrtCnvRadioTelegram* getTetraTelegram() const;
static LogViewTetraTelegramsParser *jsonParser();
static LogViewXdrParser *tetraParser();
QByteArray getData(QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Compact) const;
/**
* The time to wait after sending this telegram in milliseconds.
*/
uint32_t getWaitTime() const { return m_WaitTime; }
/**
* The time to wait after sending this telegram in milliseconds.
*
* @param newVal
*/
void setWaitTime(uint32_t newVal) { m_WaitTime = newVal; }
/**
* The name of the telegram, shown in edit-list
*/
QString getName() const { return m_Name; }
/**
* The name of the telegram, shown in edit-list
*
* @param newVal
*/
void setName(const QString &newVal) { m_Name = newVal; }
void setNextFieldAsGpsTimeField();
QVector<uint16_t> getGpsTimeField() const { return m_GpsFieldOffset; }
void setGpsTimeField(const QVector<uint16_t> &gpsFieldOffset) { m_GpsFieldOffset = gpsFieldOffset; }
void actualizeGpsTime();
/**
* Create the tooltip text for the column 'Name'
*/
void createToolTipTextForColName();
static double xdrToDouble(quint64 in);
static float xdrToFloat(uint32_t in);
static quint64 doubleToXdr(double in);
static uint32_t floatToXdr(float in);
protected:
/**
* The name of the telegram, shown in edit-list
*/
QString m_Name;
/**
* The tooltip text for caching purposes
*/
std::vector<QString> m_ToolTipText;
/**
* The time to wait after sending this telegram in milliseconds.
*/
uint32_t m_WaitTime;
int m_ParticipantId;
/**
* The ISSI of TETRA-Protocol
*/
uint32_t m_ISSI;
/**
* The allocated size of m_Data. (Used for optimizing of speed)
*/
int m_AllocatedSize;
static const LogViewXdrParser* m_Parser;
uint16_t m_ActOffset;
QVector<uint16_t> m_GpsFieldOffset;
int m_TelId;
/**
* used for dyn. array in TETRA-Protocol
*/
uint32_t m_LastUnsignedValue;
/**
* This value will be used for the dyn-array-method e_DynArrayMsgLength. This
* value will be subtracted from the message-length to get the size of the dynamic
* array.
*/
uint16_t m_MaxArraySize;
static const uint16_t START_OFFSET_CENTRAL;
static const uint16_t POS_CENTRAL_COUNTER;
static const uint16_t POS_CENTRAL_TELID;
static const uint16_t POS_CENTRAL_PARTICIPANTID;
static const uint16_t START_OFFSET_TETRA_REGISTER;
static const uint16_t START_OFFSET_TETRA_AIRLOAD;
static const uint16_t START_OFFSET_TETRA_DATA;
static const uint16_t START_OFFSET_TETRA_LOGIN;
static const uint16_t START_OFFSET_TETRA_FRAGMENT;
LogViewXdrStandardType::E_DynArraySizeMethod m_DynArraySizeMethod;
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol m_Destination;
E_Validity m_Validity;
N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol m_Protocol;
quint64 m_LogTime;
mutable QString m_logTimeText;
quint64 m_GpsTime;
QByteArray m_data;
QJsonObject m_json;
N_CoPrtCnv::CoPrtCnvRadioTelegram *m_TetraTelegram;
LogViewField *getFieldTree(const QString& a_type, const QString& a_name,
uint16_t a_arraySize, const LogViewXdrType* a_parentElement = nullptr,
const bool a_hasContent = true);
LogViewField *getFieldTreeJson(const QJsonValue &data,
const QString &name,
const StructInformation &si,
const QStringList &objectPathBase);
static void addFieldTreeStruct(const QJsonObject &parentObject,
LogViewField *parent,
const StructInformation &si,
const QString &objectNameArrayHint,
NGL::INGLLogger &logger);
static void addFieldTreeJsonString(const QJsonValue &val,
LogViewField *parent,
const QString &name,
bool isBinary,
const QString &objectNameArrayHint,
LogViewField::E_FieldKind fieldKind,
NGL::INGLLogger &logger);
static void addFieldTreeJsonPod(const QJsonValue &val,
LogViewField *parent,
const QString &name,
const QString &type,
const QString &objectNameArrayHint,
LogViewField::E_FieldKind fieldKind,
NGL::INGLLogger &logger);
static void addFieldTreeJsonEnum(const QJsonValue &val,
LogViewField *parent,
const QString &name,
const QString &type,
const QString &objectNameArrayHint,
LogViewField::E_FieldKind fieldKind,
NGL::INGLLogger &logger);
static QString typeFromStructInformation(const StructInformation &si, const QString &name);
static MemberInformation memberFromStructInformation(const StructInformation &si, const QString &name);
/**
*
* @param a_offset
*/
uint16_t getUInt16(const uint16_t a_offset) const;
/**
*
* @param a_offset
*/
uint32_t getUInt32(const uint16_t a_offset) const;
/**
*
* @param a_offset
*/
int32_t getInt32(const uint16_t a_offset) const;
/**
*
* @param a_offset
* @param a_size
* @param a_byteOrder
*/
quint64 getUIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian) const;
/**
*
* @param a_offset
* @param a_size
* @param a_byteOrder
*/
int32_t getSIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian) const;
/**
*
* @param a_offset
* @param a_size
*/
char getChar(const uint16_t a_offset, const uint8_t a_size) const;
/**
*
* @param a_standardType
* @param a_offset
* @param a_arraySize
*/
LogViewField* getContent(const LogViewXdrStandardType* a_standardType, uint16_t& a_offset, const uint16_t a_arraySize);
/**
*
* @param a_xdrType
*/
bool isScalar(const LogViewXdrType* a_xdrType) const;
/**
*
* @param a_errorText
* @param a_title
*/
void showMessageBox(const QString& a_errorText, const QString& a_title = QObject::tr("Invalid telegram")) const;
/**
*
* @param a_offset
*/
uint16_t getDynArraySize(uint16_t& a_offset) const;
/**
*
* @param a_name
* @param a_value
*/
static QString formatToolTipLine(const QString& a_name, const uint32_t a_value)
{
return formatToolTipLine(a_name, QString::number(a_value), a_value);
}
/**
*
* @param a_name
* @param a_text
* @param a_value
*/
static QString formatToolTipLine(const QString& a_name, const QString& a_text, const uint32_t a_value);
static QString formatToolTipLine(const QString& a_name, const std::string& a_text, const uint32_t a_value)
{
return formatToolTipLine(a_name, QString::fromStdString(a_text), a_value);
}
/**
* returns the data-byte at a_offset. Returns 0 if a_offset is outside of range.
*
* @param a_offset
*/
uint8_t getData(const uint16_t a_offset) const;
private:
/**
* The logger object
*/
NGL::INGLLogger &m_logger;
friend class LogViewTabWidget;
};
}
+497
View File
@@ -0,0 +1,497 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewTelegramDialog.hpp"
#include "LogViewTelegram.hpp"
#include <QApplication>
#include <QDesktopWidget>
#include <QDir>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QSettings>
#include <QScrollArea>
#include <QTextEdit>
#include <QVBoxLayout>
#include "LogViewXdrElement.hpp"
#include "LogViewField.hpp"
#include "IntegerCalculator.hpp"
#include "LogViewBooleanEdit.hpp"
#include "LogViewTextEdit.hpp"
#include "LogViewValueEdit.hpp"
#include "LogViewEnumEdit.hpp"
#include "LogViewDateTimeEdit.hpp"
#include "LogViewSpinBox.hpp"
#include "LogViewTableWidget.hpp"
#include "LogViewTabWidget.hpp"
namespace N_LogView
{
// todo:
// - feld einfärben wenn geändert, wenn falsch
// - mache hartcodierte oder konfigurierbare ranges für spezielle Werte wie GPS-Position: signed 24-bit
// ---------------------------------------------------------------
LogViewTelegramDialog::LogViewTelegramDialog(QWidget *a_parent, const bool a_readonly)
: QDialog(a_parent)
, m_ReadOnly(a_readonly)
, m_logger(getLogger("LogViewTelegramDialog"))
{
setAttribute(Qt::WA_DeleteOnClose);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showDialog(const QSharedPointer<LogViewTelegram> &a_telegram)
{
delete layout();
hide();
m_Telegram = a_telegram;
a_telegram->dump();
m_fieldTree.reset(a_telegram->getFieldTree());
if (m_fieldTree)
{
QGridLayout *dialogLayout = new QGridLayout;
if (!m_ReadOnly)
{
// edit wait-time
QLabel *waitTimeLabel = new QLabel(tr("Wartezeit [ms]"), this);
dialogLayout->addWidget(waitTimeLabel, dialogLayout->rowCount(), 0);
m_WaitTimeEdit = new QLineEdit(QString::number(a_telegram->getWaitTime()), this);
dialogLayout->addWidget(m_WaitTimeEdit, dialogLayout->rowCount() - 1, 1);
// edit name
QLabel *nameLabel = new QLabel(tr("Name"), this);
dialogLayout->addWidget(nameLabel, dialogLayout->rowCount(), 0);
m_NameEdit = new QLineEdit(a_telegram->getName(), this);
dialogLayout->addWidget(m_NameEdit, dialogLayout->rowCount() - 1, 1);
QFrame *f = new QFrame(this);
f->setFrameShape(QFrame::HLine);
f->setFrameShadow(QFrame::Sunken);
dialogLayout->addWidget(f, dialogLayout->rowCount(), 0, 1, 2);
}
//INFO_LOG(m_logger) << "--------------- create dialog " << fieldTree->getName().toStdString() << "--------------";
//m_fieldTree->dump();
showTree(m_fieldTree.data(), dialogLayout);
if (this->findChild<LogViewTableWidget *>() == nullptr)
dialogLayout->setRowStretch(dialogLayout->rowCount(), 1);
// build the dialog
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// make dialog scrollable
m_contentsWidget = new QWidget;
m_contentsWidget->setLayout(dialogLayout);
m_ScrollArea = new QScrollArea(this);
m_ScrollArea->setWidget(m_contentsWidget);
m_ScrollArea->setWidgetResizable(true);
mainLayout->addWidget(m_ScrollArea);
// buttons
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addStretch();
showButtons(btnLayout);
mainLayout->addLayout(btnLayout);
setWindowTitle(m_fieldTree->cleanName() + QStringLiteral(" (%1)").arg(a_telegram->getTelId()));
setModal(true);
show();
makePretty();
}
else
showDataDump(a_telegram, true);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showDataDump(const QSharedPointer<LogViewTelegram> &a_telegram, bool showErrorMessage)
{
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QLabel(tr("Telegramm-Dump")));
if (showErrorMessage)
// show error-message in dialog
layout->addWidget(new QLabel(tr("Konnte Dialog basierend auf Struktur \'%1\' nicht generieren!").arg(a_telegram->getStructName())));
else
layout->addWidget(new QLabel(tr("HexData from \'%1\' - telegram:").arg(a_telegram->getName())));
// generate the telegram-dump
QString theDump = QLatin1String("<code>");
const QByteArray &data = a_telegram->getData();
for (int i = 0; i < data.size(); i++)
{
if (0 == (i % 8))
theDump += QStringLiteral("%1:").arg(i, 4, 16, QLatin1Char('0'));
theDump += QStringLiteral(" %1").arg(static_cast<unsigned char>(data[i]), 2, 16, QLatin1Char('0'));
if (7 == (i % 8))
theDump += QLatin1String("<br>");
}
theDump += QLatin1String("</code>");
QTextEdit *telegramDump = new QTextEdit(theDump);
layout->addWidget(telegramDump);
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen"));
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addStretch();
btnLayout->addWidget(btnClose);
layout->addLayout(btnLayout);
connect(btnClose, &QPushButton::clicked,
this, &LogViewTelegramDialog::reject);
setLayout(layout);
show();
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::makePretty()
{
return;
// set the size and position of dialog
int sbWidth = m_ScrollArea->width() - m_ScrollArea->viewport()->width();
int wDiff = m_contentsWidget->width() - m_ScrollArea->width();
int hDiff = m_contentsWidget->height() - m_ScrollArea->viewport()->height();
const QRect screenSize = QApplication::desktop()->screenGeometry(this);
//QRect winGeo = geometry();
int newWidth = std::min(width() + wDiff + sbWidth, screenSize.width() * 9 / 10);
int newHeight = std::min(height() + hDiff, screenSize.height() * 9 / 10);
//setGeometry(winGeo);
//QSize size = settings.value(SIZE, sizeHint()).toSize();
resize(QSize(newWidth, newHeight));
//move(settings.value(POS, QPoint(0, 0)).toPoint());
// --------------------------------------------------------------------
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showTree(LogViewField *a_fieldTree, QGridLayout *a_box)
{
int i = 0;
while (LogViewField *child = a_fieldTree->child(i++))
{
if (!a_fieldTree->hasContent())
child->setHasContent(false);
switch (child->kind())
{
case LogViewField::e_FieldKindBorder:
{
QGroupBox *groupBox = new QGroupBox(child->cleanName());
QGridLayout *actBox = new QGridLayout(groupBox);
a_box->addWidget(groupBox, a_box->rowCount(), 0, 1, 2);
showTree(child, actBox);
break;
}
case LogViewField::e_FieldKindTab:
showTab(child, a_box);
break;
case LogViewField::e_FieldKindTabChild:
{
QWidget *widget = new QWidget;
widget->setContentsMargins(QMargins());
QGridLayout *actBox = new QGridLayout(widget);
a_box->addWidget(widget, a_box->rowCount(), 0, 1, 2);
showTree(child, actBox);
break;
}
case LogViewField::e_FieldKindEdit:
case LogViewField::e_FieldKindPodArray:
case LogViewField::e_FieldKindPodArrayChild:
showEditField(child, a_box);
break;
}
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::fillTelegram(LogViewTelegram *a_telegram)
{
INFO_LOG(m_logger) << "******************************************";
// check whether all changed values are valid
// ------------------------------------------
for (const auto ptr : qAsConst(m_EditInfoList))
{
if (!ptr->isValid())
{
INFO_LOG(m_logger) << ptr->field()->name() << " is invalid";
return; // abort when a value is not vaild
}
}
// now save the values
// -------------------
a_telegram->resetOffset();
a_telegram->clearJsonData();
for (auto ptr : qAsConst(m_EditInfoList))
{
if (!ptr->saveContent(a_telegram))
{
QMessageBox::warning(this, tr("Error while saving telegram"),
tr("Found an invalid value - the telegram may be not saved correctly"));
}
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::saveTelegram()
{
fillTelegram(m_Telegram.data());
// save wait-time and name
N_SST::IntegerCalculator calculator;
N_SST::IntegerCalculator::E_Error error;
m_Telegram->setWaitTime(calculator.calc(m_WaitTimeEdit->text().toStdString(), error));
m_Telegram->setName(m_NameEdit->text());
accept();
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::sendCurrentTelegram()
{
emit sendTelegram(m_Telegram);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showButtons(QLayout *a_layout)
{
if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Telegram->getProtocol())
{
QPushButton *btnSend = new QPushButton(QIcon(QLatin1String(":icons/16x16/mail-send.png")), tr("&Send"));
btnSend->setEnabled(true); // TODO: Status ob wirklich möglich ggf. überprüfen
connect(btnSend, &QPushButton::clicked, this, &LogViewTelegramDialog::sendCurrentTelegram);
a_layout->addWidget(btnSend);
}
if (m_ReadOnly)
{
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen"));
connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject);
a_layout->addWidget(btnClose);
}
else
{
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Abbrechen"));
connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject);
a_layout->addWidget(btnClose);
QPushButton *btnOk = new QPushButton(QIcon(QLatin1String(":icons/16x16/dialog-ok-apply.png")), tr("&OK"));
btnOk->setDefault(true);
// fixme: absturz, wenn feld ungültiger wert enthält und ok gedrückt wird
connect(btnOk, &QPushButton::clicked, this, &LogViewTelegramDialog::saveTelegram);
a_layout->addWidget(btnOk);
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showEditField(LogViewField *a_logViewField, QGridLayout *a_box)
{
// INFO_LOG(m_logger) << a_logViewField->getName() <<
// << " a_logViewField->getValueListSize()=" << a_logViewField->getValueListSize()
// << " a_logViewField->isIsDynamicArray()=" << a_logViewField->isIsDynamicArray()
// << " a_logViewField->getValue(0)=" << a_logViewField->getValue(0).toStdString()
// << " a_logViewField->getXdrElement())->getValueKind()=" << (int)(static_cast<const LogViewXdrStandardType*>(a_logViewField->getXdrElement())->getValueKind())
// ;
switch (a_logViewField->valueListSize())
{
case 1:
// 1 field (single or multi-line)
if (m_ReadOnly || !a_logViewField->isDynamicArray() || (LogViewXdrStandardType::e_Character == static_cast<const LogViewXdrStandardType *>(a_logViewField->xdrElement())->getValueKind()))
{
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
LogViewWidget *valueWidget = nullptr;
//QString value = a_logViewField->getValue(0);
// if (-1 == value.indexOf("<br>") && value.length() < 80)
{
// single line
// -----------
if (LogViewXdrElement::e_KindEnum == a_logViewField->xdrElement()->getKind())
{
// enum => combobox
// ----------------
valueWidget = new LogViewEnumEdit(a_logViewField, this, m_ReadOnly, 0);
}
else
{
if (a_logViewField->isDateTimeField() || a_logViewField->isMSecsField())
{
// date-time-field
// ---------------
valueWidget = new LogViewDateTimeEdit(a_logViewField, this, m_ReadOnly);
}
else
{
switch (static_cast<const LogViewXdrStandardType *>(a_logViewField->xdrElement())->getValueKind())
{
case LogViewXdrStandardType::e_Boolean:
valueWidget = new LogViewBooleanEdit(a_logViewField, this, m_ReadOnly);
break;
case LogViewXdrStandardType::e_Signed:
case LogViewXdrStandardType::e_Unsigned:
case LogViewXdrStandardType::e_Float:
case LogViewXdrStandardType::e_Data:
valueWidget = new LogViewValueEdit(a_logViewField, this, m_ReadOnly);
break;
case LogViewXdrStandardType::e_Character: // Text
valueWidget = new LogViewTextEdit(a_logViewField, this, m_ReadOnly);
break;
}
}
}
if (valueWidget)
m_EditInfoList.push_back(valueWidget);
}
// else
// {
// // ----------------------------------------------------------------
// // fixme: not used => take away
// // multi-line
// valueWidget = new QTextEdit(value);
// static_cast<QTextEdit*>(valueWidget)->setReadOnly(true);
// // make proper width of widget
// QFontMetrics fm(valueWidget->font());
// // the 0 (at end) are here, because QFontMetrics does not understand the <code> and <b> tags.
// // So not the correct font will be used for calculating the width.
// // The solution here is suboptimal, but will hopefully work with a lot of fonts...
// valueWidget->setMinimumWidth(fm.width("0000: 00 00 00 00 00 00 00")*1.7);
// // ----------------------------------------------------------------
// }
QWidget *w = dynamic_cast<QWidget *>(valueWidget);
if (w)
a_box->addWidget(w, a_box->rowCount() - 1, 1);
else
WARNING_LOG(m_logger) << "Internal error - LogViewWidget is not derived from QWidget... !?";
break;
}
// fall through for not read-only and dyn. array
Q_FALLTHROUGH();
case 0:
if (m_ReadOnly)
{
// no field
a_box->addWidget(new QLabel(tr("Keine %1").arg(a_logViewField->cleanName())));
break;
}
// fall through for not read-only
Q_FALLTHROUGH();
default:
{
// show the title of table
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
// show the spin-box for changing the dyn. array-size
LogViewSpinBox *spinBox = nullptr;
if (!m_ReadOnly && a_logViewField->isDynamicArray())
{
spinBox = new LogViewSpinBox(a_logViewField, this, a_logViewField->valueListSize());
a_box->addWidget(spinBox, a_box->rowCount() - 1, 1);
}
// show the table for changing the array-values
LogViewTableWidget *tableWidget = new LogViewTableWidget(a_logViewField, this, m_ReadOnly);
m_EditInfoList.push_back(tableWidget);
a_box->addWidget(tableWidget, a_box->rowCount(), 0, 1, 2);
// connect signals
if (spinBox)
{
connect(spinBox, &LogViewSpinBox::valueEditingFinished,
tableWidget, &LogViewTableWidget::changeSize);
}
}
break;
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showTab(LogViewField *a_logViewField, QGridLayout *a_box)
{
LogViewSpinBox *spinBox = nullptr;
if (!m_ReadOnly && a_logViewField->isDynamicArray())
{
// show the spin-box for changing the dyn. array-size
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
spinBox = new LogViewSpinBox(a_logViewField, this, 0);
a_box->addWidget(spinBox, a_box->rowCount() - 1, 1);
}
LogViewTabWidget *a_tabWidget = new LogViewTabWidget(a_logViewField, this, spinBox);
m_EditInfoList.push_back(dynamic_cast<LogViewWidget *>(a_tabWidget));
a_box->addWidget(a_tabWidget, a_box->rowCount(), 0, 1, 2);
// connect signals
if (spinBox)
{
connect(spinBox, &LogViewSpinBox::valueEditingFinished,
a_tabWidget, &LogViewTabWidget::changeSize);
}
// add the tab
if (a_logViewField->hasContent())
{
for (int i = 0; i < a_logViewField->childCount(); ++i)
a_tabWidget->addTab(a_logViewField, false, i);
}
}
// ---------------------------------------------------------------
bool LogViewTelegramDialog::removeItemsFromEditInfoList(const QStringList &jsonPath)
{
if (m_EditInfoList.empty())
return false;
for (int i = m_EditInfoList.size() - 1; i >= 0; --i)
{
LogViewWidget *lvw = m_EditInfoList.at(i);
const QStringList jsonPathChild = lvw->field()->jsonPath();
if (jsonPathChild.size() < jsonPath.size())
continue;
bool bIsChild = true;
for (int j = 0; j < jsonPath.size(); ++j)
{
if (jsonPath.at(j) != jsonPathChild.at(j))
{
bIsChild = false;
break;
}
}
if (!bIsChild)
continue;
delete m_EditInfoList.at(i);
m_EditInfoList.removeAt(i);
}
m_EditInfoList.resize(m_EditInfoList.size() - 1);
return true;
}
} // namespace N_LogView
+81
View File
@@ -0,0 +1,81 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QDialog>
#include "logger.h"
class QGridLayout;
class QTabWidget;
class QFrame;
class QScrollArea;
class QLineEdit;
namespace N_LogView
{
class LogViewWidget;
class LogViewTelegram;
class LogViewField;
/**
* @author alois.wismer
* @version 1.0
* @created 09-Feb-2010 15:05:05
*/
class LogViewTelegramDialog : public QDialog
{
Q_OBJECT
public:
explicit LogViewTelegramDialog(QWidget *a_parent = nullptr, const bool a_readonly = true);
void showDialog(const QSharedPointer<LogViewTelegram> &a_telegram);
void showDataDump(const QSharedPointer<LogViewTelegram> &a_telegram, bool showErrorMessage);
void makePretty();
void showTree(LogViewField *a_fieldTree, QGridLayout *a_box);
/**
* Removes the elements from m_EditInfoList matching the path
*/
bool removeItemsFromEditInfoList(const QStringList &jsonPath);
Q_SIGNALS:
void sendTelegram(const QSharedPointer<LogViewTelegram> &telegramToSend);
protected slots:
void saveTelegram();
void sendCurrentTelegram();
protected:
void fillTelegram(LogViewTelegram *a_telegram);
void showButtons(QLayout *a_layout);
void showEditField(LogViewField *a_logViewField, QGridLayout *a_box);
void showTab(LogViewField *a_logViewField, QGridLayout *a_box);
private:
QSharedPointer<LogViewTelegram> m_Telegram;
QVector<LogViewWidget *> m_EditInfoList;
QScopedPointer<LogViewField> m_fieldTree;
QWidget *m_contentsWidget = nullptr;
QScrollArea *m_ScrollArea = nullptr;
QLineEdit *m_NameEdit = nullptr;
QLineEdit *m_WaitTimeEdit = nullptr;
bool m_ReadOnly = false;
NGL::INGLLogger &m_logger;
};
}
+591
View File
@@ -0,0 +1,591 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#include "LogViewTelegramEdit.hpp"
#include "LogViewInjectionThread.hpp"
#include "LogViewTelegramDialog.hpp"
#include "LogViewTelegramEditModel.hpp"
#include "LogViewTelegramSelectionDialog.hpp"
#include <CoPrtCnv/CoPrtCnvHexDumpHelper.hpp>
#include <QAction>
#include <QDir>
#include <QFileDialog>
#include <QHeaderView>
#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QModelIndex>
#include <QSettings>
#include <QTableView>
#include <QTimer>
namespace N_LogView
{
QString TelegramEdit::s_DIR()
{
return QStringLiteral("Dir");
}
QString TelegramEdit::s_EDIT_TELEGRAM_GROUP()
{
return QStringLiteral("EditTelegrams");
}
QString TelegramEdit::s_TELEGRAMLIST_FILE_ID()
{
return QStringLiteral("RDETGL");
}
QString TelegramEdit::s_TELEGRAMLIST_FILES()
{
return tr("Telegrammliste-Dateien (*.tgl);;Alle Dateien (*)");
}
TelegramEdit::TelegramEdit(QWidget *parent)
: QObject(parent)
, m_addTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/list-add.png")), tr("Add Telegram"), this))
, m_editTeleAction(new QAction(QIcon(QLatin1String(":/image/Edit.png")), tr("Edit Telegram"), this))
, m_copyTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/edit-copy.png")), tr("Copy Telegram"), this))
, m_pasteTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/edit-paste.png")), tr("Paste Telegram"), this))
, m_deleteTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/list-remove.png")), tr("Delete Telegram"), this))
, m_moveTeleUpAction(new QAction(QIcon(QLatin1String(":icons/16x16/go-up.png")), tr("Move up"), this))
, m_moveTeleDownAction(new QAction(QIcon(QLatin1String(":icons/16x16/go-down.png")), tr("Move down"), this))
, m_teleListLoad(new QAction(QIcon(QLatin1String(":icons/16x16/document-open-data.png")), tr("Load Telegram list"), this))
, m_teleListAppend(new QAction(QIcon(), tr("Telegrammliste anhaengen"), this))
, m_teleListSave(new QAction(QIcon(QLatin1String(":icons/16x16/document-save.png")), tr("Save Telegram list"), this))
, m_tableView(new QTableView(parent))
, m_DoLoop(false)
, m_InjectionThread(nullptr)
, m_EditModel(new TelegramEditModel(this))
, m_logger(getLogger("LogViewTelegramEdit"))
{
m_addTeleAction->setShortcut(tr("Ctrl+A"));
m_editTeleAction->setShortcut(tr("Ctrl+E"));
m_copyTeleAction->setShortcut(tr("Ctrl+C"));
m_pasteTeleAction->setShortcut(tr("Ctrl+V"));
m_deleteTeleAction->setShortcut(Qt::Key_Delete);
m_moveTeleUpAction->setShortcut(tr("Ctrl+U"));
m_moveTeleDownAction->setShortcut(tr("Ctrl+D"));
m_teleListLoad->setShortcut(tr("Ctrl+L"));
m_teleListAppend->setShortcut(tr("Ctrl+K"));
m_teleListSave->setShortcut(tr("Ctrl+S"));
m_addTeleAction->setEnabled(true);
m_copyTeleAction->setEnabled(false);
m_pasteTeleAction->setEnabled(false);
m_deleteTeleAction->setEnabled(false);
m_moveTeleUpAction->setEnabled(false);
m_moveTeleDownAction->setEnabled(false);
m_teleListLoad->setEnabled(true);
m_teleListAppend->setEnabled(true);
m_teleListSave->setEnabled(false);
connect(m_addTeleAction, &QAction::triggered, this, &TelegramEdit::addTelegram);
connect(m_editTeleAction, &QAction::triggered, this, &TelegramEdit::editTelegram);
connect(m_copyTeleAction, &QAction::triggered, this, &TelegramEdit::copy);
connect(m_pasteTeleAction, &QAction::triggered, this, &TelegramEdit::paste);
connect(m_deleteTeleAction, &QAction::triggered, this, &TelegramEdit::deleteTelegram);
connect(m_moveTeleUpAction, &QAction::triggered, this, &TelegramEdit::moveUp);
connect(m_moveTeleDownAction, &QAction::triggered, this, &TelegramEdit::moveDown);
connect(m_teleListLoad, &QAction::triggered, this, &TelegramEdit::loadTelegramListReplace);
connect(m_teleListAppend, &QAction::triggered, this, &TelegramEdit::loadTelegramListAppend);
connect(m_teleListSave, &QAction::triggered, this, &TelegramEdit::saveTelegramList);
m_tableView->setModel(m_EditModel);
m_tableView->verticalHeader()->hide();
m_tableView->setContextMenuPolicy(Qt::CustomContextMenu);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &TelegramEdit::onSelectionChanged);
connect(m_tableView, &QTableView::doubleClicked,
this, &TelegramEdit::editTelegram);
connect(m_tableView, &QTableView::customContextMenuRequested,
this, &TelegramEdit::tableViewCustomContextMenu);
m_tableView->addAction(m_addTeleAction);
m_tableView->addAction(m_editTeleAction);
m_tableView->addAction(m_copyTeleAction);
m_tableView->addAction(m_pasteTeleAction);
m_tableView->addAction(m_deleteTeleAction);
m_tableView->addAction(m_moveTeleUpAction);
m_tableView->addAction(m_moveTeleDownAction);
}
void TelegramEdit::setInjectionThread(LogViewInjectionThread *a_injectionThread)
{
m_InjectionThread = a_injectionThread;
}
void TelegramEdit::appendTelegram(const QSharedPointer<LogViewTelegram> &telegram)
{
m_EditModel->appendTelegram(telegram);
m_teleListSave->setEnabled(true);
}
void TelegramEdit::tableViewCustomContextMenu(const QPoint &pos)
{
QMenu menu;
// add, edit and remove telegrams
// ------------------------------
menu.addAction(m_addTeleAction);
menu.addAction(m_editTeleAction);
menu.addAction(m_copyTeleAction);
menu.addAction(m_pasteTeleAction);
menu.addAction(m_deleteTeleAction);
// move telegram up/down
// ---------------------
menu.addSeparator();
menu.addAction(m_moveTeleUpAction);
menu.addAction(m_moveTeleDownAction);
menu.addSeparator();
const bool itemSelected = m_tableView->currentIndex().isValid();
// is it a central-telegram?
bool isCentral = false;
QSharedPointer<LogViewTelegram> tele = m_EditModel->telegram(m_tableView->currentIndex().row());
if (tele)
isCentral = (tele->getProtocol() == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral);
// inject telegram
// ---------------
if (isInjectionPossible())
{
QAction *action = menu.addAction(QIcon(QLatin1String(":/image/InjectCentral.png")), tr("Injektiere Zentral-Telegramm"));
// only central-telegrams can be injected
action->setEnabled(itemSelected && isCentral);
connect(action, &QAction::triggered, this, &TelegramEdit::injectCentralTelegram);
action = menu.addAction(QIcon(QLatin1String(":/image/InjectTetra.png")), tr("Injektiere Tetra-Telegramm"));
// only central-telegrams can be injected
action->setEnabled(itemSelected && isCentral);
connect(action, &QAction::triggered, this, &TelegramEdit::injectTetraTelegram);
menu.addSeparator();
// send and loop telegrams
// -----------------------
action = menu.addAction(QIcon(QLatin1String(":icons/16x16/mail-send.png")), tr("Sende Telegramm"));
// only central-telegrams can be sent
action->setEnabled(itemSelected && isCentral);
connect(action, &QAction::triggered, this, &TelegramEdit::sendCurrentTelegram);
if (m_DoLoop)
action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-playback-stop.png")), tr("Stop Loopen"));
else
{
action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-playback-start.png")), tr("Loop Telegramme"));
action->setEnabled(itemSelected);
}
connect(action, &QAction::triggered, this, &TelegramEdit::loopTelegrams);
action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-play-normal.png")), tr("Sende Sequenz"));
action->setEnabled(itemSelected);
connect(action, &QAction::triggered, this, &TelegramEdit::sequenceTelegrams);
// load/save telegram-list
// -----------------------
menu.addSeparator();
}
menu.addAction(m_teleListLoad);
menu.addAction(m_teleListAppend);
menu.addAction(m_teleListSave);
menu.exec(m_tableView->viewport()->mapToGlobal(pos));
}
// ---------------------------------------------------------------
// Adds a_telegram at a_row in table. If there is already a
// telegram it will be overwritten.
// If a_row is -1, the telegram will be added at end.
// If false is false, a_telegram will be ignored, a
// dialog for selecting an empty telegram will be shown
// instead.
// ---------------------------------------------------------------
void TelegramEdit::addTelegram()
{
// add telegram for editing
LogViewTelegramSelectionDialog telegramSelectionDialog(m_tableView);
if (QDialog::Accepted == telegramSelectionDialog.exec())
{
QSharedPointer<LogViewTelegram> newTelegram = QSharedPointer<LogViewTelegram>(new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral,
telegramSelectionDialog.getSelectedTelegramId()));
m_curEditTelegramRow = m_EditModel->appendTelegram(newTelegram);
// show the edit-telegram-dialog
LogViewTelegramDialog *editTelegramDialog = new LogViewTelegramDialog(m_tableView, false);
connect(editTelegramDialog, &LogViewTelegramDialog::finished,
this, &TelegramEdit::editTelegramDialogFinished);
connect(editTelegramDialog, &LogViewTelegramDialog::sendTelegram,
this, &TelegramEdit::sendTelegram);
editTelegramDialog->showDialog(newTelegram);
m_teleListSave->setEnabled(true);
}
}
QSharedPointer<LogViewTelegram> TelegramEdit::currentSelectedTelegram() const
{
return m_EditModel->telegram(currentSelectedIndex().row());
}
QModelIndex TelegramEdit::currentSelectedIndex() const
{
return m_tableView->currentIndex();
}
void TelegramEdit::editTelegramDialogFinished()
{
//model über geänderte Daten informieren
m_EditModel->emitDataChanged(m_curEditTelegramRow);
}
// ---------------------------------------------------------------
// shows a telegram-dialog, where the telegram can be changed.
// ---------------------------------------------------------------
void TelegramEdit::editTelegram()
{
m_curEditTelegramRow = currentSelectedIndex().row();
if (m_curEditTelegramRow < 0)
return;
LogViewTelegramDialog *editTelegramDialog = new LogViewTelegramDialog(m_tableView, false);
connect(editTelegramDialog, &LogViewTelegramDialog::finished, this, &TelegramEdit::editTelegramDialogFinished);
editTelegramDialog->showDialog(currentSelectedTelegram());
}
// ---------------------------------------------------------------
// shows a non-editable telegram-dialog
// ---------------------------------------------------------------
void TelegramEdit::showTelegram()
{
LogViewTelegramDialog *showTelegramDialog = new LogViewTelegramDialog(m_tableView, true);
showTelegramDialog->showDialog(currentSelectedTelegram());
//
// qulonglong dataPtr = m_TelegramTableWidget->item(a_tableWidget->row(), 0)->data(Qt::UserRole).toULongLong();
// LogViewTelegram* telegram = (LogViewTelegram*)dataPtr;
// LogViewTelegramDialog* telegramDialog = new LogViewTelegramDialog(this);
// telegramDialog->showDialog(telegram);
}
void TelegramEdit::deleteTelegram()
{
const QModelIndexList indexList = m_tableView->selectionModel()->selectedIndexes();
QSet<int> rows;
rows.reserve(indexList.size());
for (const QModelIndex &index : indexList)
rows += index.row();
m_EditModel->removeTelegrams(rows);
m_teleListSave->setEnabled(m_EditModel->rowCount() > 0);
}
void TelegramEdit::injectCentralTelegram()
{
injectTelegram(true);
}
void TelegramEdit::injectTetraTelegram()
{
injectTelegram(false);
}
void TelegramEdit::injectTelegram(bool a_bAsCentralTelegram)
{
injectTelegram(currentSelectedTelegram(), a_bAsCentralTelegram);
}
void TelegramEdit::injectTelegram(const QSharedPointer<LogViewTelegram> &a_telegram, bool a_bAsCentralTelegram)
{
if (!isInjectionPossible())
{
WARNING_LOG(m_logger) << "Try to inject a telegramm but the injection thread is not running";
return;
}
if (a_telegram.isNull())
{
WARNING_LOG(m_logger) << "Try to inject a telegramm but no telegramm selected";
return;
}
a_telegram->actualizeGpsTime();
m_InjectionThread->sendTelegram(a_telegram.data(), a_bAsCentralTelegram);
}
void TelegramEdit::sendCurrentTelegram()
{
sendTelegram(currentSelectedTelegram());
}
void TelegramEdit::sendTelegram(const QSharedPointer<LogViewTelegram> &a_telegram)
{
injectTelegram(a_telegram, true);
}
void TelegramEdit::loopTelegrams()
{
//gucken ob loop schon gestartet oder nicht
if (m_DoLoop)
{
m_DoLoop = false;
m_deleteTeleAction->setEnabled(m_tableView->currentIndex().isValid());
}
else
{
m_DoLoop = true;
m_deleteTeleAction->setEnabled(false);
m_currentRowToSend = currentSelectedIndex().row();
if (m_currentRowToSend < 0)
return;
QSharedPointer<LogViewTelegram> tele = currentSelectedTelegram();
sendTelegram(tele);
QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::loopNextTelegram);
}
}
void TelegramEdit::loopNextTelegram()
{
if (!m_DoLoop)
return;
++m_currentRowToSend;
// am Ende ?
if (m_currentRowToSend >= m_tableView->model()->rowCount())
m_currentRowToSend = 0;
QSharedPointer<LogViewTelegram> tele = telegramAtRow(m_currentRowToSend);
if (!tele)
return;
sendTelegram(tele);
QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::loopNextTelegram);
}
void TelegramEdit::sequenceTelegrams()
{
m_currentRowToSend = currentSelectedIndex().row();
if (m_currentRowToSend < 0) // invalid index
return;
QSharedPointer<LogViewTelegram> tele = currentSelectedTelegram();
sendTelegram(tele);
QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::sequenceNextTelegram);
}
void TelegramEdit::sequenceNextTelegram()
{
++m_currentRowToSend;
if (m_currentRowToSend >= m_tableView->model()->rowCount())
return;
QSharedPointer<LogViewTelegram> tele = telegramAtRow(m_currentRowToSend);
if (!tele)
return;
sendTelegram(tele);
QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::sequenceNextTelegram);
}
QSharedPointer<LogViewTelegram> TelegramEdit::telegramAtRow(int row)
{
return m_EditModel->telegram(row);
}
void TelegramEdit::copy()
{
m_copyTelegram = currentSelectedTelegram();
m_pasteTeleAction->setEnabled(m_copyTelegram != nullptr);
if (!m_copyTelegram)
return;
m_copyTelegram = QSharedPointer<LogViewTelegram>(new LogViewTelegram(*m_copyTelegram.data()));
}
void TelegramEdit::paste()
{
if (!m_copyTelegram)
return;
int row = currentSelectedIndex().row() + 1;
m_EditModel->pasteRows(row, m_copyTelegram);
}
void TelegramEdit::moveUp()
{
const QModelIndex idx = currentSelectedIndex();
if (m_EditModel->moveUp(idx.row()))
{
m_tableView->clearSelection();
m_tableView->setCurrentIndex(m_EditModel->index(idx.row() - 1, idx.column(), idx.parent()));
m_moveTeleUpAction->setEnabled(idx.row() > 1);
m_moveTeleDownAction->setEnabled(true);
}
}
void TelegramEdit::moveDown()
{
const QModelIndex idx = currentSelectedIndex();
if (m_EditModel->moveDown(idx.row()))
{
m_tableView->clearSelection();
m_tableView->setCurrentIndex(m_EditModel->index(idx.row() + 1, idx.column(), idx.parent()));
m_moveTeleUpAction->setEnabled(true);
m_moveTeleDownAction->setEnabled(idx.row() < m_EditModel->rowCount() - 2);
}
}
void TelegramEdit::saveTelegramList()
{
// get the filename
QSettings settings;
QString newFilename = QFileDialog::getSaveFileName(m_tableView,
tr("Dateiname der Telegrammliste"),
settings.value(s_DIR()).toString(),
s_TELEGRAMLIST_FILES());
if (!newFilename.isEmpty())
{
if (!newFilename.contains(QLatin1Char('.')))
newFilename += QLatin1String(".tgl");
// save the actual directory
QDir dir;
settings.beginGroup(s_EDIT_TELEGRAM_GROUP());
settings.setValue(s_DIR(), dir.filePath(newFilename));
settings.endGroup();
// save the telegram-list
QFile telegramFile(newFilename);
telegramFile.open(QIODevice::WriteOnly);
QDataStream stream(&telegramFile);
// write the header
uint32_t version = 1;
stream << s_TELEGRAMLIST_FILE_ID() << version;
// write the telegrams
int rows = m_tableView->model()->rowCount();
stream << rows;
for (int i = 0; i < rows; i++)
{
QSharedPointer<LogViewTelegram> telegram = telegramAtRow(i);
if (!telegram)
continue;
const QByteArray &data = telegram->getData();
const QString name = telegram->getName();
const unsigned int waitTime = telegram->getWaitTime();
stream << waitTime
<< name
<< telegram->getGpsTimeField()
<< data.size();
stream.writeRawData(data.data(), data.size());
}
telegramFile.close();
}
}
void TelegramEdit::loadTelegramListAppend()
{
loadTelegramList(true);
}
void TelegramEdit::loadTelegramListReplace()
{
loadTelegramList(false);
}
void TelegramEdit::loadTelegramList(bool checkAppend)
{
// get the filename
QSettings settings;
QString newFilename = QFileDialog::getOpenFileName(m_tableView,
tr("Dateiname der Telegrammliste"),
settings.value(s_DIR()).toString(),
s_TELEGRAMLIST_FILES());
if (!newFilename.isEmpty())
{
// save the actual directory
QDir dir;
settings.beginGroup(s_EDIT_TELEGRAM_GROUP());
settings.setValue(s_DIR(), dir.filePath(newFilename));
settings.endGroup();
// delete the actual telegram-list
{
if (!checkAppend)
m_EditModel->clearTelegrams();
}
// load the telegram-list
QFile telegramFile(newFilename);
telegramFile.open(QIODevice::ReadOnly);
QDataStream stream(&telegramFile);
// read the header
QString id;
stream >> id;
if (id != s_TELEGRAMLIST_FILE_ID())
{
QMessageBox::critical(m_tableView, tr("Error"), tr("<b>%1</b> does not contain telegram data").arg(newFilename));
return;
}
uint32_t version = 0;
stream >> version;
if (version != 1)
{
QMessageBox::critical(m_tableView, tr("Error"), tr("Wrong telegram list file version"));
return;
}
// read the telegrams
int rows = 0;
QVector<uint16_t> gpsFieldOffset;
stream >> rows;
for (int i = 0; i < rows; i++)
{
uint32_t waitTime = 0;
QString name;
int telegramSize = 0;
stream >> waitTime >> name >> gpsFieldOffset >> telegramSize;
if (telegramSize > 0)
{
DEBUG_LOG(m_logger) << "telegramSize=" << telegramSize;
QByteArray buf(telegramSize, Qt::Uninitialized);
stream.readRawData(buf.data(), telegramSize);
NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Debug, buf);
LogViewTelegram *telegram = new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral,
0,
buf);
telegram->setWaitTime(waitTime);
telegram->setName(name);
telegram->setGpsTimeField(gpsFieldOffset);
m_EditModel->appendTelegram(QSharedPointer<LogViewTelegram>(telegram));
}
}
telegramFile.close();
m_teleListSave->setEnabled(m_EditModel->rowCount() > 0);
}
}
// ---------------------------------------------------------------
bool TelegramEdit::isInjectionPossible() const
{
return m_InjectionThread ? m_InjectionThread->isSendingPossible() : false;
}
// ---------------------------------------------------------------
void TelegramEdit::onSelectionChanged()
{
const QModelIndex idx = currentSelectedIndex();
m_editTeleAction->setEnabled(idx.isValid());
m_copyTeleAction->setEnabled(idx.isValid());
m_deleteTeleAction->setEnabled(idx.isValid());
m_moveTeleUpAction->setEnabled(idx.row() > 0);
m_moveTeleDownAction->setEnabled(idx.isValid() && idx.row() < m_EditModel->rowCount() - 1);
}
} // namespace N_LogView
+126
View File
@@ -0,0 +1,126 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "LogViewTelegram.hpp"
#include <QModelIndex>
class QAction;
class QTableView;
namespace N_LogView
{
class LogViewInjectionThread;
class TelegramEditModel;
class TelegramEdit :public QObject
{
Q_OBJECT
public:
explicit TelegramEdit(QWidget *parent = nullptr);
QTableView *tableView() { return m_tableView; }
void appendTelegram(const QSharedPointer<LogViewTelegram> &telegram);
void setInjectionThread(LogViewInjectionThread* a_injectionThread);
bool isInjectionPossible() const;
protected:
QSharedPointer<LogViewTelegram> m_copyTelegram;
QSharedPointer<LogViewTelegram> currentSelectedTelegram() const;
QModelIndex currentSelectedIndex() const;
QSharedPointer<LogViewTelegram> telegramAtRow(int row);
void loadTelegramList(bool checkAppend);
protected:
QAction *m_addTeleAction;
QAction *m_editTeleAction;
QAction *m_copyTeleAction;
QAction *m_pasteTeleAction;
QAction *m_deleteTeleAction;
QAction *m_moveTeleUpAction;
QAction *m_moveTeleDownAction;
QAction *m_teleListLoad;
QAction *m_teleListAppend;
QAction *m_teleListSave;
QTableView *m_tableView;
bool m_DoLoop;
LogViewInjectionThread *m_InjectionThread;
int m_currentRowToSend;
int m_curEditTelegramRow;
TelegramEditModel *m_EditModel;
NGL::INGLLogger &m_logger;
static QString s_DIR();
static QString s_EDIT_TELEGRAM_GROUP();
static QString s_TELEGRAMLIST_FILE_ID();
static QString s_TELEGRAMLIST_FILES();
protected Q_SLOTS:
void addTelegram();
void injectTelegram(bool a_bAsCentralTelegram);
void injectTelegram(const QSharedPointer<LogViewTelegram> &a_telegram, bool a_bAsCentralTelegram);
void sendTelegram(const QSharedPointer<LogViewTelegram> &a_telegram);
void sendCurrentTelegram();
void tableViewCustomContextMenu(const QPoint &pos);
void editTelegram();
void showTelegram();
void deleteTelegram();
void injectCentralTelegram();
void injectTetraTelegram();
void loopTelegrams();
void loopNextTelegram();
void sequenceTelegrams();
void sequenceNextTelegram();
void copy();
void paste();
void moveUp();
void moveDown();
void saveTelegramList();
void loadTelegramListAppend();
void loadTelegramListReplace();
void editTelegramDialogFinished();
void onSelectionChanged();
};
}
@@ -0,0 +1,168 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#include "LogViewTelegramEditModel.hpp"
#include <algorithm>
namespace N_LogView
{
// ---------------------------------------------------------------
int TelegramEditModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_telegrams.size();
}
// ---------------------------------------------------------------
int TelegramEditModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 3;
}
// ---------------------------------------------------------------
QVariant TelegramEditModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && index.row() < m_telegrams.size())
{
if (role == Qt::DisplayRole)
{
const QSharedPointer<LogViewTelegram> telegram = m_telegrams.at(index.row());
switch (index.column())
{
case 0:
return telegram->getName();
case 1:
return telegram->getParticipantId();
case 2:
return telegram->getWaitTime();
}
}
else if (role == Qt::ToolTipRole)
{
const QSharedPointer<LogViewTelegram> telegram = m_telegrams.at(index.row());
if (telegram->isJsonTelegram())
return telegram->getData(QJsonDocument::JsonFormat::Indented);
}
}
return QVariant();
}
// ---------------------------------------------------------------
QVariant TelegramEditModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case 0:
return tr("Description");
case 1:
return tr("Equip. No.");
case 2:
return tr("Wait Time");
default:
break;
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
// ---------------------------------------------------------------
void TelegramEditModel::clearTelegrams()
{
beginResetModel();
m_telegrams.clear();
endResetModel();
}
// ---------------------------------------------------------------
void TelegramEditModel::appendTelegrams(const QVector<QSharedPointer<LogViewTelegram> > &telegrams)
{
if (telegrams.isEmpty())
return;
beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size() + telegrams.size() - 1);
m_telegrams += telegrams;
endInsertRows();
}
// ---------------------------------------------------------------
int TelegramEditModel::appendTelegram(const QSharedPointer<LogViewTelegram> &telegram)
{
beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size());
m_telegrams.push_back(telegram);
telegram->rebuildJsonString();
endInsertRows();
return m_telegrams.size() - 1; // row
}
// ---------------------------------------------------------------
QSharedPointer<LogViewTelegram> TelegramEditModel::telegram(int row) const
{
if (row >= 0 && row < m_telegrams.size())
return m_telegrams.at(row);
return QSharedPointer<LogViewTelegram>();
}
// ---------------------------------------------------------------
bool TelegramEditModel::moveUp(int row)
{
if (row <= 0 || row >= m_telegrams.size())
return false;
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
std::swap(m_telegrams[row], m_telegrams[row - 1]);
endMoveRows();
return true;
}
// ---------------------------------------------------------------
bool TelegramEditModel::moveDown(int row)
{
if (row >= (m_telegrams.size() - 1))
return false;
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 1);
std::swap(m_telegrams[row], m_telegrams[row + 1]);
endMoveRows();
return true;
}
// ---------------------------------------------------------------
void TelegramEditModel::emitDataChanged(int row)
{
QModelIndex top = createIndex(row, 0);
QModelIndex bottom = createIndex(row, columnCount() - 1);
emit dataChanged(top, bottom, {Qt::DisplayRole, Qt::ToolTipRole});
}
// ---------------------------------------------------------------
void TelegramEditModel::removeTelegrams(const QSet<int> &rows)
{
QList<int> rowList = rows.values();
std::sort(rowList.begin(), rowList.end());
// von oben her löschen um ein Verschieben der Indizes zu vermeiden
for (int i = rowList.size() - 1 ; i >= 0; --i)
{
int row = rowList.at(i);
beginRemoveRows(QModelIndex(), row, row);
m_telegrams.remove(row);
endRemoveRows();
}
}
// ---------------------------------------------------------------
void TelegramEditModel::pasteRows(int row, const QSharedPointer<LogViewTelegram> &tele)
{
if (row < 0 || row > m_telegrams.size())
return;
beginInsertRows(QModelIndex(), row, row);
m_telegrams.insert(row, QSharedPointer<LogViewTelegram>(new LogViewTelegram(*tele.data())));
endInsertRows();
}
} // namespace N_LogView
@@ -0,0 +1,49 @@
/**
* @RDE_HEADER@
* some models for LogViewGui
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QAbstractTableModel>
#include <QtCore/QSharedPointer>
#include <QtCore/QSet>
#include "LogViewTelegram.hpp"
namespace N_LogView
{
class TelegramEditModel final : public QAbstractTableModel
{
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
void clearTelegrams();
void appendTelegrams(const QVector<QSharedPointer<LogViewTelegram> > &telegrams);
int appendTelegram(const QSharedPointer<LogViewTelegram> &telegram);
QSharedPointer<LogViewTelegram> telegram(int row) const;
bool moveUp(int row);
bool moveDown(int row);
void emitDataChanged(int row);
void removeTelegrams(const QSet<int> &rows);
void pasteRows(int row, const QSharedPointer<LogViewTelegram> &tele);
protected:
QVector<QSharedPointer<LogViewTelegram> > m_telegrams;
};
}
@@ -0,0 +1,62 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewTelegramSelectionDialog.hpp"
#include <QLabel>
#include <QListWidget>
#include <QVBoxLayout>
#include "LogViewXdrType.hpp"
#include "LogViewXdrParser.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewTetraTelegramsParser.hpp"
namespace N_LogView
{
static int s_currentRow = 0;
// ---------------------------------------------------------------
LogViewTelegramSelectionDialog::LogViewTelegramSelectionDialog(QWidget* a_parent)
: QDialog(a_parent)
{
setMinimumSize(QSize(600, 500));
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(new QLabel(tr("Select a telegram:")));
m_TelegramList = new QListWidget(this);
const auto telegramMap = LogViewTelegram::jsonParser()->telegramsToCreate();
for (auto it = telegramMap.cbegin(); it != telegramMap.cend(); ++it)
{
if (it.key() == 0) // ACK
continue;
auto lwi = new QListWidgetItem(it.value() + QStringLiteral(" (%1)").arg(it.key()));
lwi->setData(Qt::UserRole, it.key());
m_TelegramList->addItem(lwi);
}
m_TelegramList->sortItems();
m_TelegramList->setCurrentRow(s_currentRow);
connect(m_TelegramList, &QListWidget::itemActivated,
this, &LogViewTelegramSelectionDialog::selectTelegram);
layout->addWidget(m_TelegramList);
setLayout(layout);
}
// ---------------------------------------------------------------
void LogViewTelegramSelectionDialog::selectTelegram(QListWidgetItem* a_telegramItem)
{
s_currentRow = m_TelegramList->currentRow();
m_SelectedTelegramId = a_telegramItem->data(Qt::UserRole).toInt();
accept();
}
} // namespace N_LogView
@@ -0,0 +1,53 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QDialog>
class QListWidget;
class QListWidgetItem;
namespace N_LogView
{
/**
* @author alois.wismer
* @version 1.0
* @created 05-Mai-2010 17:24:14
*/
class LogViewTelegramSelectionDialog : public QDialog
{
Q_OBJECT
public:
/**
*
* @param a_parent
*/
explicit LogViewTelegramSelectionDialog(QWidget* a_parent);
int getSelectedTelegramId() const { return m_SelectedTelegramId; }
protected slots:
/**
*
* @param a_telegramItem
*/
void selectTelegram(QListWidgetItem* a_telegramItem);
protected:
QListWidget *m_TelegramList;
int m_SelectedTelegramId;
};
}
@@ -0,0 +1,521 @@
/**
* Parses training_area_telegrams.h
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#include "LogViewTetraTelegramsParser.hpp"
#include <QFile>
#include <QVector>
namespace N_LogView
{
LogViewTetraTelegramsParser::LogViewTetraTelegramsParser()
: m_logger(getLogger("LogViewTetraTelegramsParser"))
{
insertPod(QStringLiteral("bool"), 1, true, true, true);
insertPod(QStringLiteral("int"), 4, true, true);
insertPod(QStringLiteral("int32_t"), 4, true, true);
insertPod(QStringLiteral("qint64"), 8, true, true);
insertPod(QStringLiteral("float"), 4, true, false);
insertPod(QStringLiteral("double"), 8, true, false);
}
EnumInformation LogViewTetraTelegramsParser::enumFromType(const QString &type) const
{
for (const auto &ei : m_enums)
{
const QString fqType = ei.ns.isEmpty() ? ei.type : (ei.ns + QStringLiteral("::") + ei.type);
if (fqType == type)
return ei;
}
return EnumInformation();
}
StructInformation LogViewTetraTelegramsParser::structFromType(const QString &type) const
{
return m_structs.value(type);
}
PodInformation LogViewTetraTelegramsParser::podFromType(const QString &type) const
{
return m_pods.value(type);
}
bool LogViewTetraTelegramsParser::isEnum(const QString &type) const
{
for (const auto &ei : m_enums)
if (ei.type == type)
return true;
return false;
}
bool LogViewTetraTelegramsParser::isStruct(const QString &type) const
{
return m_structs.contains(type);
}
bool LogViewTetraTelegramsParser::isPod(const QString &type) const
{
return m_pods.contains(type);
}
static void fillBasemembers(StructInformation &si, const QHash<QString, StructInformation> &structs)
{
if (si.baseStruct.isEmpty())
return;
StructInformation base = structs.value(si.baseStruct);
fillBasemembers(base, structs);
si.member = (base.member + si.member); // base first
}
bool LogViewTetraTelegramsParser::parse(const QString &filename)
{
m_telegramIdEnum = EnumInformation();
m_enums.clear();
m_structs.clear();
//m_pods.clear(); // only set once
m_visibleTelegrams.clear();
QFile f(filename);
if (!f.open(QIODevice::ReadOnly))
{
WARNING_LOG(m_logger) << "Can not open file " << filename << " for reading: " << f.errorString();
return false;
}
const QString content = QString::fromUtf8(f.readAll());
f.close();
const QVector<QStringRef> lines = content.splitRef(QLatin1Char('\n'));
QVector<QStringRef> linesTrimmed;
linesTrimmed.reserve(lines.size());
for (const QStringRef &line : lines)
linesTrimmed += line.trimmed();
int i = 0;
while (i < linesTrimmed.size())
{
const QStringRef &line = linesTrimmed.at(i);
if (line.startsWith(QLatin1String("struct")))
{
i = parseStruct(linesTrimmed, i);
if (i < 0)
return false;
}
else if (line.startsWith(QLatin1String("enum")))
{
i = parseEnum(linesTrimmed, i, QString());
if (i < 0)
return false;
}
else if (line.startsWith(QLatin1String("template <> struct Constraints")))
{
i = parseConstraint(linesTrimmed, i);
if (i < 0)
return false;
}
++i;
}
const auto completeStructs = m_structs;
for (StructInformation &si : m_structs)
fillBasemembers(si, completeStructs);
return true;
}
void LogViewTetraTelegramsParser::insertPod(const QString &type, int byteLen, bool isSigned, bool isIntegral, bool isBoolean)
{
PodInformation pod;
pod.type = type;
pod.byteLen = byteLen;
pod.isBoolean = isBoolean;
pod.isIntegral = isIntegral;
pod.isSigned = isSigned;
m_pods[type] = pod;
}
int LogViewTetraTelegramsParser::parseStruct(const QVector<QStringRef> &lines, int iStartPos)
{
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
if (tokens.size() < 2)
return -1;
const QStringRef &structType = tokens.at(1);
if (structType.endsWith(QLatin1Char(';'))) // forward decl
return iStartPos; // move to next line
StructInformation si;
si.type = structType.toString();
if (tokens.size() > 2)
{
if (tokens.at(2) != QLatin1String(":"))
{
WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1;
return -1;
}
for (int i = 3; i < tokens.size(); ++i)
{
if (!si.baseStruct.isEmpty())
{
WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1;
return -1;
}
QStringRef base = tokens.at(i);
if (base == QLatin1String("public") ||
base == QLatin1String("protected") ||
base == QLatin1String("private"))
continue;
if (base.endsWith(QLatin1Char(',')))
base.chop(1);
if (base.endsWith(QLatin1Char('>'))) // helper template - ignore
{
si.isVisible = true;
continue;
}
si.baseStruct = tokens.at(i).toString();
}
}
int i = iStartPos + 1;
while (i < lines.size())
{
const QVector<QStringRef> tokens = tokenize(lines.at(i));
if (!validStructTokens(tokens))
{
++i;
continue;
}
if (tokens.at(0) == QLatin1String("};"))
break;
if (tokens.at(0) == QLatin1String("enum"))
{
i = parseEnum(lines, i, si.type, &si);
if (i < 0)
return -1;
++i;
continue;
}
MemberInformation mi;
if (tokens.size() > 2)
{
const int parserCommentPos = tokens.at(2) == QLatin1String("=") ? 4 : 2;
if (tokens.size() > parserCommentPos)
{
const QStringRef &comment = tokens.at(parserCommentPos);
DEBUG_LOG(m_logger) << "comment: " << comment.toString();
if (comment.startsWith(QLatin1String("//@array: ")))
{
const QStringRef hint = comment.mid(QLatin1String("//@array: ").size());
QString structStr = QLatin1String("struct ") + si.type + QLatin1String("::") + tokens.at(0).toString() + QLatin1Char('\n') + hint.toString();
structStr.replace(QLatin1Char(';'), QLatin1String(";\n"));
DEBUG_LOG(m_logger) << "structStr: " << structStr;
parseStruct(structStr.splitRef(QLatin1Char('\n')), 0);
mi.type = si.type + QLatin1String("::") + tokens.at(0).toString();
mi.isArray = true;
}
if (comment == QLatin1String("//@invisible"))
mi.isVisible = false;
}
}
QStringRef name = tokens.at(1);
if (name.endsWith(QLatin1Char(';')))
name.chop(1);
if (mi.type.isEmpty())
mi.type += tokens.at(0).toString();
categorizeMember(mi);
mi.name = name.toString();
if (mi.isEnum && !mi.type.contains(QLatin1String("::")))
{
// fixup ns
for (const auto &ei : qAsConst(m_enums))
{
if (ei.type == mi.type)
{
if (!ei.ns.isEmpty())
mi.type = ei.ns + QLatin1String("::") + mi.type;
break;
}
}
}
si.member.push_back(std::move(mi));
++i;
}
if (m_logger.isDebugEnabled())
{
if (si.baseStruct.isEmpty())
DEBUG_LOG(m_logger) << "Found Struct: " << si.type;
else
DEBUG_LOG(m_logger) << "Found Struct: " << si.type << ", base: " << si.baseStruct;
for (int j = 0; j < si.member.size(); ++j)
{
const MemberInformation &mi = si.member.at(j);
DEBUG_LOG(m_logger) << "Member[" << j << "]: " << mi.type << " - " << mi.name;
}
}
m_structs[si.type] = si;
return i;
}
int LogViewTetraTelegramsParser::parseEnum(const QVector<QStringRef> &lines, int iStartPos, const QString &ns, StructInformation *si)
{
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
if (tokens.size() < 2)
return -1;
QStringRef enumName = tokens.at(1);
if (enumName == QLatin1String("class"))
{
if (tokens.size() < 3)
return -1;
enumName = tokens.at(2);
}
if (enumName.endsWith(QLatin1Char(';'))) // forward decl
return iStartPos; // move to next line
EnumInformation ei;
ei.type = enumName.toString();
ei.ns = ns;
int i = iStartPos + 1;
while (i < lines.size())
{
const QVector<QStringRef> tokens = tokenize(lines.at(i).split(QStringLiteral("//")).first());
if (tokens.isEmpty() ||
(tokens.at(0) == QLatin1String("{")))
{
++i;
continue;
}
if (tokens.at(0) == QLatin1String("};"))
break;
if ((tokens.size() != 1 && tokens.size() != 3) ||
(tokens.size() == 3 && tokens.at(1) != QLatin1String("=")))
{
if (tokens.size() == 4 && tokens.at(0) == QLatin1String("}") && tokens.at(3).endsWith(QLatin1Char(';')) && si)
{
// enum in struct with direct decl of member
MemberInformation mi;
if (ns.isEmpty())
mi.type = ei.type;
else
mi.type = ns + QStringLiteral("::") + ei.type;
mi.isEnum = true;
mi.name = tokens.at(1).toString();
si->member.push_back(std::move(mi));
break;
}
WARNING_LOG(m_logger) << "Could not parse enum: '" << lines.at(i).toString() << "', line: " << i + 1;
return -1;
}
EnumValue ev;
ev.key = tokens.at(0).toString();
if (tokens.size() == 3)
{
QStringRef value = tokens.at(2);
if (value.endsWith(QLatin1Char(',')))
value.chop(1);
ev.value = value.toInt();
}
else
{
int val = ei.values.isEmpty() ? 0 : (ei.values.last().value + 1);
ev.value = val;
}
ei.values.push_back(std::move(ev));
++i;
}
DEBUG_LOG(m_logger) << "Found Enum: " << ei.type;
for (const EnumValue &ev : qAsConst(ei.values))
DEBUG_LOG(m_logger) << "Member[" << i << "]: " << ev.key << " = " << ev.value;
if (ei.type == QLatin1String("TelegramId"))
m_telegramIdEnum = ei;
m_enums.push_back(std::move(ei));
return i;
}
int LogViewTetraTelegramsParser::parseConstraint(const QVector<QStringRef> &lines, int iStartPos)
{
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
if (tokens.size() != 4)
{
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'";
return -1;
}
const QStringRef &cs = tokens.at(3);
if (!cs.startsWith(QLatin1String("Constraints<")) || !cs.endsWith(QLatin1Char('>')))
{
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'";
return -1;
}
QStringRef structName = cs.mid(QLatin1String("Constraints<").size());
structName.chop(1);
DEBUG_LOG(m_logger) << "Constraint: " << structName.toString();
int i = iStartPos + 1;
while (i < lines.size())
{
const QVector<QStringRef> tokens = tokenize(lines.at(i));
if (tokens.isEmpty() ||
(tokens.at(0) == QLatin1String("{")))
{
++i;
continue;
}
if (tokens.at(0) == QLatin1String("};"))
break;
if (tokens.size() != 8 || tokens.at(2) != QLatin1String("TelegramId")) // static constexpr TelegramId id() { return TelegramId::INIT; }
{
++i;
continue;
}
const QVector<QStringRef> parts = tokens.at(6).split(QLatin1String("::"));
if (parts.size() != 2)
{
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(i).toString() << "'";
return -1;
}
QStringRef enumKey = parts.at(1);
if (enumKey.endsWith(QLatin1Char(';')))
enumKey.chop(1);
bool bFound = false;
for (const auto &v : qAsConst(m_telegramIdEnum.values))
{
if (v.key == enumKey)
{
m_visibleTelegrams.insert(v.value, structName.toString());
bFound = true;
break;
}
}
if (!bFound)
{
WARNING_LOG(m_logger) << "Could not find enum value '" << enumKey.toString() << "' in enum TelegramId";
return -1;
}
++i;
}
return i;
}
QString LogViewTetraTelegramsParser::getInnerType(const QString &type)
{
int idxLt = type.lastIndexOf(QLatin1Char('>'));
if (idxLt < 0)
return QString();
int idxGt = type.indexOf(QLatin1Char('<'));
if (idxGt < 0)
return QString();
return type.mid(idxGt + 1, idxLt - idxGt - 1);
}
void LogViewTetraTelegramsParser::categorizeMember(MemberInformation &mi) const
{
mi.isPod = isPod(mi.type);
mi.isEnum = mi.isPod ? false : isEnum(mi.type);
if (mi.type.startsWith(QLatin1String("std::vector<")))
mi.isArray = true;
mi.isStruct = mi.isArray ? false : isStruct(mi.type);
mi.isString = (mi.type == QLatin1String("std::string") || mi.type == QLatin1String("QString"));
mi.isBinary = (mi.type == QLatin1String("std::vector<unsigned char>") || mi.type == QLatin1String("QByteArray"));
}
static inline void bracketCount(const QStringRef &str, int &cntLt, int &cntGt)
{
cntLt = 0;
cntGt = 0;
for (int i = 0; i < str.size(); ++i)
{
if (str.at(i) == QLatin1Char('<'))
cntLt++;
else if (str.at(i) == QLatin1Char('>'))
cntGt++;
}
}
QVector<QStringRef> LogViewTetraTelegramsParser::tokenize(const QStringRef &line) const
{
QVector<QStringRef> ret = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
int i = 0;
while (i < ret.size())
{
const QStringRef &token = ret.at(i);
if (token.startsWith(QLatin1String("//")))
{
// all comment after this - merge into one
if (i == ret.size() - 1)
break;
const QStringRef &lastToken = ret.last();
const QStringRef newToken = QStringRef(token.string(), token.position(), lastToken.position() - token.position() + lastToken.size());
DEBUG_LOG(m_logger) << "New Token: " << newToken.toString();
ret.resize(i + 1);
ret[i] = newToken;
break;
}
if (i == ret.size() - 1)
break;
int cntLt;
int cntGt;
bracketCount(token, cntLt, cntGt);
if (cntLt == cntGt)
{
++i;
continue;
}
const QStringRef &nextToken = ret.at(i + 1);
const QStringRef newToken = QStringRef(token.string(), token.position(), nextToken.position() - token.position() + nextToken.size());
DEBUG_LOG(m_logger) << "New Token: " << newToken.toString();
ret.removeAt(i + 1);
ret[i] = newToken;
}
return ret;
}
bool LogViewTetraTelegramsParser::validStructTokens(const QVector<QStringRef> &tokens)
{
if (tokens.isEmpty() ||
(tokens.at(0) == QLatin1String("{")) ||
(tokens.at(0) == QLatin1String("{}")) ||
(tokens.at(0) == QLatin1String("}")) ||
(tokens.at(0) == QLatin1String(":")) ||
(tokens.at(0) == QLatin1String(",")) ||
(tokens.at(0) == QLatin1String("virtual")))
return false;
if (tokens.at(0) == QLatin1String("};") || tokens.at(0) == QLatin1String("enum"))
return true;
const int len = tokens.last().startsWith(QLatin1String("//")) ? tokens.size() - 1 : tokens.size();
if (len == 2)
return true;
if (len < 4)
return false;
if (len >= 4 && tokens.at(2) == QLatin1String("="))
return true;
return false;
}
} // namespace N_LogView
@@ -0,0 +1,94 @@
/**
* Parses training_area_telegrams.h
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#pragma once
#include <QHash>
#include <QString>
#include <QVector>
#include "logger.h"
namespace N_LogView
{
struct MemberInformation
{
QString name;
QString type;
bool isArray = false;
bool isBinary = false;
bool isEnum = false;
bool isPod = false;
bool isString = false;
bool isStruct = false;
bool isVisible = true;
};
struct StructInformation
{
QString type;
QString baseStruct; // we only allow one base...
QVector<MemberInformation> member;
bool isVisible = false;
};
struct EnumValue
{
QString key;
int value = 0;
};
struct EnumInformation
{
QString ns;
QString type;
QVector<EnumValue> values;
};
struct PodInformation
{
QString type;
int byteLen = 0;
bool isBoolean = false;
bool isIntegral = false;
bool isSigned = false;
};
class LogViewTetraTelegramsParser
{
public:
LogViewTetraTelegramsParser();
bool parse(const QString &filename);
EnumInformation enumFromType(const QString &type) const;
StructInformation structFromType(const QString &type) const;
PodInformation podFromType(const QString &type) const;
bool isEnum(const QString &type) const;
bool isStruct(const QString &type) const;
bool isPod(const QString &type) const;
QHash<int, QString> telegramsToCreate() const { return m_visibleTelegrams; }
QString nameFromTelegramId(int telId) const { return m_visibleTelegrams.value(telId); }
static QString getInnerType(const QString &type);
private:
void insertPod(const QString &type, int byteLen, bool isSigned, bool isIntegral, bool isBoolean = false);
int parseStruct(const QVector<QStringRef> &lines, int iStartPos);
int parseEnum(const QVector<QStringRef> &lines, int iStartPos, const QString &ns, StructInformation *si = nullptr);
int parseConstraint(const QVector<QStringRef> &lines, int iStartPos);
void categorizeMember(MemberInformation &mi) const;
QVector<QStringRef> tokenize(const QStringRef &line) const;
static bool validStructTokens(const QVector<QStringRef> &tokens);
private:
EnumInformation m_telegramIdEnum;
QVector<EnumInformation> m_enums;
QHash<QString, StructInformation> m_structs;
QHash<QString, PodInformation> m_pods;
QHash<int, QString> m_visibleTelegrams;
NGL::INGLLogger &m_logger;
};
} // namespace LogView
+96
View File
@@ -0,0 +1,96 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewTextEdit.hpp"
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewTextEdit::LogViewTextEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly)
: QLineEdit(a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
{
const QString value = a_field->value(0);
setText(value);
if (a_readonly)
{
setReadOnly(true);
setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft);
}
// set a validator for number of chars
uint16_t maxArraySize = a_field->maxArraySize();
setMaxLength(maxArraySize);
updateToolTip(value);
// make proper width of widget
QFontMetrics fm(font());
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
setMinimumWidth(fm.width(QLatin1Char(' ') + value + QLatin1Char(' ')));
#else
setMinimumWidth(fm.horizontalAdvance(QLatin1Char(' ') + value + QLatin1Char(' ')));
#endif
// connect signals
connect(this, &LogViewTextEdit::editingFinished,
this, &LogViewTextEdit::checkAndOvertakeContent);
}
// ---------------------------------------------------------------
void LogViewTextEdit::checkAndOvertakeContent()
{
updateToolTip(text()); // fixme nach jedem zeichen updaten
m_Valid = true;
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewTextEdit::saveContent(LogViewTelegram* a_telegram)
{
if (!isValid())
return false;
if (a_telegram->isJsonTelegram())
{
a_telegram->setJsonValue(m_Field->jsonPath(), text());
}
else
{
uint16_t size = getSize();
QString content = text();
uint16_t arraySize;
if (m_Field->isDynamicArray())
{
arraySize = content.length();
a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, arraySize);
// fixme: bei vielen Telegrammen muss Länge auf die Länge des Textes gesetzt werden. Dies kann nicht automatisch gemacht werden. Aber vielleicht kann man schauen, ob vor dem dyn. Array ein Feld Länge vorkommt, oder hartcodieren, oder konfigurierbaren
}
else
{
arraySize = m_Field->maxArraySize();
}
// copy the text
for (int i = 0; i < arraySize; i++)
a_telegram->setUIntX(size, i < content.length() ? content[i].toLatin1() : 0);
}
return true;
}
} // namespace N_LogView
+53
View File
@@ -0,0 +1,53 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewWidget.hpp"
#include <QLineEdit>
namespace N_LogView
{
/**
* Used for arrays of char and string.
*
* @author alois.wismer
* @version 1.0
* @created 21-Mai-2010 10:28:05
*/
class LogViewTextEdit : public QLineEdit, public LogViewWidget
{
Q_OBJECT
public:
/**
*
* @param a_field
* @param a_parent
* @param a_readonly
*/
LogViewTextEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly);
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
protected slots:
void checkAndOvertakeContent();
};
}
+135
View File
@@ -0,0 +1,135 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewValueEdit.hpp"
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewValueEdit::LogViewValueEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly)
: QLineEdit(a_parent)
, LogViewWidget(a_field, this, a_parent, a_readonly)
, m_IsFloat(false)
{
const LogViewXdrStandardType *stdType = static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement());
m_IsFloat = (LogViewXdrStandardType::e_Float == stdType->getValueKind());
const QString valueText = a_field->value(0);
setText(valueText);
// checkAndOvertakeContent();
updateToolTip(valueText);
// make proper width of widget
QFontMetrics fm(font());
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
setMinimumWidth(fm.width(QLatin1Char(' ') + valueText + QLatin1Char(' ')));
#else
setMinimumWidth(fm.horizontalAdvance(QLatin1Char(' ') + valueText + QLatin1Char(' ')));
#endif
if (a_readonly)
{
setReadOnly(true);
setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft);
}
else
{
connect(this, &LogViewValueEdit::editingFinished,
this, &LogViewValueEdit::checkAndOvertakeContent);
}
}
// ---------------------------------------------------------------
void LogViewValueEdit::checkAndOvertakeContent()
{
bool ok;
int64_t intValue = 0;
double floatValue = 0.0;
// get the calculated and checked value
if (m_IsFloat)
floatValue = getFloat(text(), (uint64_t&)intValue, ok);
else
intValue = getInteger(text(), ok);
// handle errors
if (!ok)
{
setFocus();
selectAll();
return; // abort
}
// update
if (m_IsFloat)
setText(QString::number(floatValue));
else
setText(QString::number(intValue));
updateToolTip(text());
}
// ---------------------------------------------------------------
// Writes the content into telegram.
// Returns true if successful.
// ---------------------------------------------------------------
bool LogViewValueEdit::saveContent(LogViewTelegram* a_telegram)
{
if (m_Valid)
{
bool ok;
if (m_IsFloat)
{
// save the float or double-value
uint64_t valueAsUint64;
const double value = getFloat(text(), valueAsUint64, ok);
if (ok)
{
if (a_telegram->isJsonTelegram())
{
a_telegram->setJsonValue(m_Field->jsonPath(), value);
}
else
{
const LogViewXdrStandardType *stdType = static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement());
LogViewXdrStandardType::E_ByteOrder byteOrder = stdType->getByteOrder();
a_telegram->setUIntX(getSize(), valueAsUint64, byteOrder);
}
return true;
}
}
else
{
// save the integer-value
qint64 intValue = getInteger(text(), ok);
if (ok)
{
if (a_telegram->isJsonTelegram())
a_telegram->setJsonValue(m_Field->jsonPath(), intValue);
else
a_telegram->setUIntX(getSize(), intValue);
return true;
}
}
}
return false;
}
} // namespace N_LogView
+57
View File
@@ -0,0 +1,57 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewWidget.hpp"
#include <QLineEdit>
namespace N_LogView
{
/**
* Used for scalar signed or unsigned values
*
* @author alois.wismer
* @version 1.0
* @created 20-Mai-2010 14:47:50
*/
class LogViewValueEdit : public QLineEdit, public LogViewWidget
{
Q_OBJECT
public:
/**
*
* @param a_field
* @param a_parent
* @param a_readonly
*/
LogViewValueEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly);
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
bool saveContent(LogViewTelegram* a_telegram) override;
protected:
bool m_IsFloat;
protected slots:
void checkAndOvertakeContent();
};
}
+230
View File
@@ -0,0 +1,230 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewWidget.hpp"
#include "LogViewField.hpp"
#include "LogViewTelegram.hpp"
#include "LogViewXdrStandardType.hpp"
#include "IntegerCalculator.hpp"
#include <QMessageBox>
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewWidget::LogViewWidget(LogViewField* a_field, QWidget* a_widget, QWidget* a_parent, bool a_readonly)
: m_Readonly(a_readonly)
, m_Valid(true)
, m_Widget(a_widget)
, m_Field(a_field)
, m_Parent(a_parent)
, m_logger(getLogger("LogViewWidget"))
{
}
// ---------------------------------------------------------------
uint16_t LogViewWidget::getSize() const
{
// todo: check whether really a standardtype
const LogViewXdrStandardType* xdrStandardType = static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement());
return xdrStandardType->getValueSize();
}
// ---------------------------------------------------------------
void LogViewWidget::showMessageBox(const QString &a_errorText) const
{
QMessageBox::warning(m_Parent, QObject::tr("Fehler"), a_errorText);
}
// ---------------------------------------------------------------
void LogViewWidget::updateToolTip(const QString &a_text)
{
bool isList = m_Field->valueListSize() > 1 || m_Field->isDynamicArray();
switch (m_Field->xdrElement()->getKind())
{
case LogViewXdrElement::e_KindStandardType:
switch (static_cast<const LogViewXdrStandardType*>(m_Field->xdrElement())->getValueKind())
{
case LogViewXdrStandardType::e_Character:
m_Widget->setToolTip(QObject::tr("%1 Zeichen").arg(a_text.length()));
if (!m_Readonly)
m_Widget->setToolTip(QObject::tr("%1<br><nobr>Maximal %2 Zeichen erlaubt</nobr>").arg(m_Widget->toolTip()).arg(m_Field->maxArraySize()));
break;
case LogViewXdrStandardType::e_Data:
if (m_Readonly)
m_Widget->setToolTip(QObject::tr("%1 Bytes").arg(m_Field->valueListSize()));
break;
case LogViewXdrStandardType::e_Unsigned:
case LogViewXdrStandardType::e_Signed:
if (m_Readonly && isList)
{
m_Widget->setToolTip(QObject::tr("%1 Elemente").arg(m_Field->valueListSize()));
}
else
{
// fixme: bei 3-byte werten werden fälschlicherweise 4 Bytes angezeigt
if (m_Field->isDateTimeField())
{
m_Widget->setToolTip(QObject::tr("Unixzeit: %1 ").arg(a_text));
}
else
{
m_Widget->setToolTip(QString());
}
// actual value in hex and binary
if (!isList)
{
int64_t value = a_text.toLong();
m_Widget->setToolTip(QStringLiteral("%1<b>%2</b> %3").arg(m_Widget->toolTip(), toHex(value), toBin(value)));
}
// range
if (!m_Field->isDateTimeField() && !m_Readonly)
{
const QString sep(isList ? QString() : QStringLiteral("<br>"));
m_Widget->setToolTip(QStringLiteral("%1%2<nobr>Wertebereich: %3..%4</nobr>").arg(m_Widget->toolTip(), sep).arg(m_Field->getLowestValue()).arg(m_Field->getHighestValue()));
}
}
break;
case LogViewXdrStandardType::e_Float:
if (4 == m_Field->size())
m_Widget->setToolTip(QStringLiteral("<nobr>Wertebereich: +/-3.4e+/-38</nobr>"));
else
m_Widget->setToolTip(QStringLiteral("<nobr>Wertebereich: +/-1.7e+/-308</nobr>"));
break;
case LogViewXdrStandardType::e_Boolean:
m_Widget->setToolTip(QStringLiteral("true/false"));
}
break;
case LogViewXdrElement::e_KindEnum:
{
uint64_t enumValue = a_text.toLong();
m_Widget->setToolTip(QStringLiteral("<b>%1 %2</b> %3").arg(enumValue).arg(toHex(enumValue), toBin(enumValue)));
break;
}
default:
ERROR_LOG(m_logger) << "Case not implemented";
}
}
// ---------------------------------------------------------------
double LogViewWidget::getFloat(const QString& a_text, uint64_t& a_FloatAsData, bool& a_ok, const bool a_reverse)
{
// INFO_LOG(m_logger) << "a_text=" << a_text.toStdString();
//LogViewXdrStandardType::E_ByteOrder byteOrder = ((LogViewXdrStandardType*)m_Field->xdrElement())->getByteOrder();
double value;
if (8 == getSize())
{
value = a_text.toDouble(&a_ok);
a_FloatAsData = LogViewTelegram::doubleToXdr(value);
} else {
value = a_text.toFloat(&a_ok);
a_FloatAsData = LogViewTelegram::floatToXdr(value);
}
// show error-message
// fixme zeige fehler genauer
if (!a_ok)
showMessageBox(QStringLiteral("Inalid real value: '%1'").arg(a_text));
m_Valid = a_ok;
// swap for display data on table
if (a_reverse)
{
int j = getSize() - 1;
uint64_t* ptr = &a_FloatAsData;
for (int i = 0; i < getSize() / 2; i++)
{
uint8_t data = ((uint8_t*)ptr)[j];
((uint8_t*)&a_FloatAsData)[j] = ((uint8_t*)&a_FloatAsData)[i];
((uint8_t*)&a_FloatAsData)[i] = data;
j--;
}
}
// set the upper 4 bytes to 0 for float
if (4 == getSize())
{
((uint8_t*)&a_FloatAsData)[4] = 0;
((uint8_t*)&a_FloatAsData)[5] = 0;
((uint8_t*)&a_FloatAsData)[6] = 0;
((uint8_t*)&a_FloatAsData)[7] = 0;
}
return value;
}
// ---------------------------------------------------------------
// Converts a_text into a signed integer and returns it. The
// parameter a_ok will be true if all was successful. The
// attribute m_Valid will be set to a_ok.
// The range will be checked, if the value is out of range, an
// error will be shown as messge-box and a_ok will be false.
// The input a_text can be a calculation.
// ---------------------------------------------------------------
int64_t LogViewWidget::getInteger(const QString& a_text, bool& a_ok)
{
// calculate the expression into a number
N_SST::IntegerCalculator calculator;
N_SST::IntegerCalculator::E_Error error;
int64_t value = calculator.calc(a_text.toStdString(), error);
m_Valid = false;
a_ok = true;
if (N_SST::IntegerCalculator::e_Ok != error)
{
// todo: show exact error-message
if (a_text != m_LastErrorValueText)
{
showMessageBox(QString::fromUtf8("Die Berechnung '%1' ist falsch").arg(a_text));
m_LastErrorValueText = a_text;
}
a_ok = false;
}
else
{
// check the range
int64_t highest = m_Field->getHighestValue();
if (value > highest)
{
a_ok = false;
// fixme: dieser Trick mit m_LastErrorValueText ist für den Benutzer etwas verwirrend, da
// plötzlich keine Reaktion mehr auf Tab, Ok oder wählen eines anderen Feldes passiert...
if (a_text != m_LastErrorValueText)
{
showMessageBox(QString::fromUtf8("Der Wert '%1' ist zu hoch. Maximalwert: %2").arg(a_text).arg(highest));
m_LastErrorValueText = a_text;
}
return value; // abort
}
int64_t lowest = m_Field->getLowestValue();
if (value < lowest)
{
a_ok = false;
if (a_text != m_LastErrorValueText)
{
showMessageBox(QString::fromUtf8("Der Wert '%1' ist zu tief. Minimalwert: %2").arg(a_text).arg(lowest));
m_LastErrorValueText = a_text;
}
return value; // abort
}
m_Valid = true;
}
return value;
}
} // namespace N_LogView
+101
View File
@@ -0,0 +1,101 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QWidget>
#include "logger.h"
class QWidget;
class QFont;
namespace N_LogView
{
template <typename T>
inline QString toHex(T num)
{
return QStringLiteral("0x%1").arg(num, 2, 16, QLatin1Char('0'));
}
template <typename T>
inline QString toBin(T num)
{
return QStringLiteral("0b%1").arg(num, 8, 2, QLatin1Char('0'));
}
class LogViewField;
class LogViewTelegram;
/**
* @author alois.wismer
* @version 1.0
* @created 20-Mai-2010 14:51:17
*/
class LogViewWidget
{
public:
LogViewWidget(LogViewField* a_field, QWidget* a_widget, QWidget* a_parent, bool a_readonly);
virtual ~LogViewWidget() = default;
virtual uint16_t getSize() const;
LogViewField* field() const { return m_Field; }
bool isValid() const { return m_Valid; }
/**
* The content if the field is a text-field
*/
QString getText() const { return m_Text; }
/**
* Writes the content into telegram.
* Returns true if successful.
*
* @param a_telegram
*/
virtual bool saveContent(LogViewTelegram* a_telegram) = 0;
protected:
void showMessageBox(const QString &a_errorText) const;
void updateToolTip(const QString &a_text = QString());
double getFloat(const QString& a_text, uint64_t& a_FloatAsData, bool& a_ok, const bool a_reverse = false);
/**
* Converts a_text into a signed integer and returns it. The parameter a_ok will
* be true if all was successful. The attribute m_Valid will be set to a_ok.
* The range will be checked, if the value is out of range, an error will be shown
* as messge-box and a_ok will be false.
* The input a_text can be a calculation.
*
* @param a_text
* @param a_ok
*/
int64_t getInteger(const QString& a_text, bool& a_ok);
protected:
bool m_Readonly;
bool m_Valid;
/**
* The content if the field is a text-field
*/
QString m_Text;
QString m_LastErrorValueText;
QWidget *m_Widget;
LogViewField *m_Field;
QWidget *m_Parent;
NGL::INGLLogger &m_logger;
};
}
+61
View File
@@ -0,0 +1,61 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewXdrElement.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
// Constructor of a struct or enum
// ---------------------------------------------------------------
LogViewXdrElement::LogViewXdrElement(const QString& a_name, const E_ElementKind a_kind, const char *loggerName)
: m_Name(a_name)
, m_Kind(a_kind)
, m_logger(getLogger(loggerName))
{
if (a_name.indexOf(QLatin1Char('<')) >= 0 || a_name.indexOf(QLatin1Char('[')) >= 0)
ERROR_LOG(m_logger) << "Element \'" << a_name.toStdString() << "\' has a problem";
}
// ---------------------------------------------------------------
void LogViewXdrElement::dump() const
{
INFO_LOG(m_logger) << "Element[" << getName() << "]: kind=" << getKindName();
}
// ---------------------------------------------------------------
QString LogViewXdrElement::getKindName() const
{
switch (getKind())
{
case e_KindDefine:
return QLatin1String("Define");
case e_KindEnum:
return QLatin1String("Enum");
case e_KindEnumElement:
return QLatin1String("EnumElement");
case e_KindStandardType:
return QLatin1String("StandardType");
case e_KindStruct:
return QLatin1String("Struct");
case e_KindStructElement:
return QLatin1String("StructElement");
case e_KindTypedef:
return QLatin1String("Typedef");
}
return QStringLiteral("Unknown (%1)").arg(getKind());
}
} // namespace N_LogView
+72
View File
@@ -0,0 +1,72 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QString>
#include "logger.h"
namespace N_LogView
{
/**
* @author alois.wismer
* @version 1.0
* @created 05-Feb-2010 11:24:56
*/
class LogViewXdrElement
{
public:
/**
* @author alois.wismer
* @version 1.0
* @created 10-Feb-2010 11:34:47
*/
enum E_ElementKind
{
e_KindStandardType,
e_KindTypedef,
e_KindStruct,
e_KindStructElement,
e_KindEnum,
e_KindEnumElement,
e_KindDefine
};
virtual ~LogViewXdrElement() = default;
protected:
/**
* Constructor of a struct or enum
*
* @param a_name
* @param a_kind
*/
LogViewXdrElement(const QString& a_name, const E_ElementKind a_kind, const char *loggerName);
public:
const QString& getName() const { return m_Name; }
LogViewXdrElement::E_ElementKind getKind() const { return m_Kind; }
virtual void dump() const;
protected:
QString m_Name;
E_ElementKind m_Kind;
QString getKindName() const;
NGL::INGLLogger &m_logger;
};
}
File diff suppressed because it is too large. Load diff
+274
View File
@@ -0,0 +1,274 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QString>
#include <QStringList>
#include "IntegerCalculator.hpp"
#include "logger.h"
#include "LogViewXdrStandardType.hpp"
namespace N_LogView
{
class LogViewXdrElement;
class LogViewXdrStruct;
class LogViewField;
class LogViewXdrValue;
class LogViewXdrType;
/**
* @author alois.wismer
* @version 1.0
* @created 05-Feb-2010 10:46:58
*/
class LogViewXdrParser : public N_SST::IntegerCalculator
{
public:
/**
* Defines in which structure the parser is parsing now
*
* @author alois.wismer
* @version 1.0
* @created 08-Feb-2010 17:44:52
*/
enum E_ParseState
{
e_ParseMain,
e_ParseStruct,
e_ParseEnum,
e_ParseUnion
};
LogViewXdrParser();
~LogViewXdrParser();
/**
*
* @param a_fileName
*/
void parseX_File(const QString& a_fileName);
/**
* This function delivers the name of the telegram.
* The telegram will be defined with a_telegramId.
* The name will be delivered as return-parameter.
* If the telegram was not found, error-texts instead names will be returned.
*
* @param a_telegramId
*/
QString getTelegramName(int a_telegramId) const;
/**
* This function delivers the structure name of the telegram.
* The telegram will be defined with a_telegramId.
* The structure name will be delivered as return-parameter
* If the telegram was not found, error-texts instead names will be returned.
*
* @param a_telegramId
*/
QString getStructName(int a_telegramId) const;
/**
*
* @param a_name
* @param a_value
*/
bool getDefine(const QString& a_name, int64_t& a_value) const;
/**
*
* @param a_name
*/
const LogViewXdrElement* getElement(const QString& a_name) const;
protected:
QString m_MessageBoxTitle;
bool m_WithinComment;
QString m_Line;
uint32_t m_LineNbr;
QString m_Filename;
bool m_DoReadUntilSemicolon;
QStringList m_WordList;
int m_WordListIndex;
/**
* This will be used to suppress an error-message when parsing the overall
* telegram structure.
*/
QString m_UnionType;
std::map<QString, LogViewXdrElement*> m_ElementMap;
LogViewXdrStruct *m_ActElement;
E_ParseState m_State;
std::map<QString, LogViewXdrValue> m_DefinesMap;
std::map<int, LogViewXdrType> m_TelegramMap;
/**
*
* @param a_name
* @param a_dataSize
* @param a_realSize
* @param a_kind
* @param a_dynArraySizeMethod
* @param a_byteOrder
*/
void addStandardType(const QString& a_name,
const uint16_t a_dataSize,
const uint16_t a_realSize,
const LogViewXdrStandardType::E_ValueKind a_kind,
const LogViewXdrStandardType::E_DynArraySizeMethod a_dynArraySizeMethod = LogViewXdrStandardType::e_DynArrayMsgLength,
const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian);
/**
*
* @param a_line
*/
QString removeComments(const QString& a_line);
/**
*
* @param a_line
*/
void parseTypedef(const QString &a_line);
/**
*
* @param a_line
*/
void parseDefine(const QString &a_line);
/**
*
* @param a_line
* @param a_enumSize The size in bytes of an enum-value
*/
void parseEnum(const QString &a_line, const uint16_t a_enumSize = 4);
/**
*
* @param a_line
*/
void parseStruct(const QString &a_line);
/**
*
* @param a_line
*/
void parseUnion(const QString& a_line);
/**
*
* @param a_line
* @param a_name
* @param a_value
*/
bool parseEnumLine(const QString& a_line, QString& a_name, QString& a_value) const;
/**
* Shows an error-message containing the line-nbr, the line itself and an
* additional error-text
*
* @param a_errorText
*/
void showErrorMessage(const QString& a_errorText) const;
/**
*
* @param a_calcText
* @param a_isOk
*/
int64_t calcValue(const QString& a_calcText, bool& a_isOk);
/**
*
* @param a_variableName
* @param a_value
*/
bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const override;
/**
*
* @param a_name
* @param a_dynArrayMsgOffset This offset will be used for the dyn-array-method
* e_DynArrayMsgLength. Here the value in <x> will be subtracted from the message-
* length to get the size of the dynamic array.
*/
uint16_t parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const;
/**
*
* @param a_word
* @param a_doIncrement
*/
bool isNextWord(const char *a_word, const bool a_doIncrement = true);
/**
*
* @param a_line
*/
void fillWordList(const QString& a_line);
/**
*
* @param a_errorText
*/
QString getNextWord(const char *a_errorText = nullptr);
/**
*
* @param a_ok
*/
QString getNextType(bool& a_ok);
/**
*
* @param a_enumStruct
*/
QString getNextEnum(const LogViewXdrStruct*& a_enumStruct);
/**
*
* @param a_fieldText
* @param a_firstBit
* @param a_lastBit
*/
bool parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const;
/**
* adds an element to the element-map if it does not already exist within this map.
*
* If it exists, an error-message will be raised instead and false will be
* returned.
*
* @param a_name
* @param a_element
*/
bool addToElementMap(const QString& a_name, LogViewXdrElement* a_element);
private:
/**
* The logger object
*/
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,84 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
// manual class headers
#include "LogViewXdrStandardType.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
// (a_valueKind must be Unsigned, if a_dynArraySizeMethod is
// e_DynArray...)
// ---------------------------------------------------------------
LogViewXdrStandardType::LogViewXdrStandardType(const QString& a_name, const int a_valueSize,
const int a_editSize, const E_ValueKind a_valueKind,
const E_DynArraySizeMethod a_dynArraySizeMethod, E_ByteOrder a_byteOrder)
: LogViewXdrElement(a_name, e_KindStandardType, "LogViewXdrStandardType")
, m_ValueSize(a_valueSize)
, m_EditSize(a_editSize)
, m_ValueKind(a_valueKind)
, m_ByteOrder(a_byteOrder)
, m_DynArraySizeMethod(a_dynArraySizeMethod)
{}
// ---------------------------------------------------------------
uint16_t LogViewXdrStandardType::getValueSize() const
{
return m_ValueSize;
}
// ---------------------------------------------------------------
LogViewXdrStandardType::E_ValueKind LogViewXdrStandardType::getValueKind() const
{
return m_ValueKind;
}
// ---------------------------------------------------------------
void LogViewXdrStandardType::dump() const
{
INFO_LOG(m_logger) << "Element[" << getName()
<< "]: kind=" << getKindName()
<< " valueKind=" << getValueKind()
<< " valueSize=" << getValueSize()
<< " editSize=" << getEditSize()
<< " dynArrSizeMethod=" << getDynArraySizeMethod()
<< " byteOrder=" << getByteOrder();
}
// ---------------------------------------------------------------
LogViewXdrStandardType::E_DynArraySizeMethod LogViewXdrStandardType::getDynArraySizeMethod() const
{
return m_DynArraySizeMethod;
}
// ---------------------------------------------------------------
LogViewXdrStandardType::E_ByteOrder LogViewXdrStandardType::getByteOrder() const
{
return m_ByteOrder;
}
// ---------------------------------------------------------------
// The 'real' size of the value, which will be allowd when
// editing this value
// ---------------------------------------------------------------
uint16_t LogViewXdrStandardType::getEditSize() const
{
return m_EditSize;
}
} // namespace N_LogView
+150
View File
@@ -0,0 +1,150 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewXdrElement.hpp"
namespace N_LogView
{
/**
* This class represents the standardtypes like int, char, ...
* It holds the the size of this type and its representation to user
* (signed/unsigned value or character)
*
* @author alois.wismer
* @version 1.0
* @created 16-Feb-2010 14:22:20
*/
class LogViewXdrStandardType final : public LogViewXdrElement
{
public:
/**
* @author alois.wismer
* @version 1.0
* @created 16-Feb-2010 14:34:38
*/
enum E_ValueKind
{
/**
* An unsigned 32-bit integer
*/
e_Unsigned,
/**
* An signed 32-bit integer
*/
e_Signed,
/**
* A floating-point number
*/
e_Float,
/**
* A character or string
*/
e_Character,
/**
* A boolean value
*/
e_Boolean,
/**
* Hex-Data "0000: F7 A5 07 ..."
*/
e_Data
};
/**
* @author alois.wismer
* @version 1.0
* @created 31-Mrz-2010 10:27:31
*/
enum E_ByteOrder
{
e_ByteOrderBigEndian,
e_ByteOrderLittleEndian
};
/**
* @author alois.wismer
* @version 1.0
* @created 29-Mrz-2010 13:58:44
*/
enum E_DynArraySizeMethod
{
/**
* Size of dyn array depends on message-size (size - m_DynArrayOffset) (or no dyn
* array)
* The value within <> in struct-element will be used for m_DynArrayOffset.
*/
e_DynArrayMsgLength,
/**
* Size of dyn array is defined by a field (StandardType must be Unsigned)
*/
e_DynArrayIndex,
/**
* Size of dyn array is defined by a field, which will be divided by 8 (used for
* bitfields) (StandardType must be Unsigned)
*/
e_DynArrayIndexDiv8
};
/**
* (a_valueKind must be Unsigned, if a_dynArraySizeMethod is e_DynArray...)
*
*/
LogViewXdrStandardType(const QString &a_name,
const int a_valueSize,
const int a_editSize,
const E_ValueKind a_valueKind,
const E_DynArraySizeMethod a_dynArraySizeMethod,
E_ByteOrder a_byteOrder);
uint16_t getValueSize() const;
LogViewXdrStandardType::E_ValueKind getValueKind() const;
void dump() const override;
LogViewXdrStandardType::E_DynArraySizeMethod getDynArraySizeMethod() const;
LogViewXdrStandardType::E_ByteOrder getByteOrder() const;
/**
* The 'real' size of the value, which will be allowd when editing this value
*/
uint16_t getEditSize() const;
protected:
/**
* The size of this value as stored data. It may be bigger as the real (edit) size.
*/
int m_ValueSize;
/**
* The 'real' size of the value, which will be allowd when editing this value
*/
int m_EditSize;
E_ValueKind m_ValueKind;
E_ByteOrder m_ByteOrder;
E_DynArraySizeMethod m_DynArraySizeMethod;
};
}
+105
View File
@@ -0,0 +1,105 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewXdrStruct.hpp"
#include "LogViewXdrValue.hpp"
#include "LogViewXdrType.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewXdrStruct::LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize)
: LogViewXdrElement(a_name, a_kind, "LogViewXdrStruct")
, m_EnumSize(enumSize)
{
}
LogViewXdrStruct::~LogViewXdrStruct()
{
for (auto ptr : m_ChildList)
delete ptr;
}
// ---------------------------------------------------------------
void LogViewXdrStruct::addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast)
{
m_ChildList.push_back(new LogViewXdrType(a_name, a_type, a_arraySize, a_dynArrayOffset, a_kind, a_firstBit, a_lastBit, a_isLast));
}
// ---------------------------------------------------------------
void LogViewXdrStruct::addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind)
{
m_ChildList.push_back(new LogViewXdrValue(a_name, a_value, a_kind));
}
// ---------------------------------------------------------------
LogViewXdrElement* LogViewXdrStruct::getChild(const uint32_t a_childIndex) const
{
if (m_ChildList.size() > a_childIndex)
return m_ChildList[a_childIndex];
return nullptr;
}
// ---------------------------------------------------------------
LogViewXdrType* LogViewXdrStruct::getChildAsType(const uint32_t a_childIndex) const
{
return static_cast<LogViewXdrType*>(getChild(a_childIndex)); // fixme: check ob es wirklich ein XdrType ist
}
// ---------------------------------------------------------------
LogViewXdrValue* LogViewXdrStruct::getChildAsValue(const uint32_t a_childIndex) const
{
return static_cast<LogViewXdrValue*>(getChild(a_childIndex)); // fixme: check ob es wirklich ein XdrValue ist
}
// ---------------------------------------------------------------
void LogViewXdrStruct::dump() const
{
INFO_LOG(m_logger) << "Element[" << getName().toStdString() << "]: kind=" << getKindName().toStdString() << " enumSize=" << getEnumSize();
INFO_LOG(m_logger) << "-------------- childs start -----------------";
std::vector<LogViewXdrElement*>::const_iterator iter = m_ChildList.begin();
while (iter != m_ChildList.end())
{
(*iter)->dump();
++iter;
}
INFO_LOG(m_logger) << "-------------- childs end -----------------";
}
// ---------------------------------------------------------------
uint32_t LogViewXdrStruct::getChildValue(const QString& a_name, bool* a_error) const
{
if (a_error)
*a_error = false;
std::vector<LogViewXdrElement*>::const_iterator iter = m_ChildList.begin();
while (iter != m_ChildList.end())
{
if ((*iter)->getName() == a_name)
return static_cast<const LogViewXdrValue*>(*iter)->getValue();
++iter;
}
if (a_error)
*a_error = true;
return 0;
}
} // namespace N_LogView
+65
View File
@@ -0,0 +1,65 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include <QtCore/QString>
#include "LogViewXdrElement.hpp"
#include <vector>
// forward declarations from stereotyped includes
namespace N_LogView
{
class LogViewXdrValue;
}
namespace N_LogView
{
class LogViewXdrType;
}
namespace N_LogView
{
/**
* This class represents elements which have childs.
* This are enum and struct.
* @author alois.wismer
* @version 1.0
* @created 31-Mrz-2010 11:59:19
*/
class LogViewXdrStruct final : public LogViewXdrElement
{
public:
LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize = 0);
~LogViewXdrStruct();
void addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit = -1, const int16_t a_lastBit = -1, const bool a_isLast = true);
void addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind);
LogViewXdrElement* getChild(const uint32_t a_childIndex) const;
LogViewXdrType* getChildAsType(const uint32_t a_childIndex) const;
LogViewXdrValue* getChildAsValue(const uint32_t a_childIndex) const;
void dump() const override;
uint32_t getChildValue(const QString& a_name, bool* a_error = nullptr) const;
uint16_t getEnumSize() const { return m_EnumSize; }
protected:
uint16_t m_EnumSize;
std::vector<LogViewXdrElement*> m_ChildList;
};
}
+106
View File
@@ -0,0 +1,106 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewXdrType.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind)
: LogViewXdrElement(a_name, a_kind, "LogViewXdrElement")
, m_Type(a_type)
, m_ArraySize(a_arraySize)
, m_MaxArraySize(a_dynArrayOffset)
, m_FirstBit(-1)
, m_LastBit(-1)
, m_IsLast(true)
{
}
// ---------------------------------------------------------------
LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast)
: LogViewXdrElement(a_name, a_kind, "LogViewXdrType")
, m_Type(a_type)
, m_ArraySize(a_arraySize)
, m_MaxArraySize(a_dynArrayOffset)
, m_FirstBit(a_firstBit)
, m_LastBit(a_lastBit)
, m_IsLast(a_isLast)
{
}
// ---------------------------------------------------------------
void LogViewXdrType::dump() const
{
INFO_LOG(m_logger) << "Element[" << getName()
<< "]: kind=" << getKindName()
<< " type=" << getType()
<< " arraySize=" << getArraySize()
<< " maxArraySize=" << getMaxArraySize()
<< " firstBit=" << m_FirstBit
<< " lastBit=" << m_LastBit
<< " isLast=" << m_IsLast;
}
// ---------------------------------------------------------------
const QString& LogViewXdrType::getType() const
{
return m_Type;
}
// ---------------------------------------------------------------
// 0 => opaque
// 1 => normal (scalar) element
// >1 => array
// ---------------------------------------------------------------
uint16_t LogViewXdrType::getArraySize() const
{
return m_ArraySize;
}
// ---------------------------------------------------------------
bool LogViewXdrType::maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const
{
// INFO_LOG(m_logger) << "firstBit=" << m_FirstBit << " lastBit=" << m_LastBit << " isLast=" << m_IsLast;
if (m_FirstBit != -1 && m_LastBit != -1)
{
DEBUG_LOG(m_logger) << "MaskValue for Element " << m_Name
<< " type: " << m_Type
<< " size: " << m_ArraySize
<< " first:last " << m_FirstBit << ":" << m_LastBit
<< " isLast: " << m_IsLast;
uint16_t bitshift = (a_size*8)-m_LastBit-1;
uint32_t mask = (1<<(m_LastBit-m_FirstBit+1))-1;
// INFO_LOG(m_logger) << "value=" << a_value << " bitshift=" << bitshift << " mask=" << mask;
a_value = (a_value >> bitshift) & mask;
// make bold the corresponding bits in the bitfield
a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_FirstBit, QLatin1String("<b>"));
a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_LastBit+1, QLatin1String("</b>"));
return m_IsLast;
}
return true;
}
// ---------------------------------------------------------------
uint16_t LogViewXdrType::getMaxArraySize() const
{
return m_MaxArraySize;
}
} // namespace N_LogView
+111
View File
@@ -0,0 +1,111 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewXdrElement.hpp"
namespace N_LogView
{
/**
* This class represents XDR-elements which have a type and an arraySize. This are
* typedefs and struct-elements.
* The arraySize has following possibilities:
* 0 => opaque
* 1 => scalar
* >1 => array
*
* @author alois.wismer
* @version 1.0
* @created 16-Feb-2010 15:48:24
*/
class LogViewXdrType final : public LogViewXdrElement
{
public:
/**
*
* @param a_name
* @param a_type
* @param a_arraySize
* @param a_dynArrayOffset
* @param a_kind
*/
LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind);
/**
*
* @param a_name
* @param a_type
* @param a_arraySize
* @param a_dynArrayOffset
* @param a_kind
* @param a_firstBit
* @param a_lastBit
* @param a_isLast
*/
LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast);
void dump() const override;
const QString& getType() const;
/**
* 0 => opaque
* 1 => normal (scalar) element
* >1 => array
*/
uint16_t getArraySize() const;
/**
*
* @param a_value
* @param a_size
* @param a_tooltip
*/
bool maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const;
uint16_t getMaxArraySize() const;
protected:
QString m_Type;
/**
* 0 => opaque
* 1 => normal (scalar) element
* >1 => array
*/
uint16_t m_ArraySize;
/**
* The maximum size of the array. Interesting for dynamic arrays.
*/
uint16_t m_MaxArraySize;
/**
* The first relevant bit, if we have bitfield-enum
*/
int16_t m_FirstBit;
/**
* The last relevant bit, if we have bitfield-enum
*/
int16_t m_LastBit;
/**
* used to step to next values when reading out content-data of bit-fields
*/
bool m_IsLast;
};
}
+40
View File
@@ -0,0 +1,40 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewXdrValue.hpp"
namespace N_LogView
{
// ---------------------------------------------------------------
LogViewXdrValue::LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind)
: LogViewXdrElement(a_name, a_kind, "LogViewXdrValue")
, m_Value(a_value)
{}
// ---------------------------------------------------------------
void LogViewXdrValue::dump() const
{
INFO_LOG(m_logger) << "Element[" << getName() << "]: kind=" << getKindName() << " value=" << getValue();
}
// ---------------------------------------------------------------
int64_t LogViewXdrValue::getValue() const
{
return m_Value;
}
} // namespace N_LogView
+40
View File
@@ -0,0 +1,40 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#pragma once
#include "LogViewXdrElement.hpp"
namespace N_LogView
{
/**
* This class represents XDR-elements which have a value. This are #defines and
* enum-elements.
*
* @author alois.wismer
* @version 1.0
* @created 17-Feb-2010 11:17:53
*/
class LogViewXdrValue final : public LogViewXdrElement
{
public:
LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind);
void dump() const override;
int64_t getValue() const;
protected:
int64_t m_Value;
};
}
+17
View File
@@ -0,0 +1,17 @@
log4j.reset=true
log4j.rootLogger=INFO, C
log4j.rootLogger=INFO, F
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.F=org.apache.log4j.RollingFileAppender
log4j.appender.F.File=${LOG4QT_LOGDIR}/${LOG4QT_USER}_LogView.log
log4j.appender.F.MaxFileSize=10MB
# Keep one backup file
log4j.appender.F.MaxBackupIndex=5
log4j.appender.C.layout=org.apache.log4j.PatternLayout
log4j.appender.F.layout=org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n
log4j.appender.F.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n
Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace N_LogView
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "LogView.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace LogView
+22
View File
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for AudioVideoManagement
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace N_LogView
{
typedef NGL::INGLLogger &LOGGER_T;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace LogView
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+88
View File
@@ -0,0 +1,88 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
//
// Implementation of the Class AppComponent
// **************************************************************************
#include "AppComponent.hpp"
namespace N_AppComponent
{
int32_t AppComponent::create(NGL::Settings *settings)
{
for (IAppComponent *c : m_Childs)
c->create(settings);
return 0;
}
int32_t AppComponent::destroy()
{
for (IAppComponent *c : m_Childs)
c->destroy();
return 0;
}
int32_t AppComponent::init()
{
for (IAppComponent *c : m_Childs)
c->init();
return 0;
}
int32_t AppComponent::deinit()
{
for (IAppComponent *c : m_Childs)
c->deinit();
return 0;
}
int32_t AppComponent::start()
{
for (IAppComponent *c : m_Childs)
c->start();
return 0;
}
int32_t AppComponent::stop()
{
for (IAppComponent *c : m_Childs)
c->stop();
return 0;
}
void AppComponent::addChild(IAppComponent *a_child, const QString &a_name)
{
if (a_child)
{
a_child->setName(a_name);
m_Childs.push_back(a_child);
}
}
IAppComponent *AppComponent::getChild(const QString &a_name)
{
for (IAppComponent *c : m_Childs)
{
if (a_name == c->getName())
return c;
}
return nullptr;
}
} // namespace N_AppComponent
+45
View File
@@ -0,0 +1,45 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
//
// Implementation of the Class AppComponent
// **************************************************************************
#pragma once
#include <vector>
#include "IAppComponent.hpp"
#include <PrtCnv/prtcnvlib_export.h>
namespace NGL {
class Settings;
}
namespace N_AppComponent
{
class PRTCNVLIB_EXPORT AppComponent : public N_AppComponent::IAppComponent
{
public:
AppComponent() = default;
~AppComponent() = default;
int32_t create(NGL::Settings *settings) override;
int32_t deinit() override;
int32_t destroy() override;
int32_t init() override;
int32_t start() override;
int32_t stop() override;
protected:
void addChild(IAppComponent* a_child, const QString& a_name = QString());
IAppComponent* getChild(const QString& a_name);
private:
std::vector<IAppComponent*> m_Childs;
};
}
+78
View File
@@ -0,0 +1,78 @@
#
# $Id$
# $HeadURL$
# $Author$
#
#ADD_SUBDIRECTORY(TetraTestServer)
ADD_SUBDIRECTORY(LastTest)
ADD_SUBDIRECTORY(LastTestAuswertung)
SET(PrtCnv_SRCS
logger.h
logger.cpp
AppComponent.cpp
AppComponent.hpp
IAppComponent.hpp
PrtCnvApplication.cpp
PrtCnvApplication.hpp
PrtCnvBroadcastMgr.cpp
PrtCnvBroadcastMgr.hpp
PrtCnvCentralThread.cpp
PrtCnvCentralThread.hpp
PrtCnvDbThread.cpp
PrtCnvDbThread.hpp
PrtCnvInjectionSocket.cpp
PrtCnvInjectionSocket.hpp
PrtCnvInjectionThread.cpp
PrtCnvInjectionThread.hpp
PrtCnvMember.cpp
PrtCnvMember.hpp
PrtCnvRadioThread.cpp
PrtCnvRadioThread.hpp
PrtCnvRadioTrafficThread.cpp
PrtCnvRadioTrafficThread.hpp
PrtCnvSocketThread.cpp
PrtCnvSocketThread.hpp
PrtCnvStoredCentralTelegram.hpp
PrtCnvStoredRadioTelegram.hpp
PrtCnvStoredTelegram.hpp
PrtCnvTelegramLogThread.cpp
PrtCnvTelegramLogThread.hpp
PrtCnvThread.cpp
PrtCnvThread.hpp
PrtCnvThreadStarter.cpp
PrtCnvThreadStarter.hpp
)
NGL_ADD_LIBRARY2(AAR SV PrtCnvLib SHARED ${PrtCnv_SRCS})
NGL_TARGET_LINK_LIBRARIES(PrtCnvLib
PRIVATE
ngldb
nglsettings
LtsUtilsCoreHeaderOnly
Qt5::Sql
Qt5::WebSockets
PUBLIC
CoPrtCnv
Qt5::Core
Qt5::Network
NGLLogger
)
NGL_TARGET_INCLUDE_DIRECTORIES(PrtCnvLib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_ADD_EXECUTABLE(AAR SV PrtCnv PrtCnvMain.cpp)
NGL_TARGET_LINK_LIBRARIES(PrtCnv
PrtCnvLib
Qt5::Core
LtsCommandLineParser
nglcoreapplication
)
NGL_INSTALL_TARGET(PrtCnv)
NGL_INSTALL(AAR SV FILES log4cxx_prtcnv.props DESTINATION bin)
NGL_INSTALL(AAR SV FILES PrtCnv.dat.tts DESTINATION bin)
+59
View File
@@ -0,0 +1,59 @@
// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
//
// Implementation of the Class IAppComponent
// **************************************************************************
#pragma once
#include <QtCore/QString>
namespace NGL {
class Settings;
}
namespace N_AppComponent
{
class IAppComponent
{
public:
IAppComponent() = default;
virtual ~IAppComponent() = default;
virtual int32_t create(NGL::Settings *settings) = 0;
virtual int32_t deinit() = 0;
virtual int32_t destroy() = 0;
virtual int32_t init() = 0;
virtual int32_t start() = 0;
virtual int32_t stop() = 0;
inline const QString& getName() const
{
return m_Name;
}
inline void setName(const QString& newVal)
{
m_Name = newVal;
}
protected:
QString m_Name;
};
}
+21
View File
@@ -0,0 +1,21 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(my_SRCS
main.cpp
tetra_if.cpp
tetra_if.h
)
NGL_ADD_EXECUTABLE(AAR SV PrtCnvLastTest ${my_SRCS})
NGL_TARGET_LINK_LIBRARIES(PrtCnvLastTest
Qt5::Core
Qt5::Network
CoPrtCnv
NGLLogger
ngltools
)
NGL_INSTALL_TARGET(PrtCnvLastTest)
+65
View File
@@ -0,0 +1,65 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include <QCoreApplication>
#include <QStringList>
#include <QHostAddress>
#include <stdio.h>
#include <stdlib.h>
#include "tetra_if.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
// Check alle 30 Sekunden
NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false);
NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger());
const QStringList args = app.arguments().mid(1);
if (args.count() < 4)
TetraIF::usage();
QHostAddress tetra(args[0]);
if (tetra.isNull())
{
ERROR_LOG(logger) << "Invalid IP address " << args[0];
TetraIF::usage();
}
bool bOk;
unsigned short port = args[1].toUShort(&bOk);
if (!bOk)
{
ERROR_LOG(logger) << "Invalid IP port " << args[1];
TetraIF::usage();
}
unsigned short issi = args[2].toUShort(&bOk);
if (!bOk)
{
ERROR_LOG(logger) << "Invalid ISSI id " << args[2];
TetraIF::usage();
}
const QString mode = args[3].toLower();
if (mode != QLatin1String("listen") &&
mode != QLatin1String("send_random") &&
mode != QLatin1String("send_file"))
{
ERROR_LOG(logger) << "Invalid mode " << args[3];
TetraIF::usage();
}
TetraIF t(tetra, port, issi);
if (mode == QLatin1String("listen"))
t.listenMode(args.mid(4));
else if (mode == QLatin1String("send_random"))
t.randomMode(args.mid(4));
else if (mode == QLatin1String("send_file"))
t.fileMode(args.mid(4));
t.start();
return app.exec();
}
+507
View File
@@ -0,0 +1,507 @@
/**
* Tetra-Interface für Lasttest
* $Id$
* $HeadURL$
* $Author$
*/
#include "tetra_if.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QCoreApplication>
#include <QDateTime>
#include <QDir>
#include <QNetworkInterface>
#include <QStringList>
#include <QTcpSocket>
#include <QTimer>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
#include <CoPrtCnv/CoPrtCnvHexDumpHelper.hpp>
#include <PrtCnv/PrtCnvRadioThread.hpp>
#include <PrtCnv/PrtCnvThreadStarter.hpp>
TetraIF::TetraIF(const QHostAddress &addr, unsigned short port, unsigned short issi)
: QObject()
, m_addr(addr)
, m_port(port)
, m_issi(issi)
, m_socket(new QTcpSocket(this))
, m_count(0)
, m_telegramsPerSecond(0)
, m_telegramsInCurSecond(0)
, m_secondFragment(0)
, m_timer(nullptr)
, m_SendCounter(0)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger())
{
connect(m_socket, &QTcpSocket::connected, this, &TetraIF::onConnected);
connect(m_socket, &QTcpSocket::disconnected, this, &TetraIF::onDisconnected);
connect(m_socket, &QTcpSocket::readyRead, this, &TetraIF::onReadyRead);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &TetraIF::onError);
m_outputDir = QCoreApplication::applicationDirPath();
m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-');
}
void TetraIF::start()
{
m_socket->connectToHost(m_addr, m_port);
}
void TetraIF::listenMode(const QStringList &args)
{
// take input and write them to and output directory
if (args.count() > 1)
usage();
m_outputDir = QCoreApplication::applicationDirPath();
if (args.count() == 1)
m_outputDir = args[0];
if (!QDir().mkpath(m_outputDir))
{
ERROR_LOG(m_logger) << "Error creating directory "
<< m_outputDir;
usage();
}
m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-');
}
void TetraIF::randomMode(const QStringList &args)
{
if (args.count() < 3)
{
ERROR_LOG(m_logger) << "Invalid argument count";
usage();
}
bool bOk;
int dataSize = args[0].toInt(&bOk);
if (!bOk || dataSize > 256 || dataSize < 0)
{
ERROR_LOG(m_logger) << "Invalid data size " << args[0];
usage();
}
m_count = args[1].toInt(&bOk);
if (!bOk || m_count == 0 || m_count < -1)
{
ERROR_LOG(m_logger) << "Invalid count " << args[1];
usage();
}
m_telegramsPerSecond = args[2].toInt(&bOk);
if (!bOk || m_telegramsPerSecond < 1)
{
ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2];
usage();
}
m_data.reserve(dataSize);
for (int i = 0; i < dataSize; ++i)
m_data += (i % 256);
parseISSIs(args.mid(3));
INFO_LOG(m_logger) << "Sending " << m_data.size()
<< " bytes, " << m_telegramsPerSecond
<< " telegrams/second for " << m_count
<< " time(s) to issi(s) " << getIssisAsString();
setupTimer();
}
void TetraIF::fileMode(const QStringList &args)
{
if (args.count() < 3)
{
ERROR_LOG(m_logger) << "Invalid argument count";
usage();
}
QFile f(args[0]);
if (!f.exists() || f.size() > 256)
{
ERROR_LOG(m_logger) << "Invalid file: " << args[0];
usage();
}
bool bOk;
m_count = args[1].toInt(&bOk);
if (!bOk || m_count == 0 || m_count < -1)
{
ERROR_LOG(m_logger) << "Invalid count " << args[1];
usage();
}
m_telegramsPerSecond = args[2].toInt(&bOk);
if (!bOk || m_telegramsPerSecond < 1)
{
ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2];
usage();
}
if (!f.open(QIODevice::ReadOnly))
{
ERROR_LOG(m_logger) << "Error opening file "
<< f.fileName()
<< " for reading - error: "
<< f.errorString();
}
m_data = f.readAll();
parseISSIs(args.mid(3));
INFO_LOG(m_logger) << "Sending " << m_data.size()
<< " bytes, " << m_telegramsPerSecond
<< " telegrams/second for " << m_count
<< " time(s) to issi(s) " << getIssisAsString();
setupTimer();
}
void TetraIF::usage()
{
NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger());
ERROR_LOG(logger) << "Usage : " << QCoreApplication::applicationFilePath() << " <ip> <port> <src_issi> <mode> <options>";
ERROR_LOG(logger) << " <mode> : listen|send_random|send_file";
ERROR_LOG(logger) << " <listen> : [<output_dir>]";
ERROR_LOG(logger) << " <send_random> : <size> <count> <telegrams_per_second_and_dest> [<dest_issi1> .. <dest_issiN>]";
ERROR_LOG(logger) << " <send_file> : <file> <count> <telegrams_per_second_and_dest> [<dest_issi1> .. <dest_issiN>]";
exit(1);
}
void TetraIF::onConnected()
{
INFO_LOG(m_logger) << "Connected to " << m_socket->peerName() << ":" << m_socket->peerPort();
doInitialLogin();
}
void TetraIF::onDisconnected()
{
INFO_LOG(m_logger) << "Disconnected - exiting application";
QCoreApplication::quit();
}
void TetraIF::onReadyRead()
{
do
{
DEBUG_LOG(m_logger) << "Got " << m_socket->bytesAvailable() << " bytes from socket";
// read the 4-byte frame-header for find out the length of whole telegram
N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header;
if (m_socket->bytesAvailable() < int(sizeof(header)))
return;
m_socket->peek(reinterpret_cast<char *>(&header), sizeof(header));
if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber)
{
ERROR_LOG(m_logger) << "Incorrect magic number (0x"
<< QString::number(header.m_MagicNumber, 16)
<< " - aborting";
exit(2);
}
if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length))
{
ERROR_LOG(m_logger) << "Radio-Telegram length to big: "
<< header.m_Length
<< ", but I proceed with this telegram.";
}
const quint16 dataSize = header.m_Length + sizeof(header);
if (m_socket->bytesAvailable() < dataSize)
{
INFO_LOG(m_logger) << "not enough bytes available - waiting for more data";
return;
}
QByteArray buf(dataSize, Qt::Uninitialized);
m_socket->read(buf.data(), dataSize);
handleReceivedTelegram(buf);
}
while (m_socket->bytesAvailable());
}
void TetraIF::onError(QAbstractSocket::SocketError err)
{
ERROR_LOG(m_logger) << "Socket error "
<< err
<< " ("
<< m_socket->errorString()
<< ") - aborting";
exit(2);
}
void TetraIF::doInitialLogin()
{
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_issi);
m_socket->write(tele.data());
m_socket->flush();
}
void TetraIF::handleReceivedTelegram(const QByteArray &data)
{
const auto type = N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type(data.at(4));
switch (type)
{
// response to register indication
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp:
handleRegisterRsp(data.at(5)); // registration status
break;
// payload telegram
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq:
handleDataIndReq(data);
break;
// ack-telegram - not handled here
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq:
// handleReportIndReq(data);
break;
// air-interface-load-telegram - not handled here
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq:
// handleAirInterfaceLoadReq(data);
break;
default:
return;
}
INFO_LOG(m_logger) << "PDU Type: " << type;
dumpData(data);
}
void TetraIF::handleRegisterRsp(const uint8_t a_registrationStatus)
{
QByteArray logText;
switch (a_registrationStatus)
{
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered:
INFO_LOG(m_logger) << "Valid register response from Tetra ";
if (m_timer)
m_timer->start();
return;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI:
logText = "TETRA: Register-Response: Status=Duplicate ISSI";
break;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI:
logText = "TETRA: Register-Response: Status=Invalid ISSI";
break;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress:
logText = "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address (";
{
const QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
for (const QHostAddress &addr : ipList)
logText += addr.toString().toUtf8() + ", ";
logText += ")...";
}
break;
default:
logText = "Unknown registration status: " + QByteArray::number(a_registrationStatus);
break;
}
ERROR_LOG(m_logger) << logText;
exit(2);
}
void TetraIF::dumpData(const QByteArray &data)
{
// im Listen-Mode -> Ausgabe in Directory
if (m_outputDir.isEmpty())
return;
const qint64 msecs = QDateTime::currentMSecsSinceEpoch();
const QString timeStr = QStringLiteral("%1.%2").arg(msecs / 1000).arg(msecs % 1000);
{
QFile f(m_outputDir + timeStr + QLatin1String(".dat"));
if (!f.open(QIODevice::WriteOnly))
{
ERROR_LOG(m_logger) << "Error opening file "
<< f.fileName()
<< " for writing - error: "
<< f.errorString();
}
f.write(data);
f.close();
}
if (data.size() > 27)
{
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(data);
INFO_LOG(m_logger) << "Got telegram from "
<< tele.getSrcISSI()
<< " with size "
<< data.size()
<< " and payload size "
<< tele.getPayloadSize();
NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, tele.data());
QFile f(m_outputDir + QStringLiteral("payload-%1-%2.dat").arg(QString::number(tele.getSrcISSI()), timeStr));
if (!f.open(QIODevice::WriteOnly))
{
ERROR_LOG(m_logger) << "Error opening file "
<< f.fileName()
<< " for writing - error: "
<< f.errorString();
}
// 27 Bytes Header entfernen
f.write(&data.data()[27], data.size() - 27);
f.close();
}
}
void TetraIF::onSendData()
{
++m_secondFragment;
// we're called every 10ms
if (m_secondFragment == 100)
{
m_secondFragment = 0;
m_telegramsInCurSecond = 0;
}
int telegramsToSendNow = (m_telegramsPerSecond - m_telegramsInCurSecond) / (100 - m_secondFragment);
NOTICE_LOG(m_logger) << "telegramsToSendNow: " << telegramsToSendNow << ", " << m_telegramsPerSecond << ", " << m_telegramsInCurSecond << ", " << m_secondFragment;
m_telegramsInCurSecond += telegramsToSendNow;
static uint8_t s_counter = 1;
static char s_randomChar = 0;
for (int i = 0; i < telegramsToSendNow; ++i)
{
for (unsigned short dest_issi : qAsConst(m_issiList))
{
// GEF_BESTAETIGUNG -> Dummy, gets overridden by setPayloadDataComplete()
m_data[0] = s_randomChar++;
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(GEF_BESTAETIGUNG, m_data.size(), dest_issi);
tele.setPayloadDataComplete(m_data);
tele.setSrcISSI(m_issi);
tele.setDestISSI(dest_issi);
tele.setZaehler(s_counter++);
DEBUG_LOG(m_logger) << "Sending " << tele.getSize() << " bytes to Tetra (ISSI: " << dest_issi << ")";
m_socket->write(tele.data());
}
if (m_count > 0)
{
if (--m_count <= 0)
{
INFO_LOG(m_logger) << "Finsihed";
m_socket->disconnectFromHost();
}
}
m_socket->flush();
}
}
void TetraIF::parseISSIs(const QStringList &issiList)
{
m_issiList.clear();
// broadcast
if (issiList.count() == 0)
{
m_issiList += 0;
return;
}
for (const QString &issiStr : issiList)
{
bool bOk;
unsigned short issi = issiStr.toUShort(&bOk);
if (!bOk)
{
ERROR_LOG(m_logger) << "Not a valid issi number: " << issiStr;
usage();
}
m_issiList += issi;
}
}
QString TetraIF::getIssisAsString() const
{
QString ret;
for (unsigned short issi : qAsConst(m_issiList))
ret += QString::number(issi) + QLatin1String(", ");
return ret.left(ret.size() - 2);
}
void TetraIF::handleDataIndReq(const QByteArray &data)
{
N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(data);
uint32_t m_HostISSI = 2;
if (m_HostISSI == radioTelegram->getDestISSI())
{
switch (radioTelegram->getFragmentStatus())
{
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment:
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment:
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment:
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_NotFragmented:
handleLoginTelegram(radioTelegram);
break;
default:
ERROR_LOG(m_logger) << "Unknown payload-status!: " << radioTelegram->getFragmentStatus();
break;
}
delete radioTelegram; // this deletes also a_data
}
}
void TetraIF::handleLoginTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *a_loginTelegram)
{
uint16_t identity = a_loginTelegram->getIdentity();
uint32_t issi = a_loginTelegram->getSrcISSI();
// is it a login request?
if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest == (a_loginTelegram->getPayloadDataUInt8(2) & N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginStatusMask))
{
bool sent = sendLoginResponse(issi);
if (sent)
INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " logged in";
else
INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " is NOT logged in";
}
}
bool TetraIF::sendLoginResponse(const uint32_t a_ISSI)
{
++m_SendCounter;
N_CoPrtCnv::CoPrtCnvRadioTelegram *a_telegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BESTAETIGUNG, 20, a_ISSI);
a_telegram->setZaehler(m_SendCounter);
// set our ISSI
a_telegram->setDestISSI(a_ISSI);
a_telegram->setSrcISSI(2);
gef_telegramm_id_et telId = a_telegram->isNormalTelegram() ? a_telegram->getTelID() : GEF_BESTAETIGUNG;
// send telegram to radio
INFO_LOG(m_logger) << "Send telegram to radio: telId=" << telId << " wcounter=" << a_telegram->zaehler() << " size= 28";
// Protokoll-Byte wird hier mit als Datenbyte missbraucht...
a_telegram->setProtocolIdentifier(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL);
a_telegram->setPayloadData(0x01);
a_telegram->setPayloadData(0x04);
// Bitanzahl anpassen
a_telegram->getData()[22] = 0x0d; // Warum 13 (bzw. 21) ??
char *data = a_telegram->getData();
// Header - complete Payload in Bytes
data[02] = 0x18; // 24 Bytes
// Len in Bits
data[22] = 0x0d;
data[23] = 0x00;
// Len in Bytes
data[24] = 0x02;
data[25] = 0x00;
// Data
data[13] = 0x00;
data[26] = 0x01;
data[27] = 0x40;
m_socket->write(data, 28);
delete a_telegram;
return m_socket->flush();
}
void TetraIF::setupTimer()
{
delete m_timer;
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &TetraIF::onSendData);
m_timer->setInterval(10);
}
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff. Show more