Initial commit
This commit is contained in:
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:
|
||||
@@ -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
@@ -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
|
||||
Reference in new issue
Block a user