Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+196
@@ -0,0 +1,196 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
INCLUDE(MacroRTIDDSGen)
|
||||
INCLUDE(MacroCodeGenIdl)
|
||||
|
||||
SET(xml_FILE oss_service.xml)
|
||||
|
||||
#
|
||||
# --- Library svcOssCommon --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_common
|
||||
oss_export.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
# copy oss_predefined_data.sql to share
|
||||
SET(in_file_sql "oss_predefined_data.sql")
|
||||
SET(out_dir_sql "${CMAKE_BINARY_DIR}/share/Lts/sql/")
|
||||
SET(out_file_sql "${out_dir_sql}/${in_file_sql}")
|
||||
ADD_CUSTOM_COMMAND(OUTPUT ${out_file_sql}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E make_directory ${out_dir_sql}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy_if_different ${in_file_sql} ${out_file_sql}
|
||||
DEPENDS ${in_file_sql}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
LIST(APPEND SRCS_common ${in_file_sql} ${out_file_sql})
|
||||
|
||||
# Generate oss_enums.idl / oss.idl
|
||||
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
|
||||
# Generate oss_db_impl.cpp/.h, oss_db.h
|
||||
CODEGEN_DATABASE(SRCS_common ${xml_FILE})
|
||||
|
||||
# Generate *.cpp/*.hpp from idl
|
||||
RTIDDSGEN(SRCS_common oss_enums.idl)
|
||||
RTIDDSGEN(SRCS_common oss.idl)
|
||||
|
||||
# Generate oss_dt[s,c]_types.h, oss_ft[s,c]_types.h
|
||||
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
|
||||
# Generate oss_[d|f]tc.h
|
||||
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcOssCommon SHARED ${SRCS_common})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcOssCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(svcOssCommon
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
svcMsgCommon
|
||||
ngldb
|
||||
ddscore
|
||||
NGLLogger
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcOssCommon)
|
||||
|
||||
#
|
||||
# --- Library svcOssClient --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_client
|
||||
oss_export.h
|
||||
)
|
||||
# generate oss_[d|f]tc.h, oss_[d|f]tc_impl.[cpp|h]
|
||||
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcOssClient SHARED ${SRCS_client})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcOssClient
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcOssClient
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
PUBLIC
|
||||
svcOssCommon
|
||||
ddsftc
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcOssClient)
|
||||
|
||||
#
|
||||
# --- Library svcOssServer --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_server
|
||||
oss_export.h
|
||||
)
|
||||
# generate oss_[d|f]ts.h, oss_[d|f]ts_impl.[cpp|h]
|
||||
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV svcOssServer SHARED ${SRCS_server})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcOssServer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcOssServer
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
ddsfts
|
||||
PUBLIC
|
||||
svcOssCommon
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcOssServer)
|
||||
|
||||
#
|
||||
# --- Topic Type Plugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- RecordReplayPlugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_RECORD_REPLAY_PLUGIN(${xml_FILE} _srcs_not_needed)
|
||||
|
||||
#
|
||||
# --- Executable svcOcSituationServer (sOSS) -------------------------------------------------
|
||||
#
|
||||
SET(SRCS_exe
|
||||
main.cpp
|
||||
main_handler.cpp
|
||||
main_handler.h
|
||||
central_aes_data_builder.cpp
|
||||
central_aes_data_builder.h
|
||||
central_aes_data_queue.cpp
|
||||
central_aes_data_queue.h
|
||||
dds_handler.cpp
|
||||
dds_handler.h
|
||||
handler_oc_aes_data.cpp
|
||||
handler_oc_aes_data.h
|
||||
handler_oc_central_aes_data.cpp
|
||||
handler_oc_central_aes_data.h
|
||||
handler_oc_data.cpp
|
||||
handler_oc_data.h
|
||||
handler_oc_situation_data.cpp
|
||||
handler_oc_situation_data.h
|
||||
position_converter.cpp
|
||||
position_converter.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
|
||||
oc_situation.h
|
||||
${xml_FILE}
|
||||
)
|
||||
|
||||
# Generate oss.sql, oss.xml
|
||||
CODEGEN_SQL(SRCS_exe ${xml_FILE})
|
||||
|
||||
NGL_ADD_SVC_ICON(SRCS_exe)
|
||||
NGL_ADD_EXECUTABLE(AAR SV svcOcSituationServer ${SRCS_exe})
|
||||
NGL_TARGET_LINK_LIBRARIES(svcOcSituationServer
|
||||
Qt5::Core
|
||||
svcOssCommon
|
||||
svcOssServer
|
||||
svcCoreClient
|
||||
svcAesClient
|
||||
svcAsmClient
|
||||
svcEvlClient
|
||||
svcExmClient
|
||||
svcGimClient
|
||||
svcMsgClient
|
||||
svcPpmClient
|
||||
svcTabClient
|
||||
ddsconnector
|
||||
nglsettings
|
||||
ProjectConfig
|
||||
LtsCommandLineParser
|
||||
LtsCoordTrans
|
||||
LtsUtilsCoreHeaderOnly
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
ngltools
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcOcSituationServer)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_oss.props DESTINATION bin)
|
||||
NGL_ADD_TARGET_LINK(svcOcSituationServer sOSS)
|
||||
|
||||
# Uncomment if necessary
|
||||
#ADD_SUBDIRECTORY(UnitTests)
|
||||
#ADD_SUBDIRECTORY(ModuleTests)
|
||||
|
||||
+500
@@ -0,0 +1,500 @@
|
||||
/**
|
||||
* Manages central aes data to be sent
|
||||
* $Id: handler_oc_situation_data.h 57655 2022-07-20 11:38:28Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.h $
|
||||
* $Author: karwat $
|
||||
* Created by Hannes Fritsche, SLTE, 16-08-2022
|
||||
*/
|
||||
|
||||
#include "central_aes_data_builder.h"
|
||||
#include "LtsUtils/LtsUtilsCore/qbytearray_byteaccess.h"
|
||||
#include "QLineF"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
namespace DataBuilder
|
||||
{
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::EffectCluster &effectCluster, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtExplosionCluster); // we send EffectCluster as ExplosionCluster
|
||||
addAesItemId(byteStream, effectCluster.id());
|
||||
addName(byteStream, effectCluster.name());
|
||||
addEffectStart(byteStream, effectCluster.effectStart().is_set() ? effectCluster.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, effectCluster.effectDuration());
|
||||
addArea(byteStream, effectCluster.area());
|
||||
addMhpCount(byteStream, static_cast<int32_t>(effectCluster.effectors().size()));
|
||||
addMhpRotation(byteStream, effectCluster.effectors().size() ? effectCluster.effectors()[0].mhpRotation() : 1);
|
||||
addImpactCount(byteStream, static_cast<int32_t>(effectCluster.effectors().size()));
|
||||
addChargeTypeId(byteStream, effectCluster.chargeStruct().chargeTypeId());
|
||||
addPartyId(byteStream, effectCluster.partyId().is_set() ? effectCluster.partyId().get() : -1);
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::NContamination &nContamination, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtNContamination);
|
||||
addAesItemId(byteStream, nContamination.id());
|
||||
addName(byteStream, nContamination.name());
|
||||
addEffectStart(byteStream, nContamination.effectStart().is_set() ? nContamination.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, nContamination.effectDuration());
|
||||
addChargeTypeId(byteStream, nContamination.chargeStruct().chargeTypeId());
|
||||
addImpactPosition(byteStream, nContamination.impactPosition());
|
||||
addBorderLengthInner(byteStream, nContamination.borderLengthInner());
|
||||
addBorderLengthOuter(byteStream, nContamination.borderLengthOuter());
|
||||
addImpactRadius(byteStream, nContamination.impactRadius());
|
||||
addSpanAngle(byteStream, nContamination.spanAngle());
|
||||
addRotationAngle(byteStream, nContamination.rotationAngle());
|
||||
addDetonationValue(byteStream, nContamination.detonationValue());
|
||||
addPartyId(byteStream, nContamination.partyId().is_set() ? nContamination.partyId().get() : -1);
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::BCContamination &bCContamination, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtBCContamination);
|
||||
addAesItemId(byteStream, bCContamination.id());
|
||||
addName(byteStream, bCContamination.name());
|
||||
addEffectStart(byteStream, bCContamination.effectStart().is_set() ? bCContamination.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, bCContamination.effectDuration());
|
||||
addChargeTypeId(byteStream, bCContamination.chargeStruct().chargeTypeId());
|
||||
addImpactPosition(byteStream, bCContamination.impactPosition());
|
||||
addImpactRadius(byteStream, bCContamination.impactRadius());
|
||||
addPartyId(byteStream, bCContamination.partyId().is_set() ? bCContamination.partyId().get() : -1);
|
||||
addPropagationDirection(byteStream, bCContamination.propagationDirection());
|
||||
addWindSpeed(byteStream, bCContamination.windSpeed());
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionArea &explosionArea, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtExplosionArea);
|
||||
addAesItemId(byteStream, explosionArea.id());
|
||||
addName(byteStream, explosionArea.name());
|
||||
addEffectStart(byteStream, explosionArea.effectStart().is_set() ? explosionArea.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, explosionArea.effectDuration());
|
||||
addChargeTypeId(byteStream, explosionArea.chargeStruct().chargeTypeId());
|
||||
addArea(byteStream, explosionArea.area());
|
||||
addPartyId(byteStream, explosionArea.partyId().is_set() ? explosionArea.partyId().get() : -1);
|
||||
addCannonCount(byteStream, explosionArea.cannonCount());
|
||||
addCannonRounds(byteStream, explosionArea.cannonRounds());
|
||||
addFireRequestTime(byteStream, explosionArea.fireRequestTime());
|
||||
addAltitude(byteStream, explosionArea.altitude());
|
||||
addPurpose(byteStream, explosionArea.purpose());
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionSingle &explosionSingle, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtExplosionSingle);
|
||||
addAesItemId(byteStream, explosionSingle.id());
|
||||
addName(byteStream, explosionSingle.name());
|
||||
addEffectStart(byteStream, explosionSingle.effectStart().is_set() ? explosionSingle.effectStart().get() : -1);
|
||||
addChargeTypeId(byteStream, explosionSingle.chargeStruct().chargeTypeId());
|
||||
addImpactPosition(byteStream, explosionSingle.impactPosition());
|
||||
addPartyId(byteStream, explosionSingle.partyId().is_set() ? explosionSingle.partyId().get() : -1);
|
||||
addFireRequestTime(byteStream, explosionSingle.fireRequestTime());
|
||||
addAltitude(byteStream, explosionSingle.altitude());
|
||||
addPurpose(byteStream, explosionSingle.purpose());
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::MineArea &mineArea, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtMineArea);
|
||||
addAesItemId(byteStream, mineArea.id());
|
||||
addName(byteStream, mineArea.name());
|
||||
addEffectStart(byteStream, mineArea.effectStart().is_set() ? mineArea.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, mineArea.effectDuration());
|
||||
addDensity(byteStream, mineArea.density());
|
||||
addWidth(byteStream, mineArea.width());
|
||||
addChargeTypeId(byteStream, mineArea.chargeStruct().chargeTypeId());
|
||||
addPartyId(byteStream, mineArea.partyId().is_set() ? mineArea.partyId().get() : -1);
|
||||
addAesMaLayingProcedureType(byteStream, mineArea.layingProcedureType());
|
||||
addIsLayedHidden(byteStream, mineArea.isLaidHidden());
|
||||
addIsCenterLine(byteStream, mineArea.isCenterLine());
|
||||
addSegments(byteStream, mineArea.segments());
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::FunctionalArea &functionalArea, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtFunctionalArea);
|
||||
addAesItemId(byteStream, functionalArea.id());
|
||||
addName(byteStream, functionalArea.name());
|
||||
addEffectStart(byteStream, functionalArea.effectStart().is_set() ? functionalArea.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, functionalArea.effectDuration());
|
||||
addChargeTypeId(byteStream, functionalArea.chargeStruct().chargeTypeId());
|
||||
addArea(byteStream, functionalArea.area());
|
||||
addPartyId(byteStream, functionalArea.partyId().is_set() ? functionalArea.partyId().get() : -1);
|
||||
addPointSymbol(byteStream, functionalArea.pointSymbol().is_set() ? functionalArea.pointSymbol().get() : std::string());
|
||||
addFunctionalAreaTypeId(byteStream, functionalArea.functionalAreaTypeId());
|
||||
addDeconMode(byteStream, functionalArea.deconMode());
|
||||
addDeconTime(byteStream, functionalArea.deconTime());
|
||||
addMaintMode(byteStream, functionalArea.maintMode());
|
||||
addMaintTime(byteStream, functionalArea.maintTime());
|
||||
addMedicMode(byteStream, functionalArea.medicMode());
|
||||
addMedicTime(byteStream, functionalArea.medicTime());
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::BoobyTrap &boobyTrap, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtBoobyTrap);
|
||||
addAesItemId(byteStream, boobyTrap.id());
|
||||
addName(byteStream, boobyTrap.name());
|
||||
addEffectDuration(byteStream, boobyTrap.effectDuration());
|
||||
addChargeTypeId(byteStream, boobyTrap.chargeStruct().chargeTypeId());
|
||||
addImpactPosition(byteStream, boobyTrap.impactPosition());
|
||||
addImpactRadius(byteStream, boobyTrap.impactRadius());
|
||||
addTriggerRadius(byteStream, boobyTrap.triggerRadius());
|
||||
addRotationAngle(byteStream, boobyTrap.rotationAngle().is_set() ? boobyTrap.rotationAngle().get() : -1);
|
||||
addCentralAngle(byteStream, boobyTrap.centralAngle().is_set() ? boobyTrap.centralAngle().get() : -1);
|
||||
addEffectStart(byteStream, boobyTrap.effectStart().is_set() ? boobyTrap.effectStart().get() : -1);
|
||||
addPartyId(byteStream, boobyTrap.partyId().is_set() ? boobyTrap.partyId().get() : -1);
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::OffRouteMine &offRouteMine, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
isPrioritized = false;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtOffRouteMine);
|
||||
addAesItemId(byteStream, offRouteMine.id());
|
||||
addName(byteStream, offRouteMine.name());
|
||||
addEffectDuration(byteStream, offRouteMine.effectDuration());
|
||||
addChargeTypeId(byteStream, offRouteMine.chargeStruct().chargeTypeId());
|
||||
addArea(byteStream, offRouteMine.area());
|
||||
addImpactRadius(byteStream, offRouteMine.impactRadius().is_set() ? offRouteMine.impactRadius().get() : -1);
|
||||
addEffectStart(byteStream, offRouteMine.effectStart().is_set() ? offRouteMine.effectStart().get() : -1);
|
||||
addPartyId(byteStream, offRouteMine.partyId().is_set() ? offRouteMine.partyId().get() : -1);
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionCluster &explosionCluster, bool &isPrioritized)
|
||||
{
|
||||
QByteArray byteStream;
|
||||
|
||||
addAesType(byteStream, AreaEffectSimulation::AesType::AtExplosionCluster);
|
||||
addAesItemId(byteStream, explosionCluster.id());
|
||||
addName(byteStream, explosionCluster.name());
|
||||
addEffectStart(byteStream, explosionCluster.effectStart().is_set() ? explosionCluster.effectStart().get() : -1);
|
||||
addEffectDuration(byteStream, explosionCluster.effectDuration());
|
||||
addArea(byteStream, explosionCluster.area());
|
||||
addMhpCount(byteStream, static_cast<int32_t>(explosionCluster.mhPoints().size()));
|
||||
addMhpRotation(byteStream, explosionCluster.mhpRotation());
|
||||
addImpactCount(byteStream, explosionCluster.impactCount());
|
||||
addChargeTypeId(byteStream, explosionCluster.chargeStruct().chargeTypeId());
|
||||
addPartyId(byteStream, explosionCluster.partyId().is_set() ? explosionCluster.partyId().get() : -1);
|
||||
|
||||
isPrioritized = explosionCluster.impactCount() == 1; // we prioritize every single fire
|
||||
|
||||
return byteStream;
|
||||
}
|
||||
|
||||
void addAesItemId(QByteArray &buf, int32_t aesItemId)
|
||||
{
|
||||
LtsUtils::set4Byte(aesItemId, buf);
|
||||
}
|
||||
|
||||
void addAesMaLayingProcedureType(QByteArray &buf, const AreaEffectSimulation::AesMaLayingProcedureType &aesMaLayingProcedureType)
|
||||
{
|
||||
addDdsEnumVal(buf, aesMaLayingProcedureType);
|
||||
}
|
||||
|
||||
void addAesType(QByteArray &buf, const AreaEffectSimulation::AesType &aesType)
|
||||
{
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
// we treat EffectClusters as ExplosionClusters
|
||||
addDdsEnumVal(buf, aesType == AesType::inner_enum::AtEffectCluster ? AesType::inner_enum::AtExplosionCluster : aesType);
|
||||
}
|
||||
|
||||
void addAltitude(QByteArray &buf, int32_t altitude)
|
||||
{
|
||||
LtsUtils::set4Byte(altitude, buf);
|
||||
}
|
||||
|
||||
void addArea(QByteArray &buf, const AreaEffectSimulation::Area &area)
|
||||
{
|
||||
addPosition2D(buf, area.cornerBottomLeft());
|
||||
LtsUtils::set8Byte(area.width(), buf);
|
||||
LtsUtils::set8Byte(area.height(), buf);
|
||||
LtsUtils::set8Byte(area.rotation(), buf);
|
||||
}
|
||||
|
||||
void addBorderLengthInner(QByteArray &buf, double borderLengthInner)
|
||||
{
|
||||
LtsUtils::set8Byte(borderLengthInner, buf);
|
||||
}
|
||||
|
||||
void addBorderLengthOuter(QByteArray &buf, double borderLengthOuter)
|
||||
{
|
||||
LtsUtils::set8Byte(borderLengthOuter, buf);
|
||||
}
|
||||
|
||||
void addCannonCount(QByteArray &buf, int32_t cannonCount)
|
||||
{
|
||||
LtsUtils::set4Byte(cannonCount, buf);
|
||||
}
|
||||
|
||||
void addCannonRounds(QByteArray &buf, int32_t cannonRounds)
|
||||
{
|
||||
LtsUtils::set4Byte(cannonRounds, buf);
|
||||
}
|
||||
|
||||
void addCentralAesChangeType(QByteArray &buf, OcSituation::CentralAesChangeType changeType)
|
||||
{
|
||||
LtsUtils::set1Byte(changeType, buf);
|
||||
}
|
||||
|
||||
void addCentralAngle(QByteArray &buf, double centralAngle)
|
||||
{
|
||||
LtsUtils::set8Byte(centralAngle, buf);
|
||||
}
|
||||
|
||||
void addChargeTypeId(QByteArray &buf, int32_t chargeType)
|
||||
{
|
||||
LtsUtils::set4Byte(chargeType, buf);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void addDdsEnumVal(QByteArray &buf, const T &ddsEnumVal)
|
||||
{
|
||||
LtsUtils::set4Byte(static_cast<int32_t>(ddsEnumVal.underlying()), buf);
|
||||
}
|
||||
|
||||
void addDeconMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &deconMode)
|
||||
{
|
||||
addDdsEnumVal(buf, deconMode);
|
||||
}
|
||||
|
||||
void addDeconTime(QByteArray &buf, int32_t deconTime)
|
||||
{
|
||||
LtsUtils::set4Byte(deconTime, buf);
|
||||
}
|
||||
|
||||
void addDensity(QByteArray &buf, double density)
|
||||
{
|
||||
LtsUtils::set8Byte(density, buf);
|
||||
}
|
||||
|
||||
void addDetonationValue(QByteArray &buf, double detonationValue)
|
||||
{
|
||||
LtsUtils::set8Byte(detonationValue, buf);
|
||||
}
|
||||
|
||||
void addEffectDuration(QByteArray &buf, int32_t effectDuration)
|
||||
{
|
||||
LtsUtils::set4Byte(effectDuration, buf);
|
||||
}
|
||||
|
||||
void addEffectStart(QByteArray &buf, rti::core::int64 effectStart)
|
||||
{
|
||||
LtsUtils::set8Byte(effectStart, buf);
|
||||
}
|
||||
|
||||
void addExplosionGeometry(QByteArray &buf, const AreaEffectSimulation::AesExplosionGeometry &explosionGeometry)
|
||||
{
|
||||
addDdsEnumVal(buf, explosionGeometry);
|
||||
}
|
||||
|
||||
void addFireRequestTime(QByteArray &buf, rti::core::int64 fireRequestTime)
|
||||
{
|
||||
LtsUtils::set8Byte(fireRequestTime, buf);
|
||||
}
|
||||
|
||||
void addIgniterType(QByteArray &buf, int32_t igniterTypeId)
|
||||
{
|
||||
LtsUtils::set4Byte(igniterTypeId, buf);
|
||||
}
|
||||
|
||||
void addFunctionalAreaTypeId(QByteArray &buf, int32_t functionalAreaTypeId)
|
||||
{
|
||||
LtsUtils::set4Byte(functionalAreaTypeId, buf);
|
||||
}
|
||||
|
||||
void addImpactCount(QByteArray &buf, int32_t impactCount)
|
||||
{
|
||||
LtsUtils::set4Byte(impactCount, buf);
|
||||
}
|
||||
|
||||
void addImpactPosition(QByteArray &buf, const Core::GeoPosition2D &position)
|
||||
{
|
||||
addPosition2D(buf, position);
|
||||
}
|
||||
|
||||
void addImpactRadius(QByteArray &buf, double impactRadius)
|
||||
{
|
||||
LtsUtils::set8Byte(impactRadius, buf);
|
||||
}
|
||||
|
||||
void addIsCenterLine(QByteArray &buf, bool isCenterLine)
|
||||
{
|
||||
LtsUtils::set1Byte(isCenterLine, buf);
|
||||
}
|
||||
|
||||
void addIsLayedHidden(QByteArray &buf, bool isLayedHidden)
|
||||
{
|
||||
LtsUtils::set1Byte(isLayedHidden, buf);
|
||||
}
|
||||
|
||||
void addMaintMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &maintMode)
|
||||
{
|
||||
addDdsEnumVal(buf, maintMode);
|
||||
}
|
||||
|
||||
void addMaintTime(QByteArray &buf, int32_t maintTime)
|
||||
{
|
||||
LtsUtils::set4Byte(maintTime, buf);
|
||||
}
|
||||
|
||||
void addMedicMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &medicMode)
|
||||
{
|
||||
addDdsEnumVal(buf, medicMode);
|
||||
}
|
||||
|
||||
void addMedicTime(QByteArray &buf, int32_t medicTime)
|
||||
{
|
||||
LtsUtils::set4Byte(medicTime, buf);
|
||||
}
|
||||
|
||||
void addMhpCount(QByteArray &buf, int32_t mhpCount)
|
||||
{
|
||||
LtsUtils::set4Byte(mhpCount, buf);
|
||||
}
|
||||
|
||||
void addMhpRotation(QByteArray &buf, double mhpRotation)
|
||||
{
|
||||
LtsUtils::set8Byte(mhpRotation, buf);
|
||||
}
|
||||
|
||||
void addName(QByteArray &buf, const std::string &name)
|
||||
{
|
||||
addString(buf, name, 8);
|
||||
}
|
||||
|
||||
void addPartyId(QByteArray &buf, int32_t partyId)
|
||||
{
|
||||
LtsUtils::set4Byte(partyId, buf);
|
||||
}
|
||||
|
||||
void addPointSymbol(QByteArray &buf, const std::string &pointSymbol)
|
||||
{
|
||||
addString(buf, pointSymbol, pointSymbol.length());
|
||||
}
|
||||
|
||||
void addPosition2D(QByteArray &buf, const Core::GeoPosition2D &position)
|
||||
{
|
||||
LtsUtils::set8Byte(position.lon(), buf);
|
||||
LtsUtils::set8Byte(position.lat(), buf);
|
||||
// no timestamp, as it is set in the client anyway
|
||||
}
|
||||
|
||||
void addPurpose(QByteArray &buf, const std::string &purpose)
|
||||
{
|
||||
addString(buf, purpose);
|
||||
}
|
||||
|
||||
void addRotationAngle(QByteArray &buf, double rotationAngle)
|
||||
{
|
||||
LtsUtils::set8Byte(rotationAngle, buf);
|
||||
}
|
||||
|
||||
void addSegments(QByteArray &buf, const std::vector<AreaEffectSimulation::MineSegment> &segments)
|
||||
{
|
||||
unsigned char len = segments.size() + 1;
|
||||
LtsUtils::set1Byte(len, buf);
|
||||
|
||||
if (len == 1)
|
||||
return;
|
||||
|
||||
AreaEffectSimulation::MineSegment lastSeg;
|
||||
|
||||
for (const AreaEffectSimulation::MineSegment ¤tMineSegment : qAsConst(segments))
|
||||
{
|
||||
addPosition2D(buf, currentMineSegment.positionStart());
|
||||
lastSeg = currentMineSegment;
|
||||
}
|
||||
addPosition2D(buf, lastSeg.positionEnd());
|
||||
}
|
||||
|
||||
void addSpanAngle(QByteArray &buf, double spanAngle)
|
||||
{
|
||||
LtsUtils::set8Byte(spanAngle, buf);
|
||||
}
|
||||
|
||||
void addString(QByteArray &buf, const std::string &str, size_t maxLen)
|
||||
{
|
||||
unsigned char len = std::min(str.size(), size_t(maxLen));
|
||||
LtsUtils::set1Byte(len, buf);
|
||||
buf.append(str.c_str(), len);
|
||||
}
|
||||
|
||||
void addTriggerRadius(QByteArray &buf, double triggerRadius)
|
||||
{
|
||||
LtsUtils::set8Byte(triggerRadius, buf);
|
||||
}
|
||||
|
||||
void addWidth(QByteArray &buf, double width)
|
||||
{
|
||||
LtsUtils::set8Byte(width, buf);
|
||||
}
|
||||
|
||||
void addPropagationDirection(QByteArray &buf, double propagationDirection)
|
||||
{
|
||||
LtsUtils::set8Byte(propagationDirection, buf);
|
||||
}
|
||||
|
||||
void addWindSpeed(QByteArray &buf, double windSpeed)
|
||||
{
|
||||
LtsUtils::set8Byte(windSpeed, buf);
|
||||
}
|
||||
|
||||
} // namespace DataBuilder
|
||||
|
||||
} // namespace OcSituationServer
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Manages central aes data to be sent
|
||||
* $Id: handler_oc_situation_data.h 57655 2022-07-20 11:38:28Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.h $
|
||||
* $Author: karwat $
|
||||
* Created by Hannes Fritsche, SLTE, 16-08-2022
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "AreaEffectSimulation/aes_dtc.h"
|
||||
#include "oc_situation.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
namespace DataBuilder
|
||||
{
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::EffectCluster &effectCluster, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::NContamination &nContamination, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::BCContamination &bCContamination, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionArea &explosionArea, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionSingle &explosionSingle, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::MineArea &mineArea, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::FunctionalArea &functionalArea, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::BoobyTrap &boobyTrap, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::OffRouteMine &offRouteMine, bool &isPrioritized);
|
||||
QByteArray getByteStreamAesItem(const AreaEffectSimulation::ExplosionCluster &explosionCluster, bool &isPrioritized);
|
||||
|
||||
// Building Byte Stream
|
||||
void addAesItemId(QByteArray &buf, int32_t aesItemId);
|
||||
void addAesMaLayingProcedureType(QByteArray &buf, const AreaEffectSimulation::AesMaLayingProcedureType &aesMaLayingProcedureType);
|
||||
void addAesType(QByteArray &buf, const AreaEffectSimulation::AesType &aesType);
|
||||
void addAltitude(QByteArray &buf, int32_t altitude);
|
||||
void addArea(QByteArray &buf, const AreaEffectSimulation::Area &area);
|
||||
void addBorderLengthInner(QByteArray &buf, double borderLengthInner);
|
||||
void addBorderLengthOuter(QByteArray &buf, double borderLengthOuter);
|
||||
void addCannonCount(QByteArray &buf, int32_t cannonCount);
|
||||
void addCannonRounds(QByteArray &buf, int32_t cannonRounds);
|
||||
void addCentralAesChangeType(QByteArray &buf, OcSituation::CentralAesChangeType changeType);
|
||||
void addCentralAngle(QByteArray &buf, double centralAngle);
|
||||
void addChargeTypeId(QByteArray &buf, int32_t chargeType);
|
||||
template <typename T>
|
||||
void addDdsEnumVal(QByteArray &buf, const T &ddsEnumVal);
|
||||
void addDeconMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &deconMode);
|
||||
void addDeconTime(QByteArray &buf, int32_t deconTime);
|
||||
void addDensity(QByteArray &buf, double density);
|
||||
void addDetonationValue(QByteArray &buf, double detonationValue);
|
||||
void addEffectDuration(QByteArray &buf, int32_t effectDuration);
|
||||
void addEffectStart(QByteArray &buf, rti::core::int64 effectStart);
|
||||
void addExplosionGeometry(QByteArray &buf, const AreaEffectSimulation::AesExplosionGeometry &explosionGeometry);
|
||||
void addFireRequestTime(QByteArray &buf, rti::core::int64 fireRequestTime);
|
||||
void addIgniterType(QByteArray &buf, int32_t igniterTypeId);
|
||||
void addFunctionalAreaTypeId(QByteArray &buf, int32_t functionalAreaTypeId);
|
||||
void addImpactCount(QByteArray &buf, int32_t impactCount);
|
||||
void addImpactPosition(QByteArray &buf, const Core::GeoPosition2D &position);
|
||||
void addImpactRadius(QByteArray &buf, double impactRadius);
|
||||
void addIsCenterLine(QByteArray &buf, bool isCenterLine);
|
||||
void addIsLayedHidden(QByteArray &buf, bool isLayedHidden);
|
||||
void addMaintMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &maintMode);
|
||||
void addMaintTime(QByteArray &buf, int32_t maintTime);
|
||||
void addMedicMode(QByteArray &buf, const AreaEffectSimulation::AesOperatingMode &medicMode);
|
||||
void addMedicTime(QByteArray &buf, int32_t medicTime);
|
||||
void addMhpCount(QByteArray &buf, int32_t mhpCount);
|
||||
void addMhpRotation(QByteArray &buf, double mhpRotation);
|
||||
void addName(QByteArray &buf, const std::string &name);
|
||||
void addPartyId(QByteArray &buf, int32_t partyId);
|
||||
void addPointSymbol(QByteArray &buf, const std::string &pointSymbol);
|
||||
void addPosition2D(QByteArray &buf, const Core::GeoPosition2D &position);
|
||||
void addPropagationDirection(QByteArray &buf, double propagationDirection);
|
||||
void addPurpose(QByteArray &buf, const std::string &purpose);
|
||||
void addRotationAngle(QByteArray &buf, double rotationAngle);
|
||||
void addSegments(QByteArray &buf, const std::vector<AreaEffectSimulation::MineSegment> &segments);
|
||||
void addSpanAngle(QByteArray &buf, double spanAngle);
|
||||
void addString(QByteArray &buf, const std::string &str, size_t maxLen = 15);
|
||||
void addTriggerRadius(QByteArray &buf, double triggerRadius);
|
||||
void addWidth(QByteArray &buf, double width);
|
||||
void addWindSpeed(QByteArray &buf, double windSpeed);
|
||||
|
||||
|
||||
} // namespace DataBuilder
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Manages central aes data to be sent
|
||||
* $Id: handler_oc_situation_data.h 57655 2022-07-20 11:38:28Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.h $
|
||||
* $Author: karwat $
|
||||
* Created by Hannes Fritsche, SLTE, 16-08-2022
|
||||
*/
|
||||
|
||||
#include "central_aes_data_queue.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
CentralAesDataQueue::CentralAesDataQueue(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_logger(getLogger("CentralAesDataQueue"))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(int32_t aesItemId, AreaEffectSimulation::AesType aesType, bool isPrioritized)
|
||||
{
|
||||
QMutexLocker locker(&m_accessMutex);
|
||||
QByteArray data;
|
||||
|
||||
clearSpecificMessage(aesItemId, OcSituation::Remove);
|
||||
|
||||
using namespace DataBuilder;
|
||||
|
||||
addCentralAesChangeType(data, OcSituation::Remove);
|
||||
addAesItemId(data, aesItemId);
|
||||
addAesType(data, aesType);
|
||||
|
||||
if (isPrioritized)
|
||||
m_internalPrioritizedQueue.prepend({aesItemId, OcSituation::Remove, data});
|
||||
else
|
||||
m_internalQueue.prepend({aesItemId, OcSituation::Remove, data});
|
||||
|
||||
DEBUG_LOG(m_logger) << "New remove-message added: Id = " << aesItemId
|
||||
<< ", aesType = " << aesType << ". "
|
||||
<< m_internalQueue.size() << " normal, "
|
||||
<< m_internalPrioritizedQueue.size() << " prioritized and "
|
||||
<< m_internalQueue.size() + m_internalPrioritizedQueue.size() << " remaining messages in total.";
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::EffectCluster &effectCluster)
|
||||
{
|
||||
// we treat EffectClusters as ExplosionClusters for the ABT
|
||||
addRemoveMessage(effectCluster.id(), AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::NContamination &nContamination)
|
||||
{
|
||||
addRemoveMessage(nContamination.id(), AreaEffectSimulation::AesType::inner_enum::AtNContamination);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::BCContamination &bCContamination)
|
||||
{
|
||||
addRemoveMessage(bCContamination.id(), AreaEffectSimulation::AesType::inner_enum::AtBCContamination);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::ExplosionArea &explosionArea)
|
||||
{
|
||||
addRemoveMessage(explosionArea.id(), AreaEffectSimulation::AesType::inner_enum::AtExplosionArea);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::ExplosionSingle &explosionSingle)
|
||||
{
|
||||
addRemoveMessage(explosionSingle.id(), AreaEffectSimulation::AesType::inner_enum::AtExplosionSingle);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::MineArea &mineArea)
|
||||
{
|
||||
addRemoveMessage(mineArea.id(), AreaEffectSimulation::AesType::inner_enum::AtMineArea);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::FunctionalArea &functionalArea)
|
||||
{
|
||||
addRemoveMessage(functionalArea.id(), AreaEffectSimulation::AesType::inner_enum::AtFunctionalArea);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::BoobyTrap &boobyTrap)
|
||||
{
|
||||
addRemoveMessage(boobyTrap.id(), AreaEffectSimulation::AesType::inner_enum::AtBoobyTrap);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::OffRouteMine &offRouteMine)
|
||||
{
|
||||
addRemoveMessage(offRouteMine.id(), AreaEffectSimulation::AesType::inner_enum::AtOffRouteMine);
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::addRemoveMessage(const AreaEffectSimulation::ExplosionCluster &explosionCluster)
|
||||
{
|
||||
addRemoveMessage(explosionCluster.id(), AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster, explosionCluster.impactCount() == 1); // we prioritize every single fire
|
||||
}
|
||||
|
||||
QByteArray CentralAesDataQueue::getSendingData(qint32 size)
|
||||
{
|
||||
QMutexLocker locker(&m_accessMutex);
|
||||
QByteArray result;
|
||||
|
||||
qint32 messageCounter = 0;
|
||||
|
||||
while (!m_internalPrioritizedQueue.isEmpty() && ((result.size() + m_internalPrioritizedQueue.head().data.size()) <= size))
|
||||
{
|
||||
result.append(m_internalPrioritizedQueue.dequeue().data);
|
||||
++messageCounter;
|
||||
}
|
||||
|
||||
// if the result is empty and we have messages left, there is no message small enough, to fit size
|
||||
// so we send the next best message
|
||||
if (result.isEmpty() && !m_internalPrioritizedQueue.isEmpty())
|
||||
{
|
||||
result.append(m_internalPrioritizedQueue.dequeue().data);
|
||||
|
||||
++messageCounter;
|
||||
|
||||
WARNING_LOG(m_logger) << "Could not build data with max size of " << size << " bytes. Delivering data with " << result.size() << " bytes.";
|
||||
}
|
||||
|
||||
while (!m_internalQueue.isEmpty() && ((result.size() + m_internalQueue.head().data.size()) <= size))
|
||||
{
|
||||
result.append(m_internalQueue.dequeue().data);
|
||||
++messageCounter;
|
||||
}
|
||||
|
||||
// if the result is empty and we have messages left, there is no message small enough, to fit size
|
||||
// so we send the next best message
|
||||
if (result.isEmpty() && !m_internalQueue.isEmpty())
|
||||
{
|
||||
result.append(m_internalQueue.dequeue().data);
|
||||
|
||||
++messageCounter;
|
||||
|
||||
WARNING_LOG(m_logger) << "Could not build data with max size of " << size << " bytes. Delivering data with " << result.size() << " bytes.";
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Data with max size = " << size << "requestet. " << result.size() << " bytes delivered.";
|
||||
DEBUG_LOG(m_logger) << messageCounter << " messages are sent. "
|
||||
<< m_internalQueue.size() << " normal, "
|
||||
<< m_internalPrioritizedQueue.size() << " prioritized and "
|
||||
<< m_internalQueue.size() + m_internalPrioritizedQueue.size() << " remaining messages in total.";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CentralAesDataQueue::hasMessages() const
|
||||
{
|
||||
return !m_internalQueue.isEmpty() || !m_internalPrioritizedQueue.isEmpty();
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::clear()
|
||||
{
|
||||
m_internalQueue.clear();
|
||||
m_internalPrioritizedQueue.clear();
|
||||
}
|
||||
|
||||
void CentralAesDataQueue::clearSpecificMessage(int32_t aesItemId, OcSituation::CentralAesChangeType changeType)
|
||||
{
|
||||
for (qint32 counter = 0; counter < m_internalQueue.size(); ++counter)
|
||||
{
|
||||
if (m_internalQueue.at(counter).aesItemId == aesItemId && m_internalQueue.at(counter).changeType == changeType)
|
||||
{
|
||||
m_internalQueue.removeAt(counter);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Removed already existing message. aesItemId = " << aesItemId << ", changeType = " << changeType;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (qint32 counter = 0; counter < m_internalPrioritizedQueue.size(); ++counter)
|
||||
{
|
||||
if (m_internalPrioritizedQueue.at(counter).aesItemId == aesItemId && m_internalPrioritizedQueue.at(counter).changeType == changeType)
|
||||
{
|
||||
m_internalPrioritizedQueue.removeAt(counter);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Removed already existing message. aesItemId = " << aesItemId << ", changeType = " << changeType;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Manages central aes data to be sent
|
||||
* $Id: handler_oc_situation_data.h 57655 2022-07-20 11:38:28Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.h $
|
||||
* $Author: karwat $
|
||||
* Created by Hannes Fritsche, SLTE, 16-08-2022
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QQueue>
|
||||
#include "oc_situation.h"
|
||||
#include <QObject>
|
||||
#include "logger.h"
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include "central_aes_data_builder.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
class CentralAesDataQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CentralAesDataQueue(QObject *parent = nullptr);
|
||||
|
||||
template <typename T>
|
||||
void addAesItem(const T &aesItem)
|
||||
{
|
||||
QMutexLocker locker(&m_accessMutex);
|
||||
QByteArray data;
|
||||
bool isPrioritized = false; // we prioritize every single fire
|
||||
|
||||
clearSpecificMessage(aesItem.id(), OcSituation::AddMod);
|
||||
|
||||
DataBuilder::addCentralAesChangeType(data, OcSituation::AddMod);
|
||||
data.append(DataBuilder::getByteStreamAesItem(aesItem, isPrioritized));
|
||||
|
||||
if (isPrioritized)
|
||||
m_internalPrioritizedQueue.enqueue({aesItem.id(), OcSituation::AddMod, data});
|
||||
else
|
||||
m_internalQueue.enqueue({aesItem.id(), OcSituation::AddMod, data});
|
||||
|
||||
DEBUG_LOG(m_logger) << "New AesItem added. " << m_internalQueue.size() << " normal, "
|
||||
<< m_internalPrioritizedQueue.size() << " prioritized and "
|
||||
<< m_internalQueue.size() + m_internalPrioritizedQueue.size() << " messages in total.";
|
||||
}
|
||||
|
||||
void addRemoveMessage(int32_t aesItemId, AreaEffectSimulation::AesType aesType, bool isPrioritized = false);
|
||||
void addRemoveMessage(const AreaEffectSimulation::EffectCluster &effectCluster);
|
||||
void addRemoveMessage(const AreaEffectSimulation::NContamination &nContamination);
|
||||
void addRemoveMessage(const AreaEffectSimulation::BCContamination &bCContamination);
|
||||
void addRemoveMessage(const AreaEffectSimulation::ExplosionArea &explosionArea);
|
||||
void addRemoveMessage(const AreaEffectSimulation::ExplosionSingle &explosionSingle);
|
||||
void addRemoveMessage(const AreaEffectSimulation::MineArea &mineArea);
|
||||
void addRemoveMessage(const AreaEffectSimulation::FunctionalArea &functionalArea);
|
||||
void addRemoveMessage(const AreaEffectSimulation::BoobyTrap &boobyTrap);
|
||||
void addRemoveMessage(const AreaEffectSimulation::OffRouteMine &offRouteMine);
|
||||
void addRemoveMessage(const AreaEffectSimulation::ExplosionCluster &explosionCluster);
|
||||
|
||||
QByteArray getSendingData(qint32 size);
|
||||
|
||||
bool hasMessages() const;
|
||||
|
||||
void clear();
|
||||
private:
|
||||
void clearSpecificMessage(int32_t aesItemId, OcSituation::CentralAesChangeType changeType);
|
||||
|
||||
struct SendingMessage
|
||||
{
|
||||
int32_t aesItemId;
|
||||
OcSituation::CentralAesChangeType changeType;
|
||||
QByteArray data;
|
||||
|
||||
SendingMessage()
|
||||
: aesItemId(0)
|
||||
, changeType(OcSituation::AddMod)
|
||||
, data(QByteArray())
|
||||
{}
|
||||
|
||||
SendingMessage(int32_t aesItemId, OcSituation::CentralAesChangeType changeType, const QByteArray &data)
|
||||
: aesItemId(aesItemId)
|
||||
, changeType(changeType)
|
||||
, data(data)
|
||||
{}
|
||||
};
|
||||
|
||||
// attributes
|
||||
QMutex m_accessMutex;
|
||||
QQueue<SendingMessage> m_internalQueue;
|
||||
QQueue<SendingMessage> m_internalPrioritizedQueue;
|
||||
LOGGER_T &m_logger;
|
||||
};
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
|
||||
#include "dds_handler.h"
|
||||
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
DdsHandler::DdsHandler(int domainId, int exerciseId)
|
||||
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(domainId, IDL::PartitionType::Exercise, exerciseId))
|
||||
, m_logger(getLogger("DdsHandler"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "DdsHandler(" << domainId << ") for partition: " << m_ddsConnector->getDefaultPartition();
|
||||
}
|
||||
|
||||
bool DdsHandler::init(const QStringList &qosFileList)
|
||||
{
|
||||
if (!m_ddsConnector->init(qosFileList))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
// default initialize Publisher and Subscriber
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
m_dtcCore = Core::Interface::Dtc::create(m_ddsConnector);
|
||||
bool bRet = m_dtcCore->enablePartitionTime();
|
||||
connect(m_dtcCore.get(), &Core::Interface::Dtc::partitionTimeChanged,
|
||||
this, [this](const Core::PartitionTime & t) { emit partitionTimeChanged(t.timeStamp());});
|
||||
|
||||
// Pacemaker
|
||||
m_pacemaker = std::make_shared<Core::Pacemaker>(m_ddsConnector);
|
||||
|
||||
m_ddsDts = OcSituationServer::Interface::Dts::create(m_ddsConnector);
|
||||
m_ddsFts = OcSituationServer::Interface::Fts::create(m_ddsConnector);
|
||||
|
||||
bRet &= m_ddsDts->enableAll();
|
||||
INFO_LOG(m_logger) << "Dts initialised";
|
||||
|
||||
bRet &= m_ddsFts->enableAll();
|
||||
INFO_LOG(m_logger) << "Fts initialised";
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <DDS/Core/core_dtc.h>
|
||||
|
||||
#include <OcSituationServer/oss_dts.h>
|
||||
#include <OcSituationServer/oss_fts.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class Pacemaker;
|
||||
}
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
class DdsHandler final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DdsHandler(int domainId, int exerciseId);
|
||||
|
||||
bool init(const QStringList &qosFileList = QStringList());
|
||||
|
||||
std::shared_ptr<Core::Pacemaker> pacemaker() const { return m_pacemaker; }
|
||||
std::shared_ptr<DDSConnector::DdsConnector> dds() const { return m_ddsConnector; }
|
||||
std::shared_ptr<OcSituationServer::Interface::Dts> dts() const { return m_ddsDts; }
|
||||
std::shared_ptr<OcSituationServer::Interface::Fts> fts() const { return m_ddsFts; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void partitionTimeChanged(qint64 partitionTime);
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<Core::Pacemaker> m_pacemaker;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_dtcCore;
|
||||
std::shared_ptr<OcSituationServer::Interface::Dts> m_ddsDts;
|
||||
std::shared_ptr<OcSituationServer::Interface::Fts> m_ddsFts;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+453
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
* Handler for aes data to be send to the oc-laptop transparent
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 18-04-2018
|
||||
*/
|
||||
|
||||
#include "handler_oc_aes_data.h"
|
||||
#include <functional>
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
HandlerOcAesData::HandlerOcAesData(MainHandler *mainHandler,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_aesDtc(mainHandler->aesDtc())
|
||||
, m_gimDtc(mainHandler->gimDtc())
|
||||
, m_tabFtc(mainHandler->tabFtc())
|
||||
, m_dbHandler(mainHandler->db())
|
||||
, m_positionConverter(mainHandler->positionConverter())
|
||||
, m_dangerAreaResetCnt(0)
|
||||
, m_iedResetCnt(0)
|
||||
, m_collectionTimer(QMap<OcSituation::AesType, QTimer*>())
|
||||
, m_demandingEquipments(QMap<OcSituation::AesType, QSet<int>>())
|
||||
, m_iedPositionsToBeSend(QMap<int, GuezIedManagement::IedPosition>())
|
||||
, m_iedPositionCycleTimer(new QTimer(this))
|
||||
, m_logger(getLogger("HandlerOcAesData"))
|
||||
{}
|
||||
|
||||
HandlerOcAesData::~HandlerOcAesData()
|
||||
{}
|
||||
|
||||
bool HandlerOcAesData::init()
|
||||
{
|
||||
// create collectionTimer
|
||||
m_collectionTimer[OcSituation::AesType::DangerArea] = new QTimer(this);
|
||||
m_collectionTimer[OcSituation::AesType::DangerArea]->setSingleShot(true);
|
||||
m_collectionTimer[OcSituation::AesType::DangerArea]->setInterval(Settings::aesDemandCollectionTime());
|
||||
connect(m_collectionTimer[OcSituation::AesType::DangerArea], &QTimer::timeout, this, &HandlerOcAesData::onCollectionTimeOutDemandDangerAreas);
|
||||
|
||||
m_collectionTimer[OcSituation::AesType::Ied] = new QTimer(this);
|
||||
m_collectionTimer[OcSituation::AesType::Ied]->setSingleShot(true);
|
||||
m_collectionTimer[OcSituation::AesType::Ied]->setInterval(Settings::aesDemandCollectionTime());
|
||||
connect(m_collectionTimer[OcSituation::AesType::Ied], &QTimer::timeout, this, &HandlerOcAesData::onCollectionTimeOutDemandIeds);
|
||||
|
||||
// set reset counter
|
||||
QVector<Database::OssResetCounter> dataVec;
|
||||
// read all Ieds from database
|
||||
if (!m_dbHandler->select(dataVec))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error reading reset counter from database!";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &data : qAsConst(dataVec))
|
||||
{
|
||||
switch (data.aesTypeId)
|
||||
{
|
||||
case OcSituation::AesType::DangerArea:
|
||||
{
|
||||
m_dangerAreaResetCnt = data.resetCounter;
|
||||
break;
|
||||
}
|
||||
case OcSituation::AesType::Ied:
|
||||
{
|
||||
m_iedResetCnt = data.resetCounter;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Reset counter for aes type: " << data.aesTypeId << " read from db is not handled.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AES DTC enable
|
||||
if (!m_aesDtc->enableDangerArea())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling AES Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaChanged, this, &HandlerOcAesData::onDangerAreaChanged);
|
||||
|
||||
// GIM DTC enable
|
||||
if (!m_gimDtc->enableIed() ||
|
||||
!m_gimDtc->enableIedPosition())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling GIM Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
connect(m_gimDtc.get(), &GuezIedManagement::Interface::Dtc::iedChanged, this, &HandlerOcAesData::onIedChanged);
|
||||
connect(m_gimDtc.get(), &GuezIedManagement::Interface::Dtc::iedPositionChanged, this, &HandlerOcAesData::onIedPositionChanged);
|
||||
|
||||
connect(m_iedPositionCycleTimer, &QTimer::timeout, this, &HandlerOcAesData::sendIedPositions);
|
||||
m_iedPositionCycleTimer->setInterval(Settings::iedPositionCycleTime());
|
||||
DEBUG_LOG(m_logger) << "Starting ied position timer with interval: " << m_iedPositionCycleTimer->interval();
|
||||
m_iedPositionCycleTimer->start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerOcAesData::demandAesItems(OcSituation::AesType aesType, int eqNumber)
|
||||
{
|
||||
switch (aesType)
|
||||
{
|
||||
case OcSituation::AesType::DangerArea:
|
||||
case OcSituation::AesType::Ied:
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Got demand for aes type: " << aesType << " from equipment: " << eqNumber;
|
||||
|
||||
if (!m_collectionTimer[aesType]->isActive())
|
||||
m_collectionTimer[aesType]->start();
|
||||
|
||||
m_demandingEquipments[aesType].insert(eqNumber);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Aes type: " << aesType << " is currently not handled.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onSendOcDataReply(const Core::FunctionReplyObject &reply)
|
||||
{
|
||||
if (reply.error())
|
||||
ERROR_LOG(m_logger) << "Oc data could not be send: " << reply.translated();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Oc data send successfully to TAB!";
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onDangerAreaChanged(const AreaEffectSimulation::DangerArea &data, DataModification mod)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(mod);
|
||||
incrementResetCnt(OcSituation::AesType::DangerArea);
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onIedChanged(const GuezIedManagement::Ied &data, DataModification mod)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(mod);
|
||||
incrementResetCnt(OcSituation::AesType::Ied);
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onIedPositionChanged(const GuezIedManagement::IedPosition &data, DataModification mod)
|
||||
{
|
||||
if (mod == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
GuezIedManagement::Ied ied = m_gimDtc->ied(data.id());
|
||||
if (ied.id() > 0)
|
||||
{
|
||||
if (ied.pairingState().underlying() != GuezIedManagement::IedPairingState::NotPaired)
|
||||
m_iedPositionsToBeSend.insert(data.id(), data);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Got ied position for not existing ID: " << data.id();
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onCollectionTimeOutDemandDangerAreas()
|
||||
{
|
||||
std::function<void (int)> f = std::bind(&HandlerOcAesData::sendDangerAreasToTab, this, std::placeholders::_1);
|
||||
collectionTimeout(OcSituation::AesType::DangerArea, f);
|
||||
}
|
||||
|
||||
void HandlerOcAesData::onCollectionTimeOutDemandIeds()
|
||||
{
|
||||
std::function<void (int)> f = std::bind(&HandlerOcAesData::sendIedsToTab, this, std::placeholders::_1);
|
||||
collectionTimeout(OcSituation::AesType::Ied, f);
|
||||
}
|
||||
|
||||
void HandlerOcAesData::sendIedPositions()
|
||||
{
|
||||
if (m_iedPositionsToBeSend.size() == 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "No new ied positions to be send.";
|
||||
return;
|
||||
}
|
||||
|
||||
TrainingAreaBase::SendOcDataRequest req;
|
||||
req.equipmentNumber(0); // ied positions are always send broadcast
|
||||
|
||||
QByteArray data, payload;
|
||||
int cnt = 0;
|
||||
|
||||
// set "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::IedPositions, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
|
||||
for (const auto &pos : qAsConst(m_iedPositionsToBeSend))
|
||||
{
|
||||
LtsUtils::set2Byte(m_gimDtc->ied(pos.id()).equipmentNumber(), data);
|
||||
const QPointF relCoord(m_positionConverter->relativeFromGeographic(pos.position()));
|
||||
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
||||
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
||||
|
||||
data[1] = ++cnt;
|
||||
|
||||
QByteArray ba = qCompress(data);
|
||||
DEBUG_LOG(m_logger) << "Added ied position " << pos
|
||||
<< " data size: " << data.size()
|
||||
<< " compressed size: " << ba.size();
|
||||
|
||||
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
||||
payload.append(ba);
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
|
||||
cnt = 0;
|
||||
data.clear();
|
||||
payload.clear();
|
||||
|
||||
// set new "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::IedPositions, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0) // is still data to be send?
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
||||
payload.append(qCompress(data));
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
}
|
||||
|
||||
m_iedPositionsToBeSend.clear();
|
||||
}
|
||||
|
||||
void HandlerOcAesData::collectionTimeout(OcSituation::AesType type, const std::function<void (int)> &sendFunction)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "There are " << m_demandingEquipments[type].size() << " requests for aes type: " << type
|
||||
<< " sending Items as " << ((m_demandingEquipments[type].size() > 5) ? QStringLiteral("broadcast") : QStringLiteral("direct")) << " telegram(s)";
|
||||
|
||||
if (m_demandingEquipments[type].size() > 5)
|
||||
sendFunction(0); // broadcast
|
||||
else
|
||||
for (int eqNumber : qAsConst(m_demandingEquipments[type]))
|
||||
sendFunction(eqNumber);
|
||||
|
||||
//cleanup
|
||||
m_demandingEquipments[type].clear();
|
||||
}
|
||||
|
||||
void HandlerOcAesData::sendDangerAreasToTab(int eqNumber)
|
||||
{
|
||||
TrainingAreaBase::SendOcDataRequest req;
|
||||
req.equipmentNumber(eqNumber);
|
||||
|
||||
const QMap<int, AreaEffectSimulation::DangerArea> dangerAreas = m_aesDtc->dangerAreas();
|
||||
QByteArray data, payload;
|
||||
int cnt = 0;
|
||||
|
||||
// set "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::DangerArea, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
|
||||
for (const auto &dangerArea : dangerAreas)
|
||||
{
|
||||
if (dangerArea.effectStateId() >= AreaEffectSimulation::AesEffectState::EsCreated) // do not transfer ended or deleted areas
|
||||
{
|
||||
LtsUtils::set2Byte(dangerArea.id(), data);
|
||||
QByteArray name(QByteArray::fromStdString(dangerArea.name()));
|
||||
name.resize(8);
|
||||
data.append(name);
|
||||
if (dangerArea.effectStart().is_set())
|
||||
LtsUtils::set4Byte(dangerArea.effectStart().get() / 1000, data);
|
||||
else
|
||||
LtsUtils::set4Byte(0, data);
|
||||
LtsUtils::set1Byte(dangerArea.segments().size(), data);
|
||||
for (const auto &segment : dangerArea.segments())
|
||||
{
|
||||
const QPointF relCoord(m_positionConverter->relativeFromGeographic(segment));
|
||||
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
||||
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
||||
}
|
||||
|
||||
data[1] = ++cnt;
|
||||
|
||||
QByteArray ba = qCompress(data);
|
||||
DEBUG_LOG(m_logger) << "Added danger area " << dangerArea
|
||||
<< " data size: " << data.size()
|
||||
<< " compressed size: " << ba.size();
|
||||
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
||||
payload.append(ba);
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
|
||||
cnt = 0;
|
||||
data.clear();
|
||||
payload.clear();
|
||||
|
||||
// set new "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::DangerArea, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0) // is still data to be send?
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
||||
payload.append(qCompress(data));
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcAesData::sendIedsToTab(int eqNumber)
|
||||
{
|
||||
TrainingAreaBase::SendOcDataRequest req;
|
||||
req.equipmentNumber(eqNumber);
|
||||
|
||||
const QMap<int, GuezIedManagement::Ied> ieds = m_gimDtc->ieds();
|
||||
QByteArray data, payload;
|
||||
int cnt = 0;
|
||||
|
||||
// set "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::Ied, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
|
||||
for (const auto &ied : ieds)
|
||||
{
|
||||
LtsUtils::set2Byte(ied.equipmentNumber(), data);
|
||||
LtsUtils::set1Byte(ied.type().underlying(), data);
|
||||
uint8_t trigger = (uint8_t(ied.tautWireTrigger()) << 3) |
|
||||
(uint8_t(ied.lightBarrierTrigger()) << 2) |
|
||||
(uint8_t(ied.switchTrigger()) << 1) |
|
||||
(uint8_t(ied.remoteTrigger()));
|
||||
LtsUtils::set1Byte(trigger, data);
|
||||
LtsUtils::set1Byte(ied.explosiveForce(), data);
|
||||
LtsUtils::set1Byte(ied.partyId(), data);
|
||||
LtsUtils::set1Byte(ied.tacticalState().underlying(), data);
|
||||
|
||||
// set an initial position, as only paired ieds are updated concurrently
|
||||
const auto pos = m_gimDtc->iedPosition(ied.id());
|
||||
const QPointF relCoord(m_positionConverter->relativeFromGeographic(pos.position()));
|
||||
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
||||
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
||||
|
||||
data[1] = ++cnt;
|
||||
|
||||
QByteArray ba = qCompress(data);
|
||||
DEBUG_LOG(m_logger) << "Added ied " << ied
|
||||
<< " data size: " << data.size()
|
||||
<< " compressed size: " << ba.size();
|
||||
|
||||
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
||||
payload.append(ba);
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
|
||||
cnt = 0;
|
||||
data.clear();
|
||||
payload.clear();
|
||||
|
||||
// set new "header" data
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
||||
LtsUtils::set1Byte(OcSituation::AesType::Ied, data);
|
||||
LtsUtils::set1Byte(cnt, data);
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0) // is still data to be send?
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
||||
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
||||
payload.append(qCompress(data));
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcAesData::incrementResetCnt(OcSituation::AesType aesType)
|
||||
{
|
||||
switch (aesType)
|
||||
{
|
||||
case OcSituation::AesType::DangerArea:
|
||||
{
|
||||
setResetCnt(aesType, m_dangerAreaResetCnt + 1);
|
||||
break;
|
||||
}
|
||||
case OcSituation::AesType::Ied:
|
||||
{
|
||||
setResetCnt(aesType, m_iedResetCnt + 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Reset counter for aes type: " << aesType << " is not handled in incrementResetCnt.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcAesData::setResetCnt(OcSituation::AesType aesType, int resetCnt)
|
||||
{
|
||||
Database::OssResetCounter data;
|
||||
data.aesTypeId = aesType;
|
||||
data.resetCounter = resetCnt;
|
||||
|
||||
switch (aesType)
|
||||
{
|
||||
case OcSituation::AesType::DangerArea:
|
||||
{
|
||||
m_dangerAreaResetCnt = resetCnt;
|
||||
break;
|
||||
}
|
||||
case OcSituation::AesType::Ied:
|
||||
{
|
||||
m_iedResetCnt = resetCnt;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Reset counter for aes type: " << aesType << " is not handled in setResetCnt.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// update db
|
||||
if (!m_dbHandler->update(data))
|
||||
ERROR_LOG(m_logger) << "Error updating reset counter in db.";
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Handler for aes data to be send to the oc-laptop transparent
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 18-04-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <functional>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "position_converter.h"
|
||||
#include "oc_situation.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
class HandlerOcAesData : public QObject
|
||||
, protected TrainingAreaBase::Interface::Ftc::SendOcDataReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerOcAesData(MainHandler *mainHandler,
|
||||
QObject *parent = nullptr);
|
||||
~HandlerOcAesData();
|
||||
|
||||
bool init();
|
||||
int dangerAreaResetCnt() { return m_dangerAreaResetCnt; }
|
||||
int iedResetCnt() { return m_iedResetCnt; }
|
||||
|
||||
void demandAesItems(OcSituation::AesType aesType, int eqNumber);
|
||||
|
||||
void onSendOcDataReply(const Core::FunctionReplyObject &reply);
|
||||
|
||||
private slots:
|
||||
void onDangerAreaChanged(const AreaEffectSimulation::DangerArea &data, DataModification mod);
|
||||
void onIedChanged(const GuezIedManagement::Ied &data, DataModification mod);
|
||||
void onIedPositionChanged(const GuezIedManagement::IedPosition &data, DataModification mod);
|
||||
void onCollectionTimeOutDemandDangerAreas();
|
||||
void onCollectionTimeOutDemandIeds();
|
||||
void sendIedPositions();
|
||||
|
||||
private:
|
||||
void collectionTimeout(OcSituation::AesType type, const std::function<void (int)> &sendFunction);
|
||||
void sendDangerAreasToTab(int eqNumber);
|
||||
void sendIedsToTab(int eqNumber);
|
||||
void incrementResetCnt(OcSituation::AesType aesType);
|
||||
void setResetCnt(OcSituation::AesType aesType, int resetCnt);
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> m_gimDtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> m_tabFtc;
|
||||
|
||||
std::shared_ptr<DatabaseInterface> m_dbHandler;
|
||||
std::shared_ptr<PositionConverter> m_positionConverter;
|
||||
|
||||
// add new reset counter also in oss_predefined_data.sql !!
|
||||
int m_dangerAreaResetCnt;
|
||||
int m_iedResetCnt;
|
||||
|
||||
QMap<OcSituation::AesType, QTimer *> m_collectionTimer;
|
||||
QMap<OcSituation::AesType, QSet<int>> m_demandingEquipments;
|
||||
|
||||
QMap<int, GuezIedManagement::IedPosition> m_iedPositionsToBeSend;
|
||||
QTimer *m_iedPositionCycleTimer;
|
||||
|
||||
LOGGER_T &m_logger;
|
||||
};
|
||||
} // namespace OcSituationServer
|
||||
@@ -0,0 +1,830 @@
|
||||
/**
|
||||
* Handler for all oc situation data at the server per client
|
||||
* $Id: handler_oc_situation_data.cpp 57938 2022-08-26 09:56:44Z diers $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.cpp $
|
||||
* $Author: diers $
|
||||
* Created by Philipp Dassow, NLST, 27-02-2018
|
||||
*/
|
||||
|
||||
#include "handler_oc_central_aes_data.h"
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <LtsUtilsCore/outdated_position.h>
|
||||
#include <ParticipantManagement/ppm_common.h>
|
||||
#include "settings.h"
|
||||
#include <QLineF>
|
||||
#include "central_aes_data_queue.h"
|
||||
#include <QMultiMap>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
////
|
||||
//// ThreadOcSituationData
|
||||
////
|
||||
ThreadOcCentralAesData::ThreadOcCentralAesData(MainHandler *mainHandler,
|
||||
int equipmentId,
|
||||
int centerEquipmentId,
|
||||
int radius)
|
||||
: m_baseCoordinate(mainHandler->positionConverter()->baseCoordinate())
|
||||
, m_equipmentId(equipmentId)
|
||||
, m_centerEquipmentId(centerEquipmentId)
|
||||
, m_radius(radius)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger(QStringLiteral("ThreadOcCentralAesData.") + QString::number(equipmentId)))
|
||||
{}
|
||||
|
||||
void ThreadOcCentralAesData::requestOcCentralAesData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D &position,
|
||||
int radius,
|
||||
bool initial)
|
||||
{
|
||||
INFO_LOG(m_logger) << "OC-Situation Request for centerEquipmentId: " << centerEquipmentId
|
||||
<< " from O/C-laptop-Id: " << m_equipmentId
|
||||
<< " with radius of " << radius
|
||||
<< "m, initial: " << initial;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
m_centerType = centerType;
|
||||
m_centerEquipmentId = centerEquipmentId;
|
||||
m_radius = radius;
|
||||
m_position = position;
|
||||
|
||||
if (m_handler)
|
||||
m_handler->setRequestCentralAesData(centerType, centerEquipmentId, position, radius, initial);
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Thread doesn't exist up to now! Do nothing.";
|
||||
}
|
||||
|
||||
void ThreadOcCentralAesData::run()
|
||||
{
|
||||
static QMutex s_ddsAccesMutex;
|
||||
{
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
QMutexLocker m(&s_ddsAccesMutex);
|
||||
DEBUG_LOG(m_logger) << "Instance new OC-Thread for O/C-Laptop-Id: " << m_equipmentId;
|
||||
|
||||
m_handler = new HandlerOcCentralAesData(m_mainHandler->dds(),
|
||||
m_baseCoordinate,
|
||||
m_equipmentId);
|
||||
connect(m_handler, &HandlerOcCentralAesData::sendOcData, this, &ThreadOcCentralAesData::sendOcData, Qt::QueuedConnection);
|
||||
|
||||
m_handler->setRequestCentralAesData(m_centerType, m_centerEquipmentId, m_position, m_radius, true);
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "OC-Thread started for O/C-Laptop-Id: " << m_equipmentId;
|
||||
exec();
|
||||
|
||||
{
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
QMutexLocker m(&s_ddsAccesMutex);
|
||||
delete m_handler;
|
||||
m_handler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// HandlerOcSituationData
|
||||
//
|
||||
HandlerOcCentralAesData::HandlerOcCentralAesData(const std::shared_ptr<DdsHandler> &dds,
|
||||
const LtsCoordTrans::UtmCoordinate &baseCoordinate,
|
||||
int equipmentId)
|
||||
: m_baseCoordinate(baseCoordinate)
|
||||
, m_aesDtc(AreaEffectSimulation::Interface::Dtc::create(dds->dds()))
|
||||
, m_ppmDtc(ParticipantManagement::Interface::Dtc::create(dds->dds()))
|
||||
, m_equipmentId(equipmentId)
|
||||
, m_partitionTime(QDateTime::currentMSecsSinceEpoch())
|
||||
, m_aliveTimer(new QTimer(this))
|
||||
, m_txTimer(new QTimer(this))
|
||||
, m_dataQueue(new CentralAesDataQueue(this))
|
||||
, m_logger(getLogger(QStringLiteral("HandlerOcCentralAesData.") + QString::number(equipmentId)))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Create O/C-CentralAesHandler for O/C-Laptop-Id: " << equipmentId
|
||||
<< " aliveTimeout: " << Settings::aliveTimeout() << " sec"
|
||||
<< " txCyleTime: " << Settings::txCycleTime() << " sec"
|
||||
<< " maxTransferBytes: " << Settings::maxNumOfBytePerTxCycle();
|
||||
|
||||
connect(dds.get(), &DdsHandler::partitionTimeChanged, this, &HandlerOcCentralAesData::onPartitionTimeChanged);
|
||||
|
||||
connect(m_aliveTimer, &QTimer::timeout, this, &HandlerOcCentralAesData::aliveTimeout);
|
||||
m_aliveTimer->setSingleShot(true);
|
||||
m_aliveTimer->start(Settings::aliveTimeout());
|
||||
|
||||
connect(m_txTimer, &QTimer::timeout, this, &HandlerOcCentralAesData::handleSituation);
|
||||
m_txTimer->start(Settings::txCycleTime());
|
||||
|
||||
connect(this, &HandlerOcCentralAesData::resetInternalData,
|
||||
this, &HandlerOcCentralAesData::onResetInternalData, Qt::QueuedConnection);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
|
||||
this, &HandlerOcCentralAesData::onParticipantPositionChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::effectClusterChanged,
|
||||
this, &HandlerOcCentralAesData::onEffectClusterChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
|
||||
this, &HandlerOcCentralAesData::onNContaminationChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
|
||||
this, &HandlerOcCentralAesData::onBCContaminationChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
|
||||
this, &HandlerOcCentralAesData::onExplosionAreaChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
|
||||
this, &HandlerOcCentralAesData::onExplosionSingleChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::mineAreaChanged,
|
||||
this, &HandlerOcCentralAesData::onMineAreaChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::functionalAreaChanged,
|
||||
this, &HandlerOcCentralAesData::onFunctionalAreaChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
|
||||
this, &HandlerOcCentralAesData::onBoobyTrapChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::offRouteMineChanged,
|
||||
this, &HandlerOcCentralAesData::onOffRouteMineChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionClusterChanged,
|
||||
this, &HandlerOcCentralAesData::onExplosionClusterChanged);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
||||
this, &HandlerOcCentralAesData::onAesItemViewChanged);
|
||||
|
||||
// fetch aes items
|
||||
m_aesDtc->effectClusters([this](const AreaEffectSimulation::EffectCluster & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralEffectClusters.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralEffectClusters.size() << " central EffectClusters on startup.";
|
||||
|
||||
m_aesDtc->nContaminations([this](const AreaEffectSimulation::NContamination & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralNContaminations.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralNContaminations.size() << " central NContaminations on startup.";
|
||||
|
||||
m_aesDtc->bCContaminations([this](const AreaEffectSimulation::BCContamination & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralBCContaminations.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralBCContaminations.size() << " central BCContaminations on startup.";
|
||||
|
||||
m_aesDtc->explosionAreas([this](const AreaEffectSimulation::ExplosionArea & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralExplosionsArea.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionsArea.size() << " central ExplosionsAreas on startup.";
|
||||
|
||||
m_aesDtc->explosionSingles([this](const AreaEffectSimulation::ExplosionSingle & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralExplosionsSingle.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionsSingle.size() << " central ExplosionsSingles on startup.";
|
||||
|
||||
m_aesDtc->mineAreas([this](const AreaEffectSimulation::MineArea & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralMineAreas.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralMineAreas.size() << " central MineAreas on startup.";
|
||||
|
||||
m_aesDtc->functionalAreas([this](const AreaEffectSimulation::FunctionalArea & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralFunctionalAreas.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralFunctionalAreas.size() << " central FunctionalAreas on startup.";
|
||||
|
||||
m_aesDtc->boobyTraps([this](const AreaEffectSimulation::BoobyTrap & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralBoobyTraps.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralBoobyTraps.size() << " central BoobyTraps on startup.";
|
||||
|
||||
m_aesDtc->offRouteMines([this](const AreaEffectSimulation::OffRouteMine & data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralOffRouteMines.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralOffRouteMines.size() << " central OffRouteMines on startup.";
|
||||
|
||||
m_aesDtc->explosionClusters([this](const AreaEffectSimulation::ExplosionCluster &data)
|
||||
{
|
||||
if (data.isCentral())
|
||||
m_allCentralExplosionClusters.insert(data.id(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionClusters.size() << " central ExplosionClusters on startup.";
|
||||
|
||||
//fetch aes itemviews
|
||||
QList<qint32> aesItemIds = allInternalAesItemIds();
|
||||
m_aesDtc->aesItemViews([this, aesItemIds](const AreaEffectSimulation::AesItemView & data)
|
||||
{
|
||||
if (aesItemIds.contains(data.aesItemId()))
|
||||
m_allCentralAesItemViews.insert(data.aesItemId(), data);
|
||||
});
|
||||
TRACE_LOG(m_logger) << "Got " << allInternalAesItemIds().size() << " central AesItems in total on startup. And " << m_allCentralAesItemViews.size() << " AesItemViews.";
|
||||
|
||||
m_aesDtc->enableEffectCluster();
|
||||
m_aesDtc->enableNContamination();
|
||||
m_aesDtc->enableBCContamination();
|
||||
m_aesDtc->enableExplosionArea();
|
||||
m_aesDtc->enableExplosionSingle();
|
||||
m_aesDtc->enableMineArea();
|
||||
m_aesDtc->enableFunctionalArea();
|
||||
m_aesDtc->enableBoobyTrap();
|
||||
m_aesDtc->enableOffRouteMine();
|
||||
m_aesDtc->enableExplosionCluster();
|
||||
m_aesDtc->enableAesItemView();
|
||||
|
||||
m_ppmDtc->enableParticipant();
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::setRequestCentralAesData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D ¢erPosition,
|
||||
int radius,
|
||||
bool initial)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
DEBUG_LOG(m_logger) << "Requested CenterEquipmentId: " << centerEquipmentId << " radius: " << radius;
|
||||
|
||||
bool endThread = false;
|
||||
|
||||
if (initial)
|
||||
onResetInternalData();
|
||||
|
||||
m_centerType = centerType;
|
||||
m_centerEquipmentId = centerEquipmentId;
|
||||
m_centerPosition = centerPosition;
|
||||
m_centerParticipantId = 0;
|
||||
m_radius = radius;
|
||||
|
||||
if (centerType == OcSituation::SituationCenterType::Equipment)
|
||||
{
|
||||
if (m_centerEquipmentId > 0)
|
||||
{
|
||||
ParticipantManagement::Participant centerParticipant = m_ppmDtc->participant(m_ppmDtc->participantIdByEquipmentNumber(m_centerEquipmentId));
|
||||
|
||||
if (centerParticipant.id() <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId
|
||||
<< " as center of the oc situation request does not exist!";
|
||||
endThread = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const ParticipantManagement::ParticipantPosition &partPosition = m_ppmDtc->participantPosition(m_ppmDtc->participantIdByEquipmentNumber(m_centerEquipmentId));
|
||||
|
||||
if (partPosition.participantId() == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId
|
||||
<< " as center of the oc situation request has no position!";
|
||||
endThread = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_centerPosition = partPosition.pos();
|
||||
m_centerParticipantId = centerParticipant.id();
|
||||
}
|
||||
}
|
||||
if (endThread && ++m_retryCount < 5)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Retry setting data - maybe participant is not yet available... " << m_retryCount;
|
||||
QTimer::singleShot(1000 * m_retryCount, this, [this]()
|
||||
{
|
||||
// must be initial here
|
||||
setRequestCentralAesData(m_centerType, m_centerEquipmentId, m_centerPosition, m_radius, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(m_logger) << "Situation is not requested anymore -> end thread";
|
||||
endThread = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!endThread)
|
||||
{
|
||||
if (centerType == OcSituation::SituationCenterType::Equipment)
|
||||
{
|
||||
if (m_centerParticipantId == 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_centerParticipantId == 0";
|
||||
endThread = true;
|
||||
}
|
||||
}
|
||||
else if ((centerPosition.lon() == std::nan("")) || (centerPosition.lat() == std::nan("")))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_centerParticipantId == 0";
|
||||
endThread = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_retryCount = 0;
|
||||
|
||||
if (endThread)
|
||||
m_radius = 0; // ==> no data transfer on handleSituation() and quit
|
||||
|
||||
buildSituationCircle();
|
||||
|
||||
QTimer::singleShot(0, this, &HandlerOcCentralAesData::resetAliveTimer);
|
||||
if (endThread && !initial)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Ending Thread --> stopping txTimer and resetting internal data.";
|
||||
|
||||
QTimer::singleShot(0, this, &HandlerOcCentralAesData::handleSituation);
|
||||
|
||||
emit resetInternalData();
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType)
|
||||
{
|
||||
if (modType != DataModification::eModified
|
||||
|| m_centerType != OcSituation::SituationCenterType::Equipment
|
||||
|| data.participantId() != m_centerParticipantId)
|
||||
return;
|
||||
|
||||
m_centerPosition = data.pos();
|
||||
buildSituationCircle();
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralEffectClusters, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onNContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralNContaminations, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralBCContaminations, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onExplosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralExplosionsArea, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralExplosionsSingle, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onMineAreaChanged(const AreaEffectSimulation::MineArea &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralMineAreas, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onFunctionalAreaChanged(const AreaEffectSimulation::FunctionalArea &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralFunctionalAreas, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralBoobyTraps, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onOffRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralOffRouteMines, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType)
|
||||
{
|
||||
onAesItemChanged(m_allCentralExplosionClusters, data, modType);
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
||||
{
|
||||
const QVector<AreaEffectSimulation::AesType> validTypes = {AreaEffectSimulation::AesType::inner_enum::AtEffectCluster,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtNContamination,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtBCContamination ,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtExplosionArea,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtExplosionSingle,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtMineArea,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtFunctionalArea,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtBoobyTrap,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtOffRouteMine,
|
||||
AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster};
|
||||
|
||||
if (!validTypes.contains(data.aesTypeId()))
|
||||
return;
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
if (!allInternalAesItemIds().contains(data.aesItemId()))
|
||||
return;
|
||||
|
||||
m_allCentralAesItemViews.insert(data.aesItemId(), data);
|
||||
|
||||
break;
|
||||
case DataModification::eModified:
|
||||
{
|
||||
if (!m_allCentralAesItemViews.contains(data.aesItemId()))
|
||||
return;
|
||||
|
||||
m_allCentralAesItemViews[data.aesItemId()] = data;
|
||||
|
||||
break;
|
||||
}
|
||||
case DataModification::eRemoved:
|
||||
// AesItemViews are removed from m_allCentralAesItemViews in HandlerOcCentralAesData::onAesItemChanged
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::handleSituation()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
if (m_radius == 0)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Do not send Situation as radius is 0, centerEquipmentId " << m_centerEquipmentId
|
||||
<< ", m_position " << m_centerPosition;
|
||||
QTimer::singleShot(0, this, &HandlerOcCentralAesData::aliveTimeout); // ending thread
|
||||
return;
|
||||
}
|
||||
|
||||
QSet<qint32> oldAesItemsInRange = m_aesItemsInRange;
|
||||
|
||||
fetchAesItemsInRange();
|
||||
|
||||
// 50 is the max number of AesItems which are allowed to be handled on the ABT.
|
||||
// So we have to just take the 50 nearest items.
|
||||
bool hasOverload = m_aesItemsInRange.size() > 50;
|
||||
if (hasOverload)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Got more than 50 AesItems in range. " << m_aesItemsInRange.size() << " in total --> Sorting out.";
|
||||
|
||||
QMultiMap<qreal, qint32> distances;
|
||||
|
||||
for (qint32 currentAesItemId : qAsConst(m_aesItemsInRange))
|
||||
{
|
||||
qreal distance = calculateDistanceToCircleCenter(currentAesItemId);
|
||||
|
||||
if (distance >= 0.0)
|
||||
distances.insert(distance, currentAesItemId);
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "We have " << distances.size() << " valid distances.";
|
||||
|
||||
m_aesItemsInRange.clear();
|
||||
|
||||
qint32 counter = 0;
|
||||
|
||||
for (auto it = distances.constBegin(); (it != distances.constEnd()) && (counter < 50); ++it, ++counter)
|
||||
m_aesItemsInRange.insert(it.value());
|
||||
|
||||
DEBUG_LOG(m_logger) << "We now have " << m_aesItemsInRange.size() << " AES Items to send.";
|
||||
}
|
||||
|
||||
QSet<qint32> validIds = m_aesItemsInRange - oldAesItemsInRange;
|
||||
|
||||
DEBUG_LOG(m_logger) << "After sorting out old items, we have " << validIds.size() << " items left.";
|
||||
|
||||
removeKickedOutAesItems(oldAesItemsInRange);
|
||||
|
||||
addAesItemsToBuilder(m_allCentralEffectClusters, validIds);
|
||||
addAesItemsToBuilder(m_allCentralNContaminations, validIds);
|
||||
addAesItemsToBuilder(m_allCentralBCContaminations, validIds);
|
||||
addAesItemsToBuilder(m_allCentralExplosionsArea, validIds);
|
||||
addAesItemsToBuilder(m_allCentralExplosionsSingle, validIds);
|
||||
addAesItemsToBuilder(m_allCentralMineAreas, validIds);
|
||||
addAesItemsToBuilder(m_allCentralFunctionalAreas, validIds);
|
||||
addAesItemsToBuilder(m_allCentralBoobyTraps, validIds);
|
||||
addAesItemsToBuilder(m_allCentralOffRouteMines, validIds);
|
||||
addAesItemsToBuilder(m_allCentralExplosionClusters, validIds);
|
||||
|
||||
if (m_dataQueue->hasMessages())
|
||||
{
|
||||
QByteArray payload;
|
||||
LtsUtils::set1Byte(m_bInitialDataTransfer ? OcSituation::TelegramId::CentralAesDataInitial : OcSituation::TelegramId::CentralAesData, payload);
|
||||
LtsUtils::set1Byte(hasOverload, payload); // info, if there are more than 50 aes items in range
|
||||
m_bInitialDataTransfer = false;
|
||||
|
||||
QByteArray sendingData = m_dataQueue->getSendingData(Settings::maxNumOfBytePerTxCycle());
|
||||
|
||||
payload += m_bWithCompression ? qCompress(sendingData) : sendingData;
|
||||
|
||||
TrainingAreaBase::SendOcDataRequest req;
|
||||
req.equipmentNumber(m_equipmentId);
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Sending " << req.payload().size() << " Bytes payload.";
|
||||
|
||||
emit sendOcData(req);
|
||||
}
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Sending timeout, but nothing to send.";
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::resetAliveTimer()
|
||||
{
|
||||
m_aliveTimer->start();
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::aliveTimeout()
|
||||
{
|
||||
INFO_LOG(m_logger) << "O/C-Thread keep alive timeout for O/C-Laptop-Id: " << m_equipmentId
|
||||
<< " - Thread will be finished id: " << QThread::currentThreadId();
|
||||
|
||||
QThread::currentThread()->quit();
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::onResetInternalData()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
DEBUG_LOG(m_logger) << "Resetting internal data!";
|
||||
|
||||
m_aesItemsInRange.clear();
|
||||
m_dataQueue->clear();
|
||||
|
||||
m_bInitialDataTransfer = true;
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::fetchAesItemsInRange()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
if (m_radius == 0)
|
||||
return;
|
||||
|
||||
const QPointF relCenterPos = PositionConverter::relativeFromGeographic(m_centerPosition, m_baseCoordinate);
|
||||
|
||||
if (m_centerType == OcSituation::SituationCenterType::Equipment)
|
||||
INFO_LOG(m_logger) << "Fetching AesItems in radius around equipment " << m_centerEquipmentId
|
||||
<< " with position " << relCenterPos.x() << "/" << relCenterPos.y() << " and radius: " << m_radius << ", " << m_baseCoordinate.mgrs()
|
||||
<< ", " << m_centerPosition.lon() << ", " << m_centerPosition.lat();
|
||||
else
|
||||
INFO_LOG(m_logger) << "Fetching AesItems in radius of position " << relCenterPos.x() << "/" << relCenterPos.y() << " radius: " << m_radius;
|
||||
|
||||
m_aesItemsInRange.clear();
|
||||
|
||||
qint32 effectClustersInRange = fetchAesItemsInCircle(m_allCentralEffectClusters);
|
||||
qint32 nContaminationsInRange = fetchAesItemsInCircle(m_allCentralNContaminations);
|
||||
qint32 bCContaminationsInRange = fetchAesItemsInCircle(m_allCentralBCContaminations);
|
||||
qint32 explosionsAreaInRange = fetchAesItemsInCircle(m_allCentralExplosionsArea);
|
||||
qint32 explosionsSingleInRange = fetchAesItemsInCircle(m_allCentralExplosionsSingle);
|
||||
qint32 mineAreasInRange = fetchAesItemsInCircle(m_allCentralMineAreas);
|
||||
qint32 functionalAreasInRange = fetchAesItemsInCircle(m_allCentralFunctionalAreas);
|
||||
qint32 boobyTrapsInRange = fetchAesItemsInCircle(m_allCentralBoobyTraps);
|
||||
qint32 offRouteMinesInRange = fetchAesItemsInCircle(m_allCentralOffRouteMines);
|
||||
qint32 explosionClustersInRage = fetchAesItemsInCircle(m_allCentralExplosionClusters);
|
||||
|
||||
TRACE_LOG(m_logger) << "Got " << effectClustersInRange << " EffectClusters in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << nContaminationsInRange << " NContaminations in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << bCContaminationsInRange << " BCContaminations in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << explosionsAreaInRange << " ExplosionsArea in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << explosionsSingleInRange << " ExplosionsSingle in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << mineAreasInRange << " MineAreas in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << functionalAreasInRange << " FunctionalAreas in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << boobyTrapsInRange << " BoobyTraps in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << offRouteMinesInRange << " OffRouteMines in range.";
|
||||
TRACE_LOG(m_logger) << "Got " << explosionClustersInRage << " ExplosionClusters in range.";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
qint32 HandlerOcCentralAesData::fetchAesItemsInCircle(const QHash<qint32, T> &aesItems)
|
||||
{
|
||||
qint32 aesItemsInRangeCount = 0;
|
||||
|
||||
for (auto it = aesItems.constBegin(); it != aesItems.constEnd(); ++it)
|
||||
{
|
||||
if (!m_allCentralAesItemViews.contains(it.key()))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got AesItem::id " << it.key() << " but there is no corresponding AesItemView.";
|
||||
continue;
|
||||
}
|
||||
|
||||
AreaEffectSimulation::AesItemView aesItemView = m_allCentralAesItemViews.value(it.key());
|
||||
|
||||
if (it.value().effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsExpired ||
|
||||
it.value().effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsRemoved)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "AesItem of type " << aesItemView.aesTypeId() << ", with id " << it.key() << " is removed or expired --> skipping.";
|
||||
continue;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
|
||||
if (polygonFromForm(aesItemView.form()).intersected(m_situationCircle).size() > 0)
|
||||
#else
|
||||
if (polygonFromForm(aesItemView.form()).intersects(m_situationCircle))
|
||||
#endif
|
||||
{
|
||||
m_aesItemsInRange.insert(it.key());
|
||||
++aesItemsInRangeCount;
|
||||
}
|
||||
}
|
||||
|
||||
return aesItemsInRangeCount;
|
||||
}
|
||||
|
||||
QPolygonF HandlerOcCentralAesData::polygonFromForm(const std::vector<Core::GeoPosition> &form) const
|
||||
{
|
||||
QPolygonF result;
|
||||
result.reserve(form.size());
|
||||
|
||||
for (const Core::GeoPosition ¤tPosition : qAsConst(form))
|
||||
result.append(PositionConverter::relativeFromGeographic({currentPosition.lon(), currentPosition.lat()}, m_baseCoordinate));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<qint32> HandlerOcCentralAesData::allInternalAesItemIds() const
|
||||
{
|
||||
QList<qint32> result;
|
||||
|
||||
result.reserve(m_allCentralEffectClusters.size() +
|
||||
m_allCentralNContaminations.size() +
|
||||
m_allCentralBCContaminations.size() +
|
||||
m_allCentralExplosionsArea.size() +
|
||||
m_allCentralExplosionsSingle.size() +
|
||||
m_allCentralMineAreas.size() +
|
||||
m_allCentralFunctionalAreas.size() +
|
||||
m_allCentralBoobyTraps.size() +
|
||||
m_allCentralOffRouteMines.size() +
|
||||
m_allCentralExplosionClusters.size());
|
||||
|
||||
for (auto it = m_allCentralEffectClusters.constBegin(); it != m_allCentralEffectClusters.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralNContaminations.constBegin(); it != m_allCentralNContaminations.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralBCContaminations.constBegin(); it != m_allCentralBCContaminations.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralExplosionsArea.constBegin(); it != m_allCentralExplosionsArea.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralExplosionsSingle.constBegin(); it != m_allCentralExplosionsSingle.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralMineAreas.constBegin(); it != m_allCentralMineAreas.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralFunctionalAreas.constBegin(); it != m_allCentralFunctionalAreas.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralBoobyTraps.constBegin(); it != m_allCentralBoobyTraps.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralOffRouteMines.constBegin(); it != m_allCentralOffRouteMines.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
for (auto it = m_allCentralExplosionClusters.constBegin(); it != m_allCentralExplosionClusters.constEnd(); ++it)
|
||||
result.append(it.key());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::removeKickedOutAesItems(const QSet<qint32> &aesItemsSentBefore)
|
||||
{
|
||||
QSet<qint32> kickedOutAesItems = aesItemsSentBefore - m_aesItemsInRange;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Found " << kickedOutAesItems.size() << " AesItems to kick out.";
|
||||
|
||||
AreaEffectSimulation::AesType aesType = AreaEffectSimulation::AesType::inner_enum::AtUnknown;
|
||||
|
||||
for (qint32 currentAesItemId : qAsConst(kickedOutAesItems))
|
||||
{
|
||||
if (m_allCentralAesItemViews.contains(currentAesItemId))
|
||||
aesType = m_allCentralAesItemViews.value(currentAesItemId).aesTypeId();
|
||||
else if (m_allCentralEffectClusters.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtEffectCluster;
|
||||
else if (m_allCentralNContaminations.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtNContamination;
|
||||
else if (m_allCentralBCContaminations.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtBCContamination;
|
||||
else if (m_allCentralExplosionsArea.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionArea;
|
||||
else if (m_allCentralExplosionsSingle.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionSingle;
|
||||
else if (m_allCentralMineAreas.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtMineArea;
|
||||
else if (m_allCentralFunctionalAreas.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtFunctionalArea;
|
||||
else if (m_allCentralBoobyTraps.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtBoobyTrap;
|
||||
else if (m_allCentralOffRouteMines.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtOffRouteMine;
|
||||
else if (m_allCentralExplosionClusters.contains(currentAesItemId))
|
||||
aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster;
|
||||
else
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not remove AesItem with id " << currentAesItemId << ". There is no way to find out its AesType";
|
||||
continue;
|
||||
}
|
||||
|
||||
m_dataQueue->addRemoveMessage(currentAesItemId, aesType);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcCentralAesData::buildSituationCircle()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
// building the situation "circle" --> we use a regular polygon with 8 edges
|
||||
m_situationCircle.clear();
|
||||
|
||||
QLineF tempLine;
|
||||
const qint32 edges = 8;
|
||||
const qreal angle = 360.0 / edges;
|
||||
|
||||
tempLine.setP1(PositionConverter::relativeFromGeographic(m_centerPosition, m_baseCoordinate));
|
||||
tempLine.setLength(m_radius);
|
||||
tempLine.setAngle(angle);
|
||||
|
||||
m_situationCircle << tempLine.p2();
|
||||
|
||||
for (qint32 counter = 1; counter < edges; ++counter)
|
||||
{
|
||||
tempLine.setAngle(tempLine.angle() + angle);
|
||||
m_situationCircle << tempLine.p2();
|
||||
}
|
||||
}
|
||||
|
||||
qreal HandlerOcCentralAesData::calculateDistanceToCircleCenter(qint32 aesItemId) const
|
||||
{
|
||||
if (!m_allCentralAesItemViews.contains(aesItemId))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not calculate distance to circle center, because there is no AesItemView for AesItem::id " << aesItemId;
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
QPolygonF aesItemForm = polygonFromForm(m_allCentralAesItemViews.value(aesItemId).form());
|
||||
QLineF distanceLine(aesItemForm.boundingRect().center(), m_situationCircle.boundingRect().center());
|
||||
|
||||
return distanceLine.length();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void HandlerOcCentralAesData::onAesItemChanged(QHash<qint32, T> &container, const T &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
if (!data.isCentral())
|
||||
return;
|
||||
container.insert(data.id(), data);
|
||||
|
||||
return;
|
||||
case DataModification::eModified:
|
||||
container[data.id()] = data;
|
||||
|
||||
if (m_aesItemsInRange.contains(data.id()))
|
||||
{
|
||||
if (data.effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsExpired
|
||||
|| data.effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsRemoved)
|
||||
{
|
||||
m_aesItemsInRange.remove(data.id());
|
||||
m_dataQueue->addRemoveMessage(data);
|
||||
}
|
||||
else
|
||||
m_dataQueue->addAesItem(data);
|
||||
}
|
||||
|
||||
return;
|
||||
case DataModification::eRemoved:
|
||||
container.remove(data.id());
|
||||
|
||||
if (m_allCentralAesItemViews.contains(data.id()))
|
||||
{
|
||||
AreaEffectSimulation::AesItemView aesItemView = m_allCentralAesItemViews.take(data.id());
|
||||
|
||||
if (m_aesItemsInRange.contains(data.id()))
|
||||
{
|
||||
m_aesItemsInRange.remove(data.id());
|
||||
m_dataQueue->addRemoveMessage(data.id(), aesItemView.aesTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void HandlerOcCentralAesData::addAesItemsToBuilder(const QHash<qint32, T> &aesItems, const QSet<qint32> &validIds)
|
||||
{
|
||||
for (auto it = aesItems.constBegin(); it != aesItems.constEnd(); ++it)
|
||||
{
|
||||
if (validIds.contains(it.key()))
|
||||
m_dataQueue->addAesItem(it.value());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Handler for all oc situation data at the server per client
|
||||
* $Id: handler_oc_situation_data.h 57655 2022-07-20 11:38:28Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.h $
|
||||
* $Author: karwat $
|
||||
* Created by Philipp Dassow, NLST, 27-02-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
#include <QPolygonF>
|
||||
#include <QSet>
|
||||
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "position_converter.h"
|
||||
#include "oc_situation.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
class HandlerOcCentralAesData;
|
||||
class CentralAesDataQueue;
|
||||
|
||||
class ThreadOcCentralAesData : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThreadOcCentralAesData(MainHandler *mainHandler,
|
||||
int equipmentId,
|
||||
int centerEquipmentId,
|
||||
int radius);
|
||||
|
||||
public slots:
|
||||
void requestOcCentralAesData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D &position,
|
||||
int radius,
|
||||
bool initial);
|
||||
|
||||
signals:
|
||||
void sendOcData(const TrainingAreaBase::SendOcDataRequest &);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
OcSituation::SituationCenterType m_centerType = OcSituation::SituationCenterType::Equipment; // which kind of center is used for the situation
|
||||
Core::GeoPosition2D m_position; // center position a situation can be requested around
|
||||
LtsCoordTrans::UtmCoordinate m_baseCoordinate;
|
||||
|
||||
int m_equipmentId{0}; // id from requesting OC-laptop
|
||||
int m_centerEquipmentId{0}; // equipment in the center of situation
|
||||
int m_radius{0}; // observer radius in meter
|
||||
|
||||
MainHandler *m_mainHandler{nullptr}; // provides TAB FTC and PPM DTC
|
||||
HandlerOcCentralAesData *m_handler{nullptr}; // OC-Thread-Object
|
||||
QMutex m_accessMutex; // Mutex-Object
|
||||
|
||||
LOGGER_T &m_logger; // Logger-Object
|
||||
};
|
||||
|
||||
|
||||
class HandlerOcCentralAesData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HandlerOcCentralAesData(const std::shared_ptr<DdsHandler> &dds,
|
||||
const LtsCoordTrans::UtmCoordinate &baseCoordinate,
|
||||
int equipmentId);
|
||||
|
||||
bool withCompression() const { return m_bWithCompression; }
|
||||
void setWithCompression(bool bOn) { m_bWithCompression = bOn; }
|
||||
bool withVBGTime() const { return m_bWithVBGTime; }
|
||||
void setWithVBGTime(bool bOn) { m_bWithVBGTime = bOn; }
|
||||
|
||||
private:
|
||||
void fetchAesItemsInRange();
|
||||
|
||||
template <typename T>
|
||||
qint32 fetchAesItemsInCircle(const QHash<qint32, T> &aesItems);
|
||||
|
||||
QPolygonF polygonFromForm(const std::vector<Core::GeoPosition> &form) const;
|
||||
QList<qint32> allInternalAesItemIds() const;
|
||||
|
||||
template <typename T>
|
||||
void onAesItemChanged(QHash<qint32, T> &container, const T &data, DataModification modType);
|
||||
|
||||
template <typename T>
|
||||
void addAesItemsToBuilder(const QHash<qint32, T> &aesItems, const QSet<qint32> &validIds);
|
||||
|
||||
void removeKickedOutAesItems(const QSet<qint32> &aesItemsSentBefore);
|
||||
void buildSituationCircle();
|
||||
qreal calculateDistanceToCircleCenter(qint32 aesItemId) const;
|
||||
|
||||
public slots:
|
||||
void setRequestCentralAesData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D ¢erPosition,
|
||||
int radius,
|
||||
bool initial);
|
||||
|
||||
private slots:
|
||||
void onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType);
|
||||
void onPartitionTimeChanged(qint64 partitionTime) { m_partitionTime = partitionTime; }
|
||||
|
||||
void onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &data, DataModification modType);
|
||||
void onNContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType);
|
||||
void onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType);
|
||||
void onExplosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType);
|
||||
void onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType);
|
||||
void onMineAreaChanged(const AreaEffectSimulation::MineArea &data, DataModification modType);
|
||||
void onFunctionalAreaChanged(const AreaEffectSimulation::FunctionalArea &data, DataModification modType);
|
||||
void onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType);
|
||||
void onOffRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType);
|
||||
void onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType);
|
||||
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
|
||||
|
||||
void handleSituation();
|
||||
void resetAliveTimer();
|
||||
void aliveTimeout();
|
||||
void onResetInternalData();
|
||||
|
||||
signals:
|
||||
void sendOcData(const TrainingAreaBase::SendOcDataRequest &);
|
||||
void resetInternalData();
|
||||
|
||||
private:
|
||||
//helper struct
|
||||
struct AesItemInfo
|
||||
{
|
||||
int32_t id;
|
||||
AreaEffectSimulation::AesType type;
|
||||
|
||||
AesItemInfo()
|
||||
: id(-1)
|
||||
, type(AreaEffectSimulation::AesType::inner_enum::AtUnknown)
|
||||
{}
|
||||
|
||||
AesItemInfo(int32_t id, AreaEffectSimulation::AesType type)
|
||||
: id(id)
|
||||
, type(type)
|
||||
{}
|
||||
};
|
||||
|
||||
LtsCoordTrans::UtmCoordinate m_baseCoordinate;
|
||||
QPolygonF m_situationCircle;
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
|
||||
// request data
|
||||
OcSituation::SituationCenterType m_centerType{OcSituation::SituationCenterType::Equipment}; // which kind of center is used for the situation
|
||||
Core::GeoPosition2D m_centerPosition; // center position a situation can be requested around
|
||||
int m_equipmentId{0}; // id from requesting OC-laptop
|
||||
int m_centerEquipmentId{0}; // equipment in the center of situation
|
||||
int m_centerParticipantId{0};
|
||||
int m_radius{0}; // observer radius in meter
|
||||
int m_retryCount{0};
|
||||
bool m_participantOverloaded{false};
|
||||
|
||||
// internal aes data
|
||||
QHash<qint32, AreaEffectSimulation::EffectCluster> m_allCentralEffectClusters;
|
||||
QHash<qint32, AreaEffectSimulation::NContamination> m_allCentralNContaminations;
|
||||
QHash<qint32, AreaEffectSimulation::BCContamination> m_allCentralBCContaminations;
|
||||
QHash<qint32, AreaEffectSimulation::ExplosionArea> m_allCentralExplosionsArea;
|
||||
QHash<qint32, AreaEffectSimulation::ExplosionSingle> m_allCentralExplosionsSingle;
|
||||
QHash<qint32, AreaEffectSimulation::MineArea> m_allCentralMineAreas;
|
||||
QHash<qint32, AreaEffectSimulation::FunctionalArea> m_allCentralFunctionalAreas;
|
||||
QHash<qint32, AreaEffectSimulation::BoobyTrap> m_allCentralBoobyTraps;
|
||||
QHash<qint32, AreaEffectSimulation::OffRouteMine> m_allCentralOffRouteMines;
|
||||
QHash<qint32, AreaEffectSimulation::ExplosionCluster> m_allCentralExplosionClusters;
|
||||
QHash<qint32, AreaEffectSimulation::AesItemView> m_allCentralAesItemViews; // <aesItemId, AesItemView>
|
||||
|
||||
QSet<qint32> m_aesItemsInRange;
|
||||
|
||||
// options, must be in sync with osc
|
||||
bool m_bWithCompression{true};
|
||||
bool m_bWithVBGTime{true};
|
||||
bool m_bInitialDataTransfer{true};
|
||||
|
||||
qint64 m_partitionTime;
|
||||
|
||||
// thread management
|
||||
QMutex m_accessMutex; // Mutex-Object
|
||||
QTimer *m_aliveTimer{nullptr}; // alive timer
|
||||
QTimer *m_txTimer{nullptr}; // tx cycle timer
|
||||
|
||||
CentralAesDataQueue *m_dataQueue;
|
||||
LOGGER_T &m_logger;
|
||||
};
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+633
@@ -0,0 +1,633 @@
|
||||
/**
|
||||
* Handler for all oc data at the server
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 14-02-2018
|
||||
*/
|
||||
|
||||
#include "handler_oc_data.h"
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "oc_situation.h"
|
||||
#include "handler_oc_aes_data.h"
|
||||
#include "handler_oc_situation_data.h"
|
||||
#include "handler_oc_central_aes_data.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
HandlerOcData::HandlerOcData(MainHandler *mainHandler,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, Interface::Fts::SendEquipmentMessageOcRequestHandler(mainHandler->dds()->fts())
|
||||
, Interface::Fts::EquipmentErrorRequestHandler(mainHandler->dds()->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_handlerOcAesData(new HandlerOcAesData(mainHandler, this))
|
||||
, m_dts(mainHandler->dds()->dts())
|
||||
, m_fts(mainHandler->dds()->fts())
|
||||
, m_evlDtc(mainHandler->evlDtc())
|
||||
, m_evlFtc(mainHandler->evlFtc())
|
||||
, m_msgFtc(mainHandler->msgFtc())
|
||||
, m_ppmDtc(mainHandler->ppmDtc())
|
||||
, m_ppmFtc(mainHandler->ppmFtc())
|
||||
, m_tabDtc(mainHandler->tabDtc())
|
||||
, m_tabFtc(mainHandler->tabFtc())
|
||||
, m_currentActiveEvaluationSchemaId(0)
|
||||
, m_stateInformationTimer(new QTimer(this))
|
||||
, m_logger(getLogger("HandlerOcData"))
|
||||
{}
|
||||
|
||||
HandlerOcData::~HandlerOcData()
|
||||
{}
|
||||
|
||||
bool HandlerOcData::init()
|
||||
{
|
||||
// EVL DTC enable
|
||||
if (!m_evlDtc->enableEvaluationSchema())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling EVL Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
connect(m_evlDtc.get(), &Evaluations::Interface::Dtc::evaluationSchemaChanged, this, &HandlerOcData::onEvaluationSchemaChanged);
|
||||
auto cb = [this](const Evaluations::EvaluationSchema & schema)
|
||||
{
|
||||
onEvaluationSchemaChanged(schema, DataModification::eAdded);
|
||||
};
|
||||
m_evlDtc->evaluationSchemas(cb);
|
||||
|
||||
// EVL FTC enable
|
||||
if (!m_evlFtc->enableEvlCommentModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling EVL Function-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Msg FTC enable
|
||||
if (!m_msgFtc->enableCreateOperatorMessage())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling MSG Function-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_ppmDtc->enableParticipant())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling PPM Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_ppmFtc->enableRegisterParticipant())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling PPM FTC-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TAB DTC enable
|
||||
if (!m_tabDtc->enableOcData())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling TAB Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TAB DTC enable
|
||||
if (!m_tabDtc->enableConnections())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling TAB Data-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::ocDataChanged, this, &HandlerOcData::onOcDataChanged);
|
||||
|
||||
// TAB FTC enable
|
||||
if (!m_tabFtc->enableSendOcData())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enabling TAB Function-Topics failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handler aes data
|
||||
if (!m_handlerOcAesData->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialise HandlerOcAesData.";
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(m_stateInformationTimer, &QTimer::timeout, this, &HandlerOcData::sendStateInformation);
|
||||
m_stateInformationTimer->setInterval(Settings::stateInformationCycleTime());
|
||||
INFO_LOG(m_logger) << "Starting StateInformation timer with interval: " << m_stateInformationTimer->interval();
|
||||
m_stateInformationTimer->start();
|
||||
|
||||
INFO_LOG(m_logger) << "Initialisation HandlerOcData succesful.";
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerOcData::onEvlCommentModifyReply(const Core::FunctionReplyObject &reply)
|
||||
{
|
||||
if (reply.error())
|
||||
ERROR_LOG(m_logger) << "Evaluation could not be transmitted to EVL: " << reply.translated();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Evaluation successfully transmitted to EVL!";
|
||||
}
|
||||
|
||||
void HandlerOcData::onCreateOperatorMessageReply(const Core::FunctionReplyObject &reply)
|
||||
{
|
||||
if (reply.error())
|
||||
ERROR_LOG(m_logger) << "Message could not be created by MSG: " << reply.translated();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Message created successfully by MSG!";
|
||||
}
|
||||
|
||||
void HandlerOcData::onSendOcDataReply(const Core::FunctionReplyObject &reply)
|
||||
{
|
||||
if (reply.error())
|
||||
ERROR_LOG(m_logger) << "Oc data could not be send: " << reply.translated();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Oc data send successfully to TAB!";
|
||||
}
|
||||
|
||||
void HandlerOcData::onRegisterParticipantReply(const ParticipantManagement::RegisterReply &reply)
|
||||
{
|
||||
if (reply.errorString().size())
|
||||
ERROR_LOG(m_logger) << "Modify Participant data could not be send: " << reply.errorString();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Modify Participant data send successfully to ppm!";
|
||||
}
|
||||
|
||||
void HandlerOcData::onEvaluationSchemaChanged(const Evaluations::EvaluationSchema &data, DataModification modType)
|
||||
{
|
||||
if ((modType != DataModification::eAdded) && (modType != DataModification::eModified))
|
||||
return;
|
||||
|
||||
if (data.sendToTa())
|
||||
m_currentActiveEvaluationSchemaId = data.id();
|
||||
}
|
||||
|
||||
void HandlerOcData::onOcDataChanged(const TrainingAreaBase::OcData &data, DataModification modType)
|
||||
{
|
||||
if ((modType != DataModification::eAdded) && (modType != DataModification::eModified))
|
||||
return;
|
||||
|
||||
if (data.sampleTime() < QDateTime::currentMSecsSinceEpoch() - 1000 * 60 * 10) // older than 10 mins -> ignore
|
||||
return;
|
||||
|
||||
const QByteArray payload = LtsUtils::toQByteArray(data.payload());
|
||||
unsigned int telegramId;
|
||||
|
||||
LtsUtils::get1Byte(payload, telegramId);
|
||||
|
||||
|
||||
DEBUG_LOG(m_logger) << "New OcData telegramId: " << telegramId;
|
||||
|
||||
switch (telegramId)
|
||||
{
|
||||
case OcSituation::TelegramId::Message:
|
||||
{
|
||||
handleMessage(payload);
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::DemandEvaluationSchema:
|
||||
{
|
||||
handleDemandEvaluationSchema(payload, data.equipmentNumber());
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::Evaluation:
|
||||
{
|
||||
handleEvaluation(payload);
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::DemandSituation:
|
||||
{
|
||||
handleDemandSituation(payload, data.equipmentNumber());
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::DemandAesItems:
|
||||
{
|
||||
OcSituation::AesType aesType;
|
||||
size_t pos = 1;
|
||||
LtsUtils::get1Byte(payload, pos, aesType);
|
||||
m_handlerOcAesData->demandAesItems(aesType, data.equipmentNumber());
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::EquipmentErrorRegistration:
|
||||
{
|
||||
handleEquipmentErrorRegistration(payload);
|
||||
break;
|
||||
}
|
||||
case OcSituation::TelegramId::EquipmentRegistration:
|
||||
{
|
||||
handleEquipmentRegistration(payload);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
INFO_LOG(m_logger) << "OC-data with telegram ID: " << telegramId << " is not by HandlerOcData OSS!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcData::onSendOcData(const TrainingAreaBase::SendOcDataRequest &req)
|
||||
{
|
||||
m_tabFtc->sendOcDataRequest(req, this);
|
||||
}
|
||||
|
||||
void HandlerOcData::sendStateInformation()
|
||||
{
|
||||
QByteArray payload;
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::StateInformation, payload);
|
||||
LtsUtils::set2Byte(m_currentActiveEvaluationSchemaId, payload);
|
||||
LtsUtils::set2Byte(m_handlerOcAesData->dangerAreaResetCnt(), payload);
|
||||
LtsUtils::set2Byte(m_handlerOcAesData->iedResetCnt(), payload);
|
||||
|
||||
TrainingAreaBase::SendOcDataRequest out;
|
||||
out.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
/*!
|
||||
* \details Only if Tetra is connected, the OcData telegram will be send
|
||||
* If we not check = A bunch of telegrams will be queued/stored until Tetra is connected, than Tetra is in Overload
|
||||
*/
|
||||
QMapIterator<qint32, TrainingAreaBase::Connections> conIt(m_tabDtc->connectionss());
|
||||
while (conIt.hasNext())
|
||||
{
|
||||
conIt.next();
|
||||
for (TrainingAreaBase::ConnectionState conState : conIt.value().connections())
|
||||
{
|
||||
if (conState.name() == "TETRA" && conState.state() == false)
|
||||
return;
|
||||
}
|
||||
}
|
||||
onSendOcData(out);
|
||||
}
|
||||
|
||||
void HandlerOcData::onSituationThreadExit()
|
||||
{
|
||||
ThreadOcSituationData *t = qobject_cast<ThreadOcSituationData *>(sender());
|
||||
|
||||
INFO_LOG(m_logger) << "Exit O/C-Thread for O/C-Laptop-Id: " << m_situationThreads.key(t);
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
m_situationThreads.remove(m_situationThreads.key(t));
|
||||
|
||||
t->deleteLater();
|
||||
}
|
||||
|
||||
void HandlerOcData::onCentralAesThreadExit()
|
||||
{
|
||||
ThreadOcCentralAesData *t = qobject_cast<ThreadOcCentralAesData *>(sender());
|
||||
|
||||
INFO_LOG(m_logger) << "Exit CentralAesData-Thread for O/C-Laptop-Id: " << m_centralAesDataThreads.key(t);
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
m_centralAesDataThreads.remove(m_centralAesDataThreads.key(t));
|
||||
|
||||
t->deleteLater();
|
||||
}
|
||||
|
||||
void HandlerOcData::onSendEquipmentMessageOcRequest(const rti::core::SampleIdentity &cookie, const SendEquipmentMessageRequest &request)
|
||||
{
|
||||
QByteArray preparedPayload;
|
||||
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::Message, preparedPayload);
|
||||
LtsUtils::set2Byte(0, preparedPayload); // dummy receiverId is individually set for each eqId in list
|
||||
LtsUtils::set1Byte(Messaging::AddressType::ObserverController, preparedPayload);
|
||||
LtsUtils::set2Byte(request.sender(), preparedPayload);
|
||||
LtsUtils::set1Byte(request.senderType().underlying(), preparedPayload);
|
||||
LtsUtils::set2Byte(m_mainHandler->exerciseId(), preparedPayload);
|
||||
preparedPayload.append(QByteArray::fromStdString(request.subject()));
|
||||
preparedPayload.append('\n'); // separating subject from message
|
||||
preparedPayload.append(QByteArray::fromStdString(request.message()));
|
||||
|
||||
for (const auto equipmentNumber : request.equipmentNumbers())
|
||||
{
|
||||
TrainingAreaBase::SendOcDataRequest out;
|
||||
out.equipmentNumber(equipmentNumber);
|
||||
// replace 2 bytes with current receiver
|
||||
QByteArray receiverId;
|
||||
LtsUtils::set2Byte(equipmentNumber, receiverId);
|
||||
QByteArray payload = preparedPayload.replace(1, 2, receiverId);
|
||||
out.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
onSendOcData(out);
|
||||
}
|
||||
|
||||
m_fts->sendEquipmentMessageOcReply(cookie, Core::FunctionReplyObject(request.requestId()));
|
||||
}
|
||||
|
||||
void HandlerOcData::onEquipmentErrorRequest(const rti::core::SampleIdentity &cookie, const EquipmentErrorRequest &request)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "onEquipmentErrorRequest" << request.equipmentNumber();
|
||||
EquipmentErrorRegistration out;
|
||||
// out.id(request.requestId());
|
||||
out.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
out.participant(QString::number(request.equipmentNumber()).toStdString());
|
||||
out.device(request.device());
|
||||
out.text(request.text());
|
||||
m_dts->publish(out);
|
||||
m_fts->equipmentErrorReply(cookie, Core::FunctionReplyObject(request.requestId()));
|
||||
}
|
||||
|
||||
void HandlerOcData::handleDemandSituation(const QByteArray &data, int equipmentId)
|
||||
{
|
||||
OcSituation::SituationCenterType centerType;
|
||||
int centerEquipmentId = 0, radius = 0;
|
||||
Core::GeoPosition2D position;
|
||||
position.lon(std::nan(""));
|
||||
position.lat(std::nan(""));
|
||||
bool initial = false;
|
||||
size_t pos = 1;
|
||||
|
||||
LtsUtils::get1Byte(data, pos, centerType);
|
||||
if (centerType == OcSituation::SituationCenterType::Equipment)
|
||||
{
|
||||
LtsUtils::get2Byte(data, pos, centerEquipmentId);
|
||||
LtsUtils::get2Byte(data, pos, radius);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Request from O/C-Laptop-Id: " << equipmentId
|
||||
<< " centerEquipmentId: " << centerEquipmentId << " radius: " << radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
double tmp;
|
||||
LtsUtils::get8Byte(data, pos, tmp);
|
||||
position.lon(tmp);
|
||||
LtsUtils::get8Byte(data, pos, tmp);
|
||||
position.lat(tmp);
|
||||
LtsUtils::get2Byte(data, pos, radius);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Request from O/C-Laptop-Id: " << equipmentId
|
||||
<< " center: " << position << " radius: " << radius;
|
||||
}
|
||||
bool filterActive = false;
|
||||
LtsUtils::get1Byte(data, pos, initial);
|
||||
|
||||
LtsUtils::get1Byte(data, pos, filterActive);
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClassList{};
|
||||
QSet<int> partyList{};
|
||||
if (filterActive)
|
||||
{
|
||||
// get partyTypes
|
||||
int pCount = 0;
|
||||
LtsUtils::get1Byte(data, pos, pCount);
|
||||
for (int i = 0; i < pCount; i++)
|
||||
{
|
||||
int partyId;
|
||||
LtsUtils::get2Byte(data, pos, partyId);
|
||||
partyList.insert(partyId);
|
||||
}
|
||||
//get types
|
||||
int typeCount = 0;
|
||||
LtsUtils::get1Byte(data, pos, typeCount);
|
||||
for (int i = 0; i < typeCount; i++)
|
||||
{
|
||||
int typClass;
|
||||
LtsUtils::get1Byte(data, pos, typClass);
|
||||
typeClassList.insert((ParticipantManagement::TypeClass::type)typClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
// Situation Thread
|
||||
ThreadOcSituationData *ocThread = m_situationThreads.value(equipmentId);
|
||||
bool bInitialSituation;
|
||||
if (!ocThread)
|
||||
{
|
||||
ocThread = new ThreadOcSituationData(m_mainHandler, equipmentId, centerEquipmentId, radius, filterActive, partyList, typeClassList);
|
||||
m_situationThreads.insert(equipmentId, ocThread);
|
||||
|
||||
connect(ocThread, &QThread::finished, this, &HandlerOcData::onSituationThreadExit);
|
||||
connect(ocThread, &ThreadOcSituationData::sendOcData, this, &HandlerOcData::onSendOcData);
|
||||
|
||||
ocThread->start();
|
||||
bInitialSituation = true;
|
||||
}
|
||||
else
|
||||
bInitialSituation = initial;
|
||||
|
||||
ocThread->requestOcSituationData(centerType, centerEquipmentId, position, radius, filterActive, partyList, typeClassList, bInitialSituation);
|
||||
|
||||
|
||||
// Central AES Data Thread
|
||||
bool bInitialAes;
|
||||
ThreadOcCentralAesData *centralAesDataThread = m_centralAesDataThreads.value(equipmentId);
|
||||
if (!centralAesDataThread)
|
||||
{
|
||||
centralAesDataThread = new ThreadOcCentralAesData(m_mainHandler, equipmentId, centerEquipmentId, radius);
|
||||
m_centralAesDataThreads.insert(equipmentId, centralAesDataThread);
|
||||
|
||||
connect(centralAesDataThread, &QThread::finished, this, &HandlerOcData::onCentralAesThreadExit);
|
||||
connect(centralAesDataThread, &ThreadOcCentralAesData::sendOcData, this, &HandlerOcData::onSendOcData);
|
||||
|
||||
centralAesDataThread->start();
|
||||
bInitialAes = true;
|
||||
}
|
||||
else
|
||||
bInitialAes = initial;
|
||||
|
||||
centralAesDataThread->requestOcCentralAesData(centerType, centerEquipmentId, position, radius, bInitialAes);
|
||||
}
|
||||
|
||||
void HandlerOcData::handleDemandEvaluationSchema(const QByteArray &data, int equipmentNumber)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
// ignoring requested schema ID, as we only have one active schema to be send to TA
|
||||
Evaluations::EvaluationSchema schema = m_evlDtc->evaluationSchema(m_currentActiveEvaluationSchemaId);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Sending to equipmentnumber: " << equipmentNumber << " evaluation schmema: " << m_currentActiveEvaluationSchemaId;
|
||||
|
||||
TrainingAreaBase::SendOcDataRequest out;
|
||||
out.equipmentNumber(equipmentNumber);
|
||||
QByteArray payload;
|
||||
LtsUtils::set1Byte(OcSituation::TelegramId::EvaluationSchema, payload);
|
||||
LtsUtils::set2Byte(schema.id(), payload);
|
||||
QByteArray compressed = qCompress(QByteArray::fromStdString(schema.schemadata()));
|
||||
payload.append(compressed);
|
||||
|
||||
out.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
|
||||
onSendOcData(out);
|
||||
}
|
||||
|
||||
void HandlerOcData::handleEvaluation(const QByteArray &data)
|
||||
{
|
||||
Evaluations::EvlCommentModifyRequest out;
|
||||
size_t pos = 1;
|
||||
unsigned int tmp;
|
||||
|
||||
// get schema id
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
out.schemaId(tmp);
|
||||
// get sender operator id
|
||||
LtsUtils::get4Byte(data, pos, tmp);
|
||||
out.senderOperatorId(tmp);
|
||||
// get receiver operator id
|
||||
LtsUtils::get4Byte(data, pos, tmp);
|
||||
if (tmp > 0)
|
||||
out.receiverOperatorId(dds::core::optional<int32_t>(tmp));
|
||||
// get timeStamp
|
||||
int64_t timeStamp;
|
||||
LtsUtils::get8Byte(data, pos, timeStamp);
|
||||
out.ts(timeStamp);
|
||||
// get hierarchy string
|
||||
unsigned int hierarchyLength;
|
||||
LtsUtils::get2Byte(data, pos, hierarchyLength);
|
||||
out.hierarchy(QByteArray(data.mid(pos, hierarchyLength)).toStdString());
|
||||
pos += hierarchyLength;
|
||||
// get text string
|
||||
unsigned int textLength;
|
||||
LtsUtils::get2Byte(data, pos, textLength);
|
||||
out.text(QByteArray(data.mid(pos, textLength)).toStdString());
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new evl comment: " << out;
|
||||
|
||||
m_evlFtc->evlCommentModifyRequest(out, this);
|
||||
}
|
||||
|
||||
void HandlerOcData::handleMessage(const QByteArray &data)
|
||||
{
|
||||
Messaging::CreateOperatorMessageRequest out;
|
||||
size_t pos = 1;
|
||||
unsigned int tmp = 0;
|
||||
unsigned int addressType;
|
||||
|
||||
// get receiver
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
std::vector<int32_t> recipientIds;
|
||||
recipientIds.push_back(tmp);
|
||||
// get address type
|
||||
LtsUtils::get1Byte(data, pos, addressType);
|
||||
out.recipientType(static_cast<Messaging::AddressType::inner_enum>(addressType));
|
||||
|
||||
if (addressType == Messaging::AddressType::ObserverController)
|
||||
{
|
||||
int participantId = m_ppmDtc->participantIdByEquipmentNumber(tmp);
|
||||
if (participantId > 0)
|
||||
recipientIds[0] = participantId;
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Recipient equipment number: " << tmp << " is unknown. Aborting creating message.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
out.recipientIds(recipientIds);
|
||||
|
||||
// get sender
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
|
||||
LtsUtils::get1Byte(data, pos, addressType);
|
||||
out.senderType(static_cast<Messaging::AddressType::inner_enum>(addressType));
|
||||
if (addressType == Messaging::AddressType::ObserverController)
|
||||
{
|
||||
int participantId = m_ppmDtc->participantIdByEquipmentNumber(tmp);
|
||||
if (participantId > 0)
|
||||
out.senderId(participantId);
|
||||
else
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Sender equipment number: " << tmp << " is unknown. Setting senderId to 0.";
|
||||
out.senderId(0);
|
||||
out.senderType(Messaging::AddressType::ObserverController);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no need to check if operator still exists, there is no harm if not
|
||||
out.senderId(tmp);
|
||||
}
|
||||
|
||||
// get exerciseId
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
if (tmp == 0)
|
||||
WARNING_LOG(m_logger) << "Could'n set ExerciseId" << " " << tmp << " set to 0";
|
||||
out.exerciseId(tmp);
|
||||
// get address type
|
||||
const QByteArray msg(data.right(data.size() - pos));
|
||||
int idx = msg.indexOf('\n');
|
||||
if (idx < 0)
|
||||
{
|
||||
out.subject((tr("Message from %1").arg(out.senderId())).toStdString());
|
||||
out.message(msg.constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
out.subject(msg.left(idx).constData());
|
||||
out.message(msg.mid(idx + 1).constData());
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new message: " << out;
|
||||
m_msgFtc->createOperatorMessageRequest(out, this);
|
||||
}
|
||||
|
||||
void HandlerOcData::handleEquipmentErrorRegistration(const QByteArray &data)
|
||||
{
|
||||
EquipmentErrorRegistration out;
|
||||
size_t pos = 1;
|
||||
unsigned int tmp;
|
||||
|
||||
// equipmentNumber
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
out.equipmentNumber(tmp);
|
||||
// participant
|
||||
out.participant(data.mid(pos, 36).toStdString());
|
||||
pos += 36;
|
||||
// device
|
||||
out.device(data.mid(pos, 36).toStdString());
|
||||
pos += 36;
|
||||
// length
|
||||
LtsUtils::get1Byte(data, pos, tmp);
|
||||
// text
|
||||
out.text(data.mid(pos, tmp).toStdString());
|
||||
|
||||
out.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new error registration: " << out;
|
||||
m_dts->publish(out);
|
||||
}
|
||||
|
||||
void HandlerOcData::handleEquipmentRegistration(const QByteArray &data)
|
||||
{
|
||||
size_t pos = 1;
|
||||
unsigned int tmp;
|
||||
|
||||
// participantID
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
int participantId = tmp;
|
||||
// equipmentNumber
|
||||
LtsUtils::get2Byte(data, pos, tmp);
|
||||
int equipmentNumber = tmp;
|
||||
|
||||
ParticipantManagement::Participant part = m_ppmDtc->participant(participantId);
|
||||
|
||||
if (part.equipmentNumber().is_set() && equipmentNumber > 0)
|
||||
{
|
||||
// we need a deregistration first!
|
||||
ParticipantManagement::RegisterParticipantRequest dereq;
|
||||
dereq.assignState(ParticipantManagement::ParticipantAssignState::NotAssigned);
|
||||
dereq.equipmentNumber(0);
|
||||
dereq.participantId(participantId);
|
||||
dereq.info(part.info());
|
||||
dereq.identification(part.identification());
|
||||
m_ppmFtc->registerParticipantRequest(dereq, this);
|
||||
|
||||
}
|
||||
ParticipantManagement::RegisterParticipantRequest req;
|
||||
if (equipmentNumber > 0)
|
||||
req.assignState(ParticipantManagement::ParticipantAssignState::HandoutExcon);
|
||||
else
|
||||
req.assignState(ParticipantManagement::ParticipantAssignState::NotAssigned);
|
||||
req.equipmentNumber(equipmentNumber);
|
||||
req.participantId(participantId);
|
||||
req.info(part.info());
|
||||
req.identification(part.identification());
|
||||
DEBUG_LOG(m_logger) << "Try to register part with id: " << req.participantId() << " and eqNumeber " << req.equipmentNumber();
|
||||
m_ppmFtc->registerParticipantRequest(req, this);
|
||||
}
|
||||
|
||||
} // Namespace OcSituationServer
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Handler for all oc data at the server
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 14-02-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
class ThreadOcCentralAesData;
|
||||
class ThreadOcSituationData;
|
||||
class HandlerOcAesData;
|
||||
class HandlerOcData : public QObject
|
||||
, protected Interface::Fts::SendEquipmentMessageOcRequestHandler
|
||||
, protected Interface::Fts::EquipmentErrorRequestHandler
|
||||
, protected Evaluations::Interface::Ftc::EvlCommentModifyReplyHandler
|
||||
, protected Messaging::Interface::Ftc::CreateOperatorMessageReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::RegisterParticipantReplyHandler
|
||||
, protected TrainingAreaBase::Interface::Ftc::SendOcDataReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerOcData(MainHandler *mainHandler,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
~HandlerOcData();
|
||||
|
||||
bool init();
|
||||
|
||||
protected:
|
||||
void onEvlCommentModifyReply(const Core::FunctionReplyObject &reply) override final;
|
||||
void onCreateOperatorMessageReply(const Core::FunctionReplyObject &reply) override final;
|
||||
void onSendOcDataReply(const Core::FunctionReplyObject &reply) override final;
|
||||
void onRegisterParticipantReply(const ParticipantManagement::RegisterReply &reply) override final;
|
||||
|
||||
private slots:
|
||||
void onEvaluationSchemaChanged(const Evaluations::EvaluationSchema &data, DataModification modType);
|
||||
void onOcDataChanged(const TrainingAreaBase::OcData &data, DataModification modType);
|
||||
void onSendOcData(const TrainingAreaBase::SendOcDataRequest &req);
|
||||
void sendStateInformation();
|
||||
void onSituationThreadExit();
|
||||
void onCentralAesThreadExit();
|
||||
|
||||
private:
|
||||
void onSendEquipmentMessageOcRequest(const rti::core::SampleIdentity &cookie,
|
||||
const SendEquipmentMessageRequest &request) override final;
|
||||
void onEquipmentErrorRequest(const rti::core::SampleIdentity &cookie,
|
||||
const EquipmentErrorRequest &request) override final;
|
||||
|
||||
void handleDemandSituation(const QByteArray &data, int equipmentId);
|
||||
void handleDemandEvaluationSchema(const QByteArray &data, int equipmentNumber);
|
||||
void handleEvaluation(const QByteArray &data);
|
||||
void handleMessage(const QByteArray &data);
|
||||
void handleEquipmentErrorRegistration(const QByteArray &data);
|
||||
void handleEquipmentRegistration(const QByteArray &data);
|
||||
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
HandlerOcAesData *m_handlerOcAesData;
|
||||
|
||||
std::shared_ptr<Interface::Dts> m_dts;
|
||||
std::shared_ptr<Interface::Fts> m_fts;
|
||||
|
||||
std::shared_ptr<Evaluations::Interface::Dtc> m_evlDtc;
|
||||
std::shared_ptr<Evaluations::Interface::Ftc> m_evlFtc;
|
||||
std::shared_ptr<Messaging::Interface::Ftc> m_msgFtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> m_tabDtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> m_tabFtc;
|
||||
|
||||
int m_currentActiveEvaluationSchemaId;
|
||||
QMap<int, ThreadOcSituationData *> m_situationThreads; // equipmentId, thread for situation data handling
|
||||
QMap<int, ThreadOcCentralAesData *> m_centralAesDataThreads; // equipmentId, thread for central aes data handling
|
||||
QMutex m_accessMutex; // Mutex-Object
|
||||
QTimer *m_stateInformationTimer;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,982 @@
|
||||
/**
|
||||
* Handler for all oc situation data at the server per client
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 27-02-2018
|
||||
*/
|
||||
|
||||
#include "handler_oc_situation_data.h"
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <LtsUtilsCore/outdated_position.h>
|
||||
#include <ParticipantManagement/ppm_common.h>
|
||||
#include "settings.h"
|
||||
#include <algorithm>
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
//
|
||||
// ThreadOcSituationData
|
||||
//
|
||||
ThreadOcSituationData::ThreadOcSituationData(MainHandler *mainHandler,
|
||||
int equipmentId,
|
||||
int centerEquipmentId,
|
||||
int radius,
|
||||
bool filterActive,
|
||||
QSet<int> partys,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClasses)
|
||||
: m_baseCoordinate(mainHandler->positionConverter()->baseCoordinate())
|
||||
, m_equipmentId(equipmentId)
|
||||
, m_centerEquipmentId(centerEquipmentId)
|
||||
, m_radius(radius)
|
||||
, m_partyList(partys)
|
||||
, m_filterActive(filterActive)
|
||||
, m_typeClassList(typeClasses)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger(QStringLiteral("ThreadOcSituationData.") + QString::number(equipmentId)))
|
||||
{}
|
||||
|
||||
void ThreadOcSituationData::requestOcSituationData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D &position,
|
||||
int radius,
|
||||
bool filterActive,
|
||||
QSet<int> partyList,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClassList,
|
||||
bool initial)
|
||||
{
|
||||
INFO_LOG(m_logger) << "OC-Situation Request for centerEquipmentId: " << centerEquipmentId
|
||||
<< " from O/C-laptop-Id: " << m_equipmentId
|
||||
<< " with radius of " << radius
|
||||
<< "m, initial: " << initial;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
m_centerType = centerType;
|
||||
m_centerEquipmentId = centerEquipmentId;
|
||||
m_radius = radius;
|
||||
m_position = position;
|
||||
m_filterActive = filterActive;
|
||||
m_partyList = partyList;
|
||||
m_typeClassList = typeClassList;
|
||||
|
||||
if (m_handler)
|
||||
m_handler->setRequestOcSituationData(centerType, centerEquipmentId, position, radius, filterActive, partyList, typeClassList, initial);
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Thread doesn't exist up to now! Do nothing.";
|
||||
}
|
||||
|
||||
void ThreadOcSituationData::run()
|
||||
{
|
||||
static QMutex s_ddsAccesMutex;
|
||||
{
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
QMutexLocker m(&s_ddsAccesMutex);
|
||||
DEBUG_LOG(m_logger) << "Instance new OC-Thread for O/C-Laptop-Id: " << m_equipmentId;
|
||||
|
||||
m_handler = new HandlerOcSituationData(m_mainHandler->dds(),
|
||||
m_baseCoordinate,
|
||||
m_equipmentId);
|
||||
connect(m_handler, &HandlerOcSituationData::sendOcData, this, &ThreadOcSituationData::sendOcData, Qt::QueuedConnection);
|
||||
|
||||
m_handler->setRequestOcSituationData(m_centerType, m_centerEquipmentId, m_position, m_radius, m_filterActive, m_partyList, m_typeClassList, true);
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "OC-Thread started for O/C-Laptop-Id: " << m_equipmentId;
|
||||
exec();
|
||||
|
||||
{
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
QMutexLocker m(&s_ddsAccesMutex);
|
||||
delete m_handler;
|
||||
m_handler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// HandlerOcSituationData
|
||||
//
|
||||
HandlerOcSituationData::HandlerOcSituationData(const std::shared_ptr<DdsHandler> &dds,
|
||||
const LtsCoordTrans::UtmCoordinate &baseCoordinate,
|
||||
int equipmentId)
|
||||
: m_baseCoordinate(baseCoordinate)
|
||||
, m_ppmDtc(ParticipantManagement::Interface::Dtc::create(dds->dds()))
|
||||
, m_aesDtc(AreaEffectSimulation::Interface::Dtc::create(dds->dds()))
|
||||
, m_gimDtc(GuezIedManagement::Interface::Dtc::create(dds->dds()))
|
||||
, m_equipmentId(equipmentId)
|
||||
, m_partitionTime(QDateTime::currentMSecsSinceEpoch())
|
||||
, m_aliveTimer(new QTimer(this))
|
||||
, m_txTimer(new QTimer(this))
|
||||
, m_logger(getLogger(QStringLiteral("HandlerOcSituationData.") + QString::number(equipmentId)))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Create O/C-Handler for O/C-Laptop-Id: " << equipmentId
|
||||
<< " aliveTimeout: " << Settings::aliveTimeout() << " sec"
|
||||
<< " txCyleTime: " << Settings::txCycleTime() << " sec"
|
||||
<< " maxTransferBytes: " << Settings::maxNumOfBytePerTxCycle();
|
||||
|
||||
connect(dds.get(), &DdsHandler::partitionTimeChanged, this, &HandlerOcSituationData::onPartitionTimeChanged);
|
||||
|
||||
connect(m_aliveTimer, &QTimer::timeout, this, &HandlerOcSituationData::aliveTimeout);
|
||||
m_aliveTimer->setSingleShot(true);
|
||||
m_aliveTimer->start(Settings::aliveTimeout());
|
||||
|
||||
connect(m_txTimer, &QTimer::timeout, this, &HandlerOcSituationData::handleSituation);
|
||||
m_txTimer->start(Settings::txCycleTime());
|
||||
|
||||
connect(this, &HandlerOcSituationData::resetInternalData,
|
||||
this, &HandlerOcSituationData::onResetInternalData, Qt::QueuedConnection);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
||||
this, &HandlerOcSituationData::onParticipantChanged);
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
|
||||
this, &HandlerOcSituationData::onDynamicParticipantDataChanged);
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
|
||||
this, &HandlerOcSituationData::onParticipantPositionChanged);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
||||
this, &HandlerOcSituationData::onAesItemViewChanged);
|
||||
|
||||
// REGG-5592 - Von DUS-Minen ausgefallene Teilnehmer werden in der Lagedarstellung nicht mit einer
|
||||
// Trefferanzeige in der Farbe der Sperre sondern in der Farbe des Ltg/Ausb-Dienstes (Ocker) dargestellt.
|
||||
// to handle race condition between DynamicParticipantData and DusMineState:
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dusMineStateChanged,
|
||||
this, &HandlerOcSituationData::onDusMineStateChanged);
|
||||
|
||||
m_ppmDtc->enableParticipant();
|
||||
m_ppmDtc->enableDynamicParticipantData();
|
||||
m_ppmDtc->enableParticipantPosition();
|
||||
m_ppmDtc->enableType();
|
||||
m_aesDtc->enableAesItemView();
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::setRequestOcSituationData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D ¢erPosition,
|
||||
int radius,
|
||||
bool filterActive,
|
||||
QSet<int> partys,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClasses,
|
||||
bool initial)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
DEBUG_LOG(m_logger) << "Requested CenterEquipmentId: " << centerEquipmentId << " radius: " << radius;
|
||||
|
||||
bool endThread = false;
|
||||
|
||||
m_centerType = centerType;
|
||||
m_centerEquipmentId = centerEquipmentId;
|
||||
m_centerPosition = centerPosition;
|
||||
m_centerParticipantId = 0;
|
||||
m_radius = radius;
|
||||
m_partyList.clear();
|
||||
m_typeClassList.clear();
|
||||
m_partyList = partys;
|
||||
m_typeClassList = typeClasses;
|
||||
m_filterActive = filterActive;
|
||||
|
||||
if (centerType == OcSituation::SituationCenterType::Equipment)
|
||||
{
|
||||
if (m_centerEquipmentId > 0)
|
||||
{
|
||||
ParticipantManagement::Participant centerParticipant;
|
||||
for (const auto &participant : qAsConst(m_allParticipants))
|
||||
{
|
||||
if (participant.equipmentNumber().is_set() && participant.equipmentNumber().get() == m_centerEquipmentId)
|
||||
{
|
||||
centerParticipant = participant;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (centerParticipant.id() <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId
|
||||
<< " as center of the oc situation request does not exist!";
|
||||
endThread = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const ParticipantManagement::ParticipantPosition &partPosition = m_allParticipantPositions.value(centerParticipant.id());
|
||||
if (partPosition.participantId() == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId
|
||||
<< " as center of the oc situation request has no position!";
|
||||
endThread = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_centerPosition = partPosition.pos();
|
||||
m_centerParticipantId = centerParticipant.id();
|
||||
}
|
||||
}
|
||||
if (endThread && ++m_retryCount < 5)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Retry setting data - maybe participant is not yet available... " << m_retryCount;
|
||||
QTimer::singleShot(1000 * m_retryCount, this, [this]()
|
||||
{
|
||||
// must be initial here
|
||||
setRequestOcSituationData(m_centerType, m_centerEquipmentId, m_centerPosition, m_radius, m_filterActive, m_partyList, m_typeClassList, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(m_logger) << "Situation is not requested anymore -> end thread";
|
||||
endThread = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!endThread)
|
||||
{
|
||||
if (centerType == OcSituation::SituationCenterType::Equipment)
|
||||
{
|
||||
if (m_centerParticipantId == 0)
|
||||
endThread = true;
|
||||
}
|
||||
else if ((centerPosition.lon() == std::nan("")) || (centerPosition.lat() == std::nan("")))
|
||||
endThread = true;
|
||||
}
|
||||
|
||||
m_retryCount = 0;
|
||||
|
||||
if (endThread == true)
|
||||
m_radius = 0; // ==> no data transfer on handleSituation() and quit
|
||||
|
||||
QTimer::singleShot(0, this, &HandlerOcSituationData::resetAliveTimer);
|
||||
if (initial || endThread)
|
||||
{
|
||||
// thread change ...
|
||||
QTimer::singleShot(0, this, &HandlerOcSituationData::handleSituation);
|
||||
emit resetInternalData();
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
const int participantId = data.id();
|
||||
m_allParticipants[participantId] = data;
|
||||
|
||||
if (!m_participants.contains(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_participants does not contain participant id: " << participantId;
|
||||
return; // participant is not of interest (now)
|
||||
}
|
||||
|
||||
// old data to check against
|
||||
const ParticipantManagement::Participant &oldParticipantData = m_participants[participantId];
|
||||
|
||||
// check structure
|
||||
if (oldParticipantData.equipmentNumber() != data.equipmentNumber() ||
|
||||
oldParticipantData.superiorId() != data.superiorId() ||
|
||||
oldParticipantData.symbol() != data.symbol() ||
|
||||
oldParticipantData.typeId() != data.typeId() ||
|
||||
oldParticipantData.partyId() != data.partyId())
|
||||
setModified(participantId, OcSituation::ModificationFlag::eStructure);
|
||||
|
||||
// check designator
|
||||
if (oldParticipantData.designator() != data.designator() ||
|
||||
oldParticipantData.tacticalIdentifier() != data.tacticalIdentifier())
|
||||
setModified(participantId, OcSituation::ModificationFlag::eDesignator);
|
||||
|
||||
m_participants[participantId] = data;
|
||||
DEBUG_LOG(m_logger) << "updated data in m_participants" << data;
|
||||
|
||||
if (m_modifiedFlags.contains(participantId))
|
||||
{
|
||||
INFO_LOG(m_logger) << "setModified for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId
|
||||
<< " bits: 0x" << QString::number(m_modifiedFlags[participantId], 16);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int getEquipmentStateBits(const ParticipantManagement::DynamicParticipantData &data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret |= int(data.hasNbcProtectionConfigured()) << 1;
|
||||
ret |= int(data.hasNbcProtectionActive()) << 2;
|
||||
ret |= int(data.manipulation().size() > 0) << 7;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
const int participantId = data.participantId();
|
||||
m_allDynamicParticpantData[participantId] = data;
|
||||
|
||||
if (!m_participants.contains(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_participants does not contain participant id: " << participantId;
|
||||
return; // participant does not interest us yet;
|
||||
}
|
||||
|
||||
// old data to check against
|
||||
const ParticipantManagement::DynamicParticipantData &oldDynamicData = m_dynamicParticpantData[participantId];
|
||||
|
||||
// check injury state
|
||||
ParticipantManagement::StateInformation newYoungestInformation = ParticipantManagement::youngestStateInformation(data.stateHistory());
|
||||
ParticipantManagement::StateInformation oldYoungestInformation = ParticipantManagement::youngestStateInformation(oldDynamicData.stateHistory());
|
||||
if (oldYoungestInformation.stateTime() != newYoungestInformation.stateTime() ||
|
||||
oldYoungestInformation.vulnerabilityState() != newYoungestInformation.vulnerabilityState() ||
|
||||
oldYoungestInformation.vulnerabilityBits() != newYoungestInformation.vulnerabilityBits() || // TODO: do we really want to send those bit?
|
||||
m_allParticipants.value(oldYoungestInformation.originatorId()).partyId() != m_allParticipants.value(newYoungestInformation.originatorId()).partyId())
|
||||
setModified(participantId, OcSituation::ModificationFlag::eVBG);
|
||||
|
||||
// check special bits
|
||||
if (getEquipmentStateBits(oldDynamicData) != getEquipmentStateBits(data))
|
||||
setModified(participantId, OcSituation::ModificationFlag::eState);
|
||||
|
||||
m_dynamicParticpantData[participantId] = data;
|
||||
DEBUG_LOG(m_logger) << "updated data in m_dynamicParticpantData" << data;
|
||||
|
||||
if (m_modifiedFlags.contains(participantId))
|
||||
{
|
||||
INFO_LOG(m_logger) << "setModified for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId
|
||||
<< " bits: 0x" << QString::number(m_modifiedFlags[participantId], 16);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
const int participantId = data.participantId();
|
||||
m_allParticipantPositions[participantId] = data;
|
||||
|
||||
// update current center position when we're following a participant
|
||||
if (m_centerType == OcSituation::SituationCenterType::Equipment &&
|
||||
participantId == m_centerParticipantId)
|
||||
m_centerPosition = data.pos();
|
||||
|
||||
if (!m_participants.contains(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_participants does not contain participant id: " << participantId;
|
||||
return; // participant does not interest us yet;
|
||||
}
|
||||
|
||||
// old data to check against
|
||||
const ParticipantManagement::ParticipantPosition &oldPosition = m_participantPositions[participantId];
|
||||
|
||||
// check for ePosition / ePosition3D
|
||||
if (oldPosition.sampleTime() <= data.sampleTime())
|
||||
{
|
||||
//bool isNullOld = qFuzzyIsNull(oldPosition.pos().z());
|
||||
bool isNullNew = qFuzzyIsNull(data.pos().z());
|
||||
|
||||
// if (isNullOld && isNullNew)
|
||||
if (isNullNew)
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition2D);
|
||||
else
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition3D);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
if (isNullOld && isNullNew)
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition2D);
|
||||
else if ((isNullOld && !isNullNew) ||
|
||||
(!isNullOld && isNullNew))
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition3D);
|
||||
else if (!qFuzzyCompare(oldPosition.pos().z(),
|
||||
data.pos().z()))
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition3D);
|
||||
else
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition2D);
|
||||
*/
|
||||
}
|
||||
|
||||
m_participantPositions[participantId] = data;
|
||||
DEBUG_LOG(m_logger) << "updated data in m_participantPositions" << data;
|
||||
|
||||
if (m_modifiedFlags.contains(participantId))
|
||||
{
|
||||
INFO_LOG(m_logger) << "setModified for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId
|
||||
<< " bits: 0x" << QString::number(m_modifiedFlags[participantId], 16);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
if (data.partyId().is_set())
|
||||
m_aesId2PartyId[data.id()] = data.partyId().get();
|
||||
else
|
||||
m_aesId2PartyId.remove(data.id());
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_aesId2PartyId.remove(data.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onDusMineStateChanged(const AreaEffectSimulation::DusMineState &/*data*/, DataModification /*modType*/)
|
||||
{
|
||||
auto copy = m_dynamicParticpantData;
|
||||
for (const ParticipantManagement::DynamicParticipantData &dynPartData : qAsConst(copy))
|
||||
{
|
||||
if (!m_participantWithMaybeMissingPartyId.contains(dynPartData.participantId()))
|
||||
continue;
|
||||
onDynamicParticipantDataChanged(dynPartData, DataModification::eModified);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::handleSituation()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QMutexLocker l(&m_accessMutex);
|
||||
|
||||
if (m_radius == 0)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Do not send Situation as radius is 0, centerEquipmentId " << m_centerEquipmentId
|
||||
<< ", m_position " << m_centerPosition;
|
||||
QTimer::singleShot(0, this, &HandlerOcSituationData::aliveTimeout); // ending thread
|
||||
return;
|
||||
}
|
||||
|
||||
fetchParticipantsInRange();
|
||||
|
||||
auto prioQueue = createPrioQueue();
|
||||
const QByteArray data = createDataStream(Settings::maxNumOfBytePerTxCycle(), prioQueue);
|
||||
if (data.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Don't send empty data to TAB.";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray payload;
|
||||
LtsUtils::set1Byte(m_bInitialDataTransfer ? OcSituation::TelegramId::SituationDataInitial : OcSituation::TelegramId::SituationData, payload);
|
||||
LtsUtils::set1Byte(m_participantOverloaded, payload);
|
||||
m_bInitialDataTransfer = false;
|
||||
|
||||
payload += data;
|
||||
updatePrioOfNotSendParticipants();
|
||||
|
||||
TrainingAreaBase::SendOcDataRequest req;
|
||||
req.equipmentNumber(m_equipmentId);
|
||||
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
||||
emit sendOcData(req);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::resetAliveTimer()
|
||||
{
|
||||
m_aliveTimer->start();
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::aliveTimeout()
|
||||
{
|
||||
INFO_LOG(m_logger) << "O/C-Thread keep alive timeout for O/C-Laptop-Id: " << m_equipmentId
|
||||
<< " - Thread will be finished id: " << QThread::currentThreadId();
|
||||
|
||||
QThread::currentThread()->quit();
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::onResetInternalData()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
INFO_LOG(m_logger) << "Resetting internal data!";
|
||||
m_participants.clear();
|
||||
m_dynamicParticpantData.clear();
|
||||
m_participantPositions.clear();
|
||||
m_modifiedFlags.clear();
|
||||
m_participantsToSend.clear();
|
||||
m_outdatedParticipants.clear();
|
||||
m_newlyOutdatedParticipants.clear();
|
||||
m_participantsNotSend.clear();
|
||||
m_participantId2EqId.clear();
|
||||
m_participantWithMaybeMissingPartyId.clear();
|
||||
|
||||
m_bInitialDataTransfer = true;
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::fetchParticipantsInRange()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
const QPointF relCenterPos = PositionConverter::relativeFromGeographic(m_centerPosition, m_baseCoordinate);
|
||||
|
||||
if (m_centerType == OcSituation::SituationCenterType::Equipment)
|
||||
INFO_LOG(m_logger) << "Fetching participants in radius around equipment " << m_centerEquipmentId
|
||||
<< " with position " << relCenterPos.x() << "/" << relCenterPos.y() << " and radius: " << m_radius << ", " << m_baseCoordinate.mgrs()
|
||||
<< ", " << m_centerPosition.lon() << ", " << m_centerPosition.lat();
|
||||
else
|
||||
INFO_LOG(m_logger) << "Fetching participants in radius of position " << relCenterPos.x() << "/" << relCenterPos.y() << " radius: " << m_radius;
|
||||
|
||||
const double rangeSqr = m_radius * m_radius;
|
||||
QMultiMap<double, int> curParticipantsInRange;
|
||||
QSet<int> curParticipants;
|
||||
const QHash<int, ParticipantManagement::Participant> oldParticipants = m_participants;
|
||||
|
||||
for (const auto &position : qAsConst(m_allParticipantPositions))
|
||||
{
|
||||
if (!LtsUtils::isPositionTimeOutdated(m_partitionTime, position.sampleTime())) // only if position is not outdated
|
||||
{
|
||||
ParticipantManagement::Participant participant = m_allParticipants.value(position.participantId());
|
||||
if (!participant.equipmentNumber().is_set() || participant.partyId() == 0)
|
||||
continue; // no units and participants without equipmentnumber or party: pool
|
||||
if (m_filterActive)
|
||||
{
|
||||
ParticipantManagement::TypeClass typeClass = m_ppmDtc->type(participant.typeId()).typeClass();
|
||||
if ((m_partyList.count() > 0 && m_partyList.contains(participant.partyId()) == false) ||
|
||||
(m_typeClassList.count() > 0 && m_typeClassList.contains(typeClass.underlying()) == false))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << participant.id() << " filtered out";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const QPointF relPartPos(PositionConverter::relativeFromGeographic(position.pos(), m_baseCoordinate));
|
||||
|
||||
double x = relCenterPos.x() - relPartPos.x();
|
||||
double y = relCenterPos.y() - relPartPos.y();
|
||||
int distanceSqr = qRound(x * x + y * y);
|
||||
|
||||
if (distanceSqr > rangeSqr)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Participant NOT in range equipment number: " << participant.equipmentNumber().get()
|
||||
<< " pos: " << relPartPos.x() << "/" << relPartPos.y()
|
||||
<< " distance: " << std::sqrt(distanceSqr) << " distanceSqr: " << distanceSqr;
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Participant in range equipment number: " << participant.equipmentNumber().get()
|
||||
<< " pos: " << relPartPos.x() << "/" << relPartPos.y()
|
||||
<< " distance: " << std::sqrt(distanceSqr) << " distanceSqr: " << distanceSqr;
|
||||
curParticipantsInRange.insertMulti(distanceSqr, participant.id());
|
||||
}
|
||||
}
|
||||
m_participantOverloaded = quint32(curParticipantsInRange.count()) > Settings::maxParticipantsInSituation();
|
||||
|
||||
// only the hundred nearest will be transmitted
|
||||
unsigned int cnt = 0;
|
||||
for (const int id : curParticipantsInRange)
|
||||
{
|
||||
handleParticipant(m_allParticipants.value(id));
|
||||
curParticipants.insert(id);
|
||||
DEBUG_LOG(m_logger) << "Added participant to hundred nearest: " << m_participantId2EqId[id]
|
||||
<< " / " << id;
|
||||
++cnt;
|
||||
if (cnt >= Settings::maxParticipantsInSituation())
|
||||
break;
|
||||
}
|
||||
|
||||
// insert participants, that are now out of range/outdated
|
||||
for (const auto &oldPart : oldParticipants)
|
||||
{
|
||||
const int id = oldPart.id();
|
||||
if (!curParticipants.contains(id))
|
||||
{
|
||||
if (!m_outdatedParticipants.contains(id))
|
||||
{
|
||||
m_newlyOutdatedParticipants.insert(id);
|
||||
m_outdatedParticipants.insert(id);
|
||||
DEBUG_LOG(m_logger) << "Participant outdated: " << m_participantId2EqId[id]
|
||||
<< " / " << id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::handleParticipant(const ParticipantManagement::Participant &participant)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
int participantId = participant.id();
|
||||
if (participant.equipmentNumber().is_set())
|
||||
m_participantId2EqId[participantId] = participant.equipmentNumber().get();
|
||||
else
|
||||
m_participantId2EqId.remove(participantId);
|
||||
|
||||
// now check if is a new participant
|
||||
if (!m_participants.contains(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Adding previously unknown participant to m_participants: " << m_participantId2EqId.value(participantId)
|
||||
<< " / " << participantId;
|
||||
// new participant -> all modified
|
||||
setModified(participantId, OcSituation::ModificationFlag::eAll);
|
||||
m_participants.insert(participantId, participant);
|
||||
m_dynamicParticpantData.insert(participantId, m_allDynamicParticpantData.value(participantId));
|
||||
m_participantPositions.insert(participantId, m_allParticipantPositions.value(participantId));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// old participant, check if was outdated
|
||||
if (m_outdatedParticipants.remove(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Adding old player that is inside the radius again: " << m_participantId2EqId.value(participantId)
|
||||
<< " / " << participantId;
|
||||
if (m_modifiedFlags[participantId] == OcSituation::ModificationFlag::eNone)
|
||||
setModified(participantId, OcSituation::ModificationFlag::ePosition2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sortParticipantsForRange(const QPair<int, float> &p1,
|
||||
const QPair<int, float> &p2)
|
||||
{
|
||||
return p1.second < p2.second;
|
||||
}
|
||||
|
||||
QVector<QPair<int, float>> HandlerOcSituationData::createPrioQueue() const
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QVector<QPair<int, float>> participantsPrioQueue;
|
||||
participantsPrioQueue.reserve(m_participantsToSend.size());
|
||||
|
||||
for (auto participantId : qAsConst(m_participantsToSend))
|
||||
{
|
||||
// ignore (currently) outdated players
|
||||
if (m_outdatedParticipants.contains(participantId))
|
||||
continue;
|
||||
if (!m_participants.contains(participantId))
|
||||
continue;
|
||||
const ParticipantManagement::ParticipantPosition &position = m_participantPositions[participantId];
|
||||
float x = m_centerPosition.lon() - position.pos().lon();
|
||||
float y = m_centerPosition.lat() - position.pos().lon();
|
||||
float r2 = x * x + y * y;
|
||||
float prio = r2;
|
||||
int cntNotSendDbg = 0;
|
||||
QMap<int, int>::const_iterator participantIt = m_participantsNotSend.constFind(participantId);
|
||||
if (participantIt != m_participantsNotSend.constEnd())
|
||||
{
|
||||
cntNotSendDbg = participantIt.value();
|
||||
// Je nicht gesendeten -> 5 % abziehen, aber nie alles
|
||||
const int cntNotSend = participantIt.value() > 20 ? 19 : participantIt.value();
|
||||
DEBUG_LOG(m_logger) << "prio: " << prio << ", prio / 20 * cntNotSend: " << prio / 20 * cntNotSend;
|
||||
prio -= (prio / 20 * cntNotSend);
|
||||
}
|
||||
participantsPrioQueue.push_back(qMakePair(participantId, prio));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Radius from center for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId << " = " << sqrt(r2) << "m, prio: " << prio
|
||||
<< ", not sent: " << cntNotSendDbg << " time(s)";
|
||||
}
|
||||
std::sort(participantsPrioQueue.begin(), participantsPrioQueue.end(), sortParticipantsForRange);
|
||||
return participantsPrioQueue;
|
||||
}
|
||||
|
||||
QByteArray HandlerOcSituationData::createDataStream(int maxSize,
|
||||
const QVector<QPair<int, float>> &participantsPrioQueue)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
|
||||
QByteArray ret;
|
||||
|
||||
// do not send to much in one swoop
|
||||
if (maxSize > 100)
|
||||
maxSize -= 5;
|
||||
|
||||
// first: participants that are not in range any more
|
||||
DEBUG_LOG(m_logger) << "m_newlyOutdatedParticipants: " << m_newlyOutdatedParticipants.size();
|
||||
QSet<int> copyOfOutdated = m_newlyOutdatedParticipants;
|
||||
for (const auto participantId : qAsConst(m_newlyOutdatedParticipants))
|
||||
{
|
||||
addParticipantId(ret, participantId, OcSituation::ModificationFlag::eNone);
|
||||
copyOfOutdated.remove(participantId);
|
||||
|
||||
if (ret.size() < maxSize)
|
||||
continue;
|
||||
|
||||
QByteArray ba = m_bWithCompression ? qCompress(ret) : ret;
|
||||
DEBUG_LOG(m_logger) << "Added info about oudated player " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId
|
||||
<< " data size: " << ret.size()
|
||||
<< " compressed size: " << ba.size();
|
||||
if (ba.size() > maxSize)
|
||||
{
|
||||
m_newlyOutdatedParticipants = copyOfOutdated;
|
||||
TRACE_LOG(m_logger) << "Uncompressed Data: " << ret.toHex(' ');
|
||||
return ba;
|
||||
}
|
||||
}
|
||||
m_newlyOutdatedParticipants = copyOfOutdated;
|
||||
|
||||
// Data updates
|
||||
DEBUG_LOG(m_logger) << "participantsPrioQueue: " << participantsPrioQueue.size();
|
||||
for (auto prioPair : participantsPrioQueue)
|
||||
{
|
||||
int participantId = prioPair.first;
|
||||
if (!m_modifiedFlags.contains(participantId))
|
||||
continue;
|
||||
OcSituation::ModificationBits modifiedFlags = m_modifiedFlags[participantId];
|
||||
|
||||
// should never happen
|
||||
if (modifiedFlags == OcSituation::ModificationFlag::eNone)
|
||||
continue;
|
||||
|
||||
const ParticipantManagement::Participant &data = m_participants[participantId];
|
||||
const ParticipantManagement::DynamicParticipantData &dynamicParticipantData = m_dynamicParticpantData[participantId];
|
||||
const ParticipantManagement::ParticipantPosition &participantPosition = m_participantPositions[participantId];
|
||||
|
||||
// default DynamicParticipantData crashes the tablet software. we skip it ... for now
|
||||
if (dynamicParticipantData == ParticipantManagement::DynamicParticipantData())
|
||||
{
|
||||
INFO_LOG(m_logger) << "There is only default DynamicParticipantData for participant with id " << participantId << " --> skipping";
|
||||
continue;
|
||||
}
|
||||
|
||||
addParticipantId(ret, participantId, modifiedFlags);
|
||||
addPosition2D(ret, participantPosition, (modifiedFlags & OcSituation::ModificationFlag::ePosition2D) == OcSituation::ModificationFlag::ePosition2D);
|
||||
addPosition3D(ret, participantPosition, (modifiedFlags & OcSituation::ModificationFlag::ePosition3D) == OcSituation::ModificationFlag::ePosition3D);
|
||||
addVBG(ret, dynamicParticipantData, (modifiedFlags & OcSituation::ModificationFlag::eVBG) == OcSituation::ModificationFlag::eVBG);
|
||||
addState(ret, dynamicParticipantData, (modifiedFlags & OcSituation::ModificationFlag::eState) == OcSituation::ModificationFlag:: eState);
|
||||
addStructure(ret, data, (modifiedFlags & OcSituation::ModificationFlag::eStructure) == OcSituation::ModificationFlag::eStructure);
|
||||
addDesignator(ret, data, (modifiedFlags & OcSituation::ModificationFlag::eDesignator) == OcSituation::ModificationFlag::eDesignator);
|
||||
addSymbolSidc(ret, data, (modifiedFlags & OcSituation::ModificationFlag::eSymbol) == OcSituation::ModificationFlag::eSymbol);
|
||||
|
||||
clearModified(participantId);
|
||||
|
||||
if (ret.size() < maxSize)
|
||||
continue;
|
||||
|
||||
QByteArray ba = m_bWithCompression ? qCompress(ret) : ret;
|
||||
DEBUG_LOG(m_logger) << "Added info about changed player " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId
|
||||
<< " bits: 0x" << QString::number(modifiedFlags, 16)
|
||||
<< " data size: " << ret.size()
|
||||
<< " compressed: " << ba.size();
|
||||
if (ba.size() > maxSize)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << ret.toHex(' ');
|
||||
return ba;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uncompressed Data: " << ret.toHex(' ');
|
||||
return m_bWithCompression ? qCompress(ret) : ret;
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::updatePrioOfNotSendParticipants()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
// add a prio bonus to all participants not send this cycle
|
||||
QMap<int, OcSituation::ModificationBits>::const_iterator it = m_modifiedFlags.constBegin();
|
||||
for (; it != m_modifiedFlags.constEnd(); ++it)
|
||||
{
|
||||
const int participantId = it.key();
|
||||
QMap<int, int>::iterator participantIt = m_participantsNotSend.find(participantId);
|
||||
int notSentSince = 0;
|
||||
if (participantIt == m_participantsNotSend.end())
|
||||
{
|
||||
m_participantsNotSend.insert(participantId, 1);
|
||||
notSentSince = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
participantIt.value()++;
|
||||
notSentSince = participantIt.value();
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Player " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId << " not sent for " << notSentSince << " time(s)";
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::setModified(int participantId, OcSituation::ModificationBits bits)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
DEBUG_LOG(m_logger) << "setModified " << bits << " for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId;
|
||||
m_participantsToSend.insert(participantId);
|
||||
|
||||
if (!m_modifiedFlags.contains(participantId))
|
||||
{
|
||||
// new entry
|
||||
m_modifiedFlags.insert(participantId, bits);
|
||||
return;
|
||||
}
|
||||
m_modifiedFlags[participantId] |= bits;
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::clearModified(int participantId)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION;
|
||||
DEBUG_LOG(m_logger) << "clearModified for: " << m_participantId2EqId[participantId]
|
||||
<< " / " << participantId;
|
||||
m_modifiedFlags.remove(participantId);
|
||||
m_participantsNotSend.remove(participantId);
|
||||
m_participantsToSend.remove(participantId);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addParticipantId(QByteArray &buf, const int participantId, OcSituation::ModificationBits modifiedFlags) const
|
||||
{
|
||||
LtsUtils::set2Byte(participantId, buf);
|
||||
LtsUtils::set1Byte(modifiedFlags, buf);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addPosition2D(QByteArray &buf, const ParticipantManagement::ParticipantPosition &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
LtsUtils::set8Byte(data.pos().lon(), buf);
|
||||
LtsUtils::set8Byte(data.pos().lat(), buf);
|
||||
// no timestamp, as it is set in the client anyway
|
||||
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addPosition3D(QByteArray &buf, const ParticipantManagement::ParticipantPosition &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
addPosition2D(buf, data, bAdd);
|
||||
LtsUtils::set8Byte(data.pos().z(), buf);
|
||||
LtsUtils::set2Byte(data.buildingId(), buf);
|
||||
LtsUtils::set4Byte(data.roomId(), buf);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addVBG(QByteArray &buf, const ParticipantManagement::DynamicParticipantData &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
|
||||
const ParticipantManagement::StateInformation &youngestStateInformation = ParticipantManagement::youngestStateInformation(data.stateHistory(), true, false);
|
||||
|
||||
LtsUtils::set1Byte(youngestStateInformation.vulnerabilityState().underlying(), buf);
|
||||
LtsUtils::set4Byte(youngestStateInformation.vulnerabilityKindId(), buf);
|
||||
LtsUtils::set2Byte(youngestStateInformation.vulnerabilityBits(), buf);
|
||||
|
||||
int injuryPartyId = 1;
|
||||
switch (youngestStateInformation.originatorType().underlying())
|
||||
{
|
||||
case ProjectDataManagement::StateChangeOriginator_def::Unknown:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::ExerciseControl:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::ObserverController:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::Initialization:
|
||||
injuryPartyId = 1; // O/C
|
||||
break;
|
||||
case ProjectDataManagement::StateChangeOriginator_def::Participant:
|
||||
injuryPartyId = m_allParticipants.value(youngestStateInformation.originatorId()).partyId();
|
||||
if (injuryPartyId == 0)
|
||||
injuryPartyId = 1;
|
||||
break;
|
||||
case ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::FunctionalArea:
|
||||
{
|
||||
auto it = m_aesId2PartyId.constFind(youngestStateInformation.originatorId());
|
||||
if (it != m_aesId2PartyId.constEnd())
|
||||
injuryPartyId = it.value();
|
||||
break;
|
||||
}
|
||||
case ProjectDataManagement::StateChangeOriginator_def::DusMine:
|
||||
{
|
||||
int partyId = m_aesDtc->partyForDusMine(youngestStateInformation.originatorId());
|
||||
if (partyId >= 0)
|
||||
injuryPartyId = partyId;
|
||||
|
||||
if (partyId == -1)
|
||||
m_participantWithMaybeMissingPartyId.insert(data.participantId());
|
||||
else
|
||||
m_participantWithMaybeMissingPartyId.remove(data.participantId());
|
||||
|
||||
break;
|
||||
}
|
||||
case ProjectDataManagement::StateChangeOriginator_def::ImprovisedExplosiveDevice:
|
||||
{
|
||||
const auto ied = m_gimDtc->iedForEquipmentNumber(youngestStateInformation.originatorId());
|
||||
if (ied.equipmentNumber() != 0)
|
||||
injuryPartyId = ied.partyId();
|
||||
break;
|
||||
}
|
||||
case ProjectDataManagement::StateChangeOriginator_def::WoundTreatmentDevice:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::MaintainanceDevice:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::Sanitation:
|
||||
case ProjectDataManagement::StateChangeOriginator_def::MedicalTimeout:
|
||||
// not yet used
|
||||
break;
|
||||
}
|
||||
LtsUtils::set1Byte(injuryPartyId, buf);
|
||||
|
||||
if (m_bWithVBGTime)
|
||||
LtsUtils::set4Byte(youngestStateInformation.stateTime() / 1000, buf);
|
||||
|
||||
//add vitality and sanitation result
|
||||
// Quick fix: If vitality is
|
||||
uint8_t vitRes = (youngestStateInformation.vitality() / 10);
|
||||
if (vitRes > 10)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Vitality of Participant " << data.participantId() << " is not between 0 and 100%. Putting to 100%";
|
||||
vitRes = 10;
|
||||
}
|
||||
vitRes += ((int)youngestStateInformation.sanitationResult().underlying() << 4);
|
||||
LtsUtils::set1Byte(vitRes, buf);
|
||||
//finall 1 Byte for originator and maybe more
|
||||
LtsUtils::set1Byte(youngestStateInformation.originatorType().underlying(), buf);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addState(QByteArray &buf, const ParticipantManagement::DynamicParticipantData &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
LtsUtils::set1Byte(getEquipmentStateBits(data), buf);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addStructure(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
LtsUtils::set2Byte(data.equipmentNumber().is_set() ? data.equipmentNumber().get() : 0, buf);
|
||||
LtsUtils::set2Byte(data.typeId(), buf);
|
||||
LtsUtils::set2Byte(data.partyId(), buf);
|
||||
#ifndef GUEZ_MODE
|
||||
LtsUtils::set2Byte(data.superiorId(), buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addDesignator(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
const size_t len1 = std::min(data.designator().size(), size_t(15));
|
||||
const size_t len2 = std::min(data.tacticalIdentifier().size(), size_t(15));
|
||||
unsigned char len = ((len1 & 0x0F) | ((len2 & 0x0F) << 4));
|
||||
LtsUtils::set1Byte(len, buf);
|
||||
buf.append(data.designator().c_str(), len1);
|
||||
buf.append(data.tacticalIdentifier().c_str(), len2);
|
||||
}
|
||||
|
||||
void HandlerOcSituationData::addSymbolSidc(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const
|
||||
{
|
||||
if (!bAdd)
|
||||
return;
|
||||
const auto type = m_ppmDtc->type(data.typeId());
|
||||
if (type.symbol() == data.symbol())
|
||||
{
|
||||
LtsUtils::set1Byte(0, buf); // 0 bytes -> marker for not sending the symbol sidc since it can be taken from the type
|
||||
return;
|
||||
}
|
||||
if (data.symbol().size() > 255)
|
||||
return;
|
||||
const size_t len1 = std::min(data.symbol().size(), size_t(255));
|
||||
LtsUtils::set1Byte(len1, buf);
|
||||
buf.append(data.symbol().c_str(), len1);
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Handler for all oc situation data at the server per client
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 27-02-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "position_converter.h"
|
||||
#include "oc_situation.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
class HandlerOcSituationData;
|
||||
|
||||
|
||||
class ThreadOcSituationData : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThreadOcSituationData(MainHandler *mainHandler,
|
||||
int equipmentId,
|
||||
int centerEquipmentId,
|
||||
int radius,
|
||||
bool filterActive,
|
||||
QSet<int> partys,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClasses);
|
||||
|
||||
public slots:
|
||||
void requestOcSituationData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D &position,
|
||||
int radius,
|
||||
bool filterActive,
|
||||
QSet<int> partyList,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClassList,
|
||||
bool initial);
|
||||
|
||||
signals:
|
||||
void sendOcData(const TrainingAreaBase::SendOcDataRequest &);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
OcSituation::SituationCenterType m_centerType = OcSituation::SituationCenterType::Equipment; // which kind of center is used for the situation
|
||||
Core::GeoPosition2D m_position; // center position a situation can be requested around
|
||||
LtsCoordTrans::UtmCoordinate m_baseCoordinate;
|
||||
|
||||
int m_equipmentId{0}; // id from requesting OC-laptop
|
||||
int m_centerEquipmentId{0}; // equipment in the center of situation
|
||||
int m_radius{0}; // observer radius in meter
|
||||
QSet<int> m_partyList;
|
||||
bool m_filterActive;
|
||||
QSet<ParticipantManagement::TypeClass::type> m_typeClassList;
|
||||
|
||||
MainHandler *m_mainHandler{nullptr}; // provides TAB FTC and PPM DTC
|
||||
HandlerOcSituationData *m_handler{nullptr}; // OC-Thread-Object
|
||||
QMutex m_accessMutex; // Mutex-Object
|
||||
|
||||
LOGGER_T &m_logger; // Logger-Object
|
||||
};
|
||||
|
||||
|
||||
class HandlerOcSituationData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HandlerOcSituationData(const std::shared_ptr<DdsHandler> &dds,
|
||||
const LtsCoordTrans::UtmCoordinate &baseCoordinate,
|
||||
int equipmentId);
|
||||
|
||||
bool withCompression() const { return m_bWithCompression; }
|
||||
void setWithCompression(bool bOn) { m_bWithCompression = bOn; }
|
||||
bool withVBGTime() const { return m_bWithVBGTime; }
|
||||
void setWithVBGTime(bool bOn) { m_bWithVBGTime = bOn; }
|
||||
|
||||
private:
|
||||
void fetchParticipantsInRange();
|
||||
void handleParticipant(const ParticipantManagement::Participant &participant);
|
||||
|
||||
QVector<QPair<int, float>> createPrioQueue() const;
|
||||
QByteArray createDataStream(int maxSize, const QVector<QPair<int, float>> &participantsPrioQueue);
|
||||
void updatePrioOfNotSendParticipants();
|
||||
void setModified(int participantId, OcSituation::ModificationBits bits);
|
||||
void clearModified(int participantId);
|
||||
|
||||
// Building Byte Stream
|
||||
void addParticipantId(QByteArray &buf, const int participantId, OcSituation::ModificationBits modifiedFlags) const;
|
||||
void addPosition2D(QByteArray &buf, const ParticipantManagement::ParticipantPosition &data, bool bAdd) const;
|
||||
void addPosition3D(QByteArray &buf, const ParticipantManagement::ParticipantPosition &data, bool bAdd) const;
|
||||
void addVBG(QByteArray &buf, const ParticipantManagement::DynamicParticipantData &data, bool bAdd) const;
|
||||
void addState(QByteArray &buf, const ParticipantManagement::DynamicParticipantData &data, bool bAdd) const;
|
||||
void addStructure(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const;
|
||||
void addDesignator(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const;
|
||||
void addSymbolSidc(QByteArray &buf, const ParticipantManagement::Participant &data, bool bAdd) const;
|
||||
|
||||
public slots:
|
||||
void setRequestOcSituationData(OcSituation::SituationCenterType centerType,
|
||||
int centerEquipmentId,
|
||||
const Core::GeoPosition2D ¢erPosition,
|
||||
int radius, bool filterActive,
|
||||
QSet<int> partys,
|
||||
QSet<ParticipantManagement::TypeClass::type> typeClasses,
|
||||
bool initial);
|
||||
|
||||
private slots:
|
||||
void onPartitionTimeChanged(qint64 partitionTime) { m_partitionTime = partitionTime; }
|
||||
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
|
||||
void onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType);
|
||||
void onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType);
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
|
||||
void onDusMineStateChanged(const AreaEffectSimulation::DusMineState &data, DataModification modType);
|
||||
|
||||
void handleSituation();
|
||||
void resetAliveTimer();
|
||||
void aliveTimeout();
|
||||
void onResetInternalData();
|
||||
|
||||
signals:
|
||||
void sendOcData(const TrainingAreaBase::SendOcDataRequest &);
|
||||
void resetInternalData();
|
||||
|
||||
private:
|
||||
LtsCoordTrans::UtmCoordinate m_baseCoordinate;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> m_gimDtc;
|
||||
|
||||
// request data
|
||||
OcSituation::SituationCenterType m_centerType{OcSituation::SituationCenterType::Equipment}; // which kind of center is used for the situation
|
||||
Core::GeoPosition2D m_centerPosition; // center position a situation can be requested around
|
||||
int m_equipmentId{0}; // id from requesting OC-laptop
|
||||
int m_centerEquipmentId{0}; // equipment in the center of situation
|
||||
int m_centerParticipantId{0};
|
||||
int m_radius{0}; // observer radius in meter
|
||||
int m_retryCount{0};
|
||||
bool m_participantOverloaded{false};
|
||||
|
||||
// internal participant data
|
||||
QHash<int, ParticipantManagement::Participant> m_participants;
|
||||
QHash<int, ParticipantManagement::DynamicParticipantData> m_dynamicParticpantData;
|
||||
QHash<int, ParticipantManagement::ParticipantPosition> m_participantPositions;
|
||||
|
||||
QHash<int, ParticipantManagement::Participant> m_allParticipants;
|
||||
QHash<int, ParticipantManagement::DynamicParticipantData> m_allDynamicParticpantData;
|
||||
QHash<int, ParticipantManagement::ParticipantPosition> m_allParticipantPositions;
|
||||
|
||||
mutable QSet<int> m_participantWithMaybeMissingPartyId; // <participantId> originatorType==DusMine
|
||||
|
||||
QHash<int, int> m_aesId2PartyId;
|
||||
|
||||
// situation management data
|
||||
QMap<int, OcSituation::ModificationBits> m_modifiedFlags;
|
||||
QSet<int> m_participantsToSend;
|
||||
QSet<int> m_outdatedParticipants;
|
||||
QSet<int> m_newlyOutdatedParticipants;
|
||||
QMap<int, int> m_participantsNotSend; // map <particpant Id, count of not send>
|
||||
QMap<int, int> m_participantId2EqId; // for debugging purposes
|
||||
QSet<ParticipantManagement::TypeClass::type> m_typeClassList;
|
||||
QSet<int> m_partyList;
|
||||
bool m_filterActive;
|
||||
|
||||
// options, must be in sync with osc
|
||||
bool m_bWithCompression{true};
|
||||
bool m_bWithVBGTime{true};
|
||||
bool m_bInitialDataTransfer{true};
|
||||
|
||||
qint64 m_partitionTime;
|
||||
|
||||
// thread management
|
||||
QMutex m_accessMutex; // Mutex-Object
|
||||
QTimer *m_aliveTimer{nullptr}; // alive timer
|
||||
QTimer *m_txTimer{nullptr}; // tx cycle timer
|
||||
|
||||
LOGGER_T &m_logger;
|
||||
};
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# Service: OcSituationServer
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.OSS=DEBUG
|
||||
#log4j.logger.OSS.main=DEBUG
|
||||
#log4j.logger.OSS.DdsHandler=DEBUG
|
||||
#log4j.logger.OSS.MainHandler=DEBUG
|
||||
#log4j.logger.OSS.HandlerOcAesData=DEBUG
|
||||
#log4j.logger.OSS.HandlerOcData=INFO
|
||||
#log4j.logger.OSS.HandlerOcSituationData=INFO
|
||||
#log4j.logger.OSS.ThreadOcSituationData=INFO
|
||||
#log4j.logger.OSS.HandlerOcSituationData.2501=INFO
|
||||
#log4j.logger.OSS.ThreadOcSituationData.2501=INFO
|
||||
#log4j.logger.OSS.PositionConverter=DEBUG
|
||||
#log4j.logger.OSS.HandlerOcCentralAesData=DEBUG
|
||||
#log4j.logger.OSS.ThreadOcCentralAesData=DEBUG
|
||||
#log4j.logger.OSS.CentralAesDataQueue=DEBUG
|
||||
|
||||
#
|
||||
# Lts::RollingFileAppender
|
||||
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:
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "OSS.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "oss_export.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
using LOGGER_T = NGL::INGLLogger &;
|
||||
|
||||
OSS_COMMON_EXPORT LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace OcSituationServer
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
#include "settings.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
|
||||
LtsCommandLineParser::LtsCommandLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
app.createLogger("OSS", options.exerciseId());
|
||||
|
||||
OcSituationServer::Settings::setIniFile(options.iniFile());
|
||||
|
||||
int iRet = -3;
|
||||
{
|
||||
std::unique_ptr<OcSituationServer::MainHandler> mainHandler(new OcSituationServer::MainHandler);
|
||||
|
||||
if (!mainHandler->init(options.domainId(), options.exerciseId()))
|
||||
return iRet;
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
iRet = app.exec();
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* MainHandler for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 14-02-2018
|
||||
*/
|
||||
|
||||
#include "main_handler.h"
|
||||
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
|
||||
#include "handler_oc_data.h"
|
||||
#include "position_converter.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
MainHandler::MainHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_exerciseId(0)
|
||||
, m_ddsHandler(nullptr)
|
||||
, m_dbHandler(nullptr)
|
||||
, m_handlerOcData(nullptr)
|
||||
, m_positionConverter(nullptr)
|
||||
, m_aesDtc(nullptr)
|
||||
, m_evlDtc(nullptr)
|
||||
, m_evlFtc(nullptr)
|
||||
, m_gimDtc(nullptr)
|
||||
, m_msgFtc(nullptr)
|
||||
, m_ppmDtc(nullptr)
|
||||
, m_ppmFtc(nullptr)
|
||||
, m_tabDtc(nullptr)
|
||||
, m_tabFtc(nullptr)
|
||||
, m_logger(getLogger("MainHandler"))
|
||||
{}
|
||||
|
||||
MainHandler::~MainHandler()
|
||||
{
|
||||
m_handlerOcData = nullptr;
|
||||
m_positionConverter = nullptr;
|
||||
m_aesDtc = nullptr;
|
||||
m_evlDtc = nullptr;
|
||||
m_evlFtc = nullptr;
|
||||
m_gimDtc = nullptr;
|
||||
m_msgFtc = nullptr;
|
||||
m_ppmDtc = nullptr;
|
||||
m_ppmFtc = nullptr;
|
||||
m_tabDtc = nullptr;
|
||||
m_tabFtc = nullptr;
|
||||
|
||||
m_ddsHandler = nullptr;
|
||||
m_dbHandler = nullptr;
|
||||
}
|
||||
|
||||
bool MainHandler::init(int domainId, int exerciseId)
|
||||
{
|
||||
m_exerciseId = exerciseId;
|
||||
|
||||
// register TrainingAreaBase::SendOcDataRequest for signal/slot connection from OC-threads
|
||||
qRegisterMetaType<ParticipantManagement::Participant>("ParticipantManagement::Participant");
|
||||
qRegisterMetaType<ParticipantManagement::DynamicParticipantData>("ParticipantManagement::DynamicParticipantData");
|
||||
qRegisterMetaType<ParticipantManagement::ParticipantPosition>("ParticipantManagement::ParticipantPosition");
|
||||
qRegisterMetaType<TrainingAreaBase::SendOcDataRequest>("TrainingAreaBase::SendOcDataRequest");
|
||||
qRegisterMetaType<DataModification>("DataModification");
|
||||
|
||||
// initialize database
|
||||
m_dbHandler = std::make_shared<DbHandler>();
|
||||
|
||||
if (!m_dbHandler->init(exerciseId, Settings::settings()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation dbHandler failed.";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Initialisation dbHandler succesful.";
|
||||
|
||||
// initialize DDS
|
||||
m_ddsHandler = std::make_shared<DdsHandler>(domainId, exerciseId);
|
||||
if (!m_ddsHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation ddsHandler failed.";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Initialisation ddsHandler succesful.";
|
||||
|
||||
// create AES Dtc
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created AES Dtc";
|
||||
|
||||
// create EVL Dtc
|
||||
m_evlDtc = Evaluations::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created EVL Dtc";
|
||||
|
||||
// create EVL Ftc
|
||||
m_evlFtc = Evaluations::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created EVL Ftc";
|
||||
|
||||
// create GIM Dtc
|
||||
m_gimDtc = GuezIedManagement::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created GIM Dtc";
|
||||
|
||||
// create MSG Ftc
|
||||
m_msgFtc = Messaging::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created Msg Ftc";
|
||||
|
||||
// create PPM Dtc
|
||||
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created PPM Dtc";
|
||||
|
||||
// create PPM Ftc
|
||||
m_ppmFtc = ParticipantManagement::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created PPM Dtc";
|
||||
|
||||
// create TAB Dtc
|
||||
m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created TAB Dtc";
|
||||
|
||||
// create TAB Ftc
|
||||
m_tabFtc = TrainingAreaBase::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
DEBUG_LOG(m_logger) << "Created TAB Ftc";
|
||||
|
||||
// create position converter
|
||||
m_positionConverter = std::make_shared<PositionConverter>(this);
|
||||
|
||||
// create handler oc-data
|
||||
m_handlerOcData = std::make_shared<HandlerOcData>(this, this);
|
||||
if (!m_handlerOcData->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation HandlerOcData failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::Running);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace OcSituationServer
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* MainHandler for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 14-02-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <Evaluations/evl_dtc.h>
|
||||
#include <Evaluations/evl_ftc.h>
|
||||
#include <GuezIedManagement/gim_dtc.h>
|
||||
#include <Messaging/msg_ftc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
|
||||
#include <TrainingAreaBase/tab_dtc.h>
|
||||
#include <TrainingAreaBase/tab_ftc.h>
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include <ngldb/db_service_handler.h>
|
||||
|
||||
#include "oss_db.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace NGLDB
|
||||
{
|
||||
template <typename DB> class DbServiceHandler;
|
||||
}
|
||||
namespace OcSituationServer
|
||||
{
|
||||
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
|
||||
class HandlerOcData;
|
||||
class PositionConverter;
|
||||
class MainHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainHandler(QObject *parent = nullptr);
|
||||
~MainHandler();
|
||||
|
||||
bool init(int domainId, int exerciseId);
|
||||
|
||||
std::shared_ptr<DdsHandler> dds() const { return m_ddsHandler; }
|
||||
std::shared_ptr<DatabaseInterface> db() const { return m_dbHandler->db(); }
|
||||
std::shared_ptr<PositionConverter> positionConverter() const { return m_positionConverter; }
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> aesDtc() const { return m_aesDtc; }
|
||||
std::shared_ptr<Evaluations::Interface::Dtc> evlDtc() const { return m_evlDtc; }
|
||||
std::shared_ptr<Evaluations::Interface::Ftc> evlFtc() const { return m_evlFtc; }
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> gimDtc() const { return m_gimDtc; }
|
||||
std::shared_ptr<Messaging::Interface::Ftc> msgFtc() const { return m_msgFtc; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> ppmDtc() const { return m_ppmDtc; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> ppmFtc() const { return m_ppmFtc; }
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> tabDtc() const { return m_tabDtc; }
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> tabFtc() const { return m_tabFtc; }
|
||||
|
||||
int exerciseId() const { return m_exerciseId; }
|
||||
|
||||
private:
|
||||
int m_exerciseId;
|
||||
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<HandlerOcData> m_handlerOcData;
|
||||
std::shared_ptr<PositionConverter> m_positionConverter;
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<Evaluations::Interface::Dtc> m_evlDtc;
|
||||
std::shared_ptr<Evaluations::Interface::Ftc> m_evlFtc;
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> m_gimDtc;
|
||||
std::shared_ptr<Messaging::Interface::Ftc> m_msgFtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> m_tabDtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> m_tabFtc;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace OcSituationServer
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Types to be used for transparent OC communication
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLSE, 2018-02-20
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace OcSituation
|
||||
{
|
||||
|
||||
enum TelegramId
|
||||
{
|
||||
DemandSituation = 131,
|
||||
SituationData = 132,
|
||||
StateInformation = 133,
|
||||
SituationDataInitial = 134,
|
||||
CentralAesData = 135,
|
||||
CentralAesDataInitial = 136,
|
||||
|
||||
DemandEvaluationSchema = 111,
|
||||
EvaluationSchema = 148,
|
||||
Evaluation = 112,
|
||||
|
||||
Message = 130,
|
||||
|
||||
DemandAesItems = 114,
|
||||
AesItems = 166,
|
||||
|
||||
EquipmentErrorRegistration = 113,
|
||||
EquipmentRegistration = 115,
|
||||
|
||||
SingleMine = 117,
|
||||
MineClearancePositions = 167,
|
||||
MineClearanceArea = 168
|
||||
};
|
||||
|
||||
enum CentralAesChangeType
|
||||
{
|
||||
AddMod = 1,
|
||||
Remove = 2
|
||||
};
|
||||
|
||||
enum ModificationFlag
|
||||
{
|
||||
eNone = 0, // == Player is out of range -> do not display
|
||||
ePosition2D = (1 << 0), // x,y,sampleTime
|
||||
ePosition3D = (1 << 1), // x,y,z,sampleTime
|
||||
eVBG = (1 << 2), // injuryState, partei_zustand_aenderung, sampleTime
|
||||
eState = (1 << 3), // bits, totalStateInformationBits
|
||||
eStructure = (1 << 4), // equipmentNumber, typeId, partyId
|
||||
eDesignator = (1 << 5), // designator, tacticalIdentifier
|
||||
eSymbol = (1 << 6), // SIDC string (20Bytes)
|
||||
|
||||
eAll = (ePosition3D | eVBG | eState | eStructure | eDesignator | eSymbol)
|
||||
};
|
||||
typedef int ModificationBits;
|
||||
|
||||
enum AesType
|
||||
{
|
||||
Ied = 1,
|
||||
IedPositions = 2,
|
||||
ExplosionSingleSMart = 11,
|
||||
ExplosionAreaSMart = 12,
|
||||
DusMineArea = 13,
|
||||
DangerArea = 14,
|
||||
};
|
||||
|
||||
enum SituationCenterType
|
||||
{
|
||||
Equipment = 1,
|
||||
Position = 2
|
||||
};
|
||||
|
||||
} // namespace OcSituation
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef OSS_COMMON_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define OSS_COMMON_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCOSSCOMMON_LIB)
|
||||
# define OSS_COMMON_EXPORT Q_DECL_EXPORT
|
||||
# ifndef WIN32
|
||||
# ifdef NDDSUSERDllExport
|
||||
# undef NDDSUSERDllExport
|
||||
# endif
|
||||
# define NDDSUSERDllExport Q_DECL_EXPORT
|
||||
# endif
|
||||
# else
|
||||
# define OSS_COMMON_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OSS_CLIENT_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define OSS_CLIENT_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCOSSCLIENT_LIB)
|
||||
# define OSS_CLIENT_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define OSS_CLIENT_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OSS_SERVER_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define OSS_SERVER_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCOSSSERVER_LIB)
|
||||
# define OSS_SERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define OSS_SERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Initial reset counter an creation
|
||||
-- IED reset counter
|
||||
INSERT INTO oss_reset_counter (aes_type_id, reset_counter) VALUES (1, 0);
|
||||
-- Danger area reset counter
|
||||
INSERT INTO oss_reset_counter (aes_type_id, reset_counter) VALUES (14, 0);
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<service namespace="OcSituationServer" abbreviation="OSS" procNames="OcSituationServer" exerciseDependency="Exercise" groups="ExerciseExecution,ExercisePaused" prio="">
|
||||
<rcs>
|
||||
<Id Id="$Id: ea_export_script.txt 41311 2018-04-23 09:43:45Z ehrlicher $"/>
|
||||
<HeadURL HeadURL="$HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Common/CodeGen/ea_export_script.txt $"/>
|
||||
<Author Author="$Author: ehrlicher $"/>
|
||||
</rcs>
|
||||
<tables>
|
||||
<table name="oss_reset_counter">
|
||||
<column name="aes_type_id" datatype="integer" isPrimaryKey="1">
|
||||
<sequence start="1" increment="1"/>
|
||||
</column>
|
||||
<column name="reset_counter" datatype="integer"/>
|
||||
</table>
|
||||
</tables>
|
||||
<views/>
|
||||
<dbServiceStructs>
|
||||
<serviceStruct name="OssResetCounter" table="oss_reset_counter"/>
|
||||
<table name="oss_reset_counter"/>
|
||||
</dbServiceStructs>
|
||||
<topicTypes>
|
||||
<topicType name="EquipmentErrorRegistration" isDataObject="1" autosubscribe="1" routeToClient="1" routeToServer="0" routeInReplay="0" recordTopic="1" baseValueType="Core::BaseEntity">
|
||||
<column name="equipmentNumber" idlType="long"/>
|
||||
<column name="sampleTime" idlType="long long"/>
|
||||
<column name="participant" idlType="string"/>
|
||||
<column name="device" idlType="string"/>
|
||||
<column name="text" idlType="string"/>
|
||||
</topicType>
|
||||
<topicType name="EquipmentErrorRequest">
|
||||
<column name="requestId" idlType="long" isKey="1"/>
|
||||
<column name="equipmentNumber" idlType="long"/>
|
||||
<column name="device" idlType="string"/>
|
||||
<column name="text" idlType="string"/>
|
||||
</topicType>
|
||||
<topicType name="SendEquipmentMessageRequest">
|
||||
<column name="requestId" idlType="long" isKey="1"/>
|
||||
<column name="equipmentNumbers" idlType="sequence<long>"/>
|
||||
<column name="sender" idlType="long"/>
|
||||
<column name="senderType" idlType="Messaging::AddressType"/>
|
||||
<column name="subject" idlType="string"/>
|
||||
<column name="message" idlType="string"/>
|
||||
</topicType>
|
||||
</topicTypes>
|
||||
<functionTopics>
|
||||
<functionTopic name="EquipmentError" requestTopicType="EquipmentErrorRequest" replyTopicType="Core::FunctionReply" requestTopicName="EquipmentErrorRequest" replyTopicName="EquipmentErrorReply" routeInReplay="0"/>
|
||||
<functionTopic name="SendEquipmentMessageOc" requestTopicType="SendEquipmentMessageRequest" replyTopicType="Core::FunctionReply" requestTopicName="SendEquipmentMessageOcRequest" replyTopicName="SendEquipmentMessageOcReply" routeInReplay="0"/>
|
||||
</functionTopics>
|
||||
<enumerations>
|
||||
<enumeration name="DummyEnum">
|
||||
<attribute key="dummy" value="0"/>
|
||||
</enumeration>
|
||||
</enumerations>
|
||||
</service>
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Converting positions relative to the training area
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 21-04-2018
|
||||
*/
|
||||
|
||||
#include "position_converter.h"
|
||||
|
||||
#include <AssetManagement/asm_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <QMutex>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
PositionConverter::PositionConverter(MainHandler *m_mainHandler)
|
||||
: m_mainHandler(m_mainHandler)
|
||||
, m_baseCoord(LtsCoordTrans::UtmCoordinate())
|
||||
, m_asmDtc(AssetManagement::Interface::Dtc::create(m_mainHandler->dds()->dds()))
|
||||
, m_exmDtc(ExerciseManagement::Interface::Dtc::create(m_mainHandler->dds()->dds()))
|
||||
, m_logger(getLogger("PositionConverter"))
|
||||
{
|
||||
m_exmDtc->enableExercise();
|
||||
m_asmDtc->enableTrainingArea();
|
||||
}
|
||||
|
||||
LtsCoordTrans::UtmCoordinate PositionConverter::baseCoordinate()
|
||||
{
|
||||
initCoordConversion();
|
||||
return m_baseCoord;
|
||||
}
|
||||
|
||||
bool PositionConverter::initCoordConversion()
|
||||
{
|
||||
static QMutex mutex;
|
||||
QMutexLocker l(&mutex);
|
||||
|
||||
if (!m_exmDtc)
|
||||
return true;
|
||||
|
||||
if (!m_exmDtc->waitForHistoricalDataExercise(15000))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing ExerciseManagement DTC";
|
||||
return false;
|
||||
}
|
||||
const auto ex = m_exmDtc->exercise(m_mainHandler->exerciseId());
|
||||
if (ex.id() <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not retrieve exercise information for id " << m_mainHandler->exerciseId();
|
||||
return false;
|
||||
}
|
||||
if (!m_asmDtc->waitForHistoricalDataTrainingArea(10000))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing AssetManagement DTC";
|
||||
return false;
|
||||
}
|
||||
const auto ta = m_asmDtc->trainingArea(ex.trainingAreaId());
|
||||
if (ta.id() <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not retrieve training are information for id " << ex.trainingAreaId();
|
||||
return false;
|
||||
}
|
||||
|
||||
// calc tetra base point from training area center
|
||||
const LtsCoordTrans::UtmCoordinate bottomLeft(LtsCoordTrans::UtmCoordinate::fromGeographic(ta.bottomLeft().lon(), ta.bottomLeft().lat()));
|
||||
const QPointF mid(bottomLeft.geographic(ta.width() / 2, ta.height() / 2));
|
||||
|
||||
// our center point is NNxYY 00000 00000 by definition
|
||||
// (we can also use current ta center but the it's hard to debug the coordinates in Tetra LogViewer)
|
||||
const QString mgrs(LtsCoordTrans::mgrsFromGeographic(mid.x(), mid.y(), -1) + QStringLiteral("00000000000000"));
|
||||
|
||||
// now we've the correct tetra base point
|
||||
m_baseCoord = LtsCoordTrans::UtmCoordinate::fromMgrs(mgrs);
|
||||
|
||||
m_asmDtc.reset();
|
||||
m_exmDtc.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Converting positions relative to the training area
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, NLST, 21-04-2018
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <Core/core.hpp>
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace AssetManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
|
||||
class DdsHandler;
|
||||
class PositionConverter
|
||||
{
|
||||
public:
|
||||
explicit PositionConverter(MainHandler *m_mainHandler);
|
||||
|
||||
LtsCoordTrans::UtmCoordinate baseCoordinate();
|
||||
inline QPointF relativeFromGeographic(const Core::GeoPosition2D &pos)
|
||||
{
|
||||
return relativeFromGeographic(pos, baseCoordinate());
|
||||
}
|
||||
inline static QPointF relativeFromGeographic(const Core::GeoPosition2D &pos,
|
||||
const LtsCoordTrans::UtmCoordinate &baseCoord)
|
||||
{
|
||||
// convert lon/lat to utm with the given zone from the center point
|
||||
const LtsCoordTrans::UtmCoordinate point(LtsCoordTrans::UtmCoordinate::fromGeographic(pos.lon(), pos.lat(), baseCoord.zone));
|
||||
// now calc distance from point to base point == relative position
|
||||
return QPointF(point.x - baseCoord.x, point.y - baseCoord.y);
|
||||
}
|
||||
private:
|
||||
bool initCoordConversion();
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
LtsCoordTrans::UtmCoordinate m_baseCoord;
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> m_asmDtc;
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
|
||||
LOGGER_T &m_logger;
|
||||
};
|
||||
|
||||
} // namespace OcSituationServer
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Settings for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
class NGLSettingsClass : public NGL::Settings
|
||||
{
|
||||
public:
|
||||
NGLSettingsClass()
|
||||
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
|
||||
{}
|
||||
static void setIniFile(const QString &fn)
|
||||
{
|
||||
s_iniFile = fn;
|
||||
}
|
||||
static QString s_iniFile;
|
||||
};
|
||||
QString NGLSettingsClass::s_iniFile;
|
||||
Q_GLOBAL_STATIC(NGLSettingsClass, s)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NGL::Settings *Settings::settings()
|
||||
{
|
||||
return s();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Settings::setIniFile(const QString &ini)
|
||||
{
|
||||
NGLSettingsClass::setIniFile(ini);
|
||||
}
|
||||
|
||||
quint32 Settings::aliveTimeout()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/AliveTimeout"), 5).toUInt() * 60 * 1000; // 5 minutes
|
||||
}
|
||||
|
||||
quint32 Settings::txCycleTime()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/TxCycleTime"), 10).toUInt() * 1000; // 10 seconds
|
||||
}
|
||||
|
||||
quint32 Settings::maxNumOfBytePerTxCycle()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/MaxNumOfBytePerTxCycle"), 166).toUInt();
|
||||
}
|
||||
|
||||
quint32 Settings::maxParticipantsInSituation()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/MaxParticipantsInSituation"), 100).toUInt();
|
||||
}
|
||||
|
||||
quint32 Settings::stateInformationCycleTime()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/StateInformationCycleTime"), 30).toInt() * 1000; // 30 seconds
|
||||
}
|
||||
|
||||
qint32 Settings::maxNumOfBytePerAesTxCycle()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/MaxNumOfBytePerAesTxCycle"), 200).toInt();
|
||||
}
|
||||
|
||||
quint32 Settings::aesDemandCollectionTime()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/AesDemandCollectionTime"), 10).toInt() * 1000; // 10 seconds
|
||||
}
|
||||
|
||||
quint32 Settings::iedPositionCycleTime()
|
||||
{
|
||||
return settings()->settings()->value(QLatin1String("OcSituationParameter/IedPositionCycleTime"), 30).toInt() * 1000; // 30 seconds
|
||||
}
|
||||
|
||||
} // namespace OcSituationServer
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Settings for OcSituationServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace OcSituationServer
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
NGL::Settings *settings();
|
||||
void setIniFile(const QString &ini);
|
||||
|
||||
// OC situation parameter
|
||||
quint32 aliveTimeout();
|
||||
quint32 txCycleTime();
|
||||
quint32 maxNumOfBytePerTxCycle();
|
||||
quint32 maxParticipantsInSituation();
|
||||
quint32 stateInformationCycleTime();
|
||||
|
||||
qint32 maxNumOfBytePerAesTxCycle();
|
||||
quint32 aesDemandCollectionTime();
|
||||
quint32 iedPositionCycleTime();
|
||||
} // namespace Settings
|
||||
|
||||
} // namespace OcSituationServer
|
||||
Reference in new issue
Block a user