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

@@ -0,0 +1,127 @@
#
# $Id$
# $HeadURL$
# $Author$
#
#
# --- Executable hlaTestTool -------------------------------------------------
#
SET(SRCS_exe
main.cpp
main_handler.cpp
main_handler.h
ngs_connector.cpp
ngs_connector.h
ngs_handler.cpp
ngs_handler.h
damage_model.cpp
damage_model.h
web_socket_interface.cpp
web_socket_interface.h
ws_telegrams.cpp
ws_telegrams.h
# just a test tool, so compile them twice
../Guez/rpr/rpr_global.h
../Guez/rpr/rpr_ia_munitiondetonation.cpp
../Guez/rpr/rpr_ia_munitiondetonation.h
../Guez/rpr/rpr_ia_weaponfire.cpp
../Guez/rpr/rpr_ia_weaponfire.h
../Guez/rpr/rpr_ia_guez_init.cpp
../Guez/rpr/rpr_ia_guez_init.h
../Guez/rpr/rpr_ia_guez_requestbitereport.cpp
../Guez/rpr/rpr_ia_guez_requestbitereport.h
../Guez/rpr/rpr_ia_guez_bitereport.cpp
../Guez/rpr/rpr_ia_guez_bitereport.h
../Guez/rpr/rpr_ia_guez_hit.cpp
../Guez/rpr/rpr_ia_guez_hit.h
../Guez/rpr/rpr_observer_aggregateentity_object_cb.h
../Guez/rpr/rpr_observer_aggregateentity_object_instance_cb.h
../Guez/rpr/rpr_observer_aircraft_cb_notifier.h
../Guez/rpr/rpr_observer_aircraft_object_cb.h
../Guez/rpr/rpr_observer_aircraft_object_instance_cb.h
../Guez/rpr/rpr_observer_baseentity_object_cb.h
../Guez/rpr/rpr_observer_baseentity_object_instance_cb.h
../Guez/rpr/rpr_observer_groundvehicle_cb_notifier.h
../Guez/rpr/rpr_observer_groundvehicle_object_cb.h
../Guez/rpr/rpr_observer_groundvehicle_object_instance_cb.h
../Guez/rpr/rpr_observer_human_cb_notifier.h
../Guez/rpr/rpr_observer_human_object_cb.h
../Guez/rpr/rpr_observer_human_object_instance_cb.h
../Guez/rpr/rpr_observer_lifeform_object_cb.h
../Guez/rpr/rpr_observer_lifeform_object_instance_cb.h
../Guez/rpr/rpr_observer_object_cb.h
../Guez/rpr/rpr_observer_object_instance_cb.h
../Guez/rpr/rpr_observer_physicalentity_object_cb.h
../Guez/rpr/rpr_observer_physicalentity_object_instance_cb.h
../Guez/rpr/rpr_observer_platform_object_cb.h
../Guez/rpr/rpr_observer_platform_object_instance_cb.h
../Guez/rpr/rpr_observer_guez_groundvehicle_cb_notifier.h
../Guez/rpr/rpr_observer_guez_groundvehicle_object_cb.h
../Guez/rpr/rpr_observer_guez_groundvehicle_object_instance_cb.h
../Guez/rpr/rpr_observer_guez_human_cb_notifier.h
../Guez/rpr/rpr_observer_guez_human_object_cb.h
../Guez/rpr/rpr_observer_guez_human_object_instance_cb.h
../Guez/rpr/rpr_observer_guez_observer_controller_cb_notifier.h
../Guez/rpr/rpr_observer_guez_observer_controller_object_cb.h
../Guez/rpr/rpr_observer_guez_observer_controller_object_instance_cb.h
../Guez/rpr/rpr_observer_environment_object_object_cb.h
../Guez/rpr/rpr_observer_environment_object_object_instance_cb.h
../Guez/rpr/rpr_observer_areal_object_object_cb.h
../Guez/rpr/rpr_observer_areal_object_object_instance_cb.h
../Guez/rpr/rpr_observer_other_areal_object_object_cb.h
../Guez/rpr/rpr_observer_other_areal_object_object_instance_cb.h
../Guez/rpr/rpr_observer_point_object_object_cb.h
../Guez/rpr/rpr_observer_point_object_object_instance_cb.h
../Guez/rpr/rpr_observer_other_point_object_object_cb.h
../Guez/rpr/rpr_observer_other_point_object_object_instance_cb.h
../Guez/rpr/rpr_observer_guez_minefield_cb_notifier.h
../Guez/rpr/rpr_observer_guez_minefield_object_cb.h
../Guez/rpr/rpr_observer_guez_minefield_object_instance_cb.h
../Guez/rpr/rpr_observer_guez_minefield_breach_cb_notifier.h
../Guez/rpr/rpr_observer_guez_minefield_breach_object_cb.h
../Guez/rpr/rpr_observer_guez_minefield_breach_object_instance_cb.h
)
# Due to debug output for EntityTypeStruct
SET_SOURCE_FILES_PROPERTIES(ngs_connector.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE)
#NGL_ADD_SVC_ICON(SRCS_exe)
NGL_ADD_EXECUTABLE(HLA hlaTestTool ${SRCS_exe})
NGL_TARGET_LINK_LIBRARIES(hlaTestTool
ddsconnector
LtsCommandLineParser
LtsCoordTrans
nglcoreapplication
NGLLogger
nglsettings
Qt5::Core
Qt5::Gui
Qt5::Network
Qt5::WebSockets
ngltools
# LtsUtilsDds
NGS::NGS
HlaCommon
tabTelegrams
)
NGL_INSTALL_TARGET(hlaTestTool)
#NGL_INSTALL(AAR SV FILES
# log4cxx_hla.props
# swconf.cfg
# DESTINATION bin)
#NGL_INSTALL(AAR SV FILES
# RPRFOM20d17E_saabNov2021.xml
# DESTINATION bin RENAME RPRFOM20d17E.xml)
#NGL_ADD_TARGET_LINK(hlaTestTool pHLA)
#NGL_INSTALL(AAR SV FILES
# lts-cc.hla.conf
# DESTINATION . RENAME lts-cc.hla.conf.distrib)
@@ -0,0 +1,284 @@
/**
* @RDE_HEADER@
* Damage state transaformation from/to HLA <-> Excon, see ICD, 4.4.3.5.6 - Damage Model
* $Id$
* $HeadURL$
* $Author$
*/
#include "damage_model.h"
#include <QTimer>
#include <QDateTime>
namespace HighLevelArchitecture
{
// ICD, 4.4.3.5.6 - Damage Model
// es sind dort nich alle definiert, die Reihenfolge ist DamageState - FirePower - Immobilized
DamageModel::DamageModel(const IdentifierStruct &is,
const rpr2::TacticalStatusStruct &state)
: m_is(is)
{
initTimer();
setTacticalStatusStruct(state, QDateTime::currentMSecsSinceEpoch());
}
DamageModel::DamageModel(const rpr2::TacticalStatusStruct &state)
{
setTacticalStatusStruct(state, QDateTime::currentMSecsSinceEpoch());
}
rpr2::DamageStatusEnum32::ET DamageModel::damageState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return rpr2::DamageStatusEnum32::NoDamage;
// Todo: Correct?!?
switch (m_tacticalStates.at(idx).tss.TacticalStatus)
{
case rpr2::TacticalStatusEnum8::CombatReady:
return rpr2::DamageStatusEnum32::NoDamage;
case rpr2::TacticalStatusEnum8::Immobilized:
case rpr2::TacticalStatusEnum8::ImmobilizedVisible:
case rpr2::TacticalStatusEnum8::LightHit:
return rpr2::DamageStatusEnum32::SlightDamage;
case rpr2::TacticalStatusEnum8::WeaponKill:
case rpr2::TacticalStatusEnum8::WeaponKillVisible:
case rpr2::TacticalStatusEnum8::MediumHit:
case rpr2::TacticalStatusEnum8::HeavyHit:
return rpr2::DamageStatusEnum32::ModerateDamage;
case rpr2::TacticalStatusEnum8::TotalKill:
return rpr2::DamageStatusEnum32::Destroyed;
case rpr2::TacticalStatusEnum8::HitWithoutEffect:
case rpr2::TacticalStatusEnum8::TemporaryFailure:
case rpr2::TacticalStatusEnum8::NearMiss:
return rpr2::DamageStatusEnum32::NoDamage;
}
return rpr2::DamageStatusEnum32::NoDamage;
}
rpr2::TotalStatusEnum32::ET DamageModel::totalState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return rpr2::TotalStatusEnum32::CombatReady;
return m_tacticalStates.at(idx).tss.TotalStatus;
}
bool DamageModel::immobilized(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return false;
return m_tacticalStates.at(idx).tss.TotalStatus & (rpr2::TotalStatusEnum32::Immobilized | rpr2::TotalStatusEnum32::ImmobilizedVisible);
}
bool DamageModel::firePowerDisabled(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return false;
return m_tacticalStates.at(idx).tss.TotalStatus & (rpr2::TotalStatusEnum32::WeaponKill | rpr2::TotalStatusEnum32::WeaponKillVisible);
}
static inline bool checkManipulationChanged(const rpr2::TacticalStatusStruct &oldTss,
const rpr2::TacticalStatusStruct &newTss)
{
return
(oldTss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation) !=
(newTss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation);
}
void DamageModel::setTacticalStatusStruct(const rpr2::TacticalStatusStruct &state, qint64 simTimeMSec)
{
bool bManipulationChanged = true;
const int idx = indexForTime(simTimeMSec);
if (idx > 0 && m_tacticalStates.at(idx).timeStamp == simTimeMSec)
{
// already there...
if (state == m_tacticalStates.at(idx).tss)
return;
bManipulationChanged = checkManipulationChanged(m_tacticalStates.at(idx).tss, state);
m_tacticalStates[idx].tss = state;
}
else
{
if (idx >= 0)
bManipulationChanged = checkManipulationChanged(m_tacticalStates.at(idx).tss, state);
TacticalStatusStructWithTimeStamp tssTs;
tssTs.tss = state;
tssTs.timeStamp = simTimeMSec;
m_tacticalStates.insert(idx + 1, std::move(tssTs)); // idx = -1 -> oldest, will become index 0
}
while (m_tacticalStates.size() > 10)
m_tacticalStates.pop_front();
if (bManipulationChanged)
emit playerManipulationChanged(m_is.entityNumber(), state.TotalStatus & rpr2::TotalStatusEnum32::Manipulation, simTimeMSec);
}
void DamageModel::setTacticalStatusStructWithTimestamp(TacticalStatusStructWithTimeStamp &tssTs, const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec)
{
switch (state)
{
case rpr2::HitResultEnum16::Reset:
tssTs.tss.TotalStatus = rpr2::TotalStatusEnum32::CombatReady;
tssTs.tss.TacticalStatus = rpr2::TacticalStatusEnum8::CombatReady;
break;
case rpr2::HitResultEnum16::LightDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::LightHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::LightHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::LightHit;
break;
case rpr2::HitResultEnum16::MediumDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::MediumHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::MediumHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::MediumHit;
break;
case rpr2::HitResultEnum16::HeavyDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::HeavyHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::HeavyHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::HeavyHit;
break;
case rpr2::HitResultEnum16::MobilityKill:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::Immobilized);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::Immobilized ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::Immobilized;
break;
case rpr2::HitResultEnum16::MobilityKillVisible:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::ImmobilizedVisible);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::ImmobilizedVisible ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::ImmobilizedVisible;
break;
case rpr2::HitResultEnum16::WeaponDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::WeaponKill);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::WeaponKill ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::WeaponKill;
break;
case rpr2::HitResultEnum16::WeaponDamageVisible:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::WeaponKillVisible);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::WeaponKillVisible ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::WeaponKillVisible;
break;
case rpr2::HitResultEnum16::TemporaryFailure:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::TemporaryFailure);
break;
case rpr2::HitResultEnum16::NearMiss:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::NearMiss);
break;
case rpr2::HitResultEnum16::Contaminated:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::CContamination);
break;
case rpr2::HitResultEnum16::CheatingKill:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::Manipulation);
tssTs.tss.TacticalStatus = rpr2::TacticalStatusEnum8::TotalKill;
break;
case rpr2::HitResultEnum16::HitWithNoEffect:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::HitWithoutEffect);
break;
default:
break;
}
tssTs.tss.VulnerabilityKind = 0;
tssTs.timeStamp = simTimeMSec;
}
void DamageModel::setTacticalStatus(const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec)
{
const int idx = indexForTime(simTimeMSec);
if (idx > 0 && m_tacticalStates.at(idx).timeStamp == simTimeMSec)
{
TacticalStatusStructWithTimeStamp tssTs;
setTacticalStatusStructWithTimestamp(tssTs, state, simTimeMSec); // Convert for comparison...
// already there...
if (tssTs.tss.TacticalStatus == m_tacticalStates.at(idx).tss.TacticalStatus)
return;
// When he WAS manipulated and is now being reset, also reset manipulation:
if (tssTs.tss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation &&
state == rpr2::HitResultEnum16::Reset)
emit playerManipulationChanged(m_is.entityNumber(), false, simTimeMSec);
setTacticalStatusStructWithTimestamp(m_tacticalStates[idx], state, simTimeMSec);
}
else
{
TacticalStatusStructWithTimeStamp tssTs;
setTacticalStatusStructWithTimestamp(tssTs, state, simTimeMSec);
m_tacticalStates.insert(idx + 1, std::move(tssTs)); // idx = -1 -> oldest, will become index 0
}
while (m_tacticalStates.size() > 10)
m_tacticalStates.pop_front();
// Manipulation only occurs when cheatingKill is sent:
if (state == rpr2::HitResultEnum16::CheatingKill)
emit playerManipulationChanged(m_is.entityNumber(), true, simTimeMSec);
}
ProjectDataManagement::VulnerabilityState DamageModel::vulnerabilityState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
switch (m_tacticalStates.at(idx).tss.TacticalStatus)
{
case rpr2::TacticalStatusEnum8::CombatReady:
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
case rpr2::TacticalStatusEnum8::LightHit:
return ProjectDataManagement::VulnerabilityState_def::LightDamage;
case rpr2::TacticalStatusEnum8::MediumHit:
return ProjectDataManagement::VulnerabilityState_def::MediumDamage;
case rpr2::TacticalStatusEnum8::HeavyHit:
return ProjectDataManagement::VulnerabilityState_def::HeavyDamage;
case rpr2::TacticalStatusEnum8::Immobilized:
return ProjectDataManagement::VulnerabilityState_def::MobilityKill;
case rpr2::TacticalStatusEnum8::ImmobilizedVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleMobilityKill;
case rpr2::TacticalStatusEnum8::WeaponKill:
return ProjectDataManagement::VulnerabilityState_def::WeaponSystemDamage;
case rpr2::TacticalStatusEnum8::WeaponKillVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleWeaponSystemDamage;
case rpr2::TacticalStatusEnum8::TotalKill:
return ProjectDataManagement::VulnerabilityState_def::CatastrophicKill;
case rpr2::TacticalStatusEnum8::TemporaryFailure:
return ProjectDataManagement::VulnerabilityState_def::TemporarySeverance;
case rpr2::TacticalStatusEnum8::NearMiss:
return ProjectDataManagement::VulnerabilityState_def::NearMiss;
case rpr2::TacticalStatusEnum8::HitWithoutEffect:
return ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect;
}
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
}
int DamageModel::indexForTime(qint64 simTimeMSec) const
{
const int s = m_tacticalStates.size();
if (simTimeMSec < 0 && s != 0) // = use current
return s - 1;
for (int i = s - 1; i >= 0; --i)
{
const auto &tss = m_tacticalStates.at(i);
if (tss.timeStamp <= simTimeMSec)
return i;
}
return -1;
}
void DamageModel::initTimer()
{
delete m_timer;
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_timer->start(s_waitInterval);
connect(m_timer, &QTimer::timeout,
this, [this]()
{
emit damageStateChanged();
m_timer->deleteLater();
m_timer = nullptr;
});
}
} // namespace HighLevelArchitecture
@@ -0,0 +1,80 @@
/**
* @RDE_HEADER@
* Damage state transaformation from/to HLA <-> Excon, see ICD, 4.4.3.5.6 - Damage Model
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <Common/identifierstruct.h>
#include <QObject>
#include <QVector>
#include <TacticalStatusStruct.h>
#include <EntityIdentifierStruct.h>
#include <DamageStatusEnum32.h>
#include <HitResultEnum16.h>
#include <ProjectDataManagement/pdm_enums.hpp>
class QTimer;
namespace HighLevelArchitecture
{
class DamageModel : public QObject
{
Q_OBJECT
public:
explicit DamageModel(const IdentifierStruct &is,
const rpr2::TacticalStatusStruct &state);
explicit DamageModel(const rpr2::TacticalStatusStruct &state);
explicit DamageModel(const IdentifierStruct &is)
: DamageModel(is, {rpr2::TacticalStatusEnum8::CombatReady, 0, rpr2::TotalStatusEnum32::CombatReady})
{}
const IdentifierStruct &identifierStruct() const { return m_is; }
rpr2::DamageStatusEnum32::ET damageState(qint64 simTimeMSec) const;
rpr2::TotalStatusEnum32::ET totalState(qint64 simTimeMSec) const;
ProjectDataManagement::VulnerabilityState vulnerabilityState(qint64 simTimeMSec) const;
bool immobilized(qint64 simTimeMSec) const;
bool firePowerDisabled(qint64 simTimeMSec) const;
void setTacticalStatusStruct(const rpr2::TacticalStatusStruct &state, qint64 simTimeMSec);
void setTacticalStatus(const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec);
rpr2::TacticalStatusStruct tacticalStatusStruct(qint64 timeStamp) const;
Q_SIGNALS:
void damageStateChanged();
void playerManipulationChanged(int eqNo, bool playerIsManipulated, qint64 simTimeMSecs);
private:
int indexForTime(qint64 simTimeMSec) const;
void initTimer();
private:
IdentifierStruct m_is;
QTimer *m_timer = nullptr;
struct TacticalStatusStructWithTimeStamp
{
rpr2::TacticalStatusStruct tss;
qint64 timeStamp = 0;
TacticalStatusStructWithTimeStamp()
{
tss.TacticalStatus = rpr2::TacticalStatusEnum8::CombatReady;
tss.VulnerabilityKind = 0;
tss.TotalStatus = rpr2::TotalStatusEnum32::CombatReady;
}
};
QVector<TacticalStatusStructWithTimeStamp> m_tacticalStates;
static const int s_waitInterval = 100; // 100 ms
void setTacticalStatusStructWithTimestamp(TacticalStatusStructWithTimeStamp &tssTs, const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec);
};
} // namespace HighLevelArchitecture
@@ -0,0 +1,135 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# Service: HLA
###########################################################
#log4j.logger.HLA=INFO
#log4j.logger.HLA.main=DEBUG
#log4j.logger.HLA.MainHandler=DEBUG
#log4j.logger.HLA.NgsHandler=DEBUG
#log4j.logger.HLA.NgsConnector=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.Player=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.Player.Status=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.Player.Position=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.Player.StatusChange=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.Object=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.MineField=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.MineFieldBreach=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.FireSupport=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.FireSupportSingleShot=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.ChemicalAgentArea=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.MunitionDetonation=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.WeaponFire=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.GuezHit=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.GuezExconEngagement=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.GuezInit=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.GuezBiteReport=DEBUG
#log4j.logger.HLA.NgsConnector.Inbound.GuezBiteRequest=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.Startup=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.Player=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.Player.Status=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.Player.Position=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.MineField=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.MineField.TriggeredImpacts=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.MineFieldBreach=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.FireSupport=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.FireSupport.TriggeredImpacts=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.FireSupportSingleShot=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.ChemicalAgentArea=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.NuclearAgentArea=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.MunitionDetonation=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.WeaponFire=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.GuezHit=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.GuezExconEngagement=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.GuezInit=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.GuezBiteReport=DEBUG
#log4j.logger.HLA.NgsConnector.Outbound.GuezBiteRequest=DEBUG
#log4j.logger.HLA.PpmHandler=DEBUG
#log4j.logger.HLA.Callbacks.Interaction.ActionRequest=DEBUG
#log4j.logger.HLA.Callbacks.Interaction.MunitionDetonation=DEBUG
#log4j.logger.HLA.Callbacks.Interaction.StartResume=DEBUG
#log4j.logger.HLA.Callbacks.Interaction.StopFreeze=DEBUG
#log4j.logger.HLA.Callbacks.Interaction.WeaponFire=DEBUG
#log4j.logger.HLA.WebSocketHandler=DEBUG
# File
###########################################################
log4j.appender.file=Lts::RollingFileAppender
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=9
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
# Appnd_Console
###########################################################
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
# Appnd_Syslog
###########################################################
log4j.appender.syslog=org.apache.log4j.SyslogAppender
log4j.appender.syslog.Threshold=ERROR
log4j.appender.syslog.SysLogHost=localhost
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
###########################################################
###########################################################
###########################################################
# 1) Available Levels in LOG4CXX Version 0.10.0:
# TRACE,
# DEBUG,
# INFO,
# WARN,
# ERROR
# FATAL
#
# d = date/time
# p = priority (Level)
# c = category/channel
# m = message
# F = file
# L = line
# n = platform dependent line separator character or characters.
# ....
#
# Examples for console:
# a)
# %d %p %c #%m# (%.50F:%L)%n
# date/time
# priority
# category/channel
# #message#
# (Maximal 50Character des Filename von rechts:Line)
# line separator
#
# b)
# %d (%.15F:%L) %-5p %c |#| %m%n
# date/time
# (Maximal 15Character des Filename von rechts:Line)
# priority, Right pad with spaces if the priority name is less than 5 characters long.
# category/channel
# message
# line separator
#
# Examples for files:
+56
View File
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* main for HLA
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#include <nglapplication/nglcoreapplication.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include <memory>
#include "main_handler.h"
#include <Common/logger.h>
#include <Common/settings.h>
#include <NGSApplicationBase.h>
// Corba specific stuff
class myCorbaSpecificStuff final : public NGSApplicationBase
{
public:
using NGSApplicationBase::NGSApplicationBase;
int run() override { return 1; }
};
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
qputenv("RTI_ASSISTANT_DISABLE", QByteArray("1"));
qputenv("RTI_RID_FILE", QCoreApplication::applicationDirPath().append(QLatin1String("/rid.mtl")).toLocal8Bit());
int iRet = -1;
LtsCommandLineParser::LtsCommandLineParser options;
if (!options.init())
return iRet;
app.createLogger("HLA", options.exerciseId());
myCorbaSpecificStuff corba(argc, argv);
HighLevelArchitecture::Settings::setIniFile(options.iniFile());
qputenv("MAKLMGRD_LICENSE_FILE", HighLevelArchitecture::Settings::hlaLicenseServer());
{
std::unique_ptr<HighLevelArchitecture::MainHandler> mainHandler(new HighLevelArchitecture::MainHandler);
if (mainHandler->init(options.exerciseId()))
{
STARTUP_LOG(app.baseLogger());
iRet = app.exec();
SHUTDOWN_LOG(app.baseLogger());
}
}
return iRet;
}
@@ -0,0 +1,87 @@
/**
* MainHandler for HighLevelArchitecture
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#include "main_handler.h"
#include "ngs_handler.h"
#include "web_socket_interface.h"
#include "Common/identifierstruct.h"
#include <QCoreApplication>
#include <QTimer>
#include <Common/settings.h>
#include <Common/logger.h>
#include <DDS/Core/pacemaker.h>
namespace HighLevelArchitecture
{
MainHandler::MainHandler(QObject *parent)
: QObject(parent)
, m_exerciseId(0)
, m_logger(getLogger("MainHandler"))
{}
MainHandler::~MainHandler()
{
m_ngsHandler = nullptr;
m_wsInterface = nullptr;
}
bool MainHandler::init(int exerciseId)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << ", exerciseId=" << exerciseId;
m_exerciseId = 5; // exerciseId;
IdentifierStruct::setOwnSiteId(exerciseId);
//
// NgsHandler
//
/*
if (!m_ngsHandler)
{
m_ngsHandler = std::make_shared<NgsHandler>();
// connect(m_ngsHandler.get(), &NgsHandler::ngsHandlerReady,
// m_wsHandler.get(), &WebSocketHandler::sendHlaConnectionState, Qt::UniqueConnection);
if (!m_ngsHandler->init())
{
m_ngsHandler = nullptr;
ERROR_LOG(m_logger) << "Could not init ngs - stopping application";
QCoreApplication::quit();
return false;
}
}
*/
//
// WsInterface
//
if (!m_wsInterface)
{
// requests from ws will be sent to ngsHandler:
m_wsInterface = std::make_shared<WsInterface>(m_ngsHandler, this);
int port = 23456;
if (!m_wsInterface->init(port))
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " WsInterface::init failed on port: " << port;
return false;
}
}
return true;
}
bool MainHandler::isConnectedToHla() const
{
return m_ngsHandler && m_ngsHandler->isConnectedToHla();
}
} // namespace HighLevelArchitecture
@@ -0,0 +1,40 @@
/**
* MainHandler for HighLevelArchitecture
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#pragma once
#include <QObject>
#include <memory>
//#include "dds_handler.h"
#include <Common/logger.h>
namespace HighLevelArchitecture
{
class NgsHandler;
class WsInterface;
class MainHandler : public QObject
{
Q_OBJECT
public:
explicit MainHandler(QObject *parent = nullptr);
~MainHandler();
bool init(int exerciseId);
bool isConnectedToHla() const;
std::shared_ptr<NgsHandler> ngsHandler() const { return m_ngsHandler; }
private Q_SLOTS:
private:
std::shared_ptr<NgsHandler> m_ngsHandler;
std::shared_ptr<WsInterface> m_wsInterface; // WsServer receiving requests
int m_exerciseId;
LOGGER_T m_logger;
};
} // namespace HighLevelArchitecture
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,374 @@
/**
* Connect to ngs / hla and provide the basic interface
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#pragma once
#include "ws_telegrams.h"
#include <Common/participantposition.h>
#include <QObject>
#include <IObserver.h>
#include <QMap>
#include <QSet>
#include <QTransform>
#include <ProjectDataManagement/pdm_enums.hpp>
#include <ForceIdentifierEnum8.h>
#include <HitResultEnum16.h>
namespace ngs
{
class ISimulatedWorldAdmin;
class IFederationMaster;
class IObserverObjectInstance;
}
namespace rpr2
{
class ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray;
class ArrayOfHLAoctetN_slsh_AperfectalwaysN_slsh_ADynamicHLApaddingTo32Array;
class IPlayerSOM;
class EntityTypeStruct;
class MarkingStruct;
class ClockTimeStruct;
class TacticalStatusStruct;
class IPlayerPhysicalEntityObjInstance;
class IPlayerEnvironmentObjectObjInstance;
class IPlayerBaseEntityObjInstance;
class OMT13string;
class EventIdentifierStruct;
class EntityIdentifierStruct;
class IsPartOfStruct;
class IObserverBaseEntityObjInstance;
class IObserverMunitionDetonationIntInstance;
class IObserverWeaponFireIntInstance;
class IObserverGuezHitIntInstance;
class IObserverGuezInitIntInstance;
class IObserverGuezBiteReportIntInstance;
class IObserverGuezRequestBiteReportIntInstance;
class IObserverEnvironmentObjectObjInstance;
class IObserverGuezMineFieldObjInstance;
class IObserverGuezMineFieldBreachObjInstance;
}
namespace NGL
{
class INGLLogger;
}
namespace TrainingAreaBase
{
class EquipmentGearEvent;
class EquipmentBite;
class DemandBiteRequest;
}
namespace ParticipantManagement
{
class ParticipantGearEvent;
class StateInformation;
}
namespace AreaEffectSimulation
{
class ExplosionSingle;
class ExplosionArea;
class MineArea;
class MineAreaModifyRequest;
class MineSegment;
class MineCorridor;
class MineCorridorModifyRequest;
class ExplosionSingleModifyRequest;
class NContamination;
class BCContamination;
}
namespace LtsCoordTrans
{
struct UtmCoordinate;
}
class ObserverGuezHumanCBNotifier;
class ObserverGuezObserverControllerCBNotifier;
class ObserverGuezGroundVehicleCBNotifier;
class ObserverObjectCB;
class ObserverBaseEntityObjectCB;
class ObserverPhysicalEntityObjectCB;
class ObserverPlatformObjectCB;
class ObserverGroundVehicleObjectCB;
class ObserverGuezGroundVehicleObjectCB;
class ObserverLifeformObjectCB;
class ObserverHumanObjectCB;
class ObserverGuezHumanObjectCB;
class ObserverGuezObserverControllerObjectCB;
class ObserverGuezMineFieldCBNotifier;
class ObserverGuezMineFieldBreachCBNotifier;
class ObserverEnvironmentObjectObjectCB;
class ObserverArealObjectObjectCB;
class ObserverPointObjectObjectCB;
class ObserverOtherArealObjectObjectCB;
class ObserverOtherPointObjectObjectCB;
class ObserverGuezMineFieldObjectCB;
class ObserverGuezMineFieldBreachObjectCB;
class ObserverMunitionDetonationCBNotifier;
class ObserverWeaponFireCBNotifier;
class ObserverGuezHitCBNotifier;
class ObserverGuezInitCBNotifier;
class ObserverGuezBiteReportCBNotifier;
class ObserverGuezRequestBiteReportCBNotifier;
class QTimer;
struct GuezHitStruct
{
qint32 targetId = 0;
qint64 sampleTime = 0;
ProjectDataManagement::VulnerabilityState vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::get_default();
qint32 vulnerabilityKind = 0;
qint32 vulnerabilityBits = 0;
Core::GeoPosition position = Core::GeoPosition(0, 0, 0);
qint64 originatorId = 0; // So EIS fits completely!
ProjectDataManagement::StateChangeOriginator originatorType = ProjectDataManagement::StateChangeOriginator_def::get_default();
QString originatorChargeTypeEtsString;
};
namespace HighLevelArchitecture
{
class NgsHandler;
class PlayerCallback;
class DamageModel;
class IdentifierStruct;
class TypeStruct;
struct ParticipantInformation;
class NgsConnector : public QObject
{
Q_OBJECT
void connectObserverObjectSignals(ObserverObjectCB *entity);
void connectObserverBaseEntityObjectSignals(ObserverBaseEntityObjectCB *entity);
void connectObserverPhysicalEntityObjectSignals(ObserverPhysicalEntityObjectCB *entity);
void connectObserverPlatformObjectSignals(ObserverPlatformObjectCB *entity);
void connectObserverGroundVehicleObjectSignals(ObserverGroundVehicleObjectCB *entity);
void connectObserverGuezGroundVehicleObjectSignals(ObserverGuezGroundVehicleObjectCB *entity);
void connectObserverLifeformObjectSignals(ObserverLifeformObjectCB *entity);
void connectObserverHumanObjectSignals(ObserverHumanObjectCB *entity);
void connectObserverGuezHumanObjectSignals(ObserverGuezHumanObjectCB *entity);
void connectObserverGuezObserverControllerObjectSignals(ObserverGuezObserverControllerObjectCB *entity);
void connectObserverEnvironmentObjectObjectSignals(ObserverEnvironmentObjectObjectCB *entity);
void connectObserverArealObjectObjectSignals(ObserverArealObjectObjectCB *entity);
void connectObserverPointObjectObjectSignals(ObserverPointObjectObjectCB *entity);
void connectObserverOtherArealObjectObjectSignals(ObserverOtherArealObjectObjectCB *entity);
void connectObserverOtherPointObjectObjectSignals(ObserverOtherPointObjectObjectCB *entity);
void connectObserverGuezMineFieldObjectSignals(ObserverGuezMineFieldObjectCB *entity);
void connectObserverGuezMineFieldBreachObjectSignals(ObserverGuezMineFieldBreachObjectCB *entity);
void addObserverObjectInstance(const ngs::IObserverObjectInstance &obj);
void removeObserverObjectInstance(const ngs::IObserverObjectInstance &obj);
void ensureDamageModelExists(const IdentifierStruct &is);
bool addBaseEntity(rpr2::IPlayerBaseEntityObjInstance *playerInstance, const ParticipantInformation &participantData);
bool addPhysicalEntity(rpr2::IPlayerPhysicalEntityObjInstance *playerInstance, const ParticipantInformation &playerData);
static rpr2::MarkingStruct toMarkingStruct(const QString &designator);
static rpr2::ClockTimeStruct getClockTimeStruct(qint64 msecsSinceEpoch);
static qint64 getMSecsSinceEpoch(const rpr2::ClockTimeStruct &cts);
// rpr2::EntityTypeStruct getEtsCharge(int chargeType) const;
template<typename T>
static rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray positionArray(const T &data);
static inline QTransform fromRotation(double rot) { return QTransform().rotate(rot); }
// static QPolygonF explosionArea(const AreaEffectSimulation::ExplosionArea &ea);
// static QPolygonF mineAreaSegment(const AreaEffectSimulation::MineSegment &segment, double width, double density, bool bIsCenterline);
// static QPolygonF mineCorridorSegment(const Core::GeoPosition2D &start, const Core::GeoPosition2D &end, double width);
// static QPolygonF nContamination(const AreaEffectSimulation::NContamination &awf);
// static std::vector<Core::GeoPosition> bcReduction(const std::vector<Core::GeoPosition> &form);
static QPolygonF utmToGeogrphic(const QPolygonF &polyUtm, const LtsCoordTrans::UtmCoordinate &base);
static rpr2::ArrayOfHLAoctetN_slsh_AperfectalwaysN_slsh_ADynamicHLApaddingTo32Array triggeredImpactsArray(const std::vector<uint8_t> &data);
static rpr2::HitResultEnum16::ET getHitResultEnum(const ProjectDataManagement::VulnerabilityState &ts);
static ProjectDataManagement::VulnerabilityState getTacticalStatusEnum(const rpr2::HitResultEnum16::ET &hr);
rpr2::EventIdentifierStruct getEventIdentifierStruct();
bool setVulnerabilityState(int eqNo, const ParticipantManagement::StateInformation &state);
static rpr2::TacticalStatusStruct getTacticalStatusFromState(const ParticipantManagement::StateInformation &state);
bool addMinefield(const rpr2::IObserverGuezMineFieldObjInstance *minefield);
bool addMinefieldBreach(const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach);
int getEquipmentNoByRTIObjectId(const std::string &sender) const;
static ngs::SimTime getSimTime(qint64 msecsSinceEpoch = 0);
static ngs::SimTime getSimTime(const QDateTime &dateTime);
IdentifierStruct getIdentifierStructbyEquipmentNo(const int eqId) const;
public:
NgsConnector(const QString &fedName, NgsHandler *ngsHandler);
~NgsConnector();
bool initialize(ngs::IObserver::ProtocolType protocol, const QString &playerName, const QString &appDirPath);
void uninitialize();
bool canPublishData() const { return m_bCanPublishData; }
bool addHuman(const ParticipantInformation &participantData, const rpr2::TacticalStatusStruct &state);
bool addGroundVehicle(const ParticipantInformation &participantData, const rpr2::TacticalStatusStruct &state);
bool addObserverController(const ParticipantInformation &participantData);
bool removeBaseEntity(int eqNo);
bool setParticipantName(int eqNo, const QString &designator);
bool setParticipantForce(int eqNo, const rpr2::ForceIdentifierEnum8::ET forceIdentifier);
// bool setParticipantHit(int eqNo, const ParticipantManagement::StateInformation &state,
// const ParticipantPosition &partPos, int chargeType,
// ProjectDataManagement::StateChangeOriginator originatorType, int originatorEqNo = 0);
// bool setWeaponFire(int eqNo, const ParticipantManagement::ParticipantGearEvent &data);
// bool setEquipmentBite(int eqNo, const TrainingAreaBase::EquipmentBite &data);
// AES:
bool removeAesItem(int objId);
bool guezMineField(const WsTelegramMineFieldObject &data);
// bool setItemForm(int aesItemId, int aesTypeId = 0, const std::vector<Core::GeoPosition> &form = std::vector<Core::GeoPosition>());
// bool setWorldLocation(int eqNo, const ParticipantPosition &pos, int eqNoHost = -1);
// void sendMunitionDetonation(const ParticipantPosition &pos, int chargeTypeId, rpr2::ForceIdentifierEnum8::ET forceId);
void sendParticipantBiteRequest(const int eqId, bool withSelfTest, qint64 simTimeMsecs);
void sendParticipantInitRequest(const int eqId, bool resetManipulation, bool resetVulnerabilityState, bool restockCharges, qint64 simTimeMSecs);
protected slots:
void go();
void onFirstTickFinished();
signals:
void spatialChanged(int eqId, const ParticipantPosition &pos, qint64 simTimeMSecs);
void markingChanged(int eqId, const QString &marking, qint64 simTimeMSecs);
void participantReceivedInit(int eqId, qint64 simTimeMSecs);
void virtualParticipantDeleted(int eqId);
void firstTickFinished();
void aesNameChanged(qint64 identifierInt, const std::string &name);
void aesActivationTimeChanged(qint64 identifierInt, qint64 msecsSinceEpoch);
void aesForceIdentifierChanged(qint64 identifierInt, int partyId);
void aesDurationChanged(qint64 identifierInt, quint32 msecs);
void aesChargeChanged(qint64 identifierInt, int chargeTypeId);
void aesRoundsChanged(qint64 identifierInt, quint32 rounds);
void aesDetonationLocationChanged(qint64 identifierInt, const ParticipantPosition &pos);
void aesPointsDataChanged(quint64 eqId, const std::vector<Core::GeoPosition2D> &form, qint64 simTimeMSecs);
void aesRemoveItem(qint64 identifierInt);
void munitionDetonation(AreaEffectSimulation::ExplosionSingleModifyRequest &explosion);
void weaponFire(const TrainingAreaBase::EquipmentGearEvent &event);
void guezHit(const GuezHitStruct &hitStruct);
void guezInit(int eqNo, bool resetManipulation, bool resupplyAmmo, bool resetVulnerabilityState);
void playerManipulationChanged(int eqNo, bool playerIsManipulated, qint64 simTimeMSecs);
void isPartOfChanged(int eqNo, int eqNoHost, qint64 simTimeMSecs); // Host is null, if player unmounted
void eventCountOverflow();
void biteReport(const TrainingAreaBase::EquipmentBite &report);
void biteRequest(const TrainingAreaBase::DemandBiteRequest &request);
void newMinefield(AreaEffectSimulation::MineAreaModifyRequest &ma);
void newMinefieldBreach(AreaEffectSimulation::MineCorridorModifyRequest &mc);
protected:
void subscribeAtNgs();
void unsubscribeFromNgs();
int m_enitityNumberCounter;
int m_eventCount;
NgsHandler *m_ngsHandler;
const QString m_fedName;
ngs::ISimulatedWorldAdmin *m_swadmin;
ngs::IFederationMaster *m_master;
rpr2::IPlayerSOM *m_somPlayer;
PlayerCallback *m_playerCallback;
// Callbacks:
ObserverGuezHumanCBNotifier *m_humanCallback;
ObserverGuezObserverControllerCBNotifier *m_observerControllerCallback;
ObserverGuezGroundVehicleCBNotifier *m_groundVehicleCallback;
ObserverGuezMineFieldCBNotifier *m_minefieldCallback;
ObserverGuezMineFieldBreachCBNotifier *m_minefieldBreachCallback;
ObserverMunitionDetonationCBNotifier *m_munitionDetonationCallback;
ObserverWeaponFireCBNotifier *m_weaponfireCallback;
ObserverGuezHitCBNotifier *m_hitCallback;
ObserverGuezInitCBNotifier *m_initCallback;
ObserverGuezBiteReportCBNotifier *m_biteReportCallback;
ObserverGuezRequestBiteReportCBNotifier *m_requestBiteReportCallback;
QMap<int, rpr2::IPlayerBaseEntityObjInstance *> m_playerMap; // Key: EqNo // All Players, WE handle
QMap<int, const ngs::IObserverObjectInstance *> m_observerPlayerInstances; // Key: EqNo // All of THEIR Players on the bus.
QMap<int, ParticipantPosition> m_observerPositions; // Key: EqNo
QMap<int, DamageModel *> m_damageModelMap; // Key: EqNo
QSet<const ngs::IObserverObjectInstance *> m_newObjectsWithoutParticipantIdSet;
QSet<int> m_guezHitActive;
QMap<int, rpr2::IPlayerEnvironmentObjectObjInstance *> m_environmentObjects; // Key: AesId // All EOs, WE handle
QMap<int, const ngs::IObserverObjectInstance *> m_observerEnvironmentObjects; // Key: AesId // All of THEIR EOs on the bus.
QSet<int> m_nonpublishedEnvironmentObjects; // AesId
QMap<int, std::vector<Core::GeoPosition> > m_arealObjectSingleItems; // Key: AesId
QMap<int, std::vector<Core::GeoPosition> > m_arealObjectForms; // Key: AesId
QMap<int, std::vector<uint8_t> > m_arealObjectTriggeredImpacts; // Key: AesId
bool m_bInitialized;
bool m_bCanPublishData;
QTimer *m_timer; // Todo: Start with 1 ms occurs! Needed?
NGL::INGLLogger &m_logger;
static quint16 s_ownSiteId;
static quint16 s_ownApplicationId;
static const int STATUS_WAIT_INTERVAL = 500; // Wartezeit auf Statusänderung
static const int ACTIVATION_LEAD_TIME = 5000; // Vorlaufzeit beim Aktivieren von Wirkfeldern.
private slots:
void onEntityIdentifierChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::IObserverBaseEntityObjInstance *obj);
bool onSpatialChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::WorldLocationStruct &wl, qint64 simTimeMSecs);
void onEntityTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs);
void onIsPartOfChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::IsPartOfStruct &ipos, qint64 simTimeMSecs);
bool onMarkingChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::MarkingStruct &marking, qint64 simTimeMSecs);
bool onPointsDataChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray &points, qint64 simTimeMSecs);
bool onForceIdentifierChanged(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs);
bool onForceIdentifierChangedEO(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs);
bool onTacticalStatusChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::TacticalStatusStruct &rprStatus, qint64 simTimeMSecs);
bool onDeactivatedChanged(const rpr2::EntityIdentifierStruct &eis, bool state, qint64 simTimeMSecs);
bool onPercentCompleteChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 state, qint64 simTimeMSecs);
bool onObjectIdentifierChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::IObserverEnvironmentObjectObjInstance *obj);
void onAreaEffectSimulationNameChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::OMT13string &value, qint64 simTimeMSecs);
void onActivationTimeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ClockTimeStruct &value, qint64 simTimeMSecs);
void onDurationChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 value, qint64 simTimeMSecs);
void onMineTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs);
void onNewMunitionDetonation(const rpr2::IObserverMunitionDetonationIntInstance &interaction);
void onNewWeaponFire(const rpr2::IObserverWeaponFireIntInstance &interaction);
void onNewGuezHit(const rpr2::IObserverGuezHitIntInstance &interaction);
void onNewGuezInit(const rpr2::IObserverGuezInitIntInstance &interaction);
void onNewGuezBiteReport(const rpr2::IObserverGuezBiteReportIntInstance &interaction);
void onNewGuezRequestBiteReport(const rpr2::IObserverGuezRequestBiteReportIntInstance &interaction);
};
} // namespace
@@ -0,0 +1,113 @@
/**
* NgsHandler for HighLevelArchitecture
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#include "ngs_handler.h"
#include "ngs_connector.h"
#include <Common/logger.h>
#include <Common/settings.h>
#include <QCoreApplication>
#include <QHostInfo>
//#include </opt/NGS/NGSPublic/include/RTIFacadeAPI/RTIVector.h>
#include "RTIVector.h"
#include <QVector>
namespace HighLevelArchitecture
{
NgsHandler::NgsHandler(QObject *parent)
: QObject(parent)
, m_logger(getLogger("NgsHandler"))
{}
NgsHandler::~NgsHandler()
{
m_ngsConnector = nullptr;
}
bool NgsHandler::init()
{
/*
private:
// data
T * _v;
// vectorsize
unsigned int _l;
// vectorcapacity;
unsigned int _c;
};
template <class T>
int ngsrti::Vector<T>::compare(const Vector<T>& v) const
{
unsigned int lmin = _l;
if(_v._l < lmin) lmin = _v._l;
*/
ngsrti::Vector<int> myVec;
ngsrti::Vector<int> myVec2;
if (myVec < myVec2)
{
INFO_LOG(m_logger) << "Protocol = ";
}
// initialize DDS
// m_ddsHandler = ddsHandler;
QMap<ngs::IObserver::ProtocolType, QString> protToStr;
protToStr.insert(ngs::IObserver::ProtocolType::DIS, QStringLiteral("DIS"));
protToStr.insert(ngs::IObserver::ProtocolType::HLA, QStringLiteral("HLA"));
protToStr.insert(ngs::IObserver::ProtocolType::CORBANOTIFY, QStringLiteral("CORBA"));
ngs::IObserver::ProtocolType protocol = Settings::hlaProtocol();
INFO_LOG(m_logger) << "Protocol = " << protToStr.value(protocol, QStringLiteral("UNKNOWN"));
m_ngsConnector = /* (protocol == ngs::IObserver::ProtocolType::DIS) ?
std::make_shared<NgsConnectorDis>(Settings::federationName(), this) : */
std::make_shared<NgsConnector>(Settings::federationName(), this);
connect(m_ngsConnector.get(), &NgsConnector::firstTickFinished,
this, &NgsHandler::onFirstTickFinished, Qt::UniqueConnection);
return m_ngsConnector->initialize(protocol, QHostInfo::localHostName().toUpper(), QCoreApplication::applicationDirPath());
}
bool NgsHandler::isConnectedToHla() const
{
return m_ngsConnector && m_ngsConnector->canPublishData();
}
void NgsHandler::onFirstTickFinished()
{
// m_ppmHandler = std::make_shared<PpmHandler>(this);
// m_aesHandler = std::make_shared<AesHandler>(this);
// if (!m_ppmHandler->init())
// ERROR_LOG(m_logger) << "Could not init ppm handler - not able to publish participants to HLA";
// if (!m_aesHandler->init())
// ERROR_LOG(m_logger) << "Could not init ppm handler - not able to publish area effect simulations to HLA";
emit firstTickFinished();
// connect(m_ppmHandler.get(), &PpmHandler::externalEquipmentNumberAdded,
// this, &NgsHandler::externalEquipmentNumberAdded);
// connect(m_ppmHandler.get(), &PpmHandler::externalEquipmentNumberRemoved,
// this, &NgsHandler::externalEquipmentNumberRemoved);
// connect(this, &NgsHandler::participantInitRequest, m_ppmHandler.get(), &PpmHandler::participantInitRequest);
// connect(this, &NgsHandler::participantBiteRequest, m_ppmHandler.get(), &PpmHandler::participantBiteRequest);
emit ngsHandlerReady();
}
} // namespace HighLevelArchitecture
@@ -0,0 +1,48 @@
/**
* MainHandler for HighLevelArchitecture
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#pragma once
#include <QObject>
#include <memory>
#include "ngs_handler.h"
#include <Common/logger.h>
#include "ngs_connector.h"
#include <TrainingAreaBase/training_area_telegrams.h>
namespace HighLevelArchitecture
{
class NgsHandler : public QObject
{
Q_OBJECT
public:
explicit NgsHandler(QObject *parent = nullptr);
~NgsHandler();
bool init();
std::shared_ptr<NgsConnector> ngsConnector() const { return m_ngsConnector; }
bool isConnectedToHla() const;
Q_SIGNALS:
void firstTickFinished();
// HLA -> TAB
void externalEquipmentNumberAdded(int equipNo);
void externalEquipmentNumberRemoved(int equipNo);
void ngsHandlerReady();
// TAB -> HLA
void participantInitRequest(const TrainingAreaBase::TetraIcd::Init &request);
void participantBiteRequest(const TrainingAreaBase::TetraIcd::DemandBite &request);
private slots:
void onFirstTickFinished();
private:
std::shared_ptr<NgsConnector> m_ngsConnector;
LOGGER_T m_logger;
};
} // namespace HighLevelArchitecture
+264
View File
@@ -0,0 +1,264 @@
:===============================================================================
: Simulated World Config File
:===============================================================================
:-------------------------------------------------------------------------------
: RTI config
:-------------------------------------------------------------------------------
;Linux_RTILibs[PITCH] :gcc41_64/librti1516e64.so libprtiutil64.so DefaultSimTimeConverterHLA1516E_PITCH4310/libSimTimeConverterHLA1516.so RTIFacadeHLA1516E_PITCH4310/libRTIFacadeHLA.so
;Linux_RTILibs[PITCH] : libprtiutil64.so gcc41_64/librti1516e64.so DefaultSimTimeConverterHLA1516E_PITCH4310/libSimTimeConverterHLA1516.so RTIFacadeHLA1516E_PITCH4310/libRTIFacadeHLA.so
;: pitch_4.3.1.0
;Linux_RTIClassPath[PITCH] : /opt/prti1516e/lib/prti1516e.jar
Linux_RTILibs[MAK] : /opt/NGS/makRti4.5/lib/librti1516e64.so /opt/NGS/makRti4.5/lib/librtiutil_64.so /opt/NGS/NGSPublic/lib/RTIFacadeHLA1516E_MAK450/libRTIFacadeHLA.so
;: pitch_4.3.1.0
Linux_RTIClassPath[MAK] : /opt/NGS/makRti4.5/lib/hla.jar
:-------------------------------------------------------------------------------
: SOM- and FOMName are needed to identify the necessary shared libraries
:-------------------------------------------------------------------------------
SOMName[Saab] : RPRFOM20d17E : Name of the SOM (used for library load)
FOMName[Saab] : RPRFOM20d17E : Name of the FOM (used for library load)
:-------------------------------------------------------------------------------
:
:-------------------------------------------------------------------------------
:Fedfile : ./SimulatedWorld.xml : Path for HLA 0.3 fed-file (.fed) or HLA
;Fedfile : ./RPR2-d17.xml : Path for HLA 1.3 fed-file (.fed) or HLA 1516 xml-file (.xml)
Fedfile : ./RPRFOM20d17E.xml
GoForeverCycleTime : 100 : Automatic cycle time [ms] for goForever
PlayerObserverEchoOn : true : true for automatic Player-Observer
: echo
DISConnectorConfig : disconnectorconf.cfg : Configfile of disconnector
:-------------------------------------------------------------------------------
: Update Timeouts for FOM Classes [s] 0 = off
: when no new updates are received after this time, the object is deleted
:-------------------------------------------------------------------------------
UpdateTimeoutHLA[BaseEntity] : 0 :
UpdateTimeoutHLA[PhysicalEntity] : 0 :
UpdateTimeoutHLA[Platform] : 0 :
UpdateTimeoutHLA[GroundVehicle] : 0 :
UpdateTimeoutHLA[Minefield] : 0 :
UpdateTimeoutHLA[EmbeddedSystem] : 0 :
UpdateTimeoutHLA[MinefieldData] : 0 :
UpdateTimeoutDIS[BaseEntity] : 0 :
UpdateTimeoutDIS[PhysicalEntity] : 0 :
UpdateTimeoutDIS[Platform] : 0 :
UpdateTimeoutDIS[GroundVehicle] : 0 :
UpdateTimeoutDIS[Minefield] : 0 :
UpdateTimeoutDIS[EmbeddedSystem] : 0 :
UpdateTimeoutDIS[MinefieldData] : 0 :
UpdateTimeoutCORBA[BaseEntity] : 0 :
UpdateTimeoutCORBA[PhysicalEntity] : 0 :
UpdateTimeoutCORBA[Platform] : 0 :
UpdateTimeoutCORBA[GroundVehicle] : 0 :
UpdateTimeoutCORBA[Minefield] : 0 :
UpdateTimeoutCORBA[EmbeddedSystem] : 0 :
UpdateTimeoutCORBA[MinefieldData] : 0 :
:-------------------------------------------------------------------------------
: Publish Timeouts for FOM Classes [ms] 0 = off :
: updates are sent automatically at the latest after this time (heartbeat)
:-------------------------------------------------------------------------------
PublishTimeoutHLA[BaseEntity] : 60000 :
PublishTimeoutHLA[PhysicalEntity] : 60000 :
PublishTimeoutHLA[Platform] : 60000 :
PublishTimeoutHLA[Minefield] : 60000 :
PublishTimeoutHLA[EmbeddedSystem] : 60000 :
PublishTimeoutHLA[MinefieldData] : 60000 :
PublishTimeoutDIS[BaseEntity] : 30000 :
PublishTimeoutDIS[PhysicalEntity] : 30000 :
PublishTimeoutDIS[EmitterBeam] : 0 : should always be zero
PublishTimeoutDIS[EmitterSystem] : 30000 :
PublishTimeoutDIS[Minefield] : 30000 :
PublishTimeoutDIS[EmbeddedSystem] : 30000 :
PublishTimeoutDIS[MinefieldData] : 30000 :
PublishTimeoutCORBA[BaseEntity] : 30000 :
PublishTimeoutCORBA[PhysicalEntity] : 30000 :
PublishTimeoutCORBA[Platform] : 30000 :
PublishTimeoutCORBA[Minefield] : 30000 :
PublishTimeoutCORBA[EmbeddedSystem] : 30000 :
PublishTimeoutCORBA[MinefieldData] : 30000 :
:-------------------------------------------------------------------------------
: Publish All Attributes Flags from FOM Classes :
: This emulates DIS behaviour in CORBA and HLA, on publish all valid attributs
: are sent, instead of only the modified attributesa are sent.
:-------------------------------------------------------------------------------
PublishAll[BaseEntity] : false :
PublishAll[PhysicalEntity] : false :
PublishAll[Platform] : false :
:-------------------------------------------------------------------------------
: DIS Electromagnetic Emission PDU: policy for deletion of EmitterSystem
: and EmitterBeam objects on DIS level
:-------------------------------------------------------------------------------
ElectromagneticEmissionDIS[useStateUpdate] : true : the deletion of objects
: will be announced and
: detected with complete
: state updates where the
: respective elements are
: missing
ElectromagneticEmissionDIS[useZeroBeamPower] : false : the deletion of beams will
: be announced and detected
: by zero beam power,
: emittersystems without beams
: will be considerd deleted
:-------------------------------------------------------------------------------
: Timestamps:
:
: Normal procedure would be to send timestamps when expicitly published, to keep
: timestamps when received and to use timestamps for deadreckoning when possible.
: With the parameters below this behaviour can be modified.
:
: DIS-PDU realtime-timestamps will be converted to/from the corresponding simulationtime.
:
:-------------------------------------------------------------------------------
HLALogicalTimeImplementationName : HLAfloat64Time : Name of HLALogicalTime implementation
HLATimeStampInTag[default] : true : Send DIS-Timestamp in UserSupplied Tag
SendPlayerTimeStamps[HLA] : true : true/false
SendPlayerTimeStamps[CORBA] : true : true/false
SendPlayerTimeStamps[DIS] : true : true/false
: true : published timestamps will be transmitted
: (for DIS as the realtime corresponding to the simulationtime)
: false : published timestamps will not be transmitted (or for DIS the current realtime)
: or will be replaced when ImplicitPlayerTimeStamps=true
ImplicitPlayerTimeStamps[HLA] : false : true/false
ImplicitPlayerTimeStamps[CORBA] : false : true/false
ImplicitPlayerTimeStamps[DIS] : false : true/false
: true : generation of implicit timestamps from the current simulationtime,
: when no explicit timestamp has been published or when
: SendPlayerTimeStamps=false
: false : no generation of implicit timestamps
ReceiveObserverTimeStamps[HLA] : true : true/false
ReceiveObserverTimeStamps[CORBA] : true : true/false
ReceiveObserverTimeStamps[DIS] : true : true/false
: true : received timestamps are transmitted to the observer
: (for DIS simulationtime-timestamps are generated from the PDU realtime-timestamps)
: false : received timestamps are ignored or replaced when
: ImplicitObserverTimeStamps=true
ImplicitObserverTimeStamps[HLA] : false : true/false
ImplicitObserverTimeStamps[CORBA] : false : true/false
ImplicitObserverTimeStamps[DIS] : false : true/false
: true : timestamps are implicitly generated from the current
: simulationtime when not received or ReceiveObserverTimeStamps=false
: false : no generation of implicit timestamps
:-------------------------------------------------------------------------------
: Deadreckoning time handling
:-------------------------------------------------------------------------------
IgnorePlayerTimeStampsForDeadReckoning : false : true/false
: false : deadreckoning with timestamps when present, otherwise with
: current simulationtime, never when the current simulationtime is
: invalid
: true : timestamps are ignored for dead reckoning
IgnoreObserverTimeStampsForDeadReckoning : false : true/false
: false : deadreckoning with timestamps when present, otherwise with
: current simulationtime, never when the current simulationtime is
: invalid
: true : timestamps are ignored for dead reckoning
DeadReckoningWithRealtime : false : true/false
: false : normal deadeckoning with simulationtime
: true : simulationtime is ignored, dead reckoning is always done with
: the current realtime
UseRealtime : true : true/false
: true : implicitly configure simulationtime=realtime
: can be overwritten through the api
: false : initial simulationtime is invalid
DISTimeStampRelative : true : true/false
: true : own clock is not UTC
: the LSB of generated DIS timestamps will signify relative time
: false : own clock must be UTC
: the LSB of generated DIS timestamps will signify synchronized UTC
: time
DRReceiveDelay[HLA] : 0.0 : age of data on receive, e.g.
DRReceiveDelay[DIS] : 0.0 : to compensate network delays [s]
DRReceiveDelay[CORBA] : 0.0 :
:-------------------------------------------------------------------------------
: Deadreckoning player:
: Supresses sending of object-updates, when they are only marginaly changed.
:-------------------------------------------------------------------------------
PlayerDeadReckoningOn[BaseEntity] : true : turns on the dead-reckoning
PlayerDeadReckoningOn[PhysicalEntity] : true : suppressing mechanism
PlayerDeadReckoningOn[Platform] : true : for attribute updates
MaxDRSuppressTime[BaseEntity] : 10 : Updates are sent always at the
MaxDRSuppressTime[PhysicalEntity] : 10 : latest after this time
MaxDRSuppressTime[Platform] : 10 : 0=infinte time [s]
DRThresholdTime[BaseEntity] : 0.1 : Time span (into the future) used for
DRThresholdTime[PhysicalEntity] : 0.1 : calculating threshold deviations
DRThresholdTime[Platform] : 0.1 : This time should correspond to the
: publish-interval [s]
DRPositionThreshold[BaseEntity] : 0.01 : Updates are not supressed
DRPositionThreshold[PhysicalEntity] : 0.01 : when position-changes exceed
DRPositionThreshold[Platform] : 0.01 : this threshold [m]
DROrientationThreshold[BaseEntity] : 0.01 : Updates are not supressed
DROrientationThreshold[PhysicalEntity] : 0.01 : when orientation-changes exceed
DROrientationThreshold[Platform] : 0.01 : this threshold [rad]
DRDimlessThreshold[BaseEntity] : 0.01 : Updates are not supressed
DRDimlessThreshold[PhysicalEntity] : 0.01 : when changes for dimensionless
DRDimlessThreshold[Platform] : 0.01 : values [0..1] exceed this
: threshold [1]
:-------------------------------------------------------------------------------
: Deadreckoning observer
: calculates values for deadreckoning attributes, for get() und callbacks()
:-------------------------------------------------------------------------------
ObserverDeadReckoningOn[BaseEntity] : true : turns on the dead-reckoning
ObserverDeadReckoningOn[PhysicalEntity] : true : mechanism
ObserverDeadReckoningOn[Platform] : true :
SmoothingTime[BaseEntity] : 0.2 : time interval for smoothing [s]
:-------------------------------------------------------------------------------
: Coordinate Transformation
:-------------------------------------------------------------------------------
: Jetzt neu: Wir werfen schon echte Lon/Lat-Koordinaten in den Topf
CoordTrans[algorithm] : null : algorithm
CoordTrans[datafile] : null : datafile for the algorithm
:CoordTrans[algorithm] : database : algorithm
:CoordTrans[datafile] : ProjConf.txt : datafile for the algorithm
:-------------------------------------------------------------------------------
: End of File
:-------------------------------------------------------------------------------
@@ -0,0 +1,250 @@
/**
* @RDE_HEADER@
* Websocket Server to connect to NGSConnector
* $Id$
* $HeadURL$
* $Author$
*/
#include "ngs_handler.h"
#include "ngs_connector.h"
#include "web_socket_interface.h"
#include "ws_telegrams.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QTimer>
namespace HighLevelArchitecture
{
//
// class WsInterface
//
WsInterface::WsInterface(std::shared_ptr<NgsHandler> ngsHandler, QObject *parent)
: QObject(parent)
, m_wsServer(new QWebSocketServer(QStringLiteral("GNA"), QWebSocketServer::NonSecureMode, this))
, m_ngsHandler(ngsHandler)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("HlaTestTool.WsInterface"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
WsInterface::~WsInterface()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
for (auto client : qAsConst(m_clients))
{
client->disconnect(this);
client->close();
}
qDeleteAll(m_clients);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool WsInterface::init(quint16 listenPort)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, listenPort=" << listenPort;
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, listenPort=" << listenPort;
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, listenPort=" << listenPort;
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, listenPort=" << listenPort;
if (!m_wsServer->listen(QHostAddress::Any, listenPort))
{
WARNING_LOG(m_logger) << "Cannot listen on port " << listenPort << " - aborting";
return false;
}
DEBUG_LOG(m_logger) << "Listening on port " << listenPort;
connect(m_wsServer, &QWebSocketServer::newConnection,
this, &WsInterface::onNewConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, listenPort=" << listenPort;
return true;
}
void WsInterface::onNewConnection()
{
QWebSocket *clientSocket = m_wsServer->nextPendingConnection();
if (!clientSocket)
return;
connect(clientSocket, &QWebSocket::textMessageReceived,
this, &WsInterface::onTextMessageReceived);
connect(clientSocket, &QWebSocket::disconnected,
this, &WsInterface::onWebSocketDisconnected);
NOTICE_LOG(m_logger) << "Websocket connection established, ptr: " << clientSocket;
m_clients += clientSocket;
}
void WsInterface::onWebSocketDisconnected()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
if (!ws)
return;
NOTICE_LOG(m_logger) << "Websocket connection closed, ptr: " << ws;
m_clients.remove(ws);
ws->deleteLater();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void WsInterface::onError(QAbstractSocket::SocketError error)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error occured, QAbstractSocket::SocketError = " << error;
}
void WsInterface::onTextMessageReceived(const QString &msg)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, msg='" << msg << "'";
if (msg.isEmpty())
{
ERROR_LOG(m_logger) << "Empty message received";
return;
}
DEBUG_LOG(m_logger) << "incoming telegram: " << msg;
const QByteArray baJson = msg.toUtf8();
processMessage(baJson);
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
void WsInterface::processMessage(const QByteArray baJson)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " START";
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(baJson, &parseError);
if (parseError.error != QJsonParseError::NoError)
{
ERROR_LOG(m_logger) << "Could not parse JSON "
<< ". Reason: "
<< parseError.errorString()
<< "; baJson: '"
<< baJson << "'";
return;
}
NOTICE_LOG(m_logger) << "doc1 " << doc.toJson();
NOTICE_LOG(m_logger) << "doc2 " << doc.toJson(QJsonDocument::Compact) << "<<<";
const QJsonObject obj = doc.object();
const int typeId = obj.value(QStringLiteral("typeId")).toInt();
const QJsonObject data = obj.value(QStringLiteral("data")).toObject();
NOTICE_LOG(m_logger) << "Telegram with '" << typeId << "' received";
switch (typeId)
{
/*
python:
import websocket
import json
import time
ws = websocket.create_connection("ws://192.168.133.73:23456")
epoch_time = int(time.time())*1000
print(epoch_time)
d = { 'typeId' : 8011, 'data': {'objectId': 4711, 'name': 'myname', 'timestamp': epoch_time, 'activationTime': 12345678, 'isDeactivated': True, 'duration': 10, 'centerPoint':{'lat':52.477,'lon':11.597} } }
ws.send(json.dumps(d))
# d = { 'typeId' : 8010, 'data': {'objectId': 4711, 'name': 'removeAesObject', 'timestamp': epoch_time} }
ws.close()
*/
case 8001: // Dummy - neu definieren?
{
try
{
WsTelegramPosition pos = WsTelegramPosition::fromJson(data);
NOTICE_LOG(m_logger) << "type= " << pos.type();
NOTICE_LOG(m_logger) << "objectId= " << pos.objectId;
NOTICE_LOG(m_logger) << "name= '" << pos.name << "'";
NOTICE_LOG(m_logger) << "timestamp= " << pos.timestamp;
NOTICE_LOG(m_logger) << "lat= " << pos.position.lat;
NOTICE_LOG(m_logger) << "lon= " << pos.position.lon;
}
catch (const JsonException &ex)
{
ERROR_LOG(m_logger) << "Could not parse json telegram: "
<< ", error: " << ex.what();
}
break;
}
case 8010: // remove AesObj - neu definieren?
{
WsTelegramRemoveAesObject tele;
try
{
tele = WsTelegramRemoveAesObject::fromJson(data);
NOTICE_LOG(m_logger) << "type= " << tele.type();
NOTICE_LOG(m_logger) << "objectId= " << tele.objectId;
NOTICE_LOG(m_logger) << "name= '" << tele.name << "'";
NOTICE_LOG(m_logger) << "timestamp= " << tele.timestamp;
}
catch (const JsonException &ex)
{
ERROR_LOG(m_logger) << "Could not parse json telegram: "
<< ", error: " << ex.what();
return;
}
// WsTelegramXYObject to ngs/hla
if (m_ngsHandler && m_ngsHandler->ngsConnector())
m_ngsHandler->ngsConnector()->removeAesItem(tele.objectId);
break;
}
case 8011: // create/updateMineField - neu definieren?
{
WsTelegramMineFieldObject mf;
try
{
mf = WsTelegramMineFieldObject::fromJson(data);
NOTICE_LOG(m_logger) << "type= " << mf.type();
NOTICE_LOG(m_logger) << "objectId= " << mf.objectId;
NOTICE_LOG(m_logger) << "name= '" << mf.name << "'";
NOTICE_LOG(m_logger) << "timestamp= " << std::setprecision(15) << mf.timestamp;
NOTICE_LOG(m_logger) << "activationTime= " << std::setprecision(15) << mf.activationTime;
NOTICE_LOG(m_logger) << "duration= " << mf.duration;
NOTICE_LOG(m_logger) << "isDeactivated= " << mf.isDeactivated;
NOTICE_LOG(m_logger) << "lat= " << mf.area2D.centerPoint.lat << " - lon= " << mf.area2D.centerPoint.lon;
NOTICE_LOG(m_logger) << "width= " << mf.area2D.width << " - height= " << mf.area2D.height;
}
catch (const JsonException &ex)
{
ERROR_LOG(m_logger) << "Could not parse json telegram: "
<< ", error: " << ex.what();
return;
}
// WsTelegramXYObject to ngs/hla
if (m_ngsHandler && m_ngsHandler->ngsConnector())
m_ngsHandler->ngsConnector()->guezMineField(mf);
}
break;
default:
{
ERROR_LOG(m_logger) << "Telegram with typeId '" << typeId << "' not handled in switch"
<< ", doc= " << doc.toJson(QJsonDocument::Compact) << "<<<";
}
} // switch
}
} // HighLevelArchitecture
@@ -0,0 +1,61 @@
/**
* @RDE_HEADER@
* Websocket Server to connect to NGSConnector
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QObject>
#include <QWebSocket>
#include <QWebSocketServer>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <memory>
namespace HighLevelArchitecture
{
class NgsHandler;
//
// class WsInterface
//
class WsInterface : public QObject
{
Q_OBJECT
public:
explicit WsInterface(std::shared_ptr<NgsHandler> ngsHandler, QObject *parent = 0);
~WsInterface();
bool init(quint16 listenPort);
bool isConnected() const { return !m_clients.isEmpty(); }
signals:
private:
QWebSocketServer *m_wsServer;
QSet<QWebSocket *> m_clients;
std::shared_ptr<NgsHandler> m_ngsHandler;
NGL::INGLLogger &m_logger;
private slots:
// From Websocket:
void onNewConnection();
void onWebSocketDisconnected();
void onError(QAbstractSocket::SocketError error);
void onTextMessageReceived(const QString &msg);
void processMessage(const QByteArray baJson);
// From NGSConnector:
// empty
};
} // HighLevelArchitecture
@@ -0,0 +1,41 @@
#!/usr/bin/python
# Connect to ngs / hla and provide the basic interface
# $Id$
# $HeadURL$
# $Author$
# Created by Norbert Thoden, SLSE, 2022-03-04
import websocket
import json
import time
server_ip = "192.168.133.73"
server_port = 23456
ws = websocket.create_connection("ws://%s:%s" % (server_ip, server_port))
#ws.recv()
#ws.recv()
# create/updateMineField
time.sleep(2)
epoch_time = int(time.time())*1000
print(epoch_time)
#d = { 'typeId' : 8011, 'data': {'objectId': 4711, 'name': 'myNewMindefield', 'activationTime': 12345678, 'isDeactivated': True, 'duration': 10, 'area2D':{ 'centerPoint': {'lat':52.477,'lon':11.597}, 'width' : 123 } , 'timestamp': epoch_time} }
d = { 'typeId' : 8011, 'data': {'objectId': 4711, 'name': 'myNewMindefield', 'activationTime': 12345678, 'isDeactivated': True, 'duration': 10, 'area2D':{ 'centerPoint': {'lat':52.477,'lon':11.597}, 'width' : 123 } , 'timestamp': epoch_time} }
ws.send(json.dumps(d))
# removeAesObject
# Aes == AreaEffectSimulation
time.sleep(2)
epoch_time = int(time.time())*1000
d = { 'typeId' : 8010, 'data': {'objectId': 4711, 'name': 'removeAesObject', 'timestamp': epoch_time} }
#ws.send(json.dumps(d))
print("close ws and exit")
ws.close()
@@ -0,0 +1,261 @@
/**
* Telegrams at WsTelegram
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2019-09-18
*/
#include "ws_telegrams.h"
#include <QJsonDocument>
#include <QJsonObject>
namespace HighLevelArchitecture
{
//
// Helpers
//
JsonException::JsonException(const QJsonObject &obj, const QString &key)
: m_obj(obj)
, m_key(key)
, m_what("Could not find key '" + key.toUtf8() + "' in json ('" + QJsonDocument(obj).toJson(QJsonDocument::Compact) + "')")
{}
template <typename E>
QJsonValue enumToJson(E e)
{
static_assert (std::is_enum<E>::value, "Only useable with enumerations");
return static_cast<int>(e);
}
template <typename T>
bool get(const QJsonObject &obj, const QString &key, T &val, bool bOptional = false)
{
if (bOptional)
{
try
{
val = T::fromJson(obj[key].toObject());
}
catch (const JsonException &e)
{
Q_UNUSED(e);
return false;
}
}
else
val = T::fromJson(obj[key].toObject());
return true;
}
// POD getter
template <>
bool get(const QJsonObject &obj, const QString &key, bool &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isBool())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toBool();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, int &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toInt();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, double &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toDouble();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, QString &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isString())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toString();
return true;
}
//
// enum getter
//
// FinalAttackHeadingMode
template <>
bool get(const QJsonObject &obj, const QString &key, FinalAttackHeadingMode &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<FinalAttackHeadingMode>(iVal))
{
case FinalAttackHeadingMode::None:
case FinalAttackHeadingMode::HeadingOnly:
case FinalAttackHeadingMode::HeadingWithSector:
val = static_cast<FinalAttackHeadingMode>(iVal);
return true;
}
throw JsonException(obj, key);
}
//
// GeoPosition2D
//
QJsonObject GeoPosition2D::toJson() const
{
return QJsonObject({{QStringLiteral("lat"), lat},
{QStringLiteral("lon"), lon},
});
}
GeoPosition2D GeoPosition2D::fromJson(const QJsonObject &obj)
{
GeoPosition2D ret;
get(obj, QStringLiteral("lat"), ret.lat);
get(obj, QStringLiteral("lon"), ret.lon);
return ret;
}
//
// GeoPosition3D
//
QJsonObject GeoPosition3D::toJson() const
{
return QJsonObject({{QStringLiteral("lat"), lat},
{QStringLiteral("lon"), lon},
{QStringLiteral("height"), height},
});
}
GeoPosition3D GeoPosition3D::fromJson(const QJsonObject &obj)
{
GeoPosition3D ret;
get(obj, QStringLiteral("lat"), ret.lat);
get(obj, QStringLiteral("lon"), ret.lon);
get(obj, QStringLiteral("height"), ret.height);
return ret;
}
//
// Area2D
//
QJsonObject Area2D::toJson() const
{
return QJsonObject({{QStringLiteral("width"), width},
{QStringLiteral("height"), height},
{QStringLiteral("centerPoint"), centerPoint.toJson()},
});
}
Area2D Area2D::fromJson(const QJsonObject &obj)
{
Area2D ret;
get(obj, QStringLiteral("width"), ret.width, true); // optional
get(obj, QStringLiteral("height"), ret.height, true); // optional
get(obj, QStringLiteral("centerPoint"), ret.centerPoint);
return ret;
}
//
// WsTelegramPosition
//
QJsonObject WsTelegramPosition::toJson() const
{
return QJsonObject({{QStringLiteral("objectId"), objectId},
{QStringLiteral("name"), name},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("position"), position.toJson()},
});
}
WsTelegramPosition WsTelegramPosition::fromJson(const QJsonObject &obj)
{
WsTelegramPosition ret;
get(obj, QStringLiteral("objectId"), ret.objectId);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("position"), ret.position);
return ret;
}
//
// WsTelegramRemoveAesObject
//
QJsonObject WsTelegramRemoveAesObject::toJson() const
{
return QJsonObject({{QStringLiteral("objectId"), objectId},
{QStringLiteral("name"), name},
{QStringLiteral("timestamp"), timestamp},
});
}
WsTelegramRemoveAesObject WsTelegramRemoveAesObject::fromJson(const QJsonObject &obj)
{
WsTelegramRemoveAesObject ret;
get(obj, QStringLiteral("objectId"), ret.objectId);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
return ret;
}
//
// WsTelegramMineFieldObject
//
QJsonObject WsTelegramMineFieldObject::toJson() const
{
return QJsonObject({{QStringLiteral("objectId"), objectId},
{QStringLiteral("name"), name},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("activationTime"), activationTime},
{QStringLiteral("isDeactivated"), isDeactivated},
{QStringLiteral("duration"), duration},
{QStringLiteral("area2D"), area2D.toJson()}
});
}
WsTelegramMineFieldObject WsTelegramMineFieldObject::fromJson(const QJsonObject &obj)
{
WsTelegramMineFieldObject ret;
get(obj, QStringLiteral("objectId"), ret.objectId);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("activationTime"), ret.activationTime);
get(obj, QStringLiteral("isDeactivated"), ret.isDeactivated);
get(obj, QStringLiteral("duration"), ret.duration);
get(obj, QStringLiteral("area2D"), ret.area2D);
return ret;
}
} // namespace HighLevelArchitecture
@@ -0,0 +1,145 @@
/**
* Telegrams at WsTelegram
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2019-09-18
*/
#pragma once
#include <cstdint>
#include <exception>
#include <QJsonObject>
#include <QString>
namespace HighLevelArchitecture
{
class JsonException final : public std::exception
{
public:
JsonException(const QJsonObject &obj, const QString &key);
const char *what() const noexcept override { return m_what.data(); }
private:
QJsonObject m_obj;
QString m_key;
QByteArray m_what;
};
template <typename T>
struct Constraints;
//
// Enumerations
//
enum class FinalAttackHeadingMode
{
None = 0,
HeadingOnly = 1,
HeadingWithSector = 2,
};
//
// Structs
//
// ------------------------------------------------------------------
struct GeoPosition2D
{
double lat = 0; // in degree, WGS-84
double lon = 0; // in degree, WGS-84
static GeoPosition2D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
// ------------------------------------------------------------------
struct GeoPosition3D final : public GeoPosition2D
{
double height = 0; // above MSL
static GeoPosition3D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
// ------------------------------------------------------------------
struct Area2D
{
GeoPosition2D centerPoint;
int width{100};
int height{100};
static Area2D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
// ------------------------------------------------------------------
struct WsTelegramBase
{
int objectId = 0;
QString name;
double timestamp = 0; // in msec since epoche // for debugging purpose
virtual ~WsTelegramBase() = default;
virtual QJsonObject toJson() const = 0;
virtual QString type() const = 0;
};
// ------------------------------------------------------------------
template <typename T>
struct WsTelegramBaseTmpl : WsTelegramBase
{
QString type() const override final { return Constraints<T>::type(); }
};
// ------------------------------------------------------------------
struct WsTelegramPosition final : public WsTelegramBaseTmpl<WsTelegramPosition>
{
GeoPosition3D position;
// conversion functions
static WsTelegramPosition fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<WsTelegramPosition>
{
static QString type() { return QStringLiteral("WsTelegramPosition"); }
};
// ------------------------------------------------------------------
struct WsTelegramRemoveAesObject final : public WsTelegramBaseTmpl<WsTelegramRemoveAesObject>
{
// conversion functions
static WsTelegramRemoveAesObject fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<WsTelegramRemoveAesObject>
{
static QString type() { return QStringLiteral("WsTelegramRemoveAesObject"); }
};
// ------------------------------------------------------------------
struct WsTelegramMineFieldObject final : public WsTelegramBaseTmpl<WsTelegramMineFieldObject>
{
int activationTime{0};
bool isDeactivated{false};
int duration{0};
Area2D area2D; // define center and optional width, height
// conversion functions
static WsTelegramMineFieldObject fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<WsTelegramMineFieldObject>
{
static QString type() { return QStringLiteral("WsTelegramMineFieldObject"); }
};
} // namespace HighLevelArchitecture