Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* The BiteHandler class manages everything todo with bite requests.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-06-06
|
||||
*/
|
||||
|
||||
#include "bite_handler.h"
|
||||
#include "ParticipantHandling/participant.h"
|
||||
#include "ParticipantHandling/participant_donator.h"
|
||||
#include "main_handler.h"
|
||||
#include <QTimer>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace BiteHandling
|
||||
{
|
||||
|
||||
BiteHandler::BiteHandler(MainHandler *mainHandler)
|
||||
: QObject()
|
||||
, Interface::Fts::CallBiteRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("BiteHandler"))
|
||||
{
|
||||
}
|
||||
|
||||
bool BiteHandler::init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void BiteHandler::onDemandBiteReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (replyObject.error())
|
||||
WARNING_LOG(m_logger) << "Got an demandBiteError: " << replyObject();
|
||||
|
||||
auto it = m_demandedBiteParticipantRequests.find(replyObject.id());
|
||||
if (it != m_demandedBiteParticipantRequests.end())
|
||||
{
|
||||
const DemandedParticipants &dp = it.value();
|
||||
m_mainHandler->fts()->callBiteReply(dp.cookie, replyObject);
|
||||
dp.timer->deleteLater();
|
||||
m_demandedBiteParticipants -= dp.demandedBiteParticipants;
|
||||
|
||||
m_demandedBiteParticipantRequests.erase(it);
|
||||
}
|
||||
else
|
||||
WARNING_LOG(m_logger) << "Bite request with request id " << replyObject.id() << " was not replied to by the proxy";
|
||||
}
|
||||
|
||||
void BiteHandler::onCallBiteRequest(const rti::core::SampleIdentity &cookie,
|
||||
const CallBiteRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onCallBiteRequest: " << request;
|
||||
auto ret = callBiteRequest(cookie, request);
|
||||
if (ret.error() || ret.id())
|
||||
{
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
m_mainHandler->fts()->callBiteReply(cookie, ret);
|
||||
}
|
||||
// delayed answer in non-error case
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject BiteHandler::callBiteRequest(const rti::core::SampleIdentity &cookie,
|
||||
const CallBiteRequest &request)
|
||||
{
|
||||
TrainingAreaBase::DemandBiteRequest req;
|
||||
req.equipmentNumbers().reserve(request.participantIds().size());
|
||||
req.withSelfTest(request.withSelfTest());
|
||||
|
||||
bool bOneFound = false;
|
||||
bool bAlreadyDemandedFound = false;
|
||||
QSet<int> currentDemandedParticipants;
|
||||
for (const int participantId : request.participantIds())
|
||||
{
|
||||
if (m_demandedBiteParticipants.contains(participantId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "demandBiteRequest for participant Id "
|
||||
<< participantId
|
||||
<< " already triggered - reply is still to be done";
|
||||
bAlreadyDemandedFound = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const ParticipantHandling::Participant *participant = m_mainHandler->participantHandler()->participantById(participantId);
|
||||
if (participant == nullptr)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got BITE request for non existing participant id " << participantId;
|
||||
continue;
|
||||
}
|
||||
if (participant->equipmentNumber() == 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got BITE request participant id " << participantId << " but has no equipment number set";
|
||||
continue;
|
||||
}
|
||||
bOneFound = true;
|
||||
m_demandedBiteParticipants.insert(participant->id());
|
||||
currentDemandedParticipants.insert(participant->id());
|
||||
|
||||
req.equipmentNumbers().push_back(participant->equipmentNumber());
|
||||
}
|
||||
|
||||
if (req.equipmentNumbers().size() == 0 && bAlreadyDemandedFound)
|
||||
return Core::FunctionReplyObject(req.requestId());
|
||||
|
||||
if (req.equipmentNumbers().size() != 0)
|
||||
{
|
||||
static int s_requestId = 1;
|
||||
req.requestId(s_requestId++);
|
||||
|
||||
if (!m_mainHandler->tabFtc()->demandBiteRequest(req, this))
|
||||
return Core::FunctionReplyObject(req.requestId(),
|
||||
tr_lts("dds", "Error passing the BITE request to the proxy"));
|
||||
|
||||
QTimer *timeoutTimer = new QTimer(this);
|
||||
timeoutTimer->setSingleShot(true);
|
||||
timeoutTimer->setInterval(5000);
|
||||
const int requestId = req.requestId();
|
||||
m_demandedBiteParticipantRequests.insert(requestId, {currentDemandedParticipants, cookie, timeoutTimer});
|
||||
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
onBiteRequestTimeout(requestId);
|
||||
};
|
||||
connect(timeoutTimer, &QTimer::timeout, this, cb);
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
// at least one found but this was already requested and we're waiting for answer -> don't answer with error
|
||||
if (bOneFound)
|
||||
return Core::FunctionReplyObject();
|
||||
return Core::FunctionReplyObject(req.requestId(),
|
||||
tr_lts("dds", "Got no valid participants for BITE request"));
|
||||
}
|
||||
|
||||
void BiteHandler::onBiteRequestTimeout(int requestId)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onBiteRequestTimeout for " << requestId;
|
||||
|
||||
onDemandBiteReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
}
|
||||
|
||||
} // namespace BiteHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* The BiteHandler class manages everything todo with bite requests.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-06-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
#include <TrainingAreaBase/tab_ftc.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
class QTimer;
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace BiteHandling
|
||||
{
|
||||
class BiteReplier;
|
||||
class BiteHandler final : public QObject
|
||||
, protected Interface::Fts::CallBiteRequestHandler
|
||||
, protected TrainingAreaBase::Interface::Ftc::DemandBiteReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BiteHandler(MainHandler *mainHandler);
|
||||
|
||||
bool init();
|
||||
|
||||
void onDemandBiteReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
void onCallBiteRequest(const rti::core::SampleIdentity &cookie,
|
||||
const CallBiteRequest &request) override;
|
||||
|
||||
private:
|
||||
Core::FunctionReplyObject callBiteRequest(const rti::core::SampleIdentity &cookie,
|
||||
const CallBiteRequest &request);
|
||||
void onBiteRequestTimeout(int requestId);
|
||||
|
||||
private:
|
||||
MainHandler *m_mainHandler;
|
||||
struct DemandedParticipants
|
||||
{
|
||||
QSet<int> demandedBiteParticipants;
|
||||
rti::core::SampleIdentity cookie;
|
||||
QPointer<QTimer> timer;
|
||||
};
|
||||
QMap<int, DemandedParticipants> m_demandedBiteParticipantRequests;
|
||||
QSet<int32_t> m_demandedBiteParticipants; // participant IDs
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
}; // class BiteHandler
|
||||
} // namespace BiteHandling
|
||||
} // namespace ParticipantManagement
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
INCLUDE(MacroRTIDDSGen)
|
||||
INCLUDE(MacroCodeGenIdl)
|
||||
|
||||
SET(xml_FILE ppm_service.xml)
|
||||
|
||||
#
|
||||
# --- Library svcPpmCommon --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_common
|
||||
ppm_export.h
|
||||
ppm_common.cpp
|
||||
ppm_common.h
|
||||
ppm_db_impl_custom.cpp
|
||||
ppm_db_impl_custom.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
# Generate ppm_enums.idl / ppm.idl
|
||||
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
|
||||
# Generate ppm_db_structs.cpp/.h
|
||||
CODEGEN_DATABASE_STRUCTS(SRCS_common ${xml_FILE})
|
||||
# Generate ppm_db.cpp, ppm_db_impl.cpp/.h
|
||||
CODEGEN_DATABASE_SQL(SRCS_common ${xml_FILE})
|
||||
|
||||
# Generate *.cpp/*.hpp from idl
|
||||
RTIDDSGEN(SRCS_common ppm_enums.idl)
|
||||
RTIDDSGEN(SRCS_common ppm.idl)
|
||||
|
||||
# Generate ppm_dt[s,c]_types.h, ppm_ft[s,c]_types.h
|
||||
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
|
||||
# generate ppm_[d|f]tc.h
|
||||
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS HLA svcPpmCommon SHARED ${SRCS_common})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcPpmCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(svcPpmCommon
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
LtsUtilsCore
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
ddscore
|
||||
NGLLogger
|
||||
svcPdmCommon
|
||||
LtsUtilsCore
|
||||
LtsCoordTrans
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcPpmCommon)
|
||||
|
||||
#
|
||||
# --- Library svcPpmClient --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_client
|
||||
ppm_export.h
|
||||
ppm_dtc_impl_custom.cpp
|
||||
ppm_dtc_impl_custom.h
|
||||
)
|
||||
# generate ppm_[d|f]tc_impl.[cpp|h]
|
||||
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(WS AAR SV HLA svcPpmClient SHARED ${SRCS_client})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcPpmClient
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcPpmClient
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
PUBLIC
|
||||
svcPpmCommon
|
||||
ddsftc
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcPpmClient)
|
||||
|
||||
#
|
||||
# --- Library svcPpmServer --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_server
|
||||
ppm_export.h
|
||||
convert_db_to_dds.h
|
||||
|
||||
)
|
||||
# generate ppm_[d|f]ts.h, ppm_[d|f]ts_impl.[cpp|h]
|
||||
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
|
||||
|
||||
# WS for RecordReplayPlugin
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcPpmServer SHARED ${SRCS_server})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcPpmServer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcPpmServer
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
ddsfts
|
||||
PUBLIC
|
||||
svcPpmCommon
|
||||
ngldb
|
||||
LtsUtilsCore
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcPpmServer)
|
||||
|
||||
#
|
||||
# --- Topic Type Plugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- RecordReplayPlugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_RECORD_REPLAY_PLUGIN_SHARED(${xml_FILE})
|
||||
|
||||
IF (TARGET ppmRecordReplayPlugin)
|
||||
TARGET_SOURCES(ppmRecordReplayPlugin
|
||||
PRIVATE
|
||||
RecordReplay/participant_for_replay.h
|
||||
RecordReplay/participant_handler_for_replay.cpp
|
||||
RecordReplay/participant_handler_for_replay.h
|
||||
RecordReplay/ppm_record_replay_plugin_custom.cpp
|
||||
RecordReplay/ppm_record_replay_plugin_custom.h
|
||||
ParticipantHandling/participant_donator.h
|
||||
ParticipantHandling/participant.cpp
|
||||
ParticipantHandling/participant.h
|
||||
ParticipantHandling/participant_handler.cpp
|
||||
ParticipantHandling/participant_handler.h
|
||||
ParticipantHandling/unit_position_calculator.cpp
|
||||
ParticipantHandling/unit_position_calculator.h
|
||||
|
||||
settings.cpp
|
||||
settings.h
|
||||
|
||||
web_socket_handler.cpp
|
||||
web_socket_handler.h
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(ppmRecordReplayPlugin
|
||||
Qt5::Concurrent
|
||||
Qt5::WebSockets
|
||||
tabRecordReplayPlugin
|
||||
svcBldClient
|
||||
svcPpmServer
|
||||
svcPdmClient
|
||||
LtsCoordTrans
|
||||
LtsUtilsCoreHeaderOnly # unit_position_calculator.cpp => LtsUtilsCore/qpoint3d.h
|
||||
nglsettings
|
||||
ngltools
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
#
|
||||
# --- Executable svcParticipantManagement (sPPM) -------------------------------------------------
|
||||
#
|
||||
LIST(APPEND SRCS_exe
|
||||
BiteHandling/bite_handler.cpp
|
||||
BiteHandling/bite_handler.h
|
||||
|
||||
dds_handler.cpp
|
||||
dds_handler.h
|
||||
|
||||
EquipmentEventHandling/equipment_event_handler.cpp
|
||||
EquipmentEventHandling/equipment_event_handler.h
|
||||
|
||||
exercise_time.cpp
|
||||
exercise_time.h
|
||||
main.cpp
|
||||
main_handler.cpp
|
||||
main_handler.h
|
||||
|
||||
ParticipantHandling/firing_unit_validator.cpp
|
||||
ParticipantHandling/firing_unit_validator.h
|
||||
ParticipantHandling/get_participants.cpp
|
||||
ParticipantHandling/get_participants.h
|
||||
ParticipantHandling/participant_donator.h
|
||||
ParticipantHandling/participant.cpp
|
||||
ParticipantHandling/participant.h
|
||||
ParticipantHandling/participant_for_exercise.cpp
|
||||
ParticipantHandling/participant_for_exercise.h
|
||||
ParticipantHandling/participant_handler.cpp
|
||||
ParticipantHandling/participant_handler.h
|
||||
ParticipantHandling/participant_handler_for_exercise.cpp
|
||||
ParticipantHandling/participant_handler_for_exercise.h
|
||||
ParticipantHandling/proxy_listener.cpp
|
||||
ParticipantHandling/proxy_listener.h
|
||||
ParticipantHandling/unit_position_calculator.cpp
|
||||
ParticipantHandling/unit_position_calculator.h
|
||||
|
||||
PartyHandling/party.cpp
|
||||
PartyHandling/party_donator.h
|
||||
PartyHandling/party.h
|
||||
PartyHandling/party_handler.cpp
|
||||
PartyHandling/party_handler.h
|
||||
|
||||
settings.cpp
|
||||
settings.h
|
||||
|
||||
TargetHandling/object_target_information.cpp
|
||||
TargetHandling/object_target_information.h
|
||||
TargetHandling/handler_target_information.cpp
|
||||
TargetHandling/handler_target_information.h
|
||||
|
||||
TemplateHandling/template.cpp
|
||||
TemplateHandling/template.h
|
||||
TemplateHandling/template_handler.cpp
|
||||
TemplateHandling/template_handler.h
|
||||
|
||||
TypeHandling/type_donator.h
|
||||
TypeHandling/type_handler.cpp
|
||||
TypeHandling/type_handler_exercise.cpp
|
||||
TypeHandling/type_handler_exercise.h
|
||||
TypeHandling/type_handler_global.cpp
|
||||
TypeHandling/type_handler_global.h
|
||||
TypeHandling/type_handler.h
|
||||
|
||||
UasHandling/uas.cpp
|
||||
UasHandling/uas.h
|
||||
UasHandling/uas_handler.cpp
|
||||
UasHandling/uas_handler.h
|
||||
|
||||
UasHandling/mission_plan_handler.h
|
||||
UasHandling/mission_plan_handler.cpp
|
||||
UasHandling/object_mission_plan.cpp
|
||||
UasHandling/object_mission_plan.h
|
||||
|
||||
WebSocketInterface/data_manager.cpp
|
||||
WebSocketInterface/data_manager.h
|
||||
WebSocketInterface/json_keys.h
|
||||
WebSocketInterface/websocket_interface_handler.cpp
|
||||
WebSocketInterface/websocket_interface_handler.h
|
||||
WebSocketInterface/Messages/client_message.cpp
|
||||
WebSocketInterface/Messages/client_message.h
|
||||
WebSocketInterface/Messages/reply_message.cpp
|
||||
WebSocketInterface/Messages/reply_message.h
|
||||
|
||||
web_socket_handler.cpp
|
||||
web_socket_handler.h
|
||||
|
||||
${xml_FILE}
|
||||
)
|
||||
|
||||
# Generate ppm.sql, ppm.xml
|
||||
CODEGEN_SQL(SRCS_exe ${xml_FILE})
|
||||
|
||||
NGL_ADD_SVC_ICON(SRCS_exe)
|
||||
NGL_ADD_EXECUTABLE(AAR SV svcParticipantManagement ${SRCS_exe})
|
||||
NGL_TARGET_LINK_LIBRARIES(svcParticipantManagement
|
||||
ppmRecordReplayPlugin
|
||||
Qt5::Core
|
||||
Qt5::Concurrent
|
||||
Qt5::WebSockets
|
||||
ddsconnector
|
||||
LtsCommandLineParser
|
||||
nglsettings
|
||||
nglcoreapplication
|
||||
NGLLogger
|
||||
ProjectConfig
|
||||
svcCoreClient
|
||||
svcPdmClient
|
||||
svcPpmCommon
|
||||
svcPpmServer
|
||||
svcPpmClient
|
||||
svcTabClient
|
||||
svcAesClient
|
||||
svcCesServer
|
||||
svcCesClient
|
||||
svcBldClient
|
||||
svcTabServer
|
||||
svcExmClient
|
||||
ngltools
|
||||
LtsCoordTrans
|
||||
LtsWebSocketServer
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(svcParticipantManagement)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_ppm.props DESTINATION bin)
|
||||
NGL_ADD_TARGET_LINK(svcParticipantManagement sPPM)
|
||||
|
||||
# copy ppm_predefined_data.sql to share
|
||||
SET(in_file_sql "ppm_predefined_data.sql")
|
||||
NGL_INSTALL(AAR SV FILES ppm_predefined_data.sql DESTINATION share/Lts/sql)
|
||||
|
||||
|
||||
# Uncomment if necessary
|
||||
#ADD_SUBDIRECTORY(UnitTests)
|
||||
ADD_SUBDIRECTORY(ModuleTests)
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* The DeviceEventHandler class manages device events from TAB.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Dassow Philipp, SLEA, 2017-09-04
|
||||
*/
|
||||
|
||||
#include "equipment_event_handler.h"
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "ParticipantHandling/participant.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
|
||||
ParticipantManagement::EquipmentEventHandling::EquipmentEventHandler::EquipmentEventHandler(MainHandler *mainHandler, QObject *parent)
|
||||
: QObject(parent)
|
||||
, Interface::Fts::EquipmentSystemEventDataRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler (mainHandler)
|
||||
, m_filterId(0)
|
||||
, m_logger(getLogger("EquipmentEventHandler"))
|
||||
{
|
||||
}
|
||||
|
||||
bool ParticipantManagement::EquipmentEventHandling::EquipmentEventHandler::init()
|
||||
{
|
||||
if (!m_mainHandler->tabDtc()->enableEquipmentEvent())
|
||||
{
|
||||
ERROR_LOG (m_logger) << " TAB Dtc enableEquipmentEvent() failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mainHandler->dts()->enableEquipmentSystemEventFtcReply())
|
||||
{
|
||||
ERROR_LOG (m_logger) << " Dts enableEquipmentSystemEventDataFtcReply() failed !";
|
||||
return false;
|
||||
}
|
||||
connect(m_mainHandler->tabDtc().get(), &TrainingAreaBase::Interface::Dtc::equipmentEventChanged, this, &EquipmentEventHandler::onEquipmentEventChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticipantManagement::EquipmentEventHandling::EquipmentEventHandler::onEquipmentSystemEventDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::EquipmentSystemEventDataRequest &request)
|
||||
{
|
||||
INFO_LOG(m_logger) << "IN onEquipmentSystemEventDataRequest";
|
||||
|
||||
Core::FunctionReplyObject ret;
|
||||
|
||||
QString stmt = QStringLiteral(" SELECT rec_id, equipment_number, sample_time, position_lon, position_lat, position_z, equipment_function_id, sub_device_id,"
|
||||
" unique_device_id, device_specific_event_code, event_data"
|
||||
" FROM rec_equipment_system_event WHERE sample_time > ") + QString::number(request.startTime()) + QStringLiteral(" AND "
|
||||
" sample_time <= ") + QString::number(request.endTime());
|
||||
if (request.equipmentFunctionId() > -1)
|
||||
stmt += QStringLiteral(" AND equipment_function_id=") + QString::number(request.equipmentFunctionId());
|
||||
if (request.subDeviceId() > -1)
|
||||
stmt += QStringLiteral(" AND sub_device_id=") + QString::number(request.subDeviceId());
|
||||
if (request.deviceSpecificEventCode() > -1)
|
||||
stmt += QStringLiteral(" AND device_specific_event_code=") + QString::number(request.deviceSpecificEventCode());
|
||||
|
||||
INFO_LOG(m_logger) << "stmt: " << stmt;
|
||||
|
||||
NSqlQuery q(m_mainHandler->db()->database());
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while selecting event-data ";
|
||||
ERROR_LOG(m_logger) << "stmt : " << stmt;
|
||||
ret.setStr("Error while selecting data");
|
||||
m_mainHandler->fts()->equipmentSystemEventDataReply(cookie, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Unique FilterId for each requestEquipmentSystemEventFtcReply
|
||||
m_filterId++;
|
||||
ret.setId(m_filterId);
|
||||
|
||||
QVector<qint64> keys;
|
||||
ParticipantManagement::EquipmentSystemEventFtcReply data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Unique Key with filterId important for removing from dds
|
||||
qint64 id = m_filterId;
|
||||
id <<= 32;
|
||||
id |= q.value(i++).toInt();
|
||||
keys += id;
|
||||
|
||||
data.id(id);
|
||||
|
||||
data.equipmentNumber(q.value(i++).toInt());
|
||||
data.timeStamp(q.value(i++).toLongLong());
|
||||
double pos_lon = q.value(i++).toDouble();
|
||||
double pos_lat = q.value(i++).toDouble();
|
||||
double pos_z = q.value(i++).toDouble();
|
||||
data.position(Core::GeoPosition(pos_lon, pos_lat, pos_z));
|
||||
data.equipmentFunctionId(q.value(i++).toInt());
|
||||
data.subDeviceId(q.value(i++).toInt());
|
||||
data.uniqueDeviceId(q.value(i++).toInt());
|
||||
data.deviceSpecificEventCode(q.value(i++).toInt());
|
||||
QByteArray evtData(q.value(i++).toByteArray());
|
||||
if (evtData.size() != 0)
|
||||
data.eventData(LtsUtils::convert<std::vector<uint8_t>>(evtData));
|
||||
data.filterId(m_filterId);
|
||||
|
||||
m_mainHandler->dts()->publish(data);
|
||||
}
|
||||
|
||||
QTimer::singleShot(5 * 60 * 1000, this, [keys, this](){ removeFromDDS(keys); });
|
||||
m_mainHandler->fts()->equipmentSystemEventDataReply(cookie, ret);
|
||||
}
|
||||
|
||||
void ParticipantManagement::EquipmentEventHandling::EquipmentEventHandler::onEquipmentEventChanged(const TrainingAreaBase::EquipmentEvent &data, DataModification modType)
|
||||
{
|
||||
if (modType != DataModification::eAdded && modType != DataModification::eModified)
|
||||
return;
|
||||
|
||||
ParticipantManagement::EquipmentSystemEvent event;
|
||||
|
||||
event.id(data.equipmentNumber());
|
||||
event.equipmentNumber(data.equipmentNumber());
|
||||
event.sampleTime(data.sampleTime());
|
||||
if (!std::isnan(event.position().lon()) && !std::isnan(event.position().lat()))
|
||||
event.position(Core::GeoPosition(data.position().lon(), data.position().lat(), 0.0));
|
||||
else
|
||||
event.position(m_mainHandler->participantHandler()->participantByEquipmentNumber(data.equipmentNumber())->position().pos());
|
||||
event.equipmentFunctionId(data.source().equipmentFunctionId());
|
||||
event.subDeviceId(data.source().subDeviceId());
|
||||
event.uniqueDeviceId(data.source().unqiueId());
|
||||
event.deviceSpecificEventCode(data.code());
|
||||
event.eventData(data.data());
|
||||
|
||||
if (!m_mainHandler->dts()->publish(event))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error publishing equipment event to dds from eqnr: " << event.equipmentNumber() ;
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantManagement::EquipmentEventHandling::EquipmentEventHandler::removeFromDDS(const QVector<qint64> &keys)
|
||||
{
|
||||
for (qint64 key : keys)
|
||||
m_mainHandler->dts()->removeEquipmentSystemEventFtcReplyByKey(key);
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* The EquipmentEventHandler class manages EquipmentEvents from TAB.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Dassow Philipp, SLEA, 2017-09-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <TrainingAreaBase/tab_dtc.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace EquipmentEventHandling
|
||||
{
|
||||
|
||||
class EquipmentEventHandler
|
||||
: public QObject
|
||||
, protected Interface::Fts::EquipmentSystemEventDataRequestHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EquipmentEventHandler(ParticipantManagement::MainHandler * mainHandler, QObject *parent = nullptr);
|
||||
|
||||
bool init();
|
||||
|
||||
void onEquipmentSystemEventDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const EquipmentSystemEventDataRequest &request);
|
||||
|
||||
public slots:
|
||||
void onEquipmentEventChanged(const TrainingAreaBase::EquipmentEvent &data, DataModification modType);
|
||||
|
||||
private:
|
||||
void removeFromDDS(const QVector<qint64> &keys);
|
||||
|
||||
ParticipantManagement::MainHandler *m_mainHandler;
|
||||
int m_filterId;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
}; // class EquipmentEventHandler
|
||||
} // namespace EquipmentEventHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(SRCS_PPM_TEST
|
||||
ppm_tests.cpp
|
||||
)
|
||||
SET(HDRS_PPM_TEST
|
||||
ppm_tests.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING AND TARGET svcPpmClient)
|
||||
# Testing FunctionTopic Functionality (FTC)
|
||||
ADD_EXECUTABLE(ppmTests ${SRCS_PPM_TEST} ${HDRS_PPM_TEST})
|
||||
TARGET_LINK_LIBRARIES(ppmTests
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
RTI::nddscpp2
|
||||
svcPpmClient
|
||||
svcPpmCommon
|
||||
LtsCommandLineParser
|
||||
ddsconnector
|
||||
nglcoreapplication
|
||||
)
|
||||
IF(NOT BUILD_RPM)
|
||||
NGL_INSTALL(AAR SV TARGETS ppmTests DESTINATION bin/test)
|
||||
NGL_INSTALL(AAR SV FILES ../log4cxx_ppm.props DESTINATION bin/test)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
@@ -0,0 +1,691 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
*
|
||||
* PPM Function Topic test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Hannes Baeuerle, SLSE, 2015-07-18
|
||||
*/
|
||||
|
||||
#include "ppm_tests.h"
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
ParticipantManagement::PpmTests::PpmTests(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_testId(-1)
|
||||
, m_partyId(-1)
|
||||
, m_typeId(-1)
|
||||
, m_equipmentId(-1)
|
||||
, m_participantId(1)
|
||||
, m_bTestsSuccessful(true)
|
||||
, m_logger(getLogger("Test"))
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
ParticipantManagement::PpmTests::~PpmTests()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::startTest()
|
||||
{
|
||||
INFO_LOG(m_logger) << "********* startTest **************";
|
||||
switch (m_testId)
|
||||
{
|
||||
case 1:
|
||||
tryCreateEquipmentType();
|
||||
break;
|
||||
case 2:
|
||||
tryCreateType();
|
||||
break;
|
||||
case 3:
|
||||
tryModifyType();
|
||||
break;
|
||||
case 4:
|
||||
tryRemoveType();
|
||||
break;
|
||||
case 5:
|
||||
tryCreateParticipant();
|
||||
break;
|
||||
case 6:
|
||||
tryCreateTemplate();
|
||||
break;
|
||||
case 7:
|
||||
tryUpdateInfoParticipant();
|
||||
break;
|
||||
case 8:
|
||||
tryRegisterParticipant();
|
||||
break;
|
||||
case 10:
|
||||
tryCreateParty();
|
||||
break;
|
||||
case 11:
|
||||
tryModifyParty();
|
||||
break;
|
||||
case 12:
|
||||
tryRemoveParty();
|
||||
break;
|
||||
case 13:
|
||||
trySyncParties();
|
||||
break;
|
||||
case 14:
|
||||
tryChangeUsed();
|
||||
break;
|
||||
default:
|
||||
failExit();
|
||||
break;
|
||||
}
|
||||
INFO_LOG(m_logger) << "********* endTest **************";
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool ParticipantManagement::PpmTests::init(int domainId, int exerciseId, int testId, int partyId, int typeId, int equipmentId, int participantId)
|
||||
{
|
||||
INFO_LOG(m_logger) << "init begin";
|
||||
|
||||
m_testId = testId;
|
||||
m_partyId = partyId;
|
||||
m_typeId = typeId;
|
||||
m_equipmentId = equipmentId;
|
||||
m_participantId = participantId;
|
||||
|
||||
if (exerciseId > 0)
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Exercise, exerciseId));
|
||||
else
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Global));
|
||||
|
||||
if (!m_ddsConnector->init())
|
||||
return false;
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
DEBUG_LOG(m_logger) << "create DTC PPM";
|
||||
m_dtc = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
DEBUG_LOG(m_logger) << "init DTC PPM";
|
||||
bool bRet = m_dtc->enableAll();
|
||||
|
||||
DEBUG_LOG(m_logger) << "create FTC PPM";
|
||||
m_ftc = ParticipantManagement::Interface::Ftc::create(m_ddsConnector);
|
||||
DEBUG_LOG(m_logger) << "init FTC PPM";
|
||||
bRet &= m_ftc->enableAll();
|
||||
DEBUG_LOG(m_logger) << "init end PPM - bRet = " << bRet;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Domain Id = " << domainId;
|
||||
DEBUG_LOG(m_logger) << "Test Id = " << testId;
|
||||
DEBUG_LOG(m_logger) << "Party Id = " << partyId;
|
||||
DEBUG_LOG(m_logger) << "Type Id = " << typeId;
|
||||
DEBUG_LOG(m_logger) << "Equipment Id = " << equipmentId;
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryCreateTemplate()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send Create Template";
|
||||
|
||||
std::vector<ParticipantManagement::TemplateData> data;
|
||||
|
||||
ParticipantManagement::TemplateData td;
|
||||
td.modId(100);
|
||||
td.name("Test Template 100");
|
||||
td.designator("100");
|
||||
td.hierarchyNumber(100);
|
||||
td.typeId(19);
|
||||
td.superiorModId(1);
|
||||
td.tacticalIdentifier("100");
|
||||
|
||||
data.push_back(td);
|
||||
|
||||
m_dtc->waitForHistoricalDataTemplateParticipant();
|
||||
ParticipantManagement::TemplateParticipant tp = m_dtc->templateParticipant(1);
|
||||
const ParticipantManagement::TemplateData tdSup(m_dtc->convertFromParticipantTemplateToTemplateData(tp));
|
||||
DEBUG_LOG(m_logger) << "SuperiorModId: " << tdSup.modId();
|
||||
|
||||
data.push_back(tdSup);
|
||||
|
||||
if (!m_ftc->modifyTemplateDataRequest(ModifyTemplateDataRequest(data),this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating template data";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryCreateParticipant()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send Create ParticipantData per ModifyParticipantData";
|
||||
|
||||
ParticipantManagement::ParticipantData ptd;
|
||||
ptd.modId(1);
|
||||
ptd.name("Test Participant 1");
|
||||
ptd.typeId(m_typeId);
|
||||
ptd.partyId(m_partyId);
|
||||
ptd.equipmentNumber(m_equipmentId);
|
||||
ptd.hierarchyNumber(1);
|
||||
ptd.assignState(ParticipantManagement::ParticipantAssignState_def::HandoutExcon);
|
||||
|
||||
std::vector<ParticipantManagement::ParticipantData> data;
|
||||
data.push_back(ptd);
|
||||
ModifyParticipantDataRequest req;
|
||||
req.data(data);
|
||||
|
||||
if (!m_ftc->modifyParticipantDataRequest(req,this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating participant data";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryUpdateInfoParticipant()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send update info per registerForParticantRequest";
|
||||
|
||||
ParticipantManagement::RegisterParticipantRequest rpr;
|
||||
rpr.participantId(m_participantId);
|
||||
rpr.equipmentNumber(m_equipmentId);
|
||||
rpr.assignState(ParticipantManagement::ParticipantAssignState_def::HandoutExcon);
|
||||
rpr.identification("Test Indentification");
|
||||
rpr.info("Test Info2");
|
||||
|
||||
if (!m_ftc->registerParticipantRequest(rpr,this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating info/identification for participant";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryRegisterParticipant()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send registerForParticantRequest";
|
||||
|
||||
ParticipantManagement::RegisterParticipantRequest rpr;
|
||||
rpr.participantId(m_participantId);
|
||||
rpr.equipmentNumber(m_equipmentId);
|
||||
rpr.assignState(ParticipantManagement::ParticipantAssignState_def::HandoutExcon);
|
||||
rpr.identification("Test");
|
||||
rpr.info("Test Info");
|
||||
|
||||
if (!m_ftc->registerParticipantRequest(rpr,this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating info/identification for participant";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryCreateParty()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to Create Party per ModifyPartyData";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
party.name("Test Party AAA");
|
||||
party.role(ParticipantManagement::Role::Friend);
|
||||
party.color(-65536);
|
||||
party.fadingColor(-65536);
|
||||
|
||||
ModifyPartyDataRequest req;
|
||||
req.id(-1);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(false);
|
||||
|
||||
if (!m_ftc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
party.name("Test Party BBB");
|
||||
party.role(ParticipantManagement::Role::Friend);
|
||||
party.color(-16711936);
|
||||
party.fadingColor(-16711936);
|
||||
|
||||
req.id(-1);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(false);
|
||||
|
||||
if (!m_ftc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
party.name("Test Party CCC");
|
||||
party.role(ParticipantManagement::Role::Enemy);
|
||||
party.color(-16711936);
|
||||
party.fadingColor(-16711936);
|
||||
|
||||
req.id(-1);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(false);
|
||||
|
||||
if (!m_ftc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
party.name("Test Party DDD");
|
||||
party.role(ParticipantManagement::Role::Enemy);
|
||||
party.color(-16711936);
|
||||
party.fadingColor(-16711936);
|
||||
|
||||
req.id(-1);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(false);
|
||||
|
||||
if (!m_ftc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryModifyParty()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send Modify PartyData per ModifyPartyData";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
m_dtc->waitForHistoricalDataParty();
|
||||
party = m_dtc->party(m_partyId);
|
||||
if (party.id() < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Party not found: id = " << m_partyId;
|
||||
failExit();
|
||||
}
|
||||
|
||||
ModifyPartyDataRequest req;
|
||||
req.id(m_partyId);
|
||||
req.name(std::string("Test Party ")+QString::number(m_partyId).toStdString()); // updating name
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(true); // updating isUsed
|
||||
|
||||
if (!m_ftc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error modifying party data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryRemoveParty()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send RemoveParty";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
m_dtc->waitForHistoricalDataParty();
|
||||
party = m_dtc->party(m_partyId);
|
||||
if (party.id() < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Party not found: id = " << m_partyId;
|
||||
failExit();
|
||||
}
|
||||
|
||||
RemovePartyRequest req;
|
||||
req.partyId(m_partyId);
|
||||
|
||||
if (!m_ftc->removePartyRequest(req,this))
|
||||
{
|
||||
if (party.isUsedBy())
|
||||
{
|
||||
INFO_LOG(m_logger) << "Not possible to delete used party!" ;
|
||||
successExit();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to delete not used party with id " << m_partyId;
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::trySyncParties()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to sync parties with Ex 0";
|
||||
|
||||
SyncPartiesRequest req;
|
||||
req.exerciseId(42);
|
||||
|
||||
if (!m_ftc->syncPartiesRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error sync parties";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryChangeUsed()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send change used";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
m_dtc->waitForHistoricalDataParty();
|
||||
party = m_dtc->party(m_partyId);
|
||||
if (party.id() < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Party not found: id = " << m_partyId;
|
||||
failExit();
|
||||
}
|
||||
|
||||
ChangePartyUsedStateRequest req;
|
||||
req.partyId(m_partyId);
|
||||
req.isUsedBy(false); // updating isUsed
|
||||
|
||||
if (!m_ftc->changePartyUsedStateRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error modifying used party";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryCreateEquipmentType()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send Create EquipmentType per ModifyEquipmentTypeDataRequest";
|
||||
|
||||
ParticipantManagement::EquipmentType etd;
|
||||
etd.id(1);
|
||||
etd.name("Test Equipment Type 1");
|
||||
etd.minEquipNo(1000);
|
||||
etd.maxEquipNo(1999);
|
||||
etd.traVulnerabilityModelId(1);
|
||||
etd.traPlayerTypeId(110);
|
||||
etd.wmsTypeClass(ParticipantManagement::WmsTypeClass::Human);
|
||||
etd.deletedInWms(false);
|
||||
|
||||
std::vector<ParticipantManagement::EquipmentType> data;
|
||||
data.push_back(etd);
|
||||
|
||||
if (!m_ftc->modifyEquipmentTypeDataRequest(ModifyEquipmentTypeDataRequest(data, false),this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating equipment type data";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryCreateType()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send CreateTypeRequest";
|
||||
|
||||
if (!m_ftc->modifyTypeRequest(Type(0,
|
||||
ParticipantManagement::TypeClass::SupportEntity,
|
||||
20,
|
||||
std::string("1"),
|
||||
std::string("TestType"),
|
||||
1,
|
||||
0,
|
||||
false,
|
||||
{}, std::string()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating type data";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryModifyType()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send ModifyTypeRequest";
|
||||
|
||||
if (!m_ftc->modifyTypeRequest(Type(m_typeId,
|
||||
ParticipantManagement::TypeClass::SupportEntity,
|
||||
20,
|
||||
std::string("1"),
|
||||
std::string("TestType Modified"),
|
||||
1,
|
||||
0,
|
||||
false,
|
||||
{}, std::string()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error modifying type data";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::tryRemoveType()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Trying to send RemoveTypeRequest";
|
||||
|
||||
if (!m_ftc->removeTypeRequest(RemoveTypeRequest(m_typeId), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error modifying type data";
|
||||
failExit();
|
||||
}
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
//********************* GENERAL *************************************************
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onError(const QString &reason)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Got Reply error: " << reason;
|
||||
failExit();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onCreateReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (replyObject.error())
|
||||
{
|
||||
onError(replyObject.translated());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "Got createReply with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (replyObject.error())
|
||||
{
|
||||
onError(replyObject.translated());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "Got modifyRequest with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (replyObject.error())
|
||||
{
|
||||
onError(replyObject.translated());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "Got removeReply with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onSyncPartiesReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (replyObject.error())
|
||||
{
|
||||
onError(replyObject.translated());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "Got syncParties with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::onRemovePartyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
m_dtc->waitForHistoricalDataParty();
|
||||
party = m_dtc->party(m_partyId);
|
||||
|
||||
if (replyObject.error() && !party.isUsedBy())
|
||||
{
|
||||
onError(replyObject.translated());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "Got removeReply with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
void ParticipantManagement::PpmTests::onRegisterParticipantReply(const RegisterReply &reply)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "onRegisterParticipantReply " << reply.errorString() << "exerciseId: " << reply.exerciseId();
|
||||
for ( std::string str : reply.errorParams())
|
||||
ERROR_LOG(m_logger) << "error params: " << str;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::failExit()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "FAIL EXIT !";
|
||||
m_bTestsSuccessful = false;
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void ParticipantManagement::PpmTests::successExit()
|
||||
{
|
||||
INFO_LOG(m_logger) << "SUCCESS EXIT !";
|
||||
m_bTestsSuccessful = true;
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser()
|
||||
{
|
||||
addOption( { QStringList() << QLatin1String("t") << QLatin1String("testId")
|
||||
, QLatin1String("TestId.")
|
||||
, QLatin1String("Default: -1")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
addOption( { QStringList() << QLatin1String("p") << QLatin1String("partyId")
|
||||
, QLatin1String("PartyId")
|
||||
, QLatin1String("Default: -1")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
addOption( { QStringList() << QLatin1String("y") << QLatin1String("typeId")
|
||||
, QLatin1String("TypeId")
|
||||
, QLatin1String("Default: -1")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
addOption( { QStringList() << QLatin1String("q") << QLatin1String("equipmentId")
|
||||
, QLatin1String("EquipmentId.")
|
||||
, QLatin1String("Default: -1")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
addOption( { QStringList() << QLatin1String("a") << QLatin1String("participantId")
|
||||
, QLatin1String("ParticipantId.")
|
||||
, QLatin1String("Default: 1")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
|
||||
}
|
||||
int testId() const { return isSet(QLatin1String("t")) ? value(QLatin1String("t")).toInt() : -1; }
|
||||
int partyId() const { return isSet(QLatin1String("p")) ? value(QLatin1String("p")).toInt() : -1; }
|
||||
int typeId() const { return isSet(QLatin1String("y")) ? value(QLatin1String("y")).toInt() : -1; }
|
||||
int equipmentId() const { return isSet(QLatin1String("q")) ? value(QLatin1String("q")).toInt() : -1; }
|
||||
int participantId() const { return isSet(QLatin1String("a")) ? value(QLatin1String("a")).toInt() : 1; }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int iRet = -1;
|
||||
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("PPM", 0 );
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return iRet;
|
||||
|
||||
std::unique_ptr<ParticipantManagement::PpmTests> PpmTests(new ParticipantManagement::PpmTests);
|
||||
|
||||
if(!PpmTests->init(options.domainId(), options.exerciseId(), options.testId(), options.partyId(),
|
||||
options.typeId(), options.equipmentId(), options.participantId()))
|
||||
return iRet;
|
||||
|
||||
QTimer::singleShot(0, PpmTests.get(), &ParticipantManagement::PpmTests::startTest);
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
app.exec();
|
||||
|
||||
iRet = PpmTests->testsSuccessful() ? 0 : 1;
|
||||
fprintf(stderr, "\n%d\n\n", iRet);
|
||||
|
||||
INFO_LOG(app.baseLogger()) << "** TEST result = " << iRet;
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
|
||||
return iRet;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
*
|
||||
* PPM Function Topic test executable
|
||||
*
|
||||
* ModuleTests for PPM function topics
|
||||
* ---------------------------------------------------
|
||||
*
|
||||
* => (!) Preconditons:
|
||||
* - Service svcParticipantManagement -e 0 running
|
||||
*
|
||||
* -------------------------------------------------
|
||||
*
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Hannes Baeuerle, SLSE, 2015-07-18
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
#include <ParticipantManagement/ppm_ftc_types.h>
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#include <ParticipantManagement/logger.h>
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class PpmTests : public QObject
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyTypeReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::RemoveTypeReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyEquipmentTypeDataReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyParticipantDataReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyPartyDataReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyTemplateDataReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::RemovePartyReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::SyncPartiesReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ChangePartyUsedStateReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::RegisterParticipantReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PpmTests(QObject *parent = nullptr);
|
||||
~PpmTests();
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId, int partyId, int typeId, int equipmentId, int participantId);
|
||||
bool testsSuccessful() const { return m_bTestsSuccessful; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void startTest();
|
||||
protected Q_SLOTS:
|
||||
void tryCreateEquipmentType();
|
||||
void tryCreateType();
|
||||
void tryModifyType();
|
||||
void tryRemoveType();
|
||||
void tryCreateParticipant();
|
||||
void tryCreateParty();
|
||||
void tryModifyParty();
|
||||
void tryRemoveParty();
|
||||
void trySyncParties();
|
||||
void tryChangeUsed();
|
||||
void tryCreateTemplate();
|
||||
void tryUpdateInfoParticipant();
|
||||
void tryRegisterParticipant();
|
||||
|
||||
protected:
|
||||
void onModifyTypeReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onRemoveTypeReply(const Core::FunctionReplyObject &replyObject) override final { onRemoveReply(replyObject); }
|
||||
void onModifyEquipmentTypeDataReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onModifyPartyDataReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onModifyTemplateDataReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onRemovePartyReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onSyncPartiesReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onChangePartyUsedStateReply(const Core::FunctionReplyObject &replyObject) override final { onModifyReply(replyObject); }
|
||||
void onRegisterParticipantReply(const RegisterReply &reply) override final;
|
||||
|
||||
// general
|
||||
void onError(const QString &reason);
|
||||
void onCreateReply(const Core::FunctionReplyObject &replyObject);
|
||||
void onModifyReply(const Core::FunctionReplyObject &replyObject);
|
||||
void onRemoveReply(const Core::FunctionReplyObject &replyObject);
|
||||
void failExit();
|
||||
void successExit();
|
||||
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
|
||||
|
||||
int m_testId;
|
||||
int m_partyId;
|
||||
int m_typeId;
|
||||
int m_equipmentId;
|
||||
int m_participantId;
|
||||
bool m_bTestsSuccessful;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The FiringUnitValidator regulates the rules for firing units
|
||||
* $Id: participant_dis_helper.h 37747 2017-12-08 08:07:01Z ehrlicher $
|
||||
* $HeadURL: svn://10.196.0.54/TDS/branches/product/features/24_vulcano/Lts/Plugins/ParticipantManagement/Gui/Common/participant_dis_helper.h $
|
||||
* $Author: ehrlicher $
|
||||
* Created by Hannes Fritsche, ESZS, 2024-03-07
|
||||
*/
|
||||
|
||||
#include "firing_unit_validator.h"
|
||||
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
#include "ParticipantManagement/settings.h"
|
||||
#include "TypeHandling/type_handler.h"
|
||||
#include "participant_handler.h"
|
||||
#include "participant.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
|
||||
FiringUnitValidator::FiringUnitValidator(const std::shared_ptr<ParticipantHandler> &participantHandler,
|
||||
const std::shared_ptr<TypeHandling::TypeHandler> &typeHandler,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_participantHandler(participantHandler)
|
||||
, m_typeHandler(typeHandler)
|
||||
{
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject FiringUnitValidator::firingUnitError(const QHash<int, int> &modIdToParticipantId, const QVector<ParticipantData> &participantData)
|
||||
{
|
||||
QString error;
|
||||
|
||||
for (const ParticipantData ¤tData : participantData)
|
||||
{
|
||||
if (!m_typeHandler->isFiringUnitType(currentData.typeId()))
|
||||
continue;
|
||||
|
||||
int unitModId = currentData.modId();
|
||||
|
||||
error = getError(modIdToParticipantId, participantData, unitModId);
|
||||
|
||||
if (!error.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString FiringUnitValidator::getError(const QHash<int, int> &modIdToParticipantId, const QVector<ParticipantData> &participantData, int unitModId) const
|
||||
{
|
||||
bool hasCapacityError = false;
|
||||
bool hasFalseTypeError = false;
|
||||
bool hasMixedTypeError = false;
|
||||
uint maxParticipantsPerFiringUnit = Settings::maxParticipantsPerFiringUnit();
|
||||
uint participantsInFiringUnit = nonModdedInferiorsCount(unitModId, modIdToParticipantId);
|
||||
int typeId = participantTypeInFiringUnit(unitModId, modIdToParticipantId);
|
||||
|
||||
for (const ParticipantData ¤tData : participantData)
|
||||
{
|
||||
if (currentData.superiorModId() != unitModId)
|
||||
continue;
|
||||
|
||||
// capacity error
|
||||
hasCapacityError = ++participantsInFiringUnit > maxParticipantsPerFiringUnit;
|
||||
|
||||
if (hasCapacityError)
|
||||
return tr("There are only %1 participants allowed per firing unit.").arg(maxParticipantsPerFiringUnit);
|
||||
|
||||
// false type error
|
||||
hasFalseTypeError = !m_typeHandler->isArtilleryParticipantType(currentData.typeId());
|
||||
|
||||
if (hasFalseTypeError)
|
||||
return tr("There are only artillery participants allowed in firing units.");
|
||||
|
||||
// mixed type error
|
||||
if (typeId == -1)
|
||||
typeId = currentData.typeId();
|
||||
|
||||
hasMixedTypeError = currentData.typeId() != typeId;
|
||||
|
||||
if (hasMixedTypeError)
|
||||
return tr("There are no mixed types allowed in firing units.");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
int FiringUnitValidator::nonModdedInferiorsCount(int unitModId, const QHash<int, int> &modIdToParticipantId) const
|
||||
{
|
||||
if (!modIdToParticipantId.contains(unitModId))
|
||||
return 0;
|
||||
|
||||
const int unitParticipantId = modIdToParticipantId.value(unitModId);
|
||||
const Participant *unitParticipant = m_participantHandler->participantById(unitParticipantId);
|
||||
|
||||
if (!unitParticipant)
|
||||
return 0;
|
||||
|
||||
const QList<int> moddedParticipantIds = modIdToParticipantId.keys();
|
||||
int nonModdedInferiorsCountRet = 0;
|
||||
|
||||
for (int inferiorId : unitParticipant->inferiors())
|
||||
{
|
||||
if (moddedParticipantIds.contains(inferiorId)) // only non modded participants
|
||||
continue;
|
||||
|
||||
++nonModdedInferiorsCountRet;
|
||||
}
|
||||
|
||||
return nonModdedInferiorsCountRet;
|
||||
}
|
||||
|
||||
int FiringUnitValidator::participantTypeInFiringUnit(int unitModId, const QHash<int, int> &modIdToParticipantId) const
|
||||
{
|
||||
if (!modIdToParticipantId.contains(unitModId))
|
||||
return -1;
|
||||
|
||||
const int unitParticipantId = modIdToParticipantId.value(unitModId);
|
||||
const Participant *unitParticipant = m_participantHandler->participantById(unitParticipantId);
|
||||
|
||||
if (!unitParticipant)
|
||||
return -1;
|
||||
|
||||
const QList<int> moddedParticipantIds = modIdToParticipantId.keys();
|
||||
|
||||
for (int inferiorId : unitParticipant->inferiors())
|
||||
{
|
||||
if (moddedParticipantIds.contains(inferiorId)) // only non modded participants
|
||||
continue;
|
||||
|
||||
const Participant *inferior = m_participantHandler->participantById(inferiorId);
|
||||
|
||||
if (!inferior)
|
||||
continue;
|
||||
|
||||
return inferior->typeId();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The FiringUnitValidator regulates the rules for firing units serverside
|
||||
* $Id: participant_dis_helper.h 37747 2017-12-08 08:07:01Z ehrlicher $
|
||||
* $HeadURL: svn://10.196.0.54/TDS/branches/product/features/24_vulcano/Lts/Plugins/ParticipantManagement/Gui/Common/participant_dis_helper.h $
|
||||
* $Author: ehrlicher $
|
||||
* Created by Hannes Fritsche, ESZS, 2024-03-07
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
class ParticipantData;
|
||||
|
||||
namespace TypeHandling
|
||||
{
|
||||
class TypeHandler;
|
||||
} //namespace TypeHandling
|
||||
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class ParticipantHandler;
|
||||
|
||||
class FiringUnitValidator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FiringUnitValidator(const std::shared_ptr<ParticipantHandler> &participantHandler,
|
||||
const std::shared_ptr<TypeHandling::TypeHandler> &typeHandler,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Core::FunctionReplyObject firingUnitError(const QHash<int, int> &modIdToParticipantId, const QVector<ParticipantData> &participantData);
|
||||
|
||||
private:
|
||||
QString getError(const QHash<int, int> &modIdToParticipantId, const QVector<ParticipantData> &participantData, int unitModId) const;
|
||||
|
||||
int nonModdedInferiorsCount(int unitModId, const QHash<int, int> &modIdToParticipantId) const;
|
||||
int participantTypeInFiringUnit(int unitModId, const QHash<int, int> &modIdToParticipantId) const;
|
||||
|
||||
std::shared_ptr<ParticipantHandler> m_participantHandler;
|
||||
std::shared_ptr<TypeHandling::TypeHandler> m_typeHandler;
|
||||
}; // namespace FiringUnitValidator
|
||||
} //namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handler for all request journal objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-01-13
|
||||
*/
|
||||
|
||||
#include "get_participants.h"
|
||||
#include "main_handler.h"
|
||||
|
||||
#include <ParticipantManagement/ppm_record_replay_plugin.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
GetParticipants::GetParticipants(MainHandler *mainHandler)
|
||||
: Interface::Fts::GetParticipantsRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("GetParticipants"))
|
||||
{}
|
||||
|
||||
GetParticipants::~GetParticipants()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void GetParticipants::onGetParticipantsRequest(const rti::core::SampleIdentity &cookie,
|
||||
const GetParticipantsRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onGetParticipantsRequest" << request;
|
||||
|
||||
|
||||
// Initialize RecordReplay to get initial participants
|
||||
RecordReplayPlugin recordReplay;
|
||||
// no ddsconnector - we don't want to publish data here
|
||||
recordReplay.initDtc(nullptr, m_mainHandler->exerciseId());
|
||||
|
||||
NSqlQuery q(m_mainHandler->db()->database());
|
||||
recordReplay.readParticipantAt(q, request.timeStamp());
|
||||
|
||||
// key is sampleTime -> multiMap
|
||||
auto participantsMmap = recordReplay.getParticipantMap();
|
||||
QMap<int, Participant> participants;
|
||||
|
||||
// only take the newest entries (participantsMmap may contain more than one entry per participantId
|
||||
for (auto it = participantsMmap.begin(); it != participantsMmap.end(); ++it)
|
||||
{
|
||||
Participant &p = it.value();
|
||||
if (p.isDeleted())
|
||||
participants.remove(p.id());
|
||||
else
|
||||
participants[p.id()] = std::move(p);
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Starting to read participant from record replay. Size: "
|
||||
<< participants.size();
|
||||
|
||||
GetParticipantsReply reply;
|
||||
reply.requestId(request.requestId());
|
||||
|
||||
auto &vecPart = reply.participants();
|
||||
vecPart.reserve(participants.size());
|
||||
for (auto it = participants.begin(); it != participants.end(); ++it)
|
||||
{
|
||||
if (request.partyId() >= 0 && it.value().partyId() != request.partyId())
|
||||
continue;
|
||||
vecPart.push_back(it.value());
|
||||
}
|
||||
|
||||
m_mainHandler->fts()->getParticipantsReply(cookie, reply);
|
||||
}
|
||||
|
||||
} // Namespace ParticipantManagement
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handler for all situation replay objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-01-13
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
class GetParticipants final : protected Interface::Fts::GetParticipantsRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit GetParticipants(MainHandler *mainHandler);
|
||||
~GetParticipants();
|
||||
|
||||
private:
|
||||
void onGetParticipantsRequest(const rti::core::SampleIdentity &cookie,
|
||||
const GetParticipantsRequest &request) override;
|
||||
|
||||
private:
|
||||
MainHandler *m_mainHandler;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* The Participant class is the base class for either Buildings or ExerciseParticipants.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#include <ParticipantManagement/ppm_db_structs.h>
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
#include <TrainingAreaBase/tab.hpp>
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace Interface
|
||||
{
|
||||
class Dts;
|
||||
}
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class ParticipantHandler;
|
||||
class UnitPositionCalculator;
|
||||
class Participant
|
||||
{
|
||||
public:
|
||||
Participant(ParticipantHandler *participantHandler,
|
||||
UnitPositionCalculator *unitPosCalculator,
|
||||
const Database::PpmParticipant &data,
|
||||
const char *loggerName);
|
||||
|
||||
virtual ~Participant();
|
||||
|
||||
int32_t id() const { return m_participantData.id(); }
|
||||
int32_t typeId() const { return m_participantData.typeId(); }
|
||||
int32_t superiorId() const { return m_participantData.superiorId(); }
|
||||
// return optional?
|
||||
int32_t equipmentNumber() const { return m_participantData.equipmentNumber().is_set() ? m_participantData.equipmentNumber().get() : 0; }
|
||||
int32_t partyId() const { return m_participantData.partyId(); }
|
||||
bool isDeleted() const { return m_participantData.isDeleted(); }
|
||||
ParticipantAssignState assignState() const { return m_participantData.assignState(); }
|
||||
const std::vector<int32_t> &inferiors() const { return m_participantData.inferiorIds(); }
|
||||
ParticipantPosition position() const { return m_positionPublished; }
|
||||
const DynamicParticipantData &dynamicParticipantData() const { return m_dynamicData; }
|
||||
const ParticipantManagement::Participant &participantData() const { return m_participantData; }
|
||||
|
||||
void markAsDeleted();
|
||||
|
||||
bool isValidPosition(qint64 sampleTime, const Core::GeoPosition &pos, Core::PositionReportingSource repSource) const;
|
||||
bool setPosition(const TrainingAreaBase::EquipmentPosition &newPosition);
|
||||
bool setPosition(const ParticipantManagement::ParticipantPosition &newPosition, bool bForce = false);
|
||||
// returns true when the positionTime is newer than the old positionTime
|
||||
bool setCalculatedPosition(const Core::GeoPosition &pos, int64_t positionTime);
|
||||
bool setState(const TrainingAreaBase::EquipmentState &newState, int originatorId);
|
||||
bool setSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data);
|
||||
bool setGear(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment);
|
||||
bool setSanitationMaterial(int materialCount,
|
||||
const std::vector<int> &materialStock,
|
||||
int abgSn,
|
||||
qint64 sampleTime,
|
||||
Qualification qualif,
|
||||
qint64 eqNo);
|
||||
bool setSanitation(qint64 sanitationProceduresTaken,
|
||||
TrainingAreaBase::SanitationResult sanitationResult,
|
||||
TrainingAreaBase::SanitationEvaluation sanitationEvaluation,
|
||||
int originatorId,
|
||||
TrainingAreaBase::Qualification qualification,
|
||||
qint64 sampleTime);
|
||||
bool setOperatorAction(int action, int originatorId, qint64 sampleTime);
|
||||
bool setEquipmentEvent(int event, qint64 sampleTime);
|
||||
|
||||
bool setGearCharge(const TrainingAreaBase::GearCharge &charge, qint64 sampleTime);
|
||||
bool setGearCharge(const GearInformation &gearInfo);
|
||||
void setDynamicData(const DynamicParticipantData &data);
|
||||
void setMode(const ParticipantMode &data);
|
||||
|
||||
bool isNewAssignStateValid(const ParticipantManagement::ParticipantAssignState &newAssignState, int32_t equipmentNumber) const;
|
||||
|
||||
/**
|
||||
* @brief Method to set this participants data by a modify request and to
|
||||
* detect if the request really changes the data
|
||||
* @param data - participant data from a modify request
|
||||
* @return true if data differs from this participants data, otherwise false
|
||||
*/
|
||||
bool hasToBeChanged(const ParticipantManagement::Participant &data);
|
||||
bool hasToBeChanged(const ParticipantManagement::ParticipantBase &data);
|
||||
bool hasNewSuperiorId(int32_t superiorId);
|
||||
bool hasNewInferiorStructure(std::vector<int32_t> inferiorIds);
|
||||
bool setOperationalState(const TrainingAreaBase::EquipmentOperationalState &operationalState);
|
||||
|
||||
RegisterParticipantRequest toRegisterParticipantRequest() const;
|
||||
|
||||
|
||||
virtual void removeFromDds();
|
||||
virtual bool publishPosition();
|
||||
virtual bool publishDynamicData();
|
||||
virtual bool publishMode();
|
||||
virtual bool publishParticipant();
|
||||
|
||||
Database::PpmParticipant toDbParticipant() const;
|
||||
static ParticipantManagement::Participant toDdsParticipant(const Database::PpmParticipant &data);
|
||||
|
||||
protected:
|
||||
virtual bool updateEquipmentExerciseMapping(int oldEqId, int newEqId) = 0;
|
||||
bool setPosition(const TrainingAreaBase::EquipmentPosition &newPosition, int mountedToId);
|
||||
void unmountParticipantById(const TrainingAreaBase::EquipmentPosition &newPosition, int32_t id);
|
||||
|
||||
void removeManipulation(int32_t equipmentFunctionId);
|
||||
void cleanManipulations();
|
||||
|
||||
bool gearHasCharge(int32_t gearId) const;
|
||||
int32_t indexByGearAndChargeId(int32_t gearId, int32_t chargeTypeId = -1) const;
|
||||
|
||||
ParticipantHandler *particpantHandler() { return m_participantHandler; }
|
||||
const ParticipantHandler *particpantHandler() const { return m_participantHandler; }
|
||||
qint64 currentTimeMSec() const;
|
||||
std::shared_ptr<Interface::Dts> dts() const;
|
||||
|
||||
protected: // attributes
|
||||
ParticipantHandler *m_participantHandler;
|
||||
UnitPositionCalculator *m_unitPosCalculator;
|
||||
qint64 m_lastGearUsage;
|
||||
qint64 m_lastSanMatUsage{0};
|
||||
qint64 m_lastManipulationReset;
|
||||
qint64 m_lastNbcState;
|
||||
qint64 m_lastSpecialSensorData;
|
||||
|
||||
ParticipantPosition m_positionPublished;
|
||||
ParticipantPosition m_positionToPublish;
|
||||
DynamicParticipantData m_dynamicData;
|
||||
DynamicParticipantData m_dynamicDataPublished;
|
||||
ParticipantManagement::Participant m_participantData;
|
||||
ParticipantManagement::Participant m_participantPublished;
|
||||
ParticipantManagement::ParticipantMode m_participantMode;
|
||||
ParticipantManagement::ParticipantMode m_participantModePublished;
|
||||
|
||||
bool m_bPublishPosition; // false for units
|
||||
QMutex m_mutex;
|
||||
LOGGER_T m_logger;
|
||||
}; // class ParticipantBase
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
} // namespace ParticipantHandling
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The ParticipantDonator class is an interface for returning a Participant to a given id.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-06-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class Participant;
|
||||
class ParticipantDonator
|
||||
{
|
||||
public:
|
||||
virtual Participant *participantById(int participantId) const = 0;
|
||||
virtual bool isUnitType(int typeId) const = 0;
|
||||
}; // class ParticipantDonator
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* The Participant class is the base class for either Buildings or ExerciseParticipants.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
||||
*/
|
||||
|
||||
#include "participant_for_exercise.h"
|
||||
#include "main_handler.h"
|
||||
#include "convert_db_to_dds.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
|
||||
//
|
||||
// ParticipantForExercise
|
||||
//
|
||||
ParticipantForExercise::ParticipantForExercise(MainHandler *mainHandler,
|
||||
ParticipantHandler *particpantHandler,
|
||||
UnitPositionCalculator *unitPosCalculator,
|
||||
const Database::PpmParticipant &data)
|
||||
: Participant(particpantHandler, unitPosCalculator, data, "Participant")
|
||||
, m_mainHandler(mainHandler)
|
||||
{}
|
||||
|
||||
ParticipantForExercise::~ParticipantForExercise()
|
||||
{
|
||||
removeFromDds();
|
||||
}
|
||||
|
||||
bool ParticipantForExercise::applyEquipmentExerciseMapping(int newEqId)
|
||||
{
|
||||
if (!newEqId)
|
||||
return true;
|
||||
|
||||
if (m_equipmentExerciseMappingPublished.equipmentNumber == newEqId &&
|
||||
m_equipmentExerciseMappingPublished.participantId == id() &&
|
||||
m_equipmentExerciseMappingPublished.exerciseId == m_mainHandler->exerciseId())
|
||||
return true;
|
||||
|
||||
|
||||
Database::EquipmentExerciseMapping dbEem;
|
||||
dbEem.equipmentNumber = newEqId;
|
||||
dbEem.participantId = id();
|
||||
dbEem.exerciseId = m_mainHandler->exerciseId();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Inserting EquipmentExerciseMapping into db: " << dbEem.equipmentNumber
|
||||
<< ", " << dbEem.participantId
|
||||
<< ", " << dbEem.exerciseId;
|
||||
if (!m_mainHandler->dbEx0()->insert(dbEem))
|
||||
{
|
||||
m_participantData.equipmentNumber().reset();
|
||||
m_participantData.assignState(ParticipantAssignState::NotAssigned);
|
||||
publishParticipant();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_participantHandler->setEquipmentNumberForParticipant(m_equipmentExerciseMappingPublished.equipmentNumber,
|
||||
dbEem.equipmentNumber,
|
||||
id());
|
||||
m_equipmentExerciseMappingPublished = dbEem;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticipantForExercise::removeEquipmentExerciseMapping(int oldEqId, bool bIsShutdown)
|
||||
{
|
||||
if (!oldEqId)
|
||||
return;
|
||||
m_equipmentExerciseMappingPublished = Database::EquipmentExerciseMapping();
|
||||
|
||||
if (!bIsShutdown)
|
||||
{
|
||||
Database::EquipmentExerciseMapping dbEem;
|
||||
dbEem.equipmentNumber = oldEqId;
|
||||
dbEem.participantId = id();
|
||||
dbEem.exerciseId = m_mainHandler->exerciseId();
|
||||
m_mainHandler->dbEx0()->removeEquipmentExerciseMapping(dbEem);
|
||||
m_participantHandler->setEquipmentNumberForParticipant(oldEqId, 0, id());
|
||||
}
|
||||
}
|
||||
|
||||
bool ParticipantForExercise::updateEquipmentExerciseMapping(int oldEqId, int newEqId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "updateEquipmentExerciseMapping from " << oldEqId << " to " << newEqId;
|
||||
if (oldEqId == newEqId)
|
||||
return true;
|
||||
removeEquipmentExerciseMapping(oldEqId, false);
|
||||
return applyEquipmentExerciseMapping(newEqId);
|
||||
}
|
||||
|
||||
bool ParticipantForExercise::publishParticipant()
|
||||
{
|
||||
return Participant::publishParticipant();
|
||||
}
|
||||
|
||||
void ParticipantForExercise::removeFromDds() // only called on shutdown
|
||||
{
|
||||
removeEquipmentExerciseMapping(equipmentNumber(), true);
|
||||
Participant::removeFromDds();
|
||||
}
|
||||
|
||||
void ParticipantForExercise::registerInfoFromFt(const RegisterParticipantRequest &request)
|
||||
{
|
||||
m_participantData.info(request.info());
|
||||
m_participantData.identification(request.identification());
|
||||
}
|
||||
|
||||
bool ParticipantForExercise::registerFromFt(const RegisterParticipantRequest &request)
|
||||
{
|
||||
int newEquipmentNumber = request.equipmentNumber();
|
||||
// just to be sure ...
|
||||
if (request.assignState() == ParticipantAssignState::NotAssigned)
|
||||
newEquipmentNumber = 0;
|
||||
|
||||
if (!updateEquipmentExerciseMapping(equipmentNumber(), newEquipmentNumber))
|
||||
return false;
|
||||
particpantHandler()->setEquipmentNumberForParticipant(equipmentNumber(),
|
||||
newEquipmentNumber,
|
||||
id());
|
||||
|
||||
INFO_LOG(m_logger) << "Set assign state for participant " << id() << " from "
|
||||
<< assignState() << " to " << request.assignState()
|
||||
<< ", old eqid: " << equipmentNumber() << ", new eqid: "
|
||||
<< newEquipmentNumber;
|
||||
|
||||
if (newEquipmentNumber)
|
||||
m_participantData.equipmentNumber(newEquipmentNumber);
|
||||
else
|
||||
m_participantData.equipmentNumber().reset();
|
||||
m_participantData.assignState(request.assignState());
|
||||
m_participantData.info(request.info());
|
||||
m_participantData.identification(request.identification());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* The Participant class is the base class for either Buildings or ExerciseParticipants.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "participant.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class ParticipantHandler;
|
||||
class UnitPositionCalculator;
|
||||
|
||||
class ParticipantForExercise final : public Participant
|
||||
{
|
||||
public:
|
||||
ParticipantForExercise(MainHandler *mainHandler,
|
||||
ParticipantHandler *particpantHandler,
|
||||
UnitPositionCalculator *unitPosCalculator,
|
||||
const Database::PpmParticipant &data);
|
||||
~ParticipantForExercise();
|
||||
|
||||
bool publishParticipant() override;
|
||||
void removeFromDds() override;
|
||||
|
||||
bool registerFromFt(const RegisterParticipantRequest &request);
|
||||
void registerInfoFromFt(const RegisterParticipantRequest &request);
|
||||
private:
|
||||
bool applyEquipmentExerciseMapping(int newEqId);
|
||||
void removeEquipmentExerciseMapping(int oldEqId, bool bIsShutdown);
|
||||
bool updateEquipmentExerciseMapping(int oldEqId, int newEqId) override;
|
||||
private:
|
||||
Database::EquipmentExerciseMapping m_equipmentExerciseMappingPublished;
|
||||
ParticipantManagement::MainHandler *m_mainHandler;
|
||||
|
||||
}; // class Participant
|
||||
} // namespace ParticipantManagement
|
||||
} // namespace ParticipantHandling
|
||||
+778
@@ -0,0 +1,778 @@
|
||||
/**
|
||||
* The ParticipantHandler class manages all participant related function topics and holds classes for
|
||||
* further participant data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
#include "participant_handler.h"
|
||||
|
||||
#include "participant.h"
|
||||
#include "ppm_common.h"
|
||||
#include "settings.h"
|
||||
#include "unit_position_calculator.h"
|
||||
|
||||
#include <Buildings/bld.hpp>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
|
||||
#include <LtsUtilsCore/outdated_position.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
|
||||
//
|
||||
// ParticipantHandler
|
||||
//
|
||||
ParticipantHandler::ParticipantHandler(BaseDataProvider *bdp, const char *loggerName) : QObject(), m_hitLineId(0), m_bdp(bdp), m_logger(getLogger(loggerName)) {}
|
||||
|
||||
ParticipantHandler::~ParticipantHandler()
|
||||
{
|
||||
if (m_unitPositionCalculator)
|
||||
m_unitPositionCalculator->stopCalculation();
|
||||
|
||||
clearParticipants();
|
||||
}
|
||||
|
||||
void ParticipantHandler::clearParticipants()
|
||||
{
|
||||
// clear maps
|
||||
for (auto it = m_hitLineInfoMap.cbegin(); it != m_hitLineInfoMap.cend(); ++it)
|
||||
dts()->removeHitLineInfoByKey(it.value().id());
|
||||
m_hitLineInfoMap.clear();
|
||||
|
||||
for (auto p : qAsConst(m_participants))
|
||||
{
|
||||
p->removeFromDds();
|
||||
delete p;
|
||||
}
|
||||
m_participants.clear();
|
||||
}
|
||||
|
||||
bool ParticipantHandler::init()
|
||||
{
|
||||
clearParticipants();
|
||||
|
||||
m_unitPositionCalculator.reset(new UnitPositionCalculator(this));
|
||||
|
||||
m_webSocketHandler = std::make_shared<WebSocketHandler>(this);
|
||||
|
||||
if (!m_webSocketHandler->init(Settings::getWebSocketServerPortRange(2)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not init websockethandler";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticipantHandler::setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "setEquipmentNumberForParticipant, old: " << oldEqNo << ", new: " << newEqNo << ", participant: " << participantId;
|
||||
if (oldEqNo > 0)
|
||||
m_equipNumber2ParticipantId.remove(oldEqNo);
|
||||
if (newEqNo > 0)
|
||||
{
|
||||
int &val = m_equipNumber2ParticipantId[newEqNo];
|
||||
if (val != 0 && val != participantId)
|
||||
WARNING_LOG(m_logger) << "Another participant (" << val << ") already has the equipment number " << newEqNo << " - overriding it with participant "
|
||||
<< participantId;
|
||||
val = participantId;
|
||||
}
|
||||
}
|
||||
|
||||
Participant *ParticipantHandler::participantById(int32_t participantId) const { return m_participants.value(participantId); }
|
||||
|
||||
Participant *ParticipantHandler::participantByEquipmentNumber(int32_t equipmentNumber)
|
||||
{
|
||||
const int participantId = m_equipNumber2ParticipantId.value(equipmentNumber);
|
||||
DEBUG_LOG(m_logger) << " >>>>>> [ParticipantHandler] participantByEquipmentNumber participantId: " << participantId << " | equipNumb: " << equipmentNumber;
|
||||
return participantById(participantId);
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewGearEvent(const TrainingAreaBase::EquipmentGearEvent &gearEvent)
|
||||
{
|
||||
if (isTelegramInFuture(gearEvent))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentGearEvent which has a timestamp in the future: " << gearEvent.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: gearEvent.chargeAmount() is not used because there is no usecase for this value ... atm
|
||||
|
||||
Participant *participantToBeChanged = participantByEquipmentNumber(gearEvent.equipmentNumber());
|
||||
if (!participantToBeChanged)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << gearEvent.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
participantToBeChanged->setGearCharge(gearEvent.charge(), gearEvent.sampleTime());
|
||||
participantToBeChanged->publishDynamicData();
|
||||
|
||||
// publish gear event
|
||||
dts()->publish(
|
||||
ParticipantGearEvent(participantToBeChanged->id(),
|
||||
gearEvent.sampleTime(),
|
||||
gearEvent.chargeAmount(),
|
||||
GearCharge(gearEvent.charge().gearId(), gearEvent.charge().gearTypeId(), gearEvent.charge().chargeTypeId(), gearEvent.charge().remain())));
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewGearChargeStateFromProxy(const TrainingAreaBase::EquipmentGearChargeState &chargeState)
|
||||
{
|
||||
if (isTelegramInFuture(chargeState))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentGearChargeState which has a timestamp in the future: " << chargeState.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
const int equipNo = chargeState.equipmentNumber();
|
||||
Participant *participantToBeChanged = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo);
|
||||
|
||||
if (!participantToBeChanged)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << chargeState.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const TrainingAreaBase::GearCharge &charge : chargeState.charge())
|
||||
participantToBeChanged->setGearCharge(charge, chargeState.sampleTime());
|
||||
participantToBeChanged->publishDynamicData();
|
||||
|
||||
emit gearChargeChanged(participantToBeChanged->id(), participantToBeChanged->partyId());
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewGearAssignmentFromProxy(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment)
|
||||
{
|
||||
if (isTelegramInFuture(gearAssignment))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentGearAssignment which has a timestamp in the future: " << gearAssignment.sampleTime();
|
||||
return;
|
||||
}
|
||||
Participant *participantToBeChanged = participantByEquipmentNumber(gearAssignment.equipmentNumber());
|
||||
if (!participantToBeChanged)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got gear assignment for unknown equipment number " << gearAssignment.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
participantToBeChanged->setGear(gearAssignment);
|
||||
participantToBeChanged->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewStateFromProxy(const TrainingAreaBase::EquipmentState &data)
|
||||
{
|
||||
if (isTelegramInFuture(data))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentState which has a timestamp in the future: " << data.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. handle included EquipmentPosition:
|
||||
TrainingAreaBase::EquipmentPosition pos;
|
||||
pos.equipmentNumber(data.equipmentNumber());
|
||||
pos.sampleTime(data.sampleTime());
|
||||
if (data.position().is_set())
|
||||
{
|
||||
pos.position(data.position().get());
|
||||
onNewPositionFromProxy(pos);
|
||||
}
|
||||
|
||||
// 2. handle EquipmentState
|
||||
Participant *participantToBeChanged = participantByEquipmentNumber(data.equipmentNumber());
|
||||
if (!participantToBeChanged)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got equipment state for unknown equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
// convert eqNo to participantId if originator was a participant and data.originatorId() is an equipment number
|
||||
int originatorId = data.originatorId();
|
||||
Participant *originParticipant = nullptr;
|
||||
if (data.originatorType() == ProjectDataManagement::StateChangeOriginator::Participant)
|
||||
{
|
||||
originParticipant = participantByEquipmentNumber(data.originatorId());
|
||||
if (originParticipant)
|
||||
originatorId = originParticipant->id();
|
||||
else
|
||||
originatorId = -originatorId;
|
||||
}
|
||||
|
||||
// Make Laser Designations to Laser Designations
|
||||
auto dtcPdm = m_bdp->pdmDtc();
|
||||
if (dtcPdm && dtcPdm->getChargeTypeSpecialProperty(data.originatorChargeTypeId(), 0, 0) == ProjectDataManagement::ChargeTypeProperty_def::LTD && originParticipant)
|
||||
{
|
||||
QSet<int> ldGearTypes{1043}; // Need Property for LTD...
|
||||
DynamicParticipantData dpd = originParticipant->dynamicParticipantData();
|
||||
auto it = std::find_if(dpd.gear().cbegin(), dpd.gear().cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId()); });
|
||||
if (it != dpd.gear().cend())
|
||||
{
|
||||
for (auto &ld : dpd.designations())
|
||||
{
|
||||
if (ld.gearId() != it->gearId())
|
||||
continue;
|
||||
|
||||
ld.spotLocation() = pos.position().position();
|
||||
ld.outputPower() = 1.0;
|
||||
originParticipant->setDynamicData(dpd);
|
||||
originParticipant->publishDynamicData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!participantToBeChanged->setState(data, originatorId))
|
||||
return; // outdated - ignore
|
||||
|
||||
participantToBeChanged->publishDynamicData();
|
||||
|
||||
createHitlineInfo(originatorId, originParticipant, participantToBeChanged, pos, data.originatorChargeTypeId(), data.sampleTime());
|
||||
}
|
||||
|
||||
void ParticipantHandler::createHitlineInfo(int, Participant *, Participant *, const TrainingAreaBase::EquipmentPosition &, int, qint64)
|
||||
{
|
||||
// replay participant is filled with setHitlineInfoFromReplay
|
||||
return;
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewPositionFromProxy(const TrainingAreaBase::EquipmentPosition &position)
|
||||
{
|
||||
if (isTelegramInFuture(position))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentPosition which has a timestamp in the future: " << position.sampleTime();
|
||||
return;
|
||||
}
|
||||
if (isTelegramOutdated(position) && position.position().reportingSource() != Core::PositionReportingSource::SetByOperator)
|
||||
{
|
||||
INFO_LOG(m_logger) << "position is outdated: " << position;
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Got new position from proxy: " << position;
|
||||
|
||||
const int equipNo = position.equipmentNumber();
|
||||
// negative - treat as participantId
|
||||
Participant *participantWithNewPosition = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo);
|
||||
|
||||
if (!participantWithNewPosition)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got EquipmentPosition " << position << " for unknown equipment number: " << equipNo;
|
||||
return;
|
||||
}
|
||||
|
||||
if (participantWithNewPosition->setPosition(position))
|
||||
participantWithNewPosition->publishPosition();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewEquipmentOperationalStateFromProxy(const TrainingAreaBase::EquipmentOperationalState &operationalState)
|
||||
{
|
||||
if (isTelegramInFuture(operationalState))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentOperationalState which has a timestamp in the future: " << operationalState.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
Participant *participantToUpdate = participantByEquipmentNumber(operationalState.equipmentNumber());
|
||||
if (!participantToUpdate)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got EquipmentOperationalState for unknown equipment number: " << operationalState;
|
||||
return;
|
||||
}
|
||||
|
||||
participantToUpdate->setOperationalState(operationalState);
|
||||
participantToUpdate->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewBiteFromProxy(const TrainingAreaBase::EquipmentBite &bite)
|
||||
{
|
||||
if (isTelegramInFuture(bite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the future: " << bite.sampleTime();
|
||||
return;
|
||||
}
|
||||
if (isTelegramOutdated(bite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the past: " << bite.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
Bite biteData;
|
||||
|
||||
Participant *p = participantByEquipmentNumber(bite.equipmentNumber());
|
||||
biteData.participantId(p ? p->id() : -1);
|
||||
biteData.equipmentNumber(bite.equipmentNumber());
|
||||
biteData.sampleTime(bite.sampleTime());
|
||||
biteData.registerType(bite.registerType());
|
||||
biteData.biteState(bite.biteState());
|
||||
biteData.configState(bite.configState());
|
||||
biteData.batteryState(bite.batteryState());
|
||||
biteData.configError(bite.configError());
|
||||
|
||||
biteData.biteErrors().reserve(bite.biteErrors().size());
|
||||
for (const TrainingAreaBase::EquipmentBiteError &error : bite.biteErrors())
|
||||
biteData.biteErrors().emplace_back(error.errorNumber(), error.canDeviceNumber(), error.subdeviceNumber(), error.uniqueId());
|
||||
|
||||
dts()->publish(biteData);
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewCtaDataErrorFromProxy(const TrainingAreaBase::CtaDataError &error)
|
||||
{
|
||||
CtaError ctasErrorData;
|
||||
|
||||
ctasErrorData.equipmentNumber(error.equipmentNumber());
|
||||
ctasErrorData.timeReceipt(currentTimeMSec());
|
||||
ctasErrorData.timePlayerUnit(error.sampleTime());
|
||||
ctasErrorData.errorReason(error.reason());
|
||||
ctasErrorData.telegramId(error.originTelegramId());
|
||||
|
||||
dts()->publish(ctasErrorData);
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &report)
|
||||
{
|
||||
if (isTelegramInFuture(report))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the future: " << report.sampleTime();
|
||||
return;
|
||||
}
|
||||
if (isTelegramOutdated(report))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the past: " << report.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
Participant *participant = participantByEquipmentNumber(report.equipmentNumber());
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << report.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
ParticipantMode ddsData;
|
||||
|
||||
ddsData.participantId(participant->id());
|
||||
ddsData.language(report.language());
|
||||
ddsData.opMode(report.operationMode());
|
||||
ddsData.reactivationDecontamination(report.reactivationDetoxication());
|
||||
ddsData.reactivationMaintenance(report.reactivationMaintenance());
|
||||
ddsData.reactivationMedic(report.reactivationMedic());
|
||||
ddsData.modeVest(report.protectionModeVest());
|
||||
ddsData.modeHelmet(report.protectionModeHelmet());
|
||||
ddsData.modePersonalProtection(report.personellProtectionMode());
|
||||
ddsData.protectionLevel(report.protectionLevel());
|
||||
ddsData.handgrenadeSearchMode(report.handgrenadeSearchMode());
|
||||
ddsData.internationalMode(report.internationalMode());
|
||||
ddsData.abcProtectionMode(report.abcProtectionMode());
|
||||
|
||||
ddsData.sampleTime(report.sampleTime());
|
||||
participant->setMode(ddsData);
|
||||
participant->publishMode();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data)
|
||||
{
|
||||
if (isTelegramInFuture(data))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the future: " << data.sampleTime();
|
||||
return;
|
||||
}
|
||||
if (isTelegramOutdated(data))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the past: " << data.sampleTime();
|
||||
return;
|
||||
}
|
||||
|
||||
Participant *participant = data.equipmentNumber() < 0 ? participantById(-data.equipmentNumber()) : participantByEquipmentNumber(data.equipmentNumber());
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
TrainingAreaBase::EquipmentPosition pos;
|
||||
pos.equipmentNumber(data.equipmentNumber());
|
||||
pos.sampleTime(data.sampleTime());
|
||||
if (data.position().is_set())
|
||||
{
|
||||
Core::GeoPosition geoPos(data.position().get().lon(), data.position().get().lat(), 0);
|
||||
pos.position().position(geoPos);
|
||||
if (participant->setPosition(pos))
|
||||
participant->publishPosition();
|
||||
}
|
||||
|
||||
participant->setSpecialSensorData(data);
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewLaserDesignation(const TrainingAreaBase::LaserDesignation &data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "New Laser Designation: "
|
||||
<< "Code: " << data.code() << ", GearID: " << data.gearId() << ", EqNo: " << data.equipmentNumber() << ", Lon: " << data.spotLocation().lon()
|
||||
<< ", Lat: " << data.spotLocation().lat() << ", Power: " << data.outputPower();
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicParticipantData dpd = participant->dynamicParticipantData();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Begin Update Laser Designation: ";
|
||||
updateLaserDesignation(dpd, data);
|
||||
|
||||
DEBUG_LOG(m_logger) << "End Update Laser Designation: ";
|
||||
|
||||
DEBUG_LOG(m_logger) << "Set DPD and publish ";
|
||||
participant->setDynamicData(dpd);
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onLaserDesignationRemoved(int equipmentNumber, int gearId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "On Remove Laser Designation: ";
|
||||
|
||||
Participant *participant = participantByEquipmentNumber(equipmentNumber);
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << equipmentNumber;
|
||||
return;
|
||||
}
|
||||
DynamicParticipantData dpd = participant->dynamicParticipantData();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Begin Remove Laser Designation: ";
|
||||
removeLaserDesignation(dpd, gearId);
|
||||
DEBUG_LOG(m_logger) << "End Remove Laser Designation: ";
|
||||
|
||||
DEBUG_LOG(m_logger) << "Set DPD and publish ";
|
||||
participant->setDynamicData(dpd);
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onBuildingHitLineInfo(const Buildings::BuildingHitLineInfo &data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onBuildingHitLineInfo "
|
||||
<< "BuildingId=" << data.buildingId() << " originatorParticipantId=" << data.originatorParticipantId();
|
||||
auto dtcPdm = m_bdp->pdmDtc();
|
||||
// NOTE: igniterTypeId/IgniterFunction = 0 as long as BuildingHitLineInfo does not contain values
|
||||
if (dtcPdm->getChargeTypeSpecialProperty(data.chargeTypeId(), 0, 0) != ProjectDataManagement::ChargeTypeProperty_def::LTD)
|
||||
return;
|
||||
|
||||
Participant *participant = participantById(data.originatorParticipantId());
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with participantId: " << data.originatorParticipantId();
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicParticipantData dpd = participant->dynamicParticipantData();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Begin Update Laser Designation: ";
|
||||
updateLaserDesignation(dpd, data);
|
||||
DEBUG_LOG(m_logger) << "End Update Laser Designation: ";
|
||||
|
||||
DEBUG_LOG(m_logger) << "setDynamicData";
|
||||
participant->setDynamicData(dpd);
|
||||
DEBUG_LOG(m_logger) << "publishDynamicData"
|
||||
<< " dpd.designations().size()=" << dpd.designations().size();
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onSanitaryMaterialStockReport(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onSanitaryMaterialStockReport";
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
if (data.qualification() == TrainingAreaBase::Qualification::NotDefined)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!!! Clear Materials : equipment number " << data.equipmentNumber();
|
||||
DEBUG_LOG(m_logger) << "!!! Clear Materials : sample time " << data.sampleTime();
|
||||
participant->setSanitationMaterial(0,
|
||||
std::vector<int>(),
|
||||
data.uniqueId(),
|
||||
data.sampleTime(),
|
||||
Qualification::NotAssigned,
|
||||
data.originatorEquipmentNumber()); // this is a deassociation so clear material
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!!! Set Materials : equipment number " << data.equipmentNumber();
|
||||
DEBUG_LOG(m_logger) << "!!! Set Materials : sample time " << data.sampleTime();
|
||||
participant->setSanitationMaterial(data.sanitaryMaterialCount(),
|
||||
data.sanitaryMaterialStock(),
|
||||
data.uniqueId(),
|
||||
data.sampleTime(),
|
||||
static_cast<ParticipantManagement::Qualification_def::type>(data.qualification().underlying()),
|
||||
data.originatorEquipmentNumber());
|
||||
}
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onParticipantSanitation(const TrainingAreaBase::ParticipantSanitation &data)
|
||||
{
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
Participant *participantOrig = participantByEquipmentNumber(data.originatorEquipmentNumber());
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
int participantOrigId = data.originatorEquipmentNumber();
|
||||
if (participantOrig)
|
||||
participantOrigId = participantOrig->id();
|
||||
|
||||
if (data.qualification() == TrainingAreaBase::Qualification::NotDefined && data.proceduresTaken() == 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!!! Clear Sanitation = " << data.sampleTime();
|
||||
DEBUG_LOG(m_logger) << "!!! Clear Sanitation: equipNo = " << data.equipmentNumber();
|
||||
participant->setSanitationMaterial(0, std::vector<int>(), 0, data.sampleTime(), Qualification::NotAssigned, 0); // this is a deassociation so clear material
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!!! SetSanitation: sample time = " << data.sampleTime();
|
||||
DEBUG_LOG(m_logger) << "!!! SetSanitation: equipNo = " << data.equipmentNumber();
|
||||
participant->setSanitation(data.proceduresTaken(), data.sanitationResult(), data.sanitationEvaluation(), participantOrigId, data.qualification(), data.sampleTime());
|
||||
}
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onOperatorAction(const TrainingAreaBase::OperatorAction &data)
|
||||
{
|
||||
// maybe use other commands later?!
|
||||
if (data.action() != 8 && data.action() != 35)
|
||||
return;
|
||||
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
if (participant->setOperatorAction(data.action(), data.operatorId(), data.sampleTime()))
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
void ParticipantHandler::onEquipmentEvent(const TrainingAreaBase::EquipmentEvent &data)
|
||||
{
|
||||
// maybe use other commands later?!
|
||||
if (data.source().subDeviceId() != 14 || data.source().equipmentFunctionId() != 5)
|
||||
return;
|
||||
|
||||
if (data.code() == 1 || data.code() == 2) // 1: 9Liner 2: Transport
|
||||
{
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
if (!participant)
|
||||
return;
|
||||
|
||||
if (participant->setEquipmentEvent(data.code(), data.sampleTime()))
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantHandler::onNewFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data)
|
||||
{
|
||||
Participant *participant = participantByEquipmentNumber(data.equipmentNumber());
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
TrainingAreaBase::EquipmentPosition pos;
|
||||
pos.equipmentNumber(data.equipmentNumber());
|
||||
pos.sampleTime(data.sampleTime());
|
||||
Core::GeoPosition geoPos(data.position().lon(), data.position().lat(), 0);
|
||||
pos.position().position(geoPos);
|
||||
if (participant->setPosition(pos))
|
||||
participant->publishPosition();
|
||||
|
||||
StateInformation oldState = youngestStateInformation(participant->dynamicParticipantData().stateHistory(), false);
|
||||
TrainingAreaBase::EquipmentState state;
|
||||
state.equipmentNumber(data.equipmentNumber());
|
||||
state.originatorId(data.aesItemId());
|
||||
state.originatorType(ProjectDataManagement::StateChangeOriginator::FunctionalArea);
|
||||
state.sampleTime(data.sampleTime());
|
||||
state.vulnerabilityState(ProjectDataManagement::VulnerabilityState::HitWithNoEffect); // no effect - it's an entry into a functional area
|
||||
state.vulnerabilityBits(oldState.vulnerabilityBits());
|
||||
state.vulnerabilityKindId(oldState.vulnerabilityKindId());
|
||||
state.vitality(oldState.vitality());
|
||||
|
||||
participant->setState(state, data.aesItemId());
|
||||
participant->publishDynamicData();
|
||||
}
|
||||
|
||||
inline bool isOutdated(qint64 curTime, qint64 posTime)
|
||||
{
|
||||
// maxDisplayDuration = 2min -> use 3min
|
||||
return curTime > (posTime + 3 * 60 * 1000);
|
||||
}
|
||||
|
||||
void ParticipantHandler::onHitLineInfoTimeout()
|
||||
{
|
||||
const qint64 tNow = currentTimeMSec();
|
||||
|
||||
auto it = m_hitLineInfoMap.begin();
|
||||
while (it != m_hitLineInfoMap.end())
|
||||
{
|
||||
if (!isOutdated(tNow, it.value().sampleTime()))
|
||||
break;
|
||||
dts()->removeHitLineInfoByKey(it.value().id());
|
||||
|
||||
it = m_hitLineInfoMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantHandler::setPosition(const ParticipantManagement::ParticipantPosition &data)
|
||||
{
|
||||
Participant *participant = participantById(data.participantId());
|
||||
|
||||
if (!participant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with id " << data.participantId();
|
||||
return;
|
||||
}
|
||||
|
||||
participant->setPosition(data, true);
|
||||
}
|
||||
|
||||
void ParticipantHandler::setHitlineInfoFromReplay(const HitLineInfo &data)
|
||||
{
|
||||
if (!dts()->publish(data))
|
||||
return;
|
||||
m_hitLineInfoMap.insert(data.id(), data);
|
||||
}
|
||||
|
||||
void ParticipantHandler::setUASFromReplay(const UAS &data)
|
||||
{
|
||||
dts()->publish(data);
|
||||
}
|
||||
|
||||
bool ParticipantHandler::isSupportTypeClass(const ParticipantManagement::TypeClass &typeClass)
|
||||
{
|
||||
return (typeClass == TypeClass::SupportUnit || typeClass == TypeClass::SupportEntity);
|
||||
}
|
||||
|
||||
bool ParticipantHandler::isSampleTimeOutdated(qint64 sampleTime) const
|
||||
{
|
||||
const qint64 curTime = currentTimeMSec();
|
||||
return sampleTime < curTime - 11 * 60 * 1000;
|
||||
}
|
||||
|
||||
bool ParticipantHandler::isSampleTimeInFuture(qint64 sampleTime) const
|
||||
{
|
||||
const qint64 curTime = currentTimeMSec();
|
||||
return sampleTime > curTime + 1 * 60 * 1000;
|
||||
}
|
||||
|
||||
std::shared_ptr<Interface::Dts> ParticipantHandler::dts() const { return m_bdp->dts(); }
|
||||
|
||||
qint64 ParticipantHandler::currentTimeMSec() const { return m_bdp->currentTimeMSec(); }
|
||||
|
||||
quint16 ParticipantHandler::getWebSocketPort() const { return m_webSocketHandler->listenPort(); }
|
||||
|
||||
void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &data, const TrainingAreaBase::LaserDesignation &newLaserDesignation)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Start ";
|
||||
|
||||
for (LaserDesignation &laserDesignation : data.designations())
|
||||
{
|
||||
if (laserDesignation.gearId() != newLaserDesignation.gearId())
|
||||
continue;
|
||||
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << laserDesignation.gearId() << " found in designations";
|
||||
laserDesignation.code(newLaserDesignation.code());
|
||||
|
||||
if (!qFuzzyIsNull(laserDesignation.outputPower()) && !qFuzzyIsNull(newLaserDesignation.spotLocation().lat())
|
||||
&& !qFuzzyIsNull(newLaserDesignation.spotLocation().lon()))
|
||||
laserDesignation.spotLocation(Core::GeoPosition(newLaserDesignation.spotLocation().lon(), newLaserDesignation.spotLocation().lat(), 0.0));
|
||||
|
||||
// If Laser was on before and now is turned off, we have to reset spot Location
|
||||
if (!qFuzzyIsNull(laserDesignation.outputPower()) && qFuzzyIsNull(newLaserDesignation.outputPower()))
|
||||
laserDesignation.spotLocation(Core::GeoPosition(0.0, 0.0, 0.0));
|
||||
|
||||
laserDesignation.outputPower(newLaserDesignation.outputPower());
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Data updated, returning";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId() << " NOT found in designations";
|
||||
|
||||
int gearId = newLaserDesignation.gearId();
|
||||
auto it = std::find_if(data.gear().cbegin(), data.gear().cend(), [gearId](const GearInformation &gi) { return gearId == gi.gearId(); });
|
||||
if (it == data.gear().cend()) // No gear, no designation...
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId() << " NOT found in Gears";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId() << " found in Gears";
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation - Adding new designation";
|
||||
data.designations().emplace_back(newLaserDesignation.gearId(),
|
||||
Core::GeoPosition(newLaserDesignation.spotLocation().lon(), newLaserDesignation.spotLocation().lat(), 0.0),
|
||||
newLaserDesignation.code(),
|
||||
newLaserDesignation.outputPower());
|
||||
}
|
||||
|
||||
void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &dataInOut, const Buildings::BuildingHitLineInfo &newLaserDesignation)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
|
||||
// Todo: Die erste vorhandene LaserDesignation wird angepasst. Ein Laser On muss vorher gekommen sein, damit das Element da ist.
|
||||
// Mehrere Designatoren pro Teilnehmer werden nicht unterstützt.
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info";
|
||||
|
||||
for (LaserDesignation &laserDesignation : dataInOut.designations())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Updating (first) Designation with GearId " << laserDesignation.gearId();
|
||||
laserDesignation.outputPower(1.0);
|
||||
laserDesignation.spotLocation(newLaserDesignation.buildingPos());
|
||||
return;
|
||||
}
|
||||
|
||||
QSet<int> ldGearTypes{1043}; // Need Property for LTD...
|
||||
auto it = std::find_if(dataInOut.gear().cbegin(), dataInOut.gear().cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId()); });
|
||||
if (it != dataInOut.gear().cend())
|
||||
{
|
||||
LaserDesignation ld;
|
||||
ld.gearId() = it->gearId();
|
||||
ld.code() = 0;
|
||||
ld.spotLocation() = newLaserDesignation.buildingPos();
|
||||
ld.outputPower(1.0);
|
||||
dataInOut.designations().emplace_back(ld);
|
||||
ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Added Designation";
|
||||
}
|
||||
ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - No laserDesignation available participantId="
|
||||
<< newLaserDesignation.originatorParticipantId();
|
||||
}
|
||||
|
||||
void ParticipantHandler::removeLaserDesignation(DynamicParticipantData &data, qint32 gearId)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
|
||||
|
||||
DEBUG_LOG(m_logger) << "-Remove Laser Designation: Start";
|
||||
auto validationFunction = [gearId](ParticipantManagement::LaserDesignation laserDesignation) { return laserDesignation.gearId() == gearId; };
|
||||
auto eraseIterator = std::find_if(data.designations().begin(), data.designations().end(), validationFunction);
|
||||
|
||||
if (eraseIterator == data.designations().end())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "-Remove Laser Designation: GearId NOT found";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "-Remove Laser Designation: Removing Designation";
|
||||
data.designations().erase(eraseIterator);
|
||||
}
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* The ParticipantHandler class manages all participant related function topics and holds classes for
|
||||
* further participant data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include <Proxies/TrainingAreaBase/tab_dtc.h>
|
||||
|
||||
#include <ParticipantManagement/ppm_db_structs.h>
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <ParticipantManagement/web_socket_handler.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "participant_donator.h"
|
||||
|
||||
namespace Buildings
|
||||
{
|
||||
class BuildingHitLineInfo;
|
||||
}
|
||||
|
||||
namespace ProjectDataManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
} // namespace ProjectDataManagement
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class Participant;
|
||||
class ExerciseParticipant;
|
||||
class SupportParticipant;
|
||||
class UnitPositionCalculator;
|
||||
|
||||
class BaseDataProvider
|
||||
{
|
||||
public:
|
||||
BaseDataProvider() = default;
|
||||
virtual ~BaseDataProvider() = default;
|
||||
virtual std::shared_ptr<Interface::Dts> dts() const = 0;
|
||||
virtual std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const = 0;
|
||||
virtual qint64 currentTimeMSec() const = 0;
|
||||
};
|
||||
|
||||
struct ParticipantOrganisationEx : public ParticipantOrganisation
|
||||
{
|
||||
int dbId = 0;
|
||||
void copy(const ParticipantOrganisation &o)
|
||||
{
|
||||
ParticipantOrganisation *that = this;
|
||||
*that = o;
|
||||
}
|
||||
};
|
||||
|
||||
class ParticipantHandler
|
||||
: public QObject
|
||||
, public ParticipantDonator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ParticipantHandler(BaseDataProvider *bdp, const char *loggerName);
|
||||
~ParticipantHandler();
|
||||
|
||||
void clearParticipants();
|
||||
virtual bool init();
|
||||
|
||||
virtual void setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId);
|
||||
|
||||
Participant *participantById(int32_t participantId) const override;
|
||||
Participant *participantByEquipmentNumber(int32_t equipmentNumber);
|
||||
// only needed in Exercise, correctly reimplemented in ParticipantHandlerForExercise
|
||||
bool isUnitType(int typeId) const override
|
||||
{
|
||||
Q_UNUSED(typeId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void gearChargeChanged(int participantId, int partyId);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onNewGearEvent(const TrainingAreaBase::EquipmentGearEvent &gearEvent);
|
||||
void onNewGearChargeStateFromProxy(const TrainingAreaBase::EquipmentGearChargeState &chargeState);
|
||||
void onNewGearAssignmentFromProxy(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment);
|
||||
void onNewStateFromProxy(const TrainingAreaBase::EquipmentState &data);
|
||||
void onNewPositionFromProxy(const TrainingAreaBase::EquipmentPosition &position);
|
||||
void onNewEquipmentOperationalStateFromProxy(const TrainingAreaBase::EquipmentOperationalState &operationalState);
|
||||
void onNewBiteFromProxy(const TrainingAreaBase::EquipmentBite &bite);
|
||||
void onNewCtaDataErrorFromProxy(const TrainingAreaBase::CtaDataError &error);
|
||||
void onNewParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &report);
|
||||
void onNewSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data);
|
||||
void onNewFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data);
|
||||
void onNewLaserDesignation(const TrainingAreaBase::LaserDesignation &data);
|
||||
void onLaserDesignationRemoved(int equipmentNumber, int gearId);
|
||||
void onSanitaryMaterialStockReport(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data);
|
||||
void onParticipantSanitation(const TrainingAreaBase::ParticipantSanitation &data);
|
||||
void onOperatorAction(const TrainingAreaBase::OperatorAction &data);
|
||||
void onEquipmentEvent(const TrainingAreaBase::EquipmentEvent &data);
|
||||
void onBuildingHitLineInfo(const Buildings::BuildingHitLineInfo &data);
|
||||
void onHitLineInfoTimeout();
|
||||
|
||||
public:
|
||||
void newData(const TrainingAreaBase::EquipmentGearEvent &data) { onNewGearEvent(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentGearChargeState &data) { onNewGearChargeStateFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentGearAssignment &data) { onNewGearAssignmentFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentState &data) { onNewStateFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentPosition &data) { onNewPositionFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentOperationalState &data) { onNewEquipmentOperationalStateFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentBite &data) { onNewBiteFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::CtaDataError &data) { onNewCtaDataErrorFromProxy(data); }
|
||||
void newData(const TrainingAreaBase::ParticipantModeReport &data) { onNewParticipantModeReport(data); }
|
||||
void newData(const TrainingAreaBase::SpecialSensorData &data) { onNewSpecialSensorData(data); }
|
||||
void newData(const TrainingAreaBase::ParticipantSanitation &data) { onParticipantSanitation(data); }
|
||||
void newData(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data) { onSanitaryMaterialStockReport(data); }
|
||||
void newData(const TrainingAreaBase::EquipmentEvent &data) { onEquipmentEvent(data); }
|
||||
void newData(const ParticipantPosition &data) { setPosition(data); }
|
||||
void newData(const HitLineInfo &data) { setHitlineInfoFromReplay(data); }
|
||||
void newData(const UAS &data) { setUASFromReplay(data); }
|
||||
|
||||
std::shared_ptr<Interface::Dts> dts() const;
|
||||
qint64 currentTimeMSec() const;
|
||||
|
||||
quint16 getWebSocketPort() const;
|
||||
|
||||
protected:
|
||||
static void updateLaserDesignation(DynamicParticipantData &data, const TrainingAreaBase::LaserDesignation &newLaserDesignation);
|
||||
void updateLaserDesignation(DynamicParticipantData &dataInOut, const Buildings::BuildingHitLineInfo &newLaserDesignation);
|
||||
static void removeLaserDesignation(DynamicParticipantData &data, qint32 gearId);
|
||||
void setPosition(const ParticipantPosition &data);
|
||||
void setHitlineInfoFromReplay(const HitLineInfo &data);
|
||||
void setUASFromReplay(const UAS &data);
|
||||
|
||||
virtual void createHitlineInfo(int originatorId,
|
||||
Participant *originParticipant,
|
||||
Participant *participantToBeChanged,
|
||||
const TrainingAreaBase::EquipmentPosition &pos,
|
||||
int originatorChargeTypeId,
|
||||
qint64 sampleTime);
|
||||
|
||||
static bool isSupportTypeClass(const TypeClass &typeClass);
|
||||
// t - 11min <= sampleTime
|
||||
template <typename T> inline bool isTelegramOutdated(const T &tele) const { return isSampleTimeOutdated(tele.sampleTime()); }
|
||||
virtual bool isSampleTimeOutdated(qint64 sampleTime) const;
|
||||
// sampleTime > t + 1min
|
||||
template <typename T> inline bool isTelegramInFuture(const T &tele) const { return isSampleTimeInFuture(tele.sampleTime()); }
|
||||
virtual bool isSampleTimeInFuture(qint64 sampleTime) const;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<UnitPositionCalculator> m_unitPositionCalculator;
|
||||
QHash<int, int> m_equipNumber2ParticipantId;
|
||||
QHash<int, Participant *> m_participants;
|
||||
QHash<int, ParticipantOrganisationEx> m_participantOrganisations;
|
||||
int m_hitLineId;
|
||||
QMap<int, HitLineInfo> m_hitLineInfoMap;
|
||||
|
||||
BaseDataProvider *m_bdp;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
std::shared_ptr<WebSocketHandler> m_webSocketHandler;
|
||||
|
||||
friend class Participant;
|
||||
};
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
Executable
+2026
File diff suppressed because it is too large.
Load diff
Executable
+199
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* The ParticipantHandler class manages all participant related function topics and holds classes for
|
||||
* further participant data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "participant_handler.h"
|
||||
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
#include <TrainingAreaBase/tab_dts.h>
|
||||
|
||||
class QTimer;
|
||||
class QTransform;
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class FiringUnitValidator;
|
||||
class ProxyListener;
|
||||
|
||||
class ParticipantHandlerForExercise final
|
||||
: public ParticipantHandler
|
||||
, protected Interface::Fts::ModifyStateRequestHandler
|
||||
, protected Interface::Fts::ModifyParticipantDataRequestHandler
|
||||
, protected Interface::Fts::InitParticipantRequestHandler
|
||||
, protected Interface::Fts::SetParticipantModeRequestHandler
|
||||
, protected Interface::Fts::SendMessageRequestHandler
|
||||
, protected Interface::Fts::RegisterParticipantRequestHandler
|
||||
, protected Interface::Fts::SetSimulatedPositionRequestHandler
|
||||
, protected Interface::Fts::SetSimulatedPositionRelativeRequestHandler
|
||||
, protected Interface::Fts::SetSimulatedParticipantFormationRequestHandler
|
||||
, protected Interface::Fts::SetSanitationRequestHandler
|
||||
, protected Interface::Fts::SelectiveReammunitionRequestHandler
|
||||
, protected Interface::Fts::SetAsSimulatedRequestHandler
|
||||
, protected Interface::Fts::OcCommandRequestHandler
|
||||
, protected Interface::Fts::ModifyUasStateRequestHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ParticipantHandlerForExercise(MainHandler *mainHandler);
|
||||
~ParticipantHandlerForExercise();
|
||||
bool init() override;
|
||||
|
||||
void setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId) override;
|
||||
bool isUnitType(int typeId) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void onGearChargeChanged(int participantId, int partyId);
|
||||
|
||||
protected:
|
||||
struct ParticipantFormationStruct
|
||||
{
|
||||
QString geometry = QStringLiteral("line");
|
||||
double distance = -1;
|
||||
double angle = -1;
|
||||
QString jsonData;
|
||||
QJsonObject distanceSetsObj;
|
||||
QVariantMap distanceSets;
|
||||
ParticipantFormationStruct() {}
|
||||
explicit ParticipantFormationStruct(const QString &formationProperty) : jsonData(formationProperty)
|
||||
{
|
||||
const QJsonObject formationObj = QJsonDocument::fromJson(QByteArray::fromStdString(jsonData.toStdString())).object();
|
||||
if (formationObj.isEmpty())
|
||||
return;
|
||||
geometry = formationObj[QStringLiteral("geometry")].toString(QStringLiteral("line"));
|
||||
angle = formationObj[QStringLiteral("angle")].toDouble(-1);
|
||||
distance = formationObj[QStringLiteral("distance")].toDouble(-1);
|
||||
distanceSetsObj = formationObj[QStringLiteral("distanceSets")].toObject();
|
||||
distanceSets = distanceSetsObj.toVariantMap();
|
||||
}
|
||||
|
||||
public:
|
||||
bool hasFormationData() const { return ((angle != -1) && (distance != -1)); }
|
||||
};
|
||||
|
||||
void getFormationParameters(const QString &jsdata, QString &geometry, double &distance, double &angle);
|
||||
void setFormationAsLine(Participant *participant, const SetSimulatedParticipantFormation &request, const double distance, const double angleDeg);
|
||||
|
||||
void createHitlineInfo(int originatorId,
|
||||
Participant *originParticipant,
|
||||
Participant *participantToBeChanged,
|
||||
const TrainingAreaBase::EquipmentPosition &pos,
|
||||
int originatorChargeTypeId,
|
||||
qint64 sampleTime) override;
|
||||
void onModifyParticipantDataRequest(const rti::core::SampleIdentity &cookie, const ModifyParticipantDataRequest &request) override;
|
||||
Core::FunctionReplyObject modifyParticipantDataRequest(const ModifyParticipantDataRequest &request);
|
||||
// ModifyState
|
||||
void onModifyStateRequest(const rti::core::SampleIdentity &cookie, const ModifyStateRequest &request) override;
|
||||
Core::FunctionReplyObject modifyStateRequest(const rti::core::SampleIdentity &cookie, const ModifyStateRequest &request);
|
||||
// Init
|
||||
void onInitParticipantRequest(const rti::core::SampleIdentity &cookie, const InitParticipantRequest &request) override;
|
||||
Core::FunctionReplyObject initParticipantRequest(const rti::core::SampleIdentity &cookie, const InitParticipantRequest &request);
|
||||
// Mode
|
||||
void onSetParticipantModeRequest(const rti::core::SampleIdentity &cookie, const SetParticipantModeRequest &request) override;
|
||||
Core::FunctionReplyObject setParticipantModeRequest(const rti::core::SampleIdentity &cookie, const SetParticipantModeRequest &request);
|
||||
|
||||
void onSendMessageRequest(const rti::core::SampleIdentity &cookie, const SendMessageRequest &request) override;
|
||||
Core::FunctionReplyObject sendMessageRequest(const rti::core::SampleIdentity &cookie, const SendMessageRequest &request);
|
||||
void onRegisterParticipantRequest(const rti::core::SampleIdentity &cookie, const RegisterParticipantRequest &request) override;
|
||||
Core::FunctionReplyObject registerParticipantRequest(const RegisterParticipantRequest &request_, RegisterReturnValue &retVal);
|
||||
|
||||
void onSetSimulatedPositionRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedPosition &request) override;
|
||||
Core::FunctionReplyObject setSimulatedPositionRequest(const SetSimulatedPosition &request);
|
||||
void setSimulatedPosition(Participant *participant, const SetSimulatedPosition &request);
|
||||
|
||||
void onSetSimulatedPositionRelativeRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedPositionRelative &request) override;
|
||||
Core::FunctionReplyObject setSimulatedPositionRelativeRequest(const SetSimulatedPositionRelative &request);
|
||||
void setSimulatedPositionRelative(Participant *participant, const SetSimulatedPositionRelative &request);
|
||||
|
||||
void onSetSimulatedParticipantFormationRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedParticipantFormation &request) override;
|
||||
Core::FunctionReplyObject setSimulatedParticipantFormationRequest(const SetSimulatedParticipantFormation &request);
|
||||
|
||||
void onSetSanitationRequest(const rti::core::SampleIdentity &cookie, const SetSanitationRequest &request) override;
|
||||
Core::FunctionReplyObject setSanitationRequest(const rti::core::SampleIdentity &cookie, const SetSanitationRequest &request);
|
||||
|
||||
void onSelectiveReammunitionRequest(const rti::core::SampleIdentity &cookie, const SelectiveReammunitionRequest &request) override;
|
||||
Core::FunctionReplyObject selectiveReammunitionRequest(const rti::core::SampleIdentity &cookie, const SelectiveReammunitionRequest &request);
|
||||
|
||||
void onSetAsSimulatedRequest(const rti::core::SampleIdentity &cookie, const SetAsSimulated &request) override;
|
||||
Core::FunctionReplyObject setAsSimulatedRequest(const SetAsSimulated &request);
|
||||
|
||||
// OcCommand
|
||||
void onOcCommandRequest(const rti::core::SampleIdentity &cookie, const OcCommandRequest &request) override;
|
||||
Core::FunctionReplyObject ocCommandRequest(const rti::core::SampleIdentity &cookie, const OcCommandRequest &request);
|
||||
|
||||
void updateParticipantFormation(Participant *participant, const Core::GeoPosition &position, const QPointF &offset);
|
||||
void setAsSimulated(const SetAsSimulated &request);
|
||||
void onModifyUasStateRequest(const rti::core::SampleIdentity &cookie, const ModifyUasStateRequest &request) override final;
|
||||
|
||||
private: // methods
|
||||
struct ValidateParticipantData // is needed as QtConcurrent can only handle functions with up to 5 parameter ...
|
||||
{
|
||||
QVector<ParticipantData> participantsToBeCreatedOrModified;
|
||||
QHash<int, int> modIdToParticipantId; // <modId, participantId>
|
||||
QVector<int> participantsToResetEquipmentNumber; // when move from template to pool, we have to reset the equipment number if it already exists
|
||||
bool forceAddWithId;
|
||||
};
|
||||
|
||||
Core::FunctionReplyObject createNewParticipants(std::vector<Database::PpmParticipant> &dbParticipantsToBeCreated,
|
||||
const std::vector<int> &dbParticipantsToBeCreatedIndexes,
|
||||
const QVector<ParticipantData> &participantsToBeCreatedOrModified,
|
||||
QHash<int, int> &modIdToParticipantId,
|
||||
QSet<Participant *> &participantsWithChanges);
|
||||
Core::FunctionReplyObject validateParticipantData(ValidateParticipantData &data, const ParticipantManagement::ParticipantData &participantToValidate);
|
||||
|
||||
std::vector<int32_t> inferiorIdsForParticipant(int32_t superiorParticipantId) const;
|
||||
Core::FunctionReplyObject checkDeleteParticipant(int id);
|
||||
Core::FunctionReplyObject deleteParticipant(int32_t id, bool permanentRemove, bool isTriggeredFromFtRequest = false);
|
||||
|
||||
const Type *typeById(int typeId) const;
|
||||
bool isSupportType(int typeId) const;
|
||||
bool isParticipantType(int typeId) const;
|
||||
|
||||
void startLongAction();
|
||||
void checkLongActionBreak();
|
||||
|
||||
bool participantIds2EquipmentNumbers(const std::vector<int32_t> &participantIds, std::vector<int32_t> &equipmentNumbers, int *failedParticipantId) const;
|
||||
void onEquipmentExerciseMappingChanged(const EquipmentExerciseMapping &data, DataModification mod);
|
||||
void onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification mod);
|
||||
void publishEquipmentExerciseMapping();
|
||||
bool isCurrentExerciseActive() const;
|
||||
|
||||
QString lookUpHierachy(int participantId) const;
|
||||
QString participantInfosFromId(int participantId) const;
|
||||
void customedSetGearCharges(Participant *participant);
|
||||
Core::FunctionReplyObject modifyUasStateRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::ModifyUasStateRequest &request);
|
||||
|
||||
private: // attributes
|
||||
MainHandler *m_mainHandler;
|
||||
FiringUnitValidator *m_firingUnitValidator{nullptr};
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dts> m_dtsTab;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
std::unique_ptr<ProxyListener> m_proxyListener;
|
||||
QElapsedTimer m_longActionTimer;
|
||||
QTimer *m_hitLineInfoTimer;
|
||||
QTimer *m_publishEquipmentExerciseMappingsTimer;
|
||||
QHash<int, Database::EquipmentExerciseMapping> m_equipmentExerciseMappings; // QHash<eqId, Database::EquipmentExerciseMapping>
|
||||
bool m_publishEquipmentExerciseMappings;
|
||||
}; // class ParticipantHandler
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,589 @@
|
||||
/**
|
||||
* The ProxyListener class subscribes to participant related proxy data topics and distributes
|
||||
* the collected data via Q_SIGNALS.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-13
|
||||
*/
|
||||
#include "proxy_listener.h"
|
||||
#include "main_handler.h"
|
||||
#include <UasHandling/mission_plan_handler.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
|
||||
ProxyListener::ProxyListener(MainHandler *mainHandler)
|
||||
: QObject()
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("ProxyListener"))
|
||||
{}
|
||||
|
||||
bool ProxyListener::init()
|
||||
{
|
||||
m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_mainHandler->dds());
|
||||
m_bldDtc = Buildings::Interface::Dtc::create(m_mainHandler->dds());
|
||||
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentBiteChanged,
|
||||
this, &ProxyListener::onProxyEquipmentBiteChanged);
|
||||
if (!m_tabDtc->enableEquipmentBite())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialize TraininAreaBase data topic client";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mainHandler->exerciseId() > 0)
|
||||
{
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentPositionChanged,
|
||||
this, &ProxyListener::onProxyEquipmentPositionChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentGearAssignmentChanged,
|
||||
this, &ProxyListener::onProxyEquipmentGearAssignmentChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentGearEventChanged,
|
||||
this, &ProxyListener::onProxyEquipmentGearEventChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::participantSanitaryMaterialStockReportChanged,
|
||||
this, &ProxyListener::onProxyParticipantSanitaryMaterialStockReportChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentGearChargeStateChanged,
|
||||
this, &ProxyListener::onProxyEquipmentGearChargeStateChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentStateChanged,
|
||||
this, &ProxyListener::onProxyEquipmentStateChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentOperationalStateChanged,
|
||||
this, &ProxyListener::onProxyEquipmentOperationalStateChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::ctaDataErrorChanged,
|
||||
this, &ProxyListener::onProxyCtaDataErrorChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::participantModeReportChanged,
|
||||
this, &ProxyListener::onProxyParticipantModeReportChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::specialSensorDataChanged,
|
||||
this, &ProxyListener::onSpecialSensorDataChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::functionalAreaEntryChanged,
|
||||
this, &ProxyListener::onFunctionalAreaEntryChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::laserDesignationChanged,
|
||||
this, &ProxyListener::onLaserDesignationChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::participantSanitationChanged,
|
||||
this, &ProxyListener::onProxyParticipantSanitationChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::operatorActionChanged,
|
||||
this, &ProxyListener::onOperatorActionChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::equipmentEventChanged,
|
||||
this, &ProxyListener::onEquipmentEventChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::uASStatusChanged,
|
||||
this, &ProxyListener::onUASStatusChanged);
|
||||
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::uASMissionStatusChanged,
|
||||
this, &ProxyListener::onUASMissionStatusChanged);
|
||||
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingHitLineInfoChanged,
|
||||
this, &ProxyListener::onBuildingHitLineInfoChanged);
|
||||
|
||||
if (!m_tabDtc->enableEquipmentPosition() ||
|
||||
!m_tabDtc->enableEquipmentGearAssignment() ||
|
||||
!m_tabDtc->enableEquipmentEvent() ||
|
||||
!m_tabDtc->enableEquipmentGearEvent() ||
|
||||
!m_tabDtc->enableEquipmentGearChargeState() ||
|
||||
!m_tabDtc->enableEquipmentState() ||
|
||||
!m_tabDtc->enableEquipmentOperationalState() ||
|
||||
!m_tabDtc->enableCtaDataError() ||
|
||||
!m_tabDtc->enableParticipantModeReport() ||
|
||||
!m_tabDtc->enableFunctionalAreaEntry() ||
|
||||
!m_tabDtc->enableLaserDesignation() ||
|
||||
!m_tabDtc->enableSpecialSensorData() ||
|
||||
!m_tabDtc->enableParticipantSanitaryMaterialStockReport() ||
|
||||
!m_tabDtc->enableOperatorAction() ||
|
||||
!m_tabDtc->enableParticipantSanitation() ||
|
||||
!m_tabDtc->enableUASStatus() ||
|
||||
!m_tabDtc->enableUASMissionStatus() ||
|
||||
!m_bldDtc->enableBuildingHitLineInfo())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialize TraininAreaBase data topic client";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentPositionChanged(const TrainingAreaBase::EquipmentPosition &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new position data from proxy " << data;
|
||||
|
||||
emit newPosition(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentGearAssignmentChanged(const TrainingAreaBase::EquipmentGearAssignment &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new gear assignment from proxy " << data;
|
||||
|
||||
emit newGearAssignment(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentGearEventChanged(const TrainingAreaBase::EquipmentGearEvent &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new gear event " << data;
|
||||
|
||||
emit newGearEvent(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentGearChargeStateChanged(const TrainingAreaBase::EquipmentGearChargeState &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new gear charge state " << data;
|
||||
|
||||
emit newGearChargeState(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyParticipantSanitaryMaterialStockReportChanged(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "FUCKING FUCK FUCK" << data;
|
||||
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new material stock report" << data;
|
||||
|
||||
emit newSanitaryMaterialStockReport(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentStateChanged(const TrainingAreaBase::EquipmentState &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new equipment state " << data;
|
||||
|
||||
emit newState(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentOperationalStateChanged(const TrainingAreaBase::EquipmentOperationalState &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new equipment operational state " << data;
|
||||
|
||||
emit newEquipmentOperationalState(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyEquipmentBiteChanged(const TrainingAreaBase::EquipmentBite &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new equipment bite " << data;
|
||||
|
||||
emit newEquipmentBite(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyCtaDataErrorChanged(const TrainingAreaBase::CtaDataError &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Combat Training Area Data error: " << data;
|
||||
|
||||
emit newCtaDataError(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onSpecialSensorDataChanged(const TrainingAreaBase::SpecialSensorData &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Special Sensor data: " << data;
|
||||
|
||||
emit newSpecialSensorData(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got functional area entry: " << data;
|
||||
|
||||
emit newFunctionalAreaEntryChanged(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onLaserDesignationChanged(const TrainingAreaBase::LaserDesignation &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Got no laser designation data: " << data;
|
||||
emit laserDesignationRemoved(data.equipmentNumber(), data.gearId());
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got laser designation data: " << data;
|
||||
|
||||
emit newLaserDesignationData(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyParticipantSanitationChanged(const TrainingAreaBase::ParticipantSanitation &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Participant Sanitation" << data;
|
||||
|
||||
emit newParticipantSanitation(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onOperatorActionChanged(const TrainingAreaBase::OperatorAction &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Operator Action" << data;
|
||||
|
||||
emit newOperatorAction(data);
|
||||
}
|
||||
|
||||
void ProxyListener::onEquipmentEventChanged(const TrainingAreaBase::EquipmentEvent &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Operator Action" << data;
|
||||
|
||||
emit newEquipmentEvent(data);
|
||||
|
||||
}
|
||||
|
||||
void ProxyListener::onUASStatusChanged(const TrainingAreaBase::UASStatus &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
|
||||
m_mainHandler->ddsHandler()->dtc()->waitForHistoricalDataParticipant(3000);
|
||||
int participantId = m_mainHandler->ddsHandler()->dtc()->participantIdByEquipmentNumber(data.equipmentNumber());
|
||||
|
||||
if (participantId <= 0)
|
||||
return;
|
||||
const auto uas = m_mainHandler->ddsHandler()->dtc()->getUasByParticipantId(participantId, m_mainHandler->exerciseId());
|
||||
|
||||
if (uas.id() <= 0)
|
||||
return;
|
||||
//new PPM Telegram
|
||||
UASRadioLinkConnectionStatus newState;
|
||||
newState.id(uas.id());
|
||||
newState.uasState(data.uasState());
|
||||
DEBUG_LOG(m_logger) << "Publish new UAS State " << newState;
|
||||
m_mainHandler->ddsHandler()->exAnyDts()->publish(newState);
|
||||
}
|
||||
|
||||
void ProxyListener::onUASMissionStatusChanged(const TrainingAreaBase::UASMissionStatus &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "currentTask = " << (int)data.currentTask().underlying() << ", currentMissionName = " << data.currentMissionName() << ", name of ended mission: " << data.missionEnded();
|
||||
/*
|
||||
was wenn random mehrfach hintereinander loiter gesendet wird??
|
||||
dann überspringt er eine action! der tab darf also nur senden wenn wirklich ein state change kam
|
||||
- aber wie stellt man dann sicher dass der handler den letzen state kennt?
|
||||
z.B. würde ein IA restart ein neues loiter senden und somit würde eine action übersprungen werden
|
||||
*/
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "removed - stop";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.currentMissionName().empty() || data.currentTask().underlying() != ProjectDataManagement::UasActionTask::Loiter || data.missionEnded().empty())
|
||||
{
|
||||
//DEBUG As this will happen a lot
|
||||
DEBUG_LOG(m_logger) << "not fulfilling current mission ("<<data.currentMissionName()<<") action because either a mission is still active or current task ("<<(int)data.currentTask().underlying()<<") is not Loiter or mission not ended ("<< data.missionEnded() << (data.missionEnded().empty() ? " [NOT ENDED]" : " [ ENDED ]")<<")";
|
||||
return;
|
||||
}
|
||||
|
||||
m_mainHandler->ddsHandler()->dtc()->waitForHistoricalDataParticipant(3000);
|
||||
const int participantId = m_mainHandler->ddsHandler()->dtc()->participantIdByEquipmentNumber(data.equipmentNumber());
|
||||
if (participantId <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "participant for eqid " << data.equipmentNumber() << " not found - unable to fulfill current mission action";
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(1000, [this, participantId, data]() // give tab plugin time to clean stuff up before sending new missions (by marking an action as fulfilled)
|
||||
{
|
||||
// mission empty & task = loiter? mission done, run next mission (by setting current mission's current action as fulfilled, which will trigger the next action automatically (see ces))
|
||||
if (!m_mainHandler->missionPlanHandler()->setCurrentMissionActionFulfilled(participantId, QString::fromStdString(data.missionEnded())))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "setCurrentMissionActionFulfilled didn't work out";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "setCurrentMissionActionFulfilled done !";
|
||||
});
|
||||
}
|
||||
|
||||
void ProxyListener::onBuildingHitLineInfoChanged(const Buildings::BuildingHitLineInfo &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Building Hitline Info" << data;
|
||||
|
||||
emit newBuildingHitLineInfo(data);
|
||||
|
||||
}
|
||||
|
||||
void ProxyListener::onProxyParticipantModeReportChanged(const TrainingAreaBase::ParticipantModeReport &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got new Participant Mode Report Training Area Data error " << data;
|
||||
|
||||
emit newParticipantModeReport(data);
|
||||
}
|
||||
|
||||
// VulnerabilityStateChange
|
||||
Core::FunctionReplyObject ProxyListener::demandVulnerabilityStateChange(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::DemandVulnerabilityStateChangeRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->demandVulnerabilityStateChangeRequest(req, this))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error passing the Vulnerability state change request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "VulnerabilityStateChange timeout for " << requestId;
|
||||
onDemandVulnerabilityStateChangeReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
void ProxyListener::onDemandVulnerabilityStateChangeReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->modifyStateReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "VulnerabilityStateChange");
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ProxyListener::sendModifyUasStateRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendModifyUasStateRequest &req)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " -- [ProxyListener] sendModifyUasStateRequest uasId: " << req.uasId();
|
||||
if (!m_mainHandler->tabFtc()->sendModifyUasStateRequest(req, this))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error passing the UAS state change request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "ModifyUasState timeout for " << requestId;
|
||||
onSendModifyUasStateReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
void ProxyListener::onSendModifyUasStateReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->modifyUasStateReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "ModifyUasState");
|
||||
}
|
||||
// Init
|
||||
Core::FunctionReplyObject ProxyListener::demandInitRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::DemandInitRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->demandInitRequest(req, this))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error passing the INIT request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "DemandInit timeout for " << requestId;
|
||||
onDemandInitReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
void ProxyListener::onDemandInitReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->initParticipantReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "DemandInit");
|
||||
}
|
||||
|
||||
// SendEquipmentMessage
|
||||
Core::FunctionReplyObject ProxyListener::sendEquipmentMessage(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendEquipmentMessageRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->sendEquipmentMessageRequest(req, this))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error passing SendMessage request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "SendMessage timeout for " << requestId;
|
||||
onSendEquipmentMessageReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
void ProxyListener::onSendEquipmentMessageReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->sendMessageReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "SendParticipantMessage");
|
||||
}
|
||||
|
||||
// SendParticipantMode
|
||||
Core::FunctionReplyObject ProxyListener::sendParticipantModeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendParticipantModeRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->sendParticipantModeRequest(req, this))
|
||||
return Core::FunctionReplyObject(req.participantId(), tr_lts("dds", "Error passing the INIT request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "SendParticipantMode timeout for " << requestId;
|
||||
onSendParticipantModeReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject(req.participantId());
|
||||
}
|
||||
|
||||
void ProxyListener::onSendParticipantModeReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->setParticipantModeReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "SendParticipantMode");
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ProxyListener::sendSetSanitationRequest(const rti::core::SampleIdentity &cookie, const TrainingAreaBase::SendSetSanitationRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->sendSetSanitationRequest(req, this))
|
||||
return Core::FunctionReplyObject(req.participantId(), tr_lts("dds", "Error passing the SetSanitation request to the proxy"));
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "sendSetSanitationRequest timeout for " << requestId;
|
||||
onSendSetSanitationReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
return Core::FunctionReplyObject(req.participantId());
|
||||
}
|
||||
|
||||
void ProxyListener::onSendSetSanitationReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->setSanitationReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "SetSanitationReply");
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ProxyListener::selectiveReammunitionRequest(const rti::core::SampleIdentity &cookie, const TrainingAreaBase::SendSelectiveReammunitionRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->sendSelectiveReammunitionRequest(req, this))
|
||||
return Core::FunctionReplyObject(req.participantId(), tr_lts("dds", "Error passing the SendSelectiveReammunition request to the proxy"));
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "selectiveReammunitionRequest timeout for " << requestId;
|
||||
onSendSelectiveReammunitionReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
return Core::FunctionReplyObject(req.participantId());
|
||||
}
|
||||
|
||||
void ProxyListener::onSendSelectiveReammunitionReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->selectiveReammunitionReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "SelectiveReammunitionReply");
|
||||
}
|
||||
|
||||
// OcCommand
|
||||
Core::FunctionReplyObject ProxyListener::sendOcCommandRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendOcCommandRequest &req)
|
||||
{
|
||||
if (!m_mainHandler->tabFtc()->sendOcCommandRequest(req, this))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error passing the OcCommand request to the proxy"));
|
||||
|
||||
const int requestId = req.requestId();
|
||||
auto cb = [this, requestId]()
|
||||
{
|
||||
INFO_LOG(m_logger) << "SendOcCommand timeout for " << requestId;
|
||||
onSendOcCommandReply(Core::FunctionReplyObject(requestId, tr_lts("dds", "Timeout while waiting for the proxy")));
|
||||
};
|
||||
addToTrainingAreaRequests(cb, req.requestId(), cookie);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
void ProxyListener::onSendOcCommandReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::FunctionReplyObject & replyObject)
|
||||
{
|
||||
m_mainHandler->fts()->ocCommandReply(cookie, replyObject);
|
||||
};
|
||||
handleReply(cb, replyObject, "SendOcCommand");
|
||||
}
|
||||
|
||||
// Helper
|
||||
void ProxyListener::addToTrainingAreaRequests(const std::function<void()> &cb,
|
||||
int requestId,
|
||||
const rti::core::SampleIdentity &cookie)
|
||||
{
|
||||
QTimer *timeoutTimer = new QTimer(this);
|
||||
timeoutTimer->setSingleShot(true);
|
||||
timeoutTimer->setInterval(5000);
|
||||
m_trainingAreaRequests.insert(requestId, {cookie, timeoutTimer});
|
||||
connect(timeoutTimer, &QTimer::timeout, this, cb);
|
||||
}
|
||||
|
||||
void ProxyListener::handleReply(const std::function<void(const rti::core::SampleIdentity &, const Core::FunctionReplyObject &)> &cb,
|
||||
const Core::FunctionReplyObject &replyObject,
|
||||
const char *requestType)
|
||||
{
|
||||
if (replyObject.error())
|
||||
WARNING_LOG(m_logger) << requestType << ": " << replyObject();
|
||||
|
||||
auto it = m_trainingAreaRequests.find(replyObject.id());
|
||||
if (it != m_trainingAreaRequests.end())
|
||||
{
|
||||
const auto &dp = it.value();
|
||||
if (dp.timer)
|
||||
dp.timer->deleteLater();
|
||||
cb(dp.cookie, replyObject);
|
||||
|
||||
m_trainingAreaRequests.erase(it);
|
||||
}
|
||||
else
|
||||
WARNING_LOG(m_logger) << requestType << " with request id " << replyObject.id() << " was not replied to by the proxy";
|
||||
}
|
||||
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* The ProxyListener class subscribes to participant related proxy data topics and distributes
|
||||
* the collected data via Q_SIGNALS.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-13
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "logger.h"
|
||||
#include <TrainingAreaBase/tab_dtc.h>
|
||||
#include <TrainingAreaBase/tab_ftc.h>
|
||||
|
||||
#include <Buildings/bld_dtc.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class ProxyListener final
|
||||
: public QObject
|
||||
, public TrainingAreaBase::Interface::Ftc::DemandVulnerabilityStateChangeReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::DemandInitReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendEquipmentMessageReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendParticipantModeReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendSetSanitationReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendSelectiveReammunitionReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendOcCommandReplyHandler
|
||||
, public TrainingAreaBase::Interface::Ftc::SendModifyUasStateReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProxyListener(MainHandler *mainHandler);
|
||||
|
||||
bool init();
|
||||
|
||||
Core::FunctionReplyObject demandVulnerabilityStateChange(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::DemandVulnerabilityStateChangeRequest &req);
|
||||
Core::FunctionReplyObject demandInitRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::DemandInitRequest &req);
|
||||
Core::FunctionReplyObject sendEquipmentMessage(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendEquipmentMessageRequest &req);
|
||||
Core::FunctionReplyObject sendParticipantModeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendParticipantModeRequest &req);
|
||||
Core::FunctionReplyObject sendSetSanitationRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendSetSanitationRequest &req);
|
||||
Core::FunctionReplyObject selectiveReammunitionRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendSelectiveReammunitionRequest &req);
|
||||
Core::FunctionReplyObject sendOcCommandRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendOcCommandRequest &req);
|
||||
Core::FunctionReplyObject sendModifyUasStateRequest(const rti::core::SampleIdentity &cookie,
|
||||
const TrainingAreaBase::SendModifyUasStateRequest &req);
|
||||
private:
|
||||
void onDemandVulnerabilityStateChangeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onDemandInitReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendEquipmentMessageReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendParticipantModeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendSetSanitationReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendSelectiveReammunitionReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendOcCommandReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSendModifyUasStateReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
// Helper
|
||||
void addToTrainingAreaRequests(const std::function<void()> &cb,
|
||||
int requestId,
|
||||
const rti::core::SampleIdentity &cookie);
|
||||
void handleReply(const std::function<void(const rti::core::SampleIdentity &, const Core::FunctionReplyObject &)> &cb,
|
||||
const Core::FunctionReplyObject &replyObject,
|
||||
const char *requestType);
|
||||
|
||||
Q_SIGNALS:
|
||||
void newPosition(const TrainingAreaBase::EquipmentPosition &position);
|
||||
void newState(const TrainingAreaBase::EquipmentState &state);
|
||||
void newGearAssignment(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment);
|
||||
void newGearChargeState(const TrainingAreaBase::EquipmentGearChargeState &chargeState);
|
||||
void newGearEvent(const TrainingAreaBase::EquipmentGearEvent &gearEvent);
|
||||
void newEquipmentOperationalState(const TrainingAreaBase::EquipmentOperationalState &operationalState);
|
||||
void newEquipmentBite(const TrainingAreaBase::EquipmentBite &bite);
|
||||
void newCtaDataError(const TrainingAreaBase::CtaDataError &error);
|
||||
void newParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &modeReport);
|
||||
void newSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data);
|
||||
void newFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data);
|
||||
void newLaserDesignationData(const TrainingAreaBase::LaserDesignation &data);
|
||||
void newSanitaryMaterialStockReport(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data);
|
||||
void laserDesignationRemoved(int equipmentNumber, int gearId);
|
||||
void newParticipantSanitation(const TrainingAreaBase::ParticipantSanitation &data);
|
||||
void newOperatorAction(const TrainingAreaBase::OperatorAction &data);
|
||||
void newEquipmentEvent(const TrainingAreaBase::EquipmentEvent &data);
|
||||
void newBuildingHitLineInfo(const Buildings::BuildingHitLineInfo &data);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onProxyEquipmentPositionChanged(const TrainingAreaBase::EquipmentPosition &data, DataModification modType);
|
||||
void onProxyEquipmentGearAssignmentChanged(const TrainingAreaBase::EquipmentGearAssignment &data, DataModification modType);
|
||||
void onProxyEquipmentGearEventChanged(const TrainingAreaBase::EquipmentGearEvent &data, DataModification modType);
|
||||
void onProxyEquipmentGearChargeStateChanged(const TrainingAreaBase::EquipmentGearChargeState &data, DataModification modType);
|
||||
void onProxyParticipantSanitaryMaterialStockReportChanged(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data, DataModification modType);
|
||||
void onProxyEquipmentStateChanged(const TrainingAreaBase::EquipmentState &data, DataModification modType);
|
||||
void onProxyEquipmentOperationalStateChanged(const TrainingAreaBase::EquipmentOperationalState &data, DataModification modType);
|
||||
void onProxyEquipmentBiteChanged(const TrainingAreaBase::EquipmentBite &data, DataModification modType);
|
||||
void onProxyCtaDataErrorChanged(const TrainingAreaBase::CtaDataError &data, DataModification modType);
|
||||
void onProxyParticipantModeReportChanged(const TrainingAreaBase::ParticipantModeReport &data, DataModification modType);
|
||||
void onSpecialSensorDataChanged(const TrainingAreaBase::SpecialSensorData &data, DataModification modType);
|
||||
void onFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data, DataModification modType);
|
||||
void onLaserDesignationChanged(const TrainingAreaBase::LaserDesignation &data, DataModification modType);
|
||||
void onProxyParticipantSanitationChanged(const TrainingAreaBase::ParticipantSanitation &data, DataModification modType);
|
||||
void onOperatorActionChanged(const TrainingAreaBase::OperatorAction &data, DataModification modType);
|
||||
void onEquipmentEventChanged(const TrainingAreaBase::EquipmentEvent &data, DataModification modType);
|
||||
void onUASStatusChanged(const TrainingAreaBase::UASStatus &data, DataModification modType);
|
||||
void onUASMissionStatusChanged(const TrainingAreaBase::UASMissionStatus &data, DataModification modType);
|
||||
void onBuildingHitLineInfoChanged(const Buildings::BuildingHitLineInfo &data, DataModification modType);
|
||||
|
||||
private: // attributes
|
||||
struct TrainingAreaRequests
|
||||
{
|
||||
rti::core::SampleIdentity cookie;
|
||||
QPointer<QTimer> timer;
|
||||
};
|
||||
QMap<int, TrainingAreaRequests> m_trainingAreaRequests;
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> m_tabDtc;
|
||||
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
|
||||
MainHandler *m_mainHandler;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
}; // class ProxyListener
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* Calculate the focal point for units based on it's superiors
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-09-05
|
||||
*/
|
||||
|
||||
|
||||
#include "unit_position_calculator.h"
|
||||
#include "participant_handler.h"
|
||||
#include <QTimer>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
#include <LtsUtilsCore/outdated_position.h>
|
||||
#include <QPointF>
|
||||
#include <QDateTime>
|
||||
#include <QtConcurrent>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
UnitPositionCalculator::UnitPositionCalculator(ParticipantHandler *participantHandler, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_participantHandler(participantHandler)
|
||||
, m_bSomethingChangedSinceLastCalculation(false)
|
||||
, m_timer(new QTimer(this))
|
||||
, m_bRunning(true)
|
||||
, m_logger(getLogger("UnitPositionCalculator"))
|
||||
{
|
||||
connect(m_timer, &QTimer::timeout, this, &UnitPositionCalculator::calculate);
|
||||
m_timer->setSingleShot(true);
|
||||
|
||||
connect(&m_calculationWatcher, &QFutureWatcher<Result>::finished,
|
||||
this, &UnitPositionCalculator::onCalculationDone);
|
||||
}
|
||||
|
||||
UnitPositionCalculator::~UnitPositionCalculator()
|
||||
{
|
||||
stopCalculation();
|
||||
m_calculationWatcher.disconnect(this);
|
||||
m_calculationWatcher.cancel();
|
||||
m_calculationWatcher.waitForFinished();
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::startCalculation()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Starting calculation timer";
|
||||
m_timer->start();
|
||||
m_bRunning = true;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::stopCalculation()
|
||||
{
|
||||
m_timer->stop();
|
||||
m_participantData.clear();
|
||||
m_publishedPositionData.clear();
|
||||
m_bRunning = false;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::waitForCalculationFinished()
|
||||
{
|
||||
if (m_calculationWatcher.isRunning())
|
||||
m_calculationWatcher.waitForFinished();
|
||||
}
|
||||
|
||||
|
||||
void UnitPositionCalculator::onParticipantDeleted(int participantId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Participant " << participantId << " deleted";
|
||||
auto it = m_participantData.find(participantId);
|
||||
if (it == m_participantData.end())
|
||||
return;
|
||||
m_participantData.erase(it);
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::onPositionChanged(int participantId, int64_t positionTime, const Core::GeoPosition &pos)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Position for participant " << participantId << " changed to "
|
||||
<< pos << " (" << positionTime / 1000 << "s)";
|
||||
CalculatedUnitPosition &data = getParticipant(participantId);
|
||||
if (data.sampleTimeLeader() >= positionTime)
|
||||
return;
|
||||
|
||||
data.sampleTimeCenter(positionTime);
|
||||
data.sampleTimeLeader(positionTime);
|
||||
data.positionCenter(pos);
|
||||
data.positionLeader(pos);
|
||||
m_bSomethingChangedSinceLastCalculation = true;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::onSuperiorChanged(int participantId, int superiorId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Superior for participant " << participantId << " changed to " << superiorId;
|
||||
CalculatedUnitPosition &data = getParticipant(participantId);
|
||||
data.superiorId = superiorId;
|
||||
m_bSomethingChangedSinceLastCalculation = true;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::onInferiorChanged(int participantId, const std::vector<int> &inferiorIds)
|
||||
{
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
QStringList slIds;
|
||||
slIds.reserve(inferiorIds.size());
|
||||
for (int id : inferiorIds)
|
||||
slIds += QString::number(id);
|
||||
DEBUG_LOG(m_logger) << "Inferior for participant " << participantId << " changed, size: " << slIds.join(QLatin1Char(' '));
|
||||
}
|
||||
|
||||
CalculatedUnitPosition &data = getParticipant(participantId);
|
||||
data.inferiorIds = inferiorIds;
|
||||
m_bSomethingChangedSinceLastCalculation = true;
|
||||
}
|
||||
|
||||
UnitPositionCalculator::CalculatedUnitPosition &UnitPositionCalculator::getParticipant(int participantId)
|
||||
{
|
||||
auto it = m_participantData.find(participantId);
|
||||
if (it == m_participantData.end())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "No information for participant " << participantId << " - creating dummy data";
|
||||
|
||||
CalculatedUnitPosition data;
|
||||
data.participantId(participantId);
|
||||
static const Core::GeoPosition s_invalidPos(std::nan(""), std::nan(""), std::nan(""));
|
||||
data.positionCenter(s_invalidPos);
|
||||
data.positionLeader(s_invalidPos);
|
||||
it = m_participantData.insert({participantId, std::move(data)}).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::calculate()
|
||||
{
|
||||
static bool s_bDebugOnce = false;
|
||||
// theoretisches Problem: wenn sich keiner bewegt werden die Unit-Symbole nicht aktualisiert wenn
|
||||
// dann Teilnehmer out-of-date gehen
|
||||
if (!m_bSomethingChangedSinceLastCalculation)
|
||||
{
|
||||
if (!s_bDebugOnce)
|
||||
DEBUG_LOG(m_logger) << "Nothing changed - no calculation needed -> waiting for new data";
|
||||
s_bDebugOnce = true;
|
||||
m_timer->start(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
s_bDebugOnce = false;
|
||||
m_bSomethingChangedSinceLastCalculation = false;
|
||||
// copy data (before thread starts), can be done better with c++14 (lambda captures)
|
||||
std::unordered_map<int, CalculatedUnitPosition> *participantData(new std::unordered_map<int, CalculatedUnitPosition>(m_participantData));
|
||||
const qint64 currentTime = m_participantHandler->currentTimeMSec();
|
||||
auto cb = [this, participantData, currentTime]() -> Result
|
||||
{
|
||||
const auto ret = doCalculation(*participantData, currentTime, m_logger);
|
||||
delete participantData;
|
||||
return ret;
|
||||
};
|
||||
m_calculationWatcher.setFuture(QtConcurrent::run(cb));
|
||||
}
|
||||
|
||||
UnitPositionCalculator::Result UnitPositionCalculator::doCalculation(std::unordered_map<int, CalculatedUnitPosition> &participantData,
|
||||
qint64 currentTime,
|
||||
NGL::INGLLogger &logger)
|
||||
{
|
||||
DEBUG_LOG(logger) << "Starting calculation loop";
|
||||
|
||||
Result result;
|
||||
result.reserve(participantData.size());
|
||||
|
||||
// search all top-level units
|
||||
std::vector<int> topLevelIds;
|
||||
topLevelIds.reserve(10);
|
||||
for (const auto &data : participantData)
|
||||
{
|
||||
const int superiorId = data.second.superiorId;
|
||||
const int participantId = data.second.participantId();
|
||||
DEBUG_LOG(logger) << "Participant " << participantId << " has superior " << superiorId;
|
||||
if (superiorId == 0 || participantData.find(superiorId) == participantData.end())
|
||||
{
|
||||
DEBUG_LOG(logger) << "Participant " << participantId << " is a toplevel participant";
|
||||
topLevelIds.push_back(data.second.participantId());
|
||||
}
|
||||
}
|
||||
// TODO: check for correct (non-cyclic) hierarchy?
|
||||
|
||||
for (const int topLevelId : topLevelIds)
|
||||
{
|
||||
DEBUG_LOG(logger) << "Calculating positions for toplevel participant " << topLevelId;
|
||||
calculatePosition(topLevelId, participantData, currentTime, 1, logger, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::calculatePosition(int participantId,
|
||||
std::unordered_map<int, CalculatedUnitPosition> &participantData,
|
||||
qint64 currentTime,
|
||||
int level,
|
||||
NGL::INGLLogger &logger,
|
||||
Result &result)
|
||||
{
|
||||
static const Core::GeoPosition s_invalidPos(std::nan(""), std::nan(""), std::nan(""));
|
||||
|
||||
const QByteArray dbgLvlSpaces(level, ' ');
|
||||
auto it = participantData.find(participantId);
|
||||
if (it == participantData.end())
|
||||
{
|
||||
WARNING_LOG(logger) << "Participant " << participantId << " not found for unit position calculation!";
|
||||
return;
|
||||
}
|
||||
CalculatedUnitPosition &data = it->second;
|
||||
// found leaf -> return
|
||||
if (data.inferiorIds.size() == 0)
|
||||
{
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Participant " << participantId
|
||||
<< " is a leaf: " << data.positionCenter()
|
||||
<< " (" << data.sampleTimeCenter() / 1000 << "s)";
|
||||
return;
|
||||
}
|
||||
|
||||
data.positionCenter(s_invalidPos);
|
||||
data.positionLeader(s_invalidPos);
|
||||
|
||||
// calculate position for inferiors
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Participant " << participantId << ": Start calculating child positions";
|
||||
for (const int inferiorId : data.inferiorIds)
|
||||
{
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Participant " << participantId << ": calculating child position for " << inferiorId;
|
||||
calculatePosition(inferiorId, participantData, currentTime, level + 1, logger, result);
|
||||
}
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Participant " << participantId << ": Finished calculating child positions";
|
||||
|
||||
// now calc own position
|
||||
int utmZone = -1;
|
||||
int childCount = 0;
|
||||
LtsUtils::QPoint3D pos;
|
||||
qint64 childPositionTime = 0;
|
||||
bool bFirst = true;
|
||||
for (const int inferiorId : data.inferiorIds)
|
||||
{
|
||||
auto itChild = participantData.find(inferiorId);
|
||||
// Warning was already given in loop before
|
||||
if (itChild == participantData.end())
|
||||
{
|
||||
WARNING_LOG(logger) << dbgLvlSpaces << "Child " << inferiorId << ": could not find data";
|
||||
continue;
|
||||
}
|
||||
|
||||
const CalculatedUnitPosition &child = itChild->second;
|
||||
// older than 10 minutes -> ignore
|
||||
if (LtsUtils::isPositionTimeOutdated(currentTime, child.sampleTimeCenter()))
|
||||
{
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Child " << inferiorId << ": position out-of-date - ignoring";
|
||||
continue;
|
||||
}
|
||||
|
||||
// invalid position -> ignore
|
||||
if (std::isnan(child.positionCenter().lon()) ||
|
||||
std::isnan(child.positionCenter().lat()))
|
||||
{
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces << "Child " << inferiorId << ": has invalid position - ignoring";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bFirst)
|
||||
{
|
||||
bFirst = false;
|
||||
data.positionLeader(child.positionLeader());
|
||||
data.sampleTimeLeader(child.sampleTimeLeader());
|
||||
}
|
||||
|
||||
const auto utm = LtsCoordTrans::UtmCoordinate::fromGeographic(child.positionCenter().lon(),
|
||||
child.positionCenter().lat(),
|
||||
utmZone);
|
||||
if (utmZone == -1)
|
||||
utmZone = utm.zone;
|
||||
|
||||
pos += LtsUtils::QPoint3D(utm.x, utm.y, child.positionCenter().z());
|
||||
if (child.sampleTimeCenter() > childPositionTime)
|
||||
childPositionTime = child.sampleTimeCenter();
|
||||
|
||||
++childCount;
|
||||
}
|
||||
|
||||
data.sampleTimeCenter(childPositionTime);
|
||||
if (childCount > 0)
|
||||
{
|
||||
pos /= childCount;
|
||||
const LtsCoordTrans::UtmCoordinate utm(utmZone, pos.x(), pos.y(),true);
|
||||
const QPointF lonLat = utm.geographic();
|
||||
data.positionCenter(Core::GeoPosition(lonLat.x(), lonLat.y(), pos.z()));
|
||||
}
|
||||
DEBUG_LOG(logger) << dbgLvlSpaces
|
||||
<< "Participant " << participantId
|
||||
<< ": Mean position: " << data.positionCenter()
|
||||
<< " #relavant children: " << childCount
|
||||
<< " (" << data.sampleTimeCenter() / 1000 << "s)";
|
||||
|
||||
result.push_back(std::move(data));
|
||||
}
|
||||
|
||||
void UnitPositionCalculator::onCalculationDone()
|
||||
{
|
||||
const Result &calculatedPositions = m_calculationWatcher.future().result();
|
||||
|
||||
auto dts = m_participantHandler->dts();
|
||||
for (const auto &pos : calculatedPositions)
|
||||
{
|
||||
auto it = m_publishedPositionData.find(pos.participantId());
|
||||
if (it != m_publishedPositionData.end())
|
||||
{
|
||||
ParticipantManagement::UnitPosition &up = it->second;
|
||||
DEBUG_LOG(m_logger) << "old: " << up << ", new: " << pos << ", equal: " << (up == pos);
|
||||
if (up == pos)
|
||||
continue;
|
||||
// nan == nan is always false, have to check it on our own
|
||||
if (std::isnan(up.positionCenter().lat()) && std::isnan(pos.positionCenter().lat()))
|
||||
continue;
|
||||
up = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_publishedPositionData.insert(std::make_pair(pos.participantId(), pos));
|
||||
}
|
||||
dts->publish(pos);
|
||||
}
|
||||
|
||||
m_timer->start(1000);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Calculate the focal point for units based on it's superiors
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-09-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QFutureWatcher>
|
||||
#include <Core/core.hpp>
|
||||
#include <unordered_map>
|
||||
#include "participant_handler.h"
|
||||
|
||||
class QTimer;
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
namespace ParticipantHandling
|
||||
{
|
||||
class UnitPositionCalculator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UnitPositionCalculator(ParticipantHandler *participantHandler, QObject *parent = nullptr);
|
||||
~UnitPositionCalculator();
|
||||
|
||||
void startCalculation();
|
||||
void stopCalculation(); // also clear all participants
|
||||
void waitForCalculationFinished();
|
||||
|
||||
void onParticipantDeleted(int participantId);
|
||||
void onPositionChanged(int participantId, int64_t positionTime, const Core::GeoPosition &pos);
|
||||
void onSuperiorChanged(int participantId, int superiorId);
|
||||
void onInferiorChanged(int participantId, const std::vector<int> &inferiorIds);
|
||||
|
||||
private:
|
||||
struct CalculatedUnitPosition : public ParticipantManagement::UnitPosition
|
||||
{
|
||||
int superiorId = 0;
|
||||
std::vector<int> inferiorIds;
|
||||
};
|
||||
|
||||
private:
|
||||
CalculatedUnitPosition &getParticipant(int participantId);
|
||||
void calculate();
|
||||
// no const ref - must be a copy since this is running in a different thread
|
||||
using Result = std::vector<CalculatedUnitPosition>;
|
||||
static Result doCalculation(std::unordered_map<int, CalculatedUnitPosition> &participantData,
|
||||
qint64 currentTime,
|
||||
NGL::INGLLogger &logger);
|
||||
static void calculatePosition(int participantId,
|
||||
std::unordered_map<int, CalculatedUnitPosition> &participantData,
|
||||
qint64 currentTime,
|
||||
int level,
|
||||
NGL::INGLLogger &logger,
|
||||
Result &result);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCalculationDone();
|
||||
|
||||
private:
|
||||
std::unordered_map<int, CalculatedUnitPosition> m_participantData;
|
||||
std::unordered_map<int, CalculatedUnitPosition> m_publishedPositionData;
|
||||
|
||||
QFutureWatcher<Result> m_calculationWatcher;
|
||||
|
||||
ParticipantHandler *m_participantHandler;
|
||||
bool m_bSomethingChangedSinceLastCalculation;
|
||||
QTimer *m_timer;
|
||||
bool m_bRunning;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace ParticipantHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* The Party class represents a party. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
|
||||
#include "party.h"
|
||||
|
||||
bool ParticipantManagement::PartyHandling::Party::hasChanges(const ParticipantManagement::Party &request,
|
||||
const bool bIgnoreIsUsedBy)
|
||||
{
|
||||
const QString requestProperties = QString::fromStdString(request.properties());
|
||||
bool hasChanges = request.color() != m_data.color
|
||||
|| request.fadingColor() != m_data.fadingColor
|
||||
|| request.name() != m_data.name.toStdString()
|
||||
|| request.hlaForceIdentifier().underlying() != m_data.hlaForceIdentifier
|
||||
|| request.role() != m_data.roleId
|
||||
|| requestProperties != m_data.properties;
|
||||
if (!bIgnoreIsUsedBy && !hasChanges)
|
||||
hasChanges = request.isUsedBy() != m_data.isUsedBy;
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
m_data.color = request.color();
|
||||
m_data.fadingColor = request.fadingColor();
|
||||
m_data.name = QString::fromStdString(request.name());
|
||||
m_data.roleId = request.role();
|
||||
m_data.hlaForceIdentifier = request.hlaForceIdentifier().underlying();
|
||||
m_data.properties = requestProperties;
|
||||
if (!bIgnoreIsUsedBy)
|
||||
m_data.isUsedBy = request.isUsedBy();
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
ParticipantManagement::Database::PpmParty ParticipantManagement::PartyHandling::Party::toDbParty() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
ParticipantManagement::Party ParticipantManagement::PartyHandling::Party::toDdsParty() const
|
||||
{
|
||||
ParticipantManagement::Party result;
|
||||
|
||||
result.id(id());
|
||||
result.color(m_data.color);
|
||||
result.fadingColor(m_data.fadingColor);
|
||||
result.name(m_data.name.toStdString());
|
||||
result.role(m_data.roleId);
|
||||
result.hlaForceIdentifier(static_cast<HlaForceIdentifierEnum::inner_enum>(m_data.hlaForceIdentifier));
|
||||
result.isUsedBy(m_data.isUsedBy);
|
||||
result.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
result.properties(m_data.properties.toStdString());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* The Party class represents a party. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace PartyHandling
|
||||
{
|
||||
class Party
|
||||
{
|
||||
public:
|
||||
explicit Party(const Database::PpmParty &data)
|
||||
: m_data(data)
|
||||
{}
|
||||
|
||||
int32_t id() const { return m_data.id; }
|
||||
|
||||
Database::PpmParty toDbParty() const;
|
||||
ParticipantManagement::Party toDdsParty() const;
|
||||
|
||||
bool hasChanges(const ParticipantManagement::Party &request, const bool bIgnoreIsUsedBy);
|
||||
bool isUsedBy() const { return m_data.isUsedBy; }
|
||||
|
||||
private:
|
||||
Database::PpmParty m_data;
|
||||
};
|
||||
} // namespace PartyHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* The PartyDonator class is an interface for returning a Patry to a given id.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-06-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace PartyHandling
|
||||
{
|
||||
class Party;
|
||||
class PartyDonator
|
||||
{
|
||||
public:
|
||||
virtual Party *partyById(int partyId) const = 0;
|
||||
}; // class PartyDonator
|
||||
} // namespace PartyHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
* The PartyHandler class manages all party related function topics and holds classes for
|
||||
* further party data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
|
||||
#include "PartyHandling/party_handler.h"
|
||||
#include "PartyHandling/party.h"
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include <ppm_db.h>
|
||||
#include "main_handler.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
//------------------------------------------------------------------------------------------
|
||||
PartyHandling::PartyHandler::PartyHandler(MainHandler *mainHandler)
|
||||
: ModifyPartyDataRequestHandler(mainHandler->fts())
|
||||
, RemovePartyRequestHandler(mainHandler->fts())
|
||||
, SyncPartiesRequestHandler(mainHandler->exerciseId() <= 0 ? nullptr : mainHandler->fts())
|
||||
, ChangePartyUsedStateRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("PartyHandler"))
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
PartyHandling::PartyHandler::~PartyHandler()
|
||||
{
|
||||
qDeleteAll(m_parties);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
PartyHandling::Party *PartyHandling::PartyHandler::partyById(int32_t partyId) const
|
||||
{
|
||||
return m_parties.value(partyId, nullptr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
bool PartyHandling::PartyHandler::init()
|
||||
{
|
||||
qDeleteAll(m_parties);
|
||||
m_parties.clear();
|
||||
QVector<Database::PpmParty> partyVec;
|
||||
|
||||
// read parties from db
|
||||
if (!m_mainHandler->db()->select(partyVec))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading party data from database";
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there are no parties in db and this instance of ParticipantManagement runs not in ex_0
|
||||
// parties are fetched from ex_0 PPM
|
||||
if (m_mainHandler->exerciseId() > 0 && partyVec.isEmpty())
|
||||
partyVec = loadDefaultParties(true);
|
||||
|
||||
if (partyVec.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading party data from database";
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( Database::PpmParty currentParty : qAsConst(partyVec))
|
||||
{
|
||||
resetAdlerProperties(currentParty.properties, currentParty.id);
|
||||
PartyHandling::Party *newParty = new PartyHandling::Party(currentParty);
|
||||
m_parties.insert(currentParty.id, newParty);
|
||||
m_mainHandler->dts()->publish(newParty->toDdsParty());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void PartyHandling::PartyHandler::resetAdlerProperties( QString &properties, const int partyId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "properties: " << properties;
|
||||
QJsonObject obj = QJsonDocument::fromJson(properties.toUtf8()).object();
|
||||
|
||||
if (!obj.contains(QStringLiteral("Adler")))
|
||||
return;
|
||||
|
||||
const ParticipantManagement::ConnectState connectState = m_mainHandler->ddsHandler()->dtc()->saaConnectedState(partyId);
|
||||
if (connectState == ParticipantManagement::ConnectState::Undefined)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "connectState: " << connectState;
|
||||
|
||||
if (connectState != ParticipantManagement::ConnectState::Disconnected)
|
||||
{
|
||||
QJsonObject propAdler = obj[QStringLiteral("Adler")].toObject();
|
||||
propAdler[QStringLiteral("saaConnectedState")] = ParticipantManagement::ConnectState::Disconnected;
|
||||
obj[QStringLiteral("Adler")] = propAdler;
|
||||
const QByteArray propertiesStr = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
properties = QString::fromStdString(propertiesStr.data());
|
||||
|
||||
INFO_LOG(m_logger) << "isSaaConnected set to false";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
QVector<Database::PpmParty> PartyHandling::PartyHandler::loadDefaultParties(bool withInsert) const
|
||||
{
|
||||
QVector<Database::PpmParty> partyVec;
|
||||
|
||||
if (!m_mainHandler->dbEx0()->select(partyVec))
|
||||
ERROR_LOG(m_logger) << "Error while reading party data from database (ex_0)";
|
||||
|
||||
auto cb = [](const Database::PpmParty &p1,const Database::PpmParty &p2) -> bool
|
||||
{
|
||||
return p1.id < p2.id;
|
||||
};
|
||||
std::sort(partyVec.begin(), partyVec.end(), cb);
|
||||
|
||||
if (withInsert)
|
||||
{
|
||||
for (auto it = partyVec.begin(); it != partyVec.end(); ++it)
|
||||
{
|
||||
// just inserting a new party, means is not in use
|
||||
(*it).isUsedBy = false;
|
||||
m_mainHandler->db()->insert(*it);
|
||||
}
|
||||
|
||||
m_mainHandler->db()->fixUpSequencePpmParty();
|
||||
}
|
||||
|
||||
return partyVec;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void PartyHandling::PartyHandler::onModifyPartyDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::Party &request)
|
||||
{
|
||||
auto ret = modifyPartyDataRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
|
||||
m_mainHandler->fts()->modifyPartyDataReply(cookie, ret);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject PartyHandling::PartyHandler::modifyPartyDataRequest(const ParticipantManagement::Party &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onModifyPartyDataRequest: " << request;
|
||||
Party *partyToPublish = m_parties.value(request.id());
|
||||
|
||||
if (!partyToPublish && request.id() >= 0)
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not modify party with id %1, because no party with that id exists"))
|
||||
.arg(request.id());
|
||||
|
||||
if (!partyToPublish) // create new party
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating new party";
|
||||
|
||||
// insert into database
|
||||
Database::PpmParty newDbParty;
|
||||
|
||||
newDbParty.color = request.color();
|
||||
newDbParty.fadingColor = request.fadingColor();
|
||||
newDbParty.name = QString::fromStdString(request.name());
|
||||
newDbParty.roleId = request.role();
|
||||
newDbParty.isUsedBy = request.isUsedBy();
|
||||
newDbParty.hlaForceIdentifier = request.hlaForceIdentifier().underlying();
|
||||
newDbParty.properties = QString::fromStdString(request.properties());
|
||||
|
||||
if (!m_mainHandler->db()->insert(newDbParty))
|
||||
{
|
||||
QString errText = m_mainHandler->db()->getLastError().databaseText();
|
||||
ERROR_LOG(m_logger) << "Error inserting Party into database: " << errText;
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Error inserting new party to database: %1")).arg(errText);
|
||||
}
|
||||
|
||||
partyToPublish = new Party(newDbParty);
|
||||
m_parties.insert(partyToPublish->id(), partyToPublish);
|
||||
}
|
||||
else // modify existing party
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Modifying party with id " << partyToPublish->id();
|
||||
|
||||
if (!partyToPublish->hasChanges(request, true))
|
||||
partyToPublish = nullptr; // so it will not be published at the end of this method ...
|
||||
else // update in database
|
||||
{
|
||||
if (!m_mainHandler->db()->update(partyToPublish->toDbParty()))
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Error updating party in database"));
|
||||
}
|
||||
}
|
||||
if (partyToPublish)
|
||||
{
|
||||
auto party = partyToPublish->toDdsParty();
|
||||
m_mainHandler->dts()->publish(party);
|
||||
}
|
||||
return Core::FunctionReplyObject(request.id());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void PartyHandling::PartyHandler::onRemovePartyRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::RemovePartyRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onRemovePartyRequest: " << request;
|
||||
auto ret = removePartyRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
|
||||
m_mainHandler->fts()->removePartyReply(cookie, ret);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject PartyHandling::PartyHandler::removePartyRequest(const ParticipantManagement::RemovePartyRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onRemovePartyRequest " << request;
|
||||
|
||||
if (request.partyId() < 0)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Got request to delete a party, but no valid party id to delete"));
|
||||
|
||||
Party *partyToDelete = m_parties.value(request.partyId());
|
||||
if (!partyToDelete)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Could not delete party with id %1, because no party with that id exists"))
|
||||
.arg(request.partyId());
|
||||
|
||||
if (partyToDelete->isUsedBy() == true)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Not possible to delete a party in use"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Removing party with ID " << request.partyId();
|
||||
|
||||
return removeParty(partyToDelete);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject PartyHandling::PartyHandler::removeParty(Party *partyToDelete)
|
||||
{
|
||||
const int partyId = partyToDelete->id();
|
||||
// delete from db
|
||||
if (!m_mainHandler->db()->removePpmParty(partyId))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error removing party with id %1 from database")).arg(partyId);
|
||||
// delete from dds
|
||||
m_mainHandler->dts()->removePartyByKey(partyId);
|
||||
|
||||
// delete from map
|
||||
m_parties.remove(partyId);
|
||||
delete partyToDelete;
|
||||
|
||||
return Core::FunctionReplyObject(partyId);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void PartyHandling::PartyHandler::onSyncPartiesRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::SyncPartiesRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onSyncPartiesRequest: " << request;
|
||||
|
||||
Core::FunctionReplyObject rep;
|
||||
QVector<Database::PpmParty> partyVec = loadDefaultParties(false);
|
||||
|
||||
for (auto it = partyVec.begin(); it != partyVec.end(); ++it)
|
||||
{
|
||||
int partyId = (*it).id;
|
||||
DEBUG_LOG(m_logger) << "Checking Party Id: " << partyId;
|
||||
|
||||
Database::PpmParty partyEx0 = (*it);
|
||||
|
||||
if (!m_parties.contains(partyId))
|
||||
{
|
||||
// just inserting a new party, means is not yet in use
|
||||
partyEx0.isUsedBy = false;
|
||||
if (!m_mainHandler->db()->insert(partyEx0))
|
||||
{
|
||||
QString errText = m_mainHandler->db()->getLastError().databaseText();
|
||||
WARNING_LOG(m_logger) << "Error inserting new party with id " << partyId << " to database: " << errText;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Inserting Party Id: " << partyId;
|
||||
PartyHandling::Party *newParty = new PartyHandling::Party(partyEx0);
|
||||
m_parties.insert(partyEx0.id, newParty);
|
||||
m_mainHandler->dts()->publish(newParty->toDdsParty());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Party *partyEx = m_parties.value(partyId);
|
||||
|
||||
bool hasChanges = partyEx0.color != partyEx->toDbParty().color
|
||||
|| partyEx0.fadingColor != partyEx->toDbParty().fadingColor
|
||||
|| partyEx0.name != partyEx->toDbParty().name
|
||||
|| partyEx0.hlaForceIdentifier != partyEx->toDbParty().hlaForceIdentifier
|
||||
|| partyEx0.roleId != partyEx->toDbParty().roleId;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Has changes = " << hasChanges;
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
ParticipantManagement::Party req;
|
||||
req.id(partyId);
|
||||
|
||||
// taking new properties from ex_0
|
||||
req.color(partyEx0.color);
|
||||
req.fadingColor(partyEx0.fadingColor);
|
||||
req.name(partyEx0.name.toStdString());
|
||||
req.role(partyEx0.roleId);
|
||||
req.hlaForceIdentifier(static_cast<HlaForceIdentifierEnum::inner_enum>(partyEx0.hlaForceIdentifier));
|
||||
|
||||
// this remains as it is
|
||||
req.isUsedBy(partyEx->isUsedBy());
|
||||
|
||||
auto ret = modifyPartyDataRequest(req);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
}
|
||||
}
|
||||
}
|
||||
// now checking for non-existent parties in ex_0
|
||||
const auto partiesCopy(m_parties);
|
||||
for (Party *curParty : partiesCopy)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto it = partyVec.begin(); it != partyVec.end(); ++it)
|
||||
{
|
||||
int partyId = (*it).id;
|
||||
if (partyId == curParty->id())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Party id to be deleted = " << curParty->id();
|
||||
if (curParty->isUsedBy())
|
||||
INFO_LOG(m_logger) << "Party with id " << curParty->id() << " cannot be deleted, is in use";
|
||||
else
|
||||
{
|
||||
auto ret = removeParty(curParty); // removed from map etc
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
}
|
||||
}
|
||||
}
|
||||
m_mainHandler->db()->fixUpSequencePpmParty();
|
||||
m_mainHandler->fts()->syncPartiesReply(cookie, rep);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void PartyHandling::PartyHandler::onChangePartyUsedStateRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::ChangePartyUsedStateRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onChangePartyUsedStateRequest: " << request;
|
||||
auto ret = changePartyUsedStateRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
m_mainHandler->fts()->changePartyUsedStateReply(cookie, ret);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject PartyHandling::PartyHandler::changePartyUsedStateRequest(const ParticipantManagement::ChangePartyUsedStateRequest &request)
|
||||
{
|
||||
Party *party = m_parties.value(request.partyId());
|
||||
if (!party)
|
||||
return Core::FunctionReplyObject(request.partyId(), tr_lts("dds", "Could not modify party with id %1, because no party with that id exists"))
|
||||
.arg(request.partyId());
|
||||
|
||||
ParticipantManagement::Party ddsParty = party->toDdsParty();
|
||||
ddsParty.isUsedBy(request.isUsedBy());
|
||||
if (party->hasChanges(ddsParty, false))
|
||||
{
|
||||
if (!m_mainHandler->db()->update(party->toDbParty()))
|
||||
return Core::FunctionReplyObject(request.partyId(), tr_lts("dds", "Error updating party used state in database"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Change used state for party " << party->id() << " to " << party->isUsedBy();
|
||||
m_mainHandler->dts()->publish(party->toDdsParty());
|
||||
}
|
||||
return Core::FunctionReplyObject(request.partyId());
|
||||
}
|
||||
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* The PartyHandler class manages all party related function topics and holds classes for
|
||||
* further party data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QHash>
|
||||
|
||||
#include "PartyHandling/party_donator.h"
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
#include "logger.h"
|
||||
#include "ppm_db.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace PartyHandling
|
||||
{
|
||||
class Party;
|
||||
class PartyHandler final
|
||||
: public PartyDonator
|
||||
, protected Interface::Fts::ModifyPartyDataRequestHandler
|
||||
, protected Interface::Fts::RemovePartyRequestHandler
|
||||
, protected Interface::Fts::SyncPartiesRequestHandler
|
||||
, protected Interface::Fts::ChangePartyUsedStateRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit PartyHandler(MainHandler *mainHandler);
|
||||
~PartyHandler();
|
||||
Party *partyById(int32_t partyId) const override;
|
||||
|
||||
bool init();
|
||||
void resetAdlerProperties(QString &properties, const int partyId);
|
||||
|
||||
Core::FunctionReplyObject changePartyUsedStateRequest(const ChangePartyUsedStateRequest &request);
|
||||
protected:
|
||||
void onChangePartyUsedStateRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ChangePartyUsedStateRequest &request) override;
|
||||
void onModifyPartyDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::Party &request) override;
|
||||
Core::FunctionReplyObject modifyPartyDataRequest(const ParticipantManagement::Party &request);
|
||||
void onRemovePartyRequest(const rti::core::SampleIdentity &cookie,
|
||||
const RemovePartyRequest &request) override;
|
||||
Core::FunctionReplyObject removePartyRequest(const RemovePartyRequest &request);
|
||||
Core::FunctionReplyObject removeParty(Party *partyToDelete);
|
||||
void onSyncPartiesRequest(const rti::core::SampleIdentity &cookie,
|
||||
const SyncPartiesRequest &request) override;
|
||||
|
||||
private:
|
||||
QVector<Database::PpmParty> loadDefaultParties(bool withInsert) const;
|
||||
private:
|
||||
MainHandler *m_mainHandler;
|
||||
QHash<int32_t, Party *> m_parties; // <partyId, Party>
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace PartyHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include <ParticipantHandling/participant.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class ParticipantForReplay final : public ParticipantHandling::Participant
|
||||
{
|
||||
public:
|
||||
ParticipantForReplay(ParticipantHandling::ParticipantHandler *participantHandler,
|
||||
ParticipantHandling::UnitPositionCalculator *unitPosCalculator,
|
||||
const Database::PpmParticipant &data)
|
||||
: ParticipantHandling::Participant(participantHandler,
|
||||
unitPosCalculator,
|
||||
data,
|
||||
"ParticipantForReplay")
|
||||
{}
|
||||
protected:
|
||||
bool updateEquipmentExerciseMapping(int, int) { return true; }
|
||||
};
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include "participant_handler_for_replay.h"
|
||||
|
||||
#include "participant_for_replay.h"
|
||||
#include "ppm_record_replay_plugin_custom.h"
|
||||
#include <ParticipantHandling/unit_position_calculator.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
//
|
||||
// ParticipantHandlerForReplay
|
||||
//
|
||||
ParticipantHandlerForReplay::ParticipantHandlerForReplay(RecordReplayPluginCustom *replayPlugin)
|
||||
: ParticipantHandling::ParticipantHandler(replayPlugin, "ParticipantHandlerForReplay")
|
||||
{}
|
||||
|
||||
static inline Database::PpmParticipant toDb(const ParticipantManagement::Participant &ddsPart)
|
||||
{
|
||||
Database::PpmParticipant db;
|
||||
db.id = ddsPart.id();
|
||||
db.assignState = ddsPart.assignState();
|
||||
db.partyId = ddsPart.partyId();
|
||||
db.typeId = ddsPart.typeId();
|
||||
db.externalId = ddsPart.externalId();
|
||||
db.designator = QString::fromStdString(ddsPart.designator());
|
||||
db.equipmentNumber = ddsPart.equipmentNumber().is_set() ? ddsPart.equipmentNumber().get() : 0;
|
||||
db.hierarchyNumber = ddsPart.hierarchyNumber();
|
||||
db.identification = QString::fromStdString(ddsPart.identification());
|
||||
db.info = QString::fromStdString(ddsPart.info());
|
||||
db.isDeleted = ddsPart.isDeleted();
|
||||
db.isSimulated = ddsPart.isSimulated();
|
||||
db.name = QString::fromStdString(ddsPart.name());
|
||||
db.superiorId = ddsPart.superiorId();
|
||||
db.symbol = QString::fromStdString(ddsPart.symbol());
|
||||
db.tacticalIdentifier = QString::fromStdString(ddsPart.tacticalIdentifier());
|
||||
db.properties = QString::fromStdString(ddsPart.properties());
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::createUpdateParticipant(const ParticipantManagement::Participant &ddsPart)
|
||||
{
|
||||
auto *p = m_participants.value(ddsPart.id());
|
||||
if (!p)
|
||||
{
|
||||
p = new ParticipantForReplay(this,
|
||||
m_unitPositionCalculator.get(),
|
||||
toDb(ddsPart));
|
||||
m_participants.insert(ddsPart.id(), p);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->hasToBeChanged(ddsPart);
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::removeParticipant(const ParticipantManagement::Participant &ddsPart)
|
||||
{
|
||||
// maybe clear m_hitLineInfoMap for this participant also but is this a real-world problem?
|
||||
|
||||
auto *p = m_participants.take(ddsPart.id());
|
||||
if (p)
|
||||
{
|
||||
p->removeFromDds();
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticipantHandlerForReplay::setDynamicParticipantData(const ParticipantManagement::DynamicParticipantData &dynPart)
|
||||
{
|
||||
auto *p = m_participants.value(dynPart.participantId());
|
||||
if (!p) {
|
||||
WARNING_LOG(m_logger) << "Got dynamic participant data for unknown participant with id " << dynPart.participantId();
|
||||
return;
|
||||
}
|
||||
p->setDynamicData(dynPart);
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::publishData()
|
||||
{
|
||||
for (auto p : qAsConst(m_participants))
|
||||
{
|
||||
p->publishParticipant();
|
||||
p->publishDynamicData();
|
||||
p->publishPosition();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::startUnitPositionCalculator()
|
||||
{
|
||||
m_unitPositionCalculator->startCalculation();
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::stopUnitPositionCalculator()
|
||||
{
|
||||
m_unitPositionCalculator->stopCalculation();
|
||||
}
|
||||
|
||||
void ParticipantHandlerForReplay::waitForUnitPositionCalculator()
|
||||
{
|
||||
m_unitPositionCalculator->waitForCalculationFinished();
|
||||
}
|
||||
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <ParticipantHandling/participant_handler.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class RecordReplayPluginCustom;
|
||||
class ParticipantHandlerForReplay final : public ParticipantHandling::ParticipantHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ParticipantHandlerForReplay(RecordReplayPluginCustom *replayPlugin);
|
||||
|
||||
void createUpdateParticipant(const ParticipantManagement::Participant &ddsPart);
|
||||
void removeParticipant(const ParticipantManagement::Participant &ddsPart);
|
||||
void setDynamicParticipantData(const ParticipantManagement::DynamicParticipantData &dynPart);
|
||||
|
||||
void publishData();
|
||||
|
||||
void startUnitPositionCalculator();
|
||||
void stopUnitPositionCalculator();
|
||||
void waitForUnitPositionCalculator();
|
||||
protected:
|
||||
bool isSampleTimeInFuture(qint64 sampleTime) const { Q_UNUSED(sampleTime); return false; }
|
||||
bool isSampleTimeOutdated(qint64 sampleTime) const { Q_UNUSED(sampleTime); return false; }
|
||||
};
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "ppm_record_replay_plugin_custom.h"
|
||||
#include "participant_handler_for_replay.h"
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
#include <DDS/DTC/generic_dtc_impl.h>
|
||||
|
||||
#include <QtConcurrent>
|
||||
static bool OPTIMZE = true; // GUEZE-3521 "Überarbeitung des Replays zur Performance Steigerung"
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
//
|
||||
// RecordReplayPluginCustom
|
||||
//
|
||||
RecordReplayPluginCustom::RecordReplayPluginCustom()
|
||||
: m_participantHandler(nullptr)
|
||||
, m_tabRecordReplay(nullptr)
|
||||
, m_currentReplayTime(0)
|
||||
{
|
||||
INFO_LOG(m_logger) << "RecordReplayPluginCustom ctor";
|
||||
}
|
||||
|
||||
RecordReplayPluginCustom::~RecordReplayPluginCustom()
|
||||
{
|
||||
delete m_tabRecordReplay;
|
||||
delete m_participantHandler;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query)
|
||||
{
|
||||
m_tabRecordReplay = new TrainingAreaBase::RecordReplayPluginCustom;
|
||||
// they will both return false due to missing ddsConnector...
|
||||
m_tabRecordReplay->initDts(nullptr, exerciseId, bCanHandleSchemas, query);
|
||||
RecordReplayPlugin::initDts(nullptr, exerciseId, bCanHandleSchemas, query);
|
||||
|
||||
// *after* initDts
|
||||
m_ddsConnector = ddsConnector;
|
||||
|
||||
// own published data
|
||||
m_ddsDts = ParticipantManagement::Interface::Dts::create(m_ddsConnector);
|
||||
m_ddsDts->enableBite();
|
||||
m_ddsDts->enableDynamicParticipantData();
|
||||
m_ddsDts->enableHitLineInfo();
|
||||
m_ddsDts->enableUAS();
|
||||
m_ddsDts->enableParticipant();
|
||||
m_ddsDts->enableParticipantGearEvent();
|
||||
m_ddsDts->enableParticipantMode();
|
||||
m_ddsDts->enableParticipantPosition();
|
||||
m_ddsDts->enableUnitPosition();
|
||||
|
||||
m_ddsDts->enableParticipant();
|
||||
|
||||
// data from recording tables (published via RecordReplayPlugin::publishFoo() functions)
|
||||
m_dtsParty.reset(m_ddsConnector->createDTS<DTS::PartyImpl>());
|
||||
// publish initial party information to be able to fill the comboboxes (e.g. for filtering)
|
||||
const qint64 startTime = time(nullptr) * 1000LL;
|
||||
readPartyAt(query, startTime);
|
||||
publishParty(startTime);
|
||||
readParticipantAt(query, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readParticipantAt before" << m_participantMap.count();
|
||||
removeOld(m_participantMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readParticipantAt AFTER " << m_participantMap.count();
|
||||
publishParticipant(startTime);
|
||||
DEBUG_LOG(m_logger) << "RecordReplayPluginCustom::initDts successful";
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RecordReplayPluginCustom::removeOld(QMultiMap<long long, T> &map, qint64 desiredTime)
|
||||
{
|
||||
if (!OPTIMZE)
|
||||
return;
|
||||
Q_UNUSED(desiredTime);
|
||||
|
||||
auto copy = map;
|
||||
for (const auto &item : copy.keys())
|
||||
{
|
||||
for (const auto &inner : map.values(item))
|
||||
{
|
||||
// Remove delted ones
|
||||
if (inner.isDeleted())
|
||||
{
|
||||
map.remove(item, inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RecordReplayPluginCustom::setReplayStartTime(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "setReplayStartTime " << startTime;
|
||||
m_currentReplayTime = 0;
|
||||
|
||||
if (!readParticipantAt(q, startTime))
|
||||
return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readParticipantAt " << startTime << " DONE";
|
||||
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readParticipantAt before" << m_participantMap.count();
|
||||
removeOld(m_participantMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readParticipantAt after" << m_participantMap.count();
|
||||
|
||||
//create eqMap
|
||||
// 2026-03-16: N.Thoden, E01562-183 "Prüfung Replay"
|
||||
// If container 'm_equipmentNumbers' is filled and used at makeConcurrent()
|
||||
// (at least for type EquipmentPosition) some participant are accidentally skipped:
|
||||
// Since manually 'move players' / 'Tln nachführen' uses the participant id (and not eqno),
|
||||
// they are not honored by preparing 'm_equipmentNumbers'
|
||||
// Later on, while preparing the publishing of the EquipmentPosition, the corresponding
|
||||
// Participant does not exist and so the EquipmentPosition could not be published.
|
||||
// So keep m_equipmentNumbers empty or remove the completly.
|
||||
m_equipmentNumbers.clear();
|
||||
// if (OPTIMZE)
|
||||
// {
|
||||
// for (const auto &p : m_participantMap)
|
||||
// {
|
||||
// if (p.equipmentNumber().is_set())
|
||||
// m_equipmentNumbers.insert(p.equipmentNumber().get());
|
||||
// }
|
||||
// DEBUG_LOG(m_logger) << "setReplayStartTime-m_equipmentNumbers after" << m_equipmentNumbers.count();
|
||||
// }
|
||||
|
||||
|
||||
if (!readDynamicParticipantDataAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
//Manual
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt before" << m_dynamicParticipantDataMap.count();
|
||||
if (OPTIMZE)
|
||||
{
|
||||
const auto &backup = m_dynamicParticipantDataMap;
|
||||
for (const auto &key : backup.keys())
|
||||
{
|
||||
const auto &inner = backup.values(key);
|
||||
for (const auto &value : inner)
|
||||
{
|
||||
if (m_participantKeys.find(value.participantId()) == m_participantKeys.end())
|
||||
m_dynamicParticipantDataMap.remove(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt after" << m_dynamicParticipantDataMap.count();
|
||||
|
||||
|
||||
|
||||
if (!readPartyAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readPartyAt " << startTime << " DONE";
|
||||
|
||||
if (!readHitLineInfoAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readHitLineInfoAt " << startTime << " DONE";
|
||||
//removeOld(m_hitLineInfoMap, startTime);
|
||||
|
||||
if (!readUASAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readUASAt" << startTime << " DONE";
|
||||
|
||||
if (!m_tabRecordReplay->ppmSetReplayStartTime(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-ppmSetReplayStartTime " << startTime << " DONE";
|
||||
|
||||
publishParty(startTime);
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-publishParty " << startTime << " DONE";
|
||||
|
||||
// create data for ParticipantManagement
|
||||
if (!m_participantHandler)
|
||||
{
|
||||
m_participantHandler = new ParticipantHandlerForReplay(this);
|
||||
if (!m_participantHandler->init())
|
||||
return false;
|
||||
}
|
||||
m_participantHandler->stopUnitPositionCalculator();
|
||||
m_participantHandler->clearParticipants();
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-clearParticipants " << startTime << " DONE";
|
||||
|
||||
for (const auto &ddsParticipant : qAsConst(m_participantMap))
|
||||
m_participantHandler->createUpdateParticipant(ddsParticipant);
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-createUpdateParticipant " << startTime << " DONE";
|
||||
|
||||
for (const auto &dynParticipant : qAsConst(m_dynamicParticipantDataMap))
|
||||
m_participantHandler->setDynamicParticipantData(dynParticipant);
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-setDynamicParticipantData " << startTime << " DONE";
|
||||
|
||||
|
||||
setDataForParticipants(startTime);
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-setDataForParticipants " << startTime << " DONE";
|
||||
|
||||
m_currentReplayTime = startTime;
|
||||
m_participantHandler->startUnitPositionCalculator();
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-startUnitPositionCalculator " << startTime << " DONE";
|
||||
|
||||
INFO_LOG(m_logger) << "setReplayStartTime " << startTime << " ... DONE";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "ddsTopicsFromDatabase " << fromTime << " to " << toTime;
|
||||
if (!readParticipant(q, fromTime, toTime)) return false;
|
||||
if (!readParty(q, fromTime, toTime)) return false;
|
||||
if (!readHitLineInfo(q, fromTime, toTime)) return false;
|
||||
if (!readUAS(q, fromTime, toTime)) return false;
|
||||
|
||||
return m_tabRecordReplay->ppmDdsTopicsFromDatabase(q, fromTime, toTime);
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::publishData(qint64 desiredTime)
|
||||
{
|
||||
if (!m_participantHandler)
|
||||
return false;
|
||||
INFO_LOG(m_logger) << "publishData " << desiredTime;
|
||||
m_currentReplayTime = desiredTime;
|
||||
|
||||
if (!publishParty(desiredTime))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not publish party information for " << desiredTime;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const Participant &p : qAsConst(m_participantMap))
|
||||
m_participantHandler->createUpdateParticipant(p);
|
||||
for (const Participant &p : qAsConst(m_participantDisposedMap))
|
||||
m_participantHandler->removeParticipant(p);
|
||||
|
||||
setDataForParticipants(desiredTime);
|
||||
m_participantHandler->onHitLineInfoTimeout();
|
||||
m_participantHandler->publishData();
|
||||
|
||||
m_equipmentNumbers.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::waitForAsyncOperations(qint64 desiredTime)
|
||||
{
|
||||
if (!m_participantHandler)
|
||||
return false;
|
||||
Q_UNUSED(desiredTime);
|
||||
m_participantHandler->waitForUnitPositionCalculator();
|
||||
m_participantHandler->publishData();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordReplayPluginCustom::clearData()
|
||||
{
|
||||
RecordReplayPlugin::clearData();
|
||||
if (m_tabRecordReplay)
|
||||
m_tabRecordReplay->clearData();
|
||||
if (m_participantHandler)
|
||||
m_participantHandler->clearParticipants();
|
||||
// we do not remove the party information here so we're able to modify the filters during stop
|
||||
// clearDataParty();
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void RecordReplayPluginCustom::newDataForParticipants(T &cont, qint64 desiredTime)
|
||||
{
|
||||
auto it = cont.begin();
|
||||
while (it != cont.end() && it.key() <= desiredTime)
|
||||
{
|
||||
m_participantHandler->newData(*it);
|
||||
it = cont.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QVector<QFuture<void>> RecordReplayPluginCustom::makeConcurrentWithoutEquipNo(T &content, qint64 startTime)
|
||||
{
|
||||
QVector<T> contentVec;
|
||||
contentVec.append(T());
|
||||
|
||||
QVector<QFuture<void>> result;
|
||||
|
||||
// split content into several (contentVec)
|
||||
auto it = content.begin();
|
||||
while (it != content.end() && it.key() <= startTime)
|
||||
{
|
||||
contentVec[contentVec.size() - 1].insert(it.key(), it.value());
|
||||
|
||||
if (contentVec[contentVec.size() - 1].size() == 200)
|
||||
contentVec.append(T());
|
||||
|
||||
it = content.erase(it);
|
||||
} // while
|
||||
|
||||
for (auto contentIndex : qAsConst(contentVec))
|
||||
{
|
||||
// execute in workerThread
|
||||
result.append(QtConcurrent::run([this, contentIndex]()
|
||||
{
|
||||
for (auto it = contentIndex.begin(); it != contentIndex.end(); ++it)
|
||||
{
|
||||
m_participantHandler->newData(*it);
|
||||
}
|
||||
}));
|
||||
} // for
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
QVector<QFuture<void>> RecordReplayPluginCustom::makeConcurrent(T &content, qint64 startTime)
|
||||
{
|
||||
QVector<T> contentVec;
|
||||
contentVec.append(T());
|
||||
|
||||
QVector<QFuture<void>> result;
|
||||
|
||||
// split content into several (contentVec)
|
||||
auto it = content.begin();
|
||||
while (it != content.end() && it.key() <= startTime)
|
||||
{
|
||||
contentVec[contentVec.size() - 1].insert(it.key(), it.value());
|
||||
|
||||
if (contentVec[contentVec.size() - 1].size() == 200)
|
||||
contentVec.append(T());
|
||||
|
||||
it = content.erase(it);
|
||||
} // while
|
||||
|
||||
for (auto contentIndex : qAsConst(contentVec))
|
||||
{
|
||||
// execute in workerThread
|
||||
result.append(QtConcurrent::run([this, contentIndex]()
|
||||
{
|
||||
for (auto it = contentIndex.begin(); it != contentIndex.end(); ++it)
|
||||
{
|
||||
// following is relavant to a) OPTIMZE = true; // GUEZE-3521 and b) E01562-183 "Prüfung Replay"
|
||||
if (m_equipmentNumbers.isEmpty() || m_equipmentNumbers.contains(abs(it->equipmentNumber())))
|
||||
m_participantHandler->newData(*it);
|
||||
}
|
||||
}));
|
||||
} // for
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPluginCustom::setDataForParticipants(qint64 startTime)
|
||||
{
|
||||
if (!m_participantHandler)
|
||||
return false;
|
||||
// now read data from Tab
|
||||
// not (yet) used functions in ParticipantHandler:
|
||||
// void onNewCtaDataErrorFromProxy(const TrainingAreaBase::CtaDataError &error);
|
||||
// void onNewParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &report);
|
||||
// not (yet) used TAB topics
|
||||
// getCtaDataErrorMap()
|
||||
// getDefinitionIedMap()
|
||||
// getEquipmentConfigurationReportMap()
|
||||
// getEquipmentEventMap()
|
||||
// getEquipmentMessageMap()
|
||||
// getFireSmokeMarkerDataMap()
|
||||
// getFunctionalAreaEntryMap()
|
||||
// getGeopairingDataMap()
|
||||
// getMineTriggeredMap()
|
||||
// getMinelayerThrowerDataMap()
|
||||
// getMinelayerTrailerDataMap()
|
||||
// getOperatorActionMap()
|
||||
// getParticipantConfigurationReportMap()
|
||||
// getParticipantModeReportMap()
|
||||
// getParticipantSwVersionsMap()
|
||||
// getStateIedMap()
|
||||
// getTargetDataMap()
|
||||
|
||||
//#define USE_THIS_THREAD
|
||||
#ifdef USE_THIS_THREAD
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentBiteMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearAssignmentMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearChargeStateMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearEventMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentOperationalStateMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentPositionMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentStateMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getSpecialSensorDataMap(), startTime);
|
||||
newDataForParticipants(getHitLineInfoMap(), startTime);
|
||||
#else
|
||||
// This approach is from Hannes to overcome blocking dds writer:
|
||||
QVector<QFuture<void>> futVec = makeConcurrent(m_tabRecordReplay->getEquipmentPositionMap(), startTime);
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentBiteMap(), startTime));
|
||||
//futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentGearAssignmentMap(), startTime));
|
||||
//futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentGearChargeStateMap(), startTime));
|
||||
//futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentGearEventMap(), startTime));
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearAssignmentMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearChargeStateMap(), startTime);
|
||||
newDataForParticipants(m_tabRecordReplay->getEquipmentGearEventMap(), startTime);
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentOperationalStateMap(), startTime));
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentStateMap(), startTime));
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getSpecialSensorDataMap(), startTime));
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getParticipantSanitationMap(), startTime));
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getParticipantSanitaryMaterialStockReportMap(), startTime));
|
||||
futVec.append(makeConcurrent(m_tabRecordReplay->getEquipmentEventMap(), startTime));
|
||||
futVec.append(makeConcurrentWithoutEquipNo(getHitLineInfoMap(), startTime));
|
||||
futVec.append(makeConcurrentWithoutEquipNo(getUASMap(), startTime));
|
||||
|
||||
for (QFuture<void> &futRef : futVec)
|
||||
futRef.waitForFinished();
|
||||
#endif // USE_THIS_THREAD
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_record_replay_plugin.h>
|
||||
#include <TrainingAreaBase/tab_record_replay_plugin_custom.h>
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <ParticipantManagement/ParticipantHandling/participant_handler.h>
|
||||
#include <QFuture>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class ParticipantHandlerForReplay;
|
||||
class PPMRECORDREPLAYPLUGIN_EXPORT RecordReplayPluginCustom final : public RecordReplayPlugin
|
||||
, public ParticipantHandling::BaseDataProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "special:3:recordreplay.ppm")
|
||||
Q_INTERFACES(RecordReplay::RecordReplayPlugin)
|
||||
public:
|
||||
RecordReplayPluginCustom();
|
||||
~RecordReplayPluginCustom();
|
||||
|
||||
bool initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query) override;
|
||||
bool setReplayStartTime(NSqlQuery &q, qint64 startTime) override;
|
||||
bool ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime) override;
|
||||
bool publishData(qint64 desiredTime) override;
|
||||
bool waitForAsyncOperations(qint64 desiredTime) override;
|
||||
void clearData() override;
|
||||
|
||||
qint64 currentTimeMSec() const override { return m_currentReplayTime; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> dts() const override { return m_ddsDts; }
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const override { return nullptr; }
|
||||
private:
|
||||
template<typename T>
|
||||
void newDataForParticipants(T &cont, qint64 desiredTime);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void removeOld(QMultiMap<long long int , T> &map, qint64 desiredTime);
|
||||
|
||||
|
||||
template<typename T>
|
||||
QVector<QFuture<void>> makeConcurrent(T &content, qint64 startTime);
|
||||
template<typename T>
|
||||
QVector<QFuture<void>> makeConcurrentWithoutEquipNo(T &content, qint64 startTime);
|
||||
|
||||
bool setDataForParticipants(qint64 startTime);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> m_ddsDts;
|
||||
ParticipantHandlerForReplay *m_participantHandler;
|
||||
|
||||
TrainingAreaBase::RecordReplayPluginCustom *m_tabRecordReplay;
|
||||
QSet<int64_t> m_equipmentNumbers;
|
||||
qint64 m_currentReplayTime;
|
||||
};
|
||||
} // namespace ParticipantManagement
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Handler ShootbackTargets (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, NLE, 06.04.2020
|
||||
*/
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "handler_target_information.h"
|
||||
#include "object_target_information.h"
|
||||
|
||||
using namespace ParticipantManagement;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
HandlerTargetInformation::HandlerTargetInformation(MainHandler *mainHandler)
|
||||
: ModifyTargetInformationRequestHandler(mainHandler->fts())
|
||||
, RemoveTargetInformationRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("HandlerTargetInformation"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
HandlerTargetInformation::~HandlerTargetInformation()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool HandlerTargetInformation::init()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
bool bRet = true;
|
||||
// create objects
|
||||
auto cb = [this, &bRet](const Database::PpmTargetInformation & data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Reading from DB PpmTargetInformation with id = " << data.id;
|
||||
ObjectTargetInformation *ifs(new ObjectTargetInformation(m_mainHandler));
|
||||
Core::FunctionReplyObject ret = ifs->createObject(ObjectTargetInformation::toDdsData(data));
|
||||
if (ret.error())
|
||||
{
|
||||
delete ifs;
|
||||
ERROR_LOG(m_logger) << ret();
|
||||
bRet = false;
|
||||
return;
|
||||
}
|
||||
m_objectMap.insert(ifs->getId(), ifs);
|
||||
};
|
||||
if (!m_mainHandler->db()->select(cb) || !bRet)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error reading data from database!";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "m_objectMap.size() = " << m_objectMap.size();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HandlerTargetInformation::onModifyTargetInformationRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ModifyTargetInformationRequest &request)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
const auto ret = targetInformationModifyRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
|
||||
m_mainHandler->fts()->modifyTargetInformationReply(cookie, ret);
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject HandlerTargetInformation::targetInformationModifyRequest(const ModifyTargetInformationRequest &request)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
const int requestId = request.targetInfo().id();
|
||||
// modify
|
||||
if (requestId > 0)
|
||||
{
|
||||
ObjectTargetInformation *ifs = m_objectMap.value(requestId);
|
||||
if (!ifs)
|
||||
return Core::FunctionReplyObject(requestId, tr_lts("dds", "TargetInformation with id %1 not found")).arg(requestId);
|
||||
|
||||
auto ret = ifs->updateObject(request.targetInfo());
|
||||
return ret;
|
||||
}
|
||||
// create
|
||||
ObjectTargetInformation *ifs(new ObjectTargetInformation(m_mainHandler));
|
||||
auto ret = ifs->createObject(request.targetInfo());
|
||||
if (ret.error())
|
||||
{
|
||||
delete ifs;
|
||||
ifs = nullptr;
|
||||
}
|
||||
else
|
||||
m_objectMap.insert(ifs->getId(), ifs);
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HandlerTargetInformation::onRemoveTargetInformationRequest(const rti::core::SampleIdentity &cookie,
|
||||
const RemoveTargetInformationRequest &request)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " request=" << request;
|
||||
|
||||
Core::FunctionReplyObject ret;
|
||||
ObjectTargetInformation *ifs = m_objectMap.value(request.id());
|
||||
|
||||
if (ifs == nullptr)
|
||||
{
|
||||
ret = Core::FunctionReplyObject(request.id(), tr_lts("dds", "ShootbackTarget with id %1 not found")).arg(request.id());
|
||||
m_mainHandler->fts()->removeTargetInformationReply(cookie, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ifs->removeObject();
|
||||
if (ret.error())
|
||||
ERROR_LOG(m_logger) << ret();
|
||||
else
|
||||
{
|
||||
// delete Object
|
||||
delete ifs;
|
||||
m_objectMap.remove(request.id());
|
||||
}
|
||||
|
||||
m_mainHandler->fts()->removeTargetInformationReply(cookie, ret);
|
||||
return;
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Handler ShootbackTargets (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, NLE, 06.04.2020
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "dds_handler.h"
|
||||
#include <ParticipantManagement/logger.h>
|
||||
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
class ObjectTargetInformation;
|
||||
|
||||
class HandlerTargetInformation final
|
||||
: protected Interface::Fts::ModifyTargetInformationRequestHandler
|
||||
, protected Interface::Fts::RemoveTargetInformationRequestHandler
|
||||
{
|
||||
public:
|
||||
|
||||
explicit HandlerTargetInformation(MainHandler *mainHandler);
|
||||
~HandlerTargetInformation();
|
||||
|
||||
/**
|
||||
* Initialize the handler to manage information
|
||||
*/
|
||||
bool init();
|
||||
|
||||
const QHash<int, ObjectTargetInformation *> &getObjectMap() const { return m_objectMap; }
|
||||
|
||||
ObjectTargetInformation *data(int id)
|
||||
{
|
||||
if (!m_objectMap.contains(id))
|
||||
return nullptr;
|
||||
return m_objectMap[id];
|
||||
}
|
||||
|
||||
private: // methods
|
||||
void onModifyTargetInformationRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ModifyTargetInformationRequest &request) override;
|
||||
Core::FunctionReplyObject targetInformationModifyRequest(const ModifyTargetInformationRequest &request);
|
||||
void onRemoveTargetInformationRequest(const rti::core::SampleIdentity &cookie,
|
||||
const RemoveTargetInformationRequest &request) override;
|
||||
|
||||
private: // attributes
|
||||
|
||||
QHash<int, ObjectTargetInformation *> m_objectMap;
|
||||
MainHandler *m_mainHandler;
|
||||
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
|
||||
|
||||
};
|
||||
} // namespace ParticipantManagement
|
||||
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* Handler ShootbackTargets (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, SLTE, 31.05.2022
|
||||
*/
|
||||
|
||||
#include "object_target_information.h"
|
||||
#include "../main_handler.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
//
|
||||
// Core::GeoPosition2D
|
||||
Core::GeoPosition2D posFromJson(const QJsonValue &val)
|
||||
{
|
||||
const QJsonObject objElement(val.toObject());
|
||||
Core::GeoPosition2D element;
|
||||
{
|
||||
const QJsonValue valLon(objElement.value(QStringLiteral("lon")));
|
||||
element.lon(valLon.toDouble());
|
||||
}
|
||||
{
|
||||
const QJsonValue valLat(objElement.value(QStringLiteral("lat")));
|
||||
element.lat(valLat.toDouble());
|
||||
}
|
||||
return element;
|
||||
}
|
||||
QJsonObject toJson(const Core::GeoPosition2D &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("lon")] = element.lon();
|
||||
obj[QStringLiteral("lat")] = element.lat();
|
||||
return obj;
|
||||
}
|
||||
|
||||
//
|
||||
// ShootbackArea
|
||||
ShootbackArea areaFromJson(const QJsonValue &val)
|
||||
{
|
||||
ShootbackArea area;
|
||||
// use val.toObject().value instead val[key] introduced with qt5.10
|
||||
area.identifier(val.toObject().value(QStringLiteral("identifier")).toString().toStdString());
|
||||
|
||||
if (val.toObject().value(QStringLiteral("coords")).isArray())
|
||||
{
|
||||
const QJsonArray &arr = val.toObject().value(QStringLiteral("coords")).toArray();
|
||||
if (arr.size() > 0) area.coord1( posFromJson(arr.at(0)) );
|
||||
if (arr.size() > 1) area.coord2( posFromJson(arr.at(1)) );
|
||||
if (arr.size() > 2) area.coord3( posFromJson(arr.at(2)) );
|
||||
if (arr.size() > 3) area.coord4( posFromJson(arr.at(3)) );
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
QJsonObject toJson(const ShootbackArea &area)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("identifier"), QString::fromStdString(area.identifier()));
|
||||
|
||||
QJsonArray arr;
|
||||
arr.push_back(toJson(area.coord1()));
|
||||
arr.push_back(toJson(area.coord2()));
|
||||
arr.push_back(toJson(area.coord3()));
|
||||
arr.push_back(toJson(area.coord4()));
|
||||
obj.insert(QStringLiteral("coords"), arr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
//
|
||||
// vector<ShootbackArea>
|
||||
QJsonObject toJson(const std::vector<ShootbackArea>& shootback_areas)
|
||||
{
|
||||
if (shootback_areas.size() == 0)
|
||||
return {};
|
||||
QJsonArray arr;
|
||||
for (const ShootbackArea &area : shootback_areas)
|
||||
arr.push_back(toJson(area));
|
||||
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("shootback_areas"), arr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
std::vector<ShootbackArea> vecfromJson(const QJsonValue &val)
|
||||
{
|
||||
std::vector<ShootbackArea> ret;
|
||||
if (val.isNull())
|
||||
return ret;
|
||||
|
||||
// use val.toObject().value instead val[key] introduced with qt5.10
|
||||
if (val.toObject().value(QStringLiteral("shootback_areas")).isArray())
|
||||
{
|
||||
const QJsonArray &arr = val.toObject().value(QStringLiteral("shootback_areas")).toArray();
|
||||
ret.reserve(arr.size());
|
||||
for (const auto& item : arr)
|
||||
ret.push_back(areaFromJson(item));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ObjectTargetInformation::ObjectTargetInformation(MainHandler *mainHandler)
|
||||
: m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("ObjectTargetInformation"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ObjectTargetInformation::~ObjectTargetInformation()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
if (isValid())
|
||||
m_mainHandler->dts()->removeTargetInformationByKey(m_data.id());
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool ObjectTargetInformation::isValid() const
|
||||
{
|
||||
return m_data.id() > 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject ObjectTargetInformation::createObject(const TargetInformation &data)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
m_data = data;
|
||||
|
||||
if (m_data.id() <= 0)
|
||||
{
|
||||
Database::PpmTargetInformation dbData(toDbData(data));
|
||||
|
||||
if (!m_mainHandler->db()->insert(dbData))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting TargetInformation-data into database"));
|
||||
|
||||
m_data.id(dbData.id);
|
||||
DEBUG_LOG(m_logger) << "New PpmTargetInformation: " /*<< m_data.id()*/;
|
||||
}
|
||||
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return Core::FunctionReplyObject(m_data.id());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject ObjectTargetInformation::updateObject(const TargetInformation &data)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, participantId=" << data.participantId()
|
||||
<< " size =" << data.shootbackAreas().size();
|
||||
Database::PpmTargetInformation dbData;
|
||||
dbData = toDbData(data);
|
||||
|
||||
if (!m_mainHandler->db()->update(dbData))
|
||||
return Core::FunctionReplyObject(data.id(), tr_lts("dds", "Error updating TargetInformation-data into database"));
|
||||
|
||||
m_data = data;
|
||||
DEBUG_LOG(m_logger) << "Data changed for TargetInformation: " << m_data.participantId();
|
||||
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, id=" << data.id()
|
||||
<< " size =" << data.shootbackAreas().size();
|
||||
return Core::FunctionReplyObject(m_data.id());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject ObjectTargetInformation::removeObject()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (!m_mainHandler->db()->removePpmTargetInformation(m_data.id()))
|
||||
return Core::FunctionReplyObject(m_data.id(), tr_lts("dds", "TargetInformation with id %1 can not be removed from DB")).arg(m_data.id());
|
||||
|
||||
if (!m_mainHandler->dts()->removeTargetInformationByKey(m_data.id()))
|
||||
return Core::FunctionReplyObject(m_data.id(), tr_lts("dds", "TargetInformation with id %1 can not be removed from DDS")).arg(m_data.id());
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return Core::FunctionReplyObject(m_data.id());
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ObjectTargetInformation::onPublishData()
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Publish TargetInformation-data to dds (" << m_data.id() << ") ...";
|
||||
|
||||
if (!m_mainHandler->dts()->publish(m_data))
|
||||
ERROR_LOG(m_logger) << "Error publishing TargetInformation-data to dds";
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// convert methods
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ParticipantManagement::TargetInformation => Database::PpmTargetInformation
|
||||
Database::PpmTargetInformation ObjectTargetInformation::toDbData(const TargetInformation &ddsData)
|
||||
{
|
||||
Database::PpmTargetInformation dbData;
|
||||
|
||||
dbData.id = ddsData.id();
|
||||
dbData.participantId = ddsData.participantId();
|
||||
|
||||
dbData.preWarningInterval = ddsData.prewarningInterval();
|
||||
dbData.preWarningEffect = static_cast<int>(ddsData.prewarningEffect().underlying());
|
||||
dbData.takeDownInterval = ddsData.takedownInterval();
|
||||
dbData.takeDownEffect = static_cast<int>(ddsData.takedownEffect().underlying());
|
||||
|
||||
const std::vector<ParticipantManagement::ShootbackArea>& shootback_areas = ddsData.shootbackAreas();
|
||||
|
||||
const QJsonObject &obj = toJson(shootback_areas);
|
||||
dbData.properties = QString::fromStdString( QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString() );
|
||||
|
||||
return dbData;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// Database::PpmTargetInformation => ParticipantManagement::TargetInformation
|
||||
TargetInformation ObjectTargetInformation::toDdsData(const Database::PpmTargetInformation &dbData)
|
||||
{
|
||||
TargetInformation ddsData;
|
||||
|
||||
ddsData.id(dbData.id);
|
||||
ddsData.participantId(dbData.participantId);
|
||||
|
||||
ddsData.prewarningInterval(dbData.preWarningInterval);
|
||||
ddsData.prewarningEffect(static_cast<ProjectDataManagement::VulnerabilityState::inner_enum>(dbData.preWarningEffect));
|
||||
ddsData.takedownInterval(dbData.takeDownInterval);
|
||||
ddsData.takedownEffect(static_cast<ProjectDataManagement::VulnerabilityState::inner_enum>(dbData.takeDownEffect));
|
||||
|
||||
const QByteArray &propertiesBa = dbData.properties.toUtf8();
|
||||
QJsonParseError parserError;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(propertiesBa, &parserError));
|
||||
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
qCritical() << "Error parsing json document: " << parserError.errorString() << " '" << propertiesBa << "'";
|
||||
|
||||
qDebug() << "json to parse: " << doc.toJson();
|
||||
|
||||
QJsonObject obj(doc.object());
|
||||
const std::vector<ShootbackArea> &sbAreas = vecfromJson(obj);
|
||||
ddsData.shootbackAreas(sbAreas);
|
||||
|
||||
return ddsData;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
|
||||
} // Namespace ParticipantManagement
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Handler ObjectTargetInformation (L400)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by N. Thoden, SLTE, 31.05.2022
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include <ParticipantManagement/logger.h>
|
||||
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
|
||||
// Generated
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
class ObjectTargetInformation
|
||||
{
|
||||
public:
|
||||
explicit ObjectTargetInformation(MainHandler *mainHandler);
|
||||
~ObjectTargetInformation();
|
||||
|
||||
Core::FunctionReplyObject createObject(const TargetInformation &data);
|
||||
Core::FunctionReplyObject updateObject(const TargetInformation &data);
|
||||
Core::FunctionReplyObject removeObject();
|
||||
|
||||
qint32 getId() const { return m_data.id(); }
|
||||
qint32 getParticipantId() const { return m_data.participantId(); }
|
||||
const TargetInformation &getData() const { return m_data; }
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
// convert methods
|
||||
static Database::PpmTargetInformation toDbData(const TargetInformation &ddsData); // dds -> db
|
||||
static TargetInformation toDdsData(const Database::PpmTargetInformation &dbData); // db -> dds
|
||||
|
||||
protected:
|
||||
void onPublishData();
|
||||
|
||||
private:
|
||||
MainHandler *m_mainHandler;
|
||||
TargetInformation m_data;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
||||
*/
|
||||
#include "template.h"
|
||||
|
||||
|
||||
ParticipantManagement::TemplateParticipant ParticipantManagement::TemplateHandling::Template::toDdsTemplateParticipant() const
|
||||
{
|
||||
TemplateParticipant result;
|
||||
|
||||
result.templateId(id());
|
||||
result.typeId(typeId());
|
||||
result.name(m_data.name.toStdString());
|
||||
result.designator(m_data.designator.toStdString());
|
||||
result.info(m_data.info.toStdString());
|
||||
result.symbol(m_data.symbol.toStdString());
|
||||
result.tacticalIdentifier(m_data.tacticalIdentifier.toStdString());
|
||||
result.hierarchyNumber(m_data.hierarchyNumber);
|
||||
result.superiorTemplateId(superiorId());
|
||||
result.equipmentNumber(m_data.equipmentNumber);
|
||||
if (!m_inferiorIds.empty())
|
||||
result.inferiorIds().set(m_inferiorIds);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ParticipantManagement::TemplateHandling::Template::hasToBeChanged(const ParticipantManagement::TemplateData &newData)
|
||||
{
|
||||
bool hasNoChanges =
|
||||
m_data.typeId == newData.typeId() &&
|
||||
m_data.hierarchyNumber == newData.hierarchyNumber() &&
|
||||
m_data.equipmentNumber == newData.equipmentNumber() &&
|
||||
m_data.name == QString::fromStdString(newData.name()) &&
|
||||
m_data.symbol == QString::fromStdString(newData.symbol()) &&
|
||||
m_data.info == QString::fromStdString(newData.info()) &&
|
||||
m_data.designator == QString::fromStdString(newData.designator()) &&
|
||||
m_data.tacticalIdentifier == QString::fromStdString(newData.tacticalIdentifier());
|
||||
|
||||
if (!hasNoChanges)
|
||||
{
|
||||
m_data.typeId = newData.typeId();
|
||||
m_data.hierarchyNumber = newData.hierarchyNumber();
|
||||
m_data.name = QString::fromStdString(newData.name());
|
||||
m_data.symbol = QString::fromStdString(newData.symbol());
|
||||
m_data.info = QString::fromStdString(newData.info());
|
||||
m_data.designator = QString::fromStdString(newData.designator());
|
||||
m_data.tacticalIdentifier = QString::fromStdString(newData.tacticalIdentifier());
|
||||
m_data.equipmentNumber = newData.equipmentNumber();
|
||||
}
|
||||
|
||||
return !hasNoChanges;
|
||||
}
|
||||
|
||||
bool ParticipantManagement::TemplateHandling::Template::hasNewSuperiorId(int32_t superiorId)
|
||||
{
|
||||
bool result = m_data.superiorId != superiorId;
|
||||
m_data.superiorId = superiorId;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ParticipantManagement::TemplateHandling::Template::hasNewInferiorStructure(std::vector<int32_t> inferiorIds)
|
||||
{
|
||||
std::sort(inferiorIds.begin(), inferiorIds.end());
|
||||
|
||||
if (m_inferiorIds != inferiorIds)
|
||||
{
|
||||
std::swap(m_inferiorIds, inferiorIds);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ParticipantManagement::Database::PpmTemplate ParticipantManagement::TemplateHandling::Template::dbEntry() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace TemplateHandling
|
||||
{
|
||||
class Template
|
||||
{
|
||||
public:
|
||||
explicit Template(const Database::PpmTemplate &tmpl)
|
||||
: m_data(tmpl)
|
||||
{}
|
||||
|
||||
int32_t id() const { return m_data.id; }
|
||||
int32_t typeId() const { return m_data.typeId; }
|
||||
int32_t superiorId() const { return m_data.superiorId; }
|
||||
TemplateParticipant toDdsTemplateParticipant() const;
|
||||
|
||||
bool hasToBeChanged(const TemplateData &newData);
|
||||
bool hasNewSuperiorId(int32_t superiorId);
|
||||
bool hasNewInferiorStructure(std::vector<int32_t> inferiorIds);
|
||||
|
||||
Database::PpmTemplate dbEntry() const;
|
||||
|
||||
private:
|
||||
Database::PpmTemplate m_data;
|
||||
std::vector<int32_t> m_inferiorIds;
|
||||
}; // class Template
|
||||
} //namespace TemplateHandling
|
||||
} //namespace ParticipantManagement
|
||||
@@ -0,0 +1,381 @@
|
||||
/**
|
||||
* The TemplateHandler class manages all template related function topics and holds classes for
|
||||
* further tempalte data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-07-27
|
||||
*/
|
||||
#include "template_handler.h"
|
||||
#include "template.h"
|
||||
#include "main_handler.h"
|
||||
#include <TypeHandling/type_donator.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace TemplateHandling
|
||||
{
|
||||
|
||||
TemplateHandler::TemplateHandler(MainHandler *mainHandler)
|
||||
: Interface::Fts::ModifyTemplateDataRequestHandler(mainHandler->exerciseId() <= 0 ? mainHandler->fts() : nullptr)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("TemplateHandler"))
|
||||
{}
|
||||
|
||||
TemplateHandler::~TemplateHandler()
|
||||
{
|
||||
qDeleteAll(m_templates);
|
||||
}
|
||||
|
||||
bool TemplateHandler::init()
|
||||
{
|
||||
auto cb = [this](const Database::PpmTemplate ¤tTemplate)
|
||||
{
|
||||
Template *newTemplate = new Template(currentTemplate);
|
||||
m_templates.insert(newTemplate->id(), newTemplate);
|
||||
};
|
||||
if (!m_mainHandler->db()->select(cb))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading template data from database";
|
||||
return false;
|
||||
}
|
||||
|
||||
// build hierarchy an publish
|
||||
m_mainHandler->exAnyDts()->enableTemplateParticipant();
|
||||
for (auto it = m_templates.begin(); it != m_templates.end(); ++it)
|
||||
{
|
||||
it.value()->hasNewInferiorStructure(inferiorIdsForTemplate(it.key()));
|
||||
m_mainHandler->exAnyDts()->publish(it.value()->toDdsTemplateParticipant());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TemplateHandler::onModifyTemplateDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::ModifyTemplateDataRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onModifyTemplateDataRequest: " << request;
|
||||
const auto ret = modifyTemplateDataRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
m_mainHandler->fts()->modifyTemplateDataReply(cookie, ret);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TemplateHandler::modifyTemplateDataRequest(const ParticipantManagement::ModifyTemplateDataRequest &request)
|
||||
{
|
||||
QVector<Template *> templatesWithChanges;
|
||||
QHash<int32_t, int32_t> modIdToTemplateId; // <modId, templateId>
|
||||
QVector<ParticipantManagement::TemplateData> templatesToBeCreatedOrModified;
|
||||
|
||||
templatesToBeCreatedOrModified.reserve(request.data().size());
|
||||
|
||||
DBTransaction removeTransaction(m_mainHandler->db()->database());
|
||||
// first remove templates which are marked to be removed
|
||||
for (const TemplateData ¤tTemplate : request.data())
|
||||
{
|
||||
if (currentTemplate.isDeleted())
|
||||
{
|
||||
if (currentTemplate.templateId() <= 0)
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Internal error - Not possible to remove templateData with modId %1, because it does not have templateId set"))
|
||||
.arg(currentTemplate.modId());
|
||||
const auto ret = deleteTemplateById(currentTemplate.templateId(), true);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
templatesToBeCreatedOrModified.append(currentTemplate);
|
||||
}
|
||||
removeTransaction.commit();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Starting validating ModifyTemplateDataRequest";
|
||||
if (templatesToBeCreatedOrModified.size() >= 1000) // concurrent validation for big requests
|
||||
{
|
||||
QVector<QFuture<Core::FunctionReplyObject>> futureVec;
|
||||
|
||||
int vecSize = templatesToBeCreatedOrModified.size();
|
||||
if (templatesToBeCreatedOrModified.size() % QThread::idealThreadCount())
|
||||
vecSize += (QThread::idealThreadCount() - (vecSize % QThread::idealThreadCount()));
|
||||
|
||||
const int range = vecSize / QThread::idealThreadCount();
|
||||
futureVec.reserve(vecSize);
|
||||
for (int startIndex = 0; startIndex < templatesToBeCreatedOrModified.size(); startIndex += range)
|
||||
{
|
||||
QFuture<Core::FunctionReplyObject> fut = QtConcurrent::run(this,
|
||||
&TemplateHandler::validateTemplateData,
|
||||
templatesToBeCreatedOrModified,
|
||||
modIdToTemplateId,
|
||||
startIndex,
|
||||
range);
|
||||
futureVec += fut;
|
||||
}
|
||||
|
||||
for (const QFuture<Core::FunctionReplyObject> ¤tFut : qAsConst(futureVec))
|
||||
{
|
||||
Core::FunctionReplyObject ret = currentFut.result();
|
||||
if (ret.error())
|
||||
return ret;;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const ParticipantManagement::TemplateData ¤tTemplate : qAsConst(templatesToBeCreatedOrModified))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Validating template: " << currentTemplate;
|
||||
auto ret = validateTemplateData(templatesToBeCreatedOrModified, modIdToTemplateId, currentTemplate);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DBTransaction trans(m_mainHandler->db()->database());
|
||||
// only continue if there was no error detected
|
||||
DEBUG_LOG(m_logger) << "ModifyTemplateDataRequest has valid data";
|
||||
|
||||
// create new and update existing templates
|
||||
DEBUG_LOG(m_logger) << "Creating new and updating existing templates ...";
|
||||
|
||||
for (const TemplateData ¤tData : qAsConst(templatesToBeCreatedOrModified))
|
||||
{
|
||||
Template *templateToUpdate = m_templates.value(modIdToTemplateId.value(currentData.modId()));
|
||||
if (!templateToUpdate)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating new template: " << currentData;
|
||||
const auto ret = createNewTemplate(currentData, modIdToTemplateId, templatesWithChanges);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update existing template
|
||||
if (templateToUpdate->hasToBeChanged(currentData) &&
|
||||
!templatesWithChanges.contains(templateToUpdate))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Template changed: " << templateToUpdate->toDdsTemplateParticipant();
|
||||
templatesWithChanges.append(templateToUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "New templates created and existing templates updated";
|
||||
|
||||
// build hierarchy
|
||||
for (const TemplateData ¤tData : qAsConst(templatesToBeCreatedOrModified)) // first set superiorIds
|
||||
{
|
||||
Template *templateToUpdate = m_templates.value(modIdToTemplateId.value(currentData.modId()), nullptr);
|
||||
const int superiorId = modIdToTemplateId.value(currentData.superiorModId());
|
||||
if (!templateToUpdate->hasNewSuperiorId(superiorId) ||
|
||||
templatesWithChanges.contains(templateToUpdate))
|
||||
continue;
|
||||
templatesWithChanges.append(templateToUpdate);
|
||||
}
|
||||
|
||||
for (Template *currentTemplate : qAsConst(m_templates)) // set inferiorIds
|
||||
{
|
||||
if (!currentTemplate->hasNewInferiorStructure(inferiorIdsForTemplate(currentTemplate->id())) ||
|
||||
templatesWithChanges.contains(currentTemplate))
|
||||
continue;
|
||||
DEBUG_LOG(m_logger) << "Template got new inferiors: " << currentTemplate->toDdsTemplateParticipant();
|
||||
templatesWithChanges.append(currentTemplate);
|
||||
}
|
||||
|
||||
// update in Database
|
||||
for (Template *currentTemplate : qAsConst(templatesWithChanges))
|
||||
{
|
||||
if (!m_mainHandler->db()->update(currentTemplate->dbEntry()))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Could not update template data in database, template data may be inconsistent"));
|
||||
}
|
||||
trans.commit();
|
||||
|
||||
// finally ... publish template data via dds if no error occured
|
||||
for (Template *currentTemplate : qAsConst(templatesWithChanges))
|
||||
m_mainHandler->exAnyDts()->publish(currentTemplate->toDdsTemplateParticipant());
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
std::vector<int32_t> TemplateHandler::inferiorIdsForTemplate(int32_t superiorTemplateId) const
|
||||
{
|
||||
std::vector<int32_t> result;
|
||||
result.reserve(10);
|
||||
|
||||
for (Template *currentTemplate : qAsConst(m_templates))
|
||||
{
|
||||
if (currentTemplate->superiorId() == superiorTemplateId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Building hierarchy, parentId: " << superiorTemplateId << " has child " << currentTemplate->id();
|
||||
result.push_back(currentTemplate->id());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TemplateHandler::createNewTemplate(const ParticipantManagement::TemplateData ¤tData,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
QVector<Template *> &templatesWithChanges)
|
||||
{
|
||||
// create new template
|
||||
Database::PpmTemplate newDbTemplate;
|
||||
|
||||
newDbTemplate.typeId = currentData.typeId();
|
||||
newDbTemplate.name = QString::fromStdString(currentData.name());
|
||||
newDbTemplate.symbol = QString::fromStdString(currentData.symbol());
|
||||
newDbTemplate.info = QString::fromStdString(currentData.info());
|
||||
newDbTemplate.designator = QString::fromStdString(currentData.designator());
|
||||
newDbTemplate.tacticalIdentifier = QString::fromStdString(currentData.tacticalIdentifier());
|
||||
newDbTemplate.superiorId = modIdToTemplateId.value(currentData.superiorModId(), 0);
|
||||
newDbTemplate.hierarchyNumber = currentData.hierarchyNumber();
|
||||
newDbTemplate.equipmentNumber = currentData.equipmentNumber();
|
||||
|
||||
// creating db entry
|
||||
if (!m_mainHandler->db()->insert(newDbTemplate))
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Error inserting new template into database, template data may be inconsistent"));
|
||||
|
||||
// adding the new template
|
||||
Template *newTemplate = new Template(newDbTemplate);
|
||||
|
||||
m_templates.insert(newTemplate->id(), newTemplate);
|
||||
modIdToTemplateId.insert(currentData.modId(), newTemplate->id());
|
||||
if (!templatesWithChanges.contains(newTemplate))
|
||||
templatesWithChanges.append(newTemplate);
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TemplateHandler::validateTemplateData(const QVector<TemplateData> &dataVec,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
const ParticipantManagement::TemplateData &templateToValidate)
|
||||
{
|
||||
if (templateToValidate.templateId() != 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Checking template id";
|
||||
Template *existingTemplate = m_templates.value(templateToValidate.templateId(), nullptr);
|
||||
if (existingTemplate == nullptr)
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Could not execute ModifyTemplateDataRequest, because an invalid template ID (%1) was given"))
|
||||
.arg(templateToValidate.templateId());
|
||||
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
{
|
||||
QMutexLocker l(&m_mutex);
|
||||
modIdToTemplateId.insert(templateToValidate.modId(), existingTemplate->id()); /* register template to indicate that this template
|
||||
should just be modified and not newly created */
|
||||
}
|
||||
}
|
||||
|
||||
// superior ids valid?
|
||||
if (templateToValidate.superiorModId() > 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "checking superiorIds";
|
||||
// superior exists?
|
||||
bool isExistingSuperiorId = false;
|
||||
for (const TemplateData &dat : dataVec)
|
||||
{
|
||||
if (templateToValidate.superiorModId() == dat.modId())
|
||||
{
|
||||
isExistingSuperiorId = true;
|
||||
break; // for (const TemplateData &dat : dataVec)
|
||||
}
|
||||
}
|
||||
if (!isExistingSuperiorId)
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Could not execute ModifyTemplateDataRequest, the data set with modId %1 has an invalid superiorModId %2"))
|
||||
.arg(templateToValidate.modId())
|
||||
.arg(templateToValidate.superiorModId());
|
||||
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
|
||||
if (templateToValidate.hierarchyNumber() <= 0)
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Could not execute ModifyTemplateDataRequest, because a data set has a superior but no hierarchyNumber set"));
|
||||
|
||||
// all hierarchy numbers with same superior unique?
|
||||
DEBUG_LOG(m_logger) << "Checking hierarchyNumbers";
|
||||
for (const TemplateData &dat : dataVec)
|
||||
{
|
||||
// operator==() on optionals returns false if not set ...
|
||||
if (dat.modId() != templateToValidate.modId() &&
|
||||
dat.superiorModId() == templateToValidate.superiorModId() &&
|
||||
dat.hierarchyNumber() == templateToValidate.hierarchyNumber())
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Could not execute ModifyTemplateDataRequest, because for superiorModId %1 hierarchyNumber %2 is not unique"))
|
||||
.arg(dat.superiorModId())
|
||||
.arg(dat.hierarchyNumber());
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
}
|
||||
|
||||
// typeId valid?
|
||||
DEBUG_LOG(m_logger) << "Checking typeId";
|
||||
if (m_mainHandler->typeHandler()->typeById(templateToValidate.typeId()) == nullptr)
|
||||
return Core::FunctionReplyObject(tr_lts("dds",
|
||||
"Could not execute ModifyTemplateDataRequest, because data set with modId %1 has invalid typeId %2"))
|
||||
.arg(templateToValidate.modId())
|
||||
.arg(templateToValidate.typeId());
|
||||
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TemplateHandler::validateTemplateData(const QVector<TemplateData> &dataVec,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
int startIndex,
|
||||
int range)
|
||||
{
|
||||
int endIndex;
|
||||
if (startIndex + range > dataVec.size())
|
||||
endIndex = dataVec.size() - startIndex - 1;
|
||||
else
|
||||
endIndex = startIndex + range - 1;
|
||||
|
||||
for (int currentIndex = startIndex; currentIndex <= endIndex; ++currentIndex)
|
||||
{
|
||||
const ParticipantManagement::TemplateData &templateToValidate = dataVec.at(currentIndex);
|
||||
auto ret = validateTemplateData(dataVec, modIdToTemplateId, templateToValidate);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
}
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TemplateHandler::deleteTemplateById(int32_t templateId, bool isTriggeredFromFtRequest)
|
||||
{
|
||||
Template *templateToBeRemoved = m_templates.value(templateId);
|
||||
if (!templateToBeRemoved)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Can not find template with id %1 which should be removed")).arg(templateId);
|
||||
|
||||
const auto inferiors(inferiorIdsForTemplate(templateId));
|
||||
for(int32_t currentInferiorTemplateId : inferiors)
|
||||
{
|
||||
const Core::FunctionReplyObject ret = deleteTemplateById(currentInferiorTemplateId);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!m_mainHandler->db()->removePpmTemplate(templateId))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Could not remove template with id %1 from database")).arg(templateId);
|
||||
|
||||
m_mainHandler->exAnyDts()->removeTemplateParticipantByKey(templateId);
|
||||
m_templates.remove(templateId);
|
||||
|
||||
if (isTriggeredFromFtRequest && templateToBeRemoved->superiorId()) // refresh inferiors from parent and publish in dds
|
||||
{
|
||||
Template *parentTemplate = m_templates.value(templateToBeRemoved->superiorId());
|
||||
|
||||
if (parentTemplate->hasNewInferiorStructure(inferiorIdsForTemplate(parentTemplate->id())))
|
||||
m_mainHandler->exAnyDts()->publish(parentTemplate->toDdsTemplateParticipant());
|
||||
}
|
||||
delete templateToBeRemoved;
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
} // namespace TemplateHandling
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* The TemplateHandler class manages all template related function topics and holds classes for
|
||||
* further tempalte data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-07-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QHash>
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace TemplateHandling
|
||||
{
|
||||
class Template;
|
||||
class TemplateHandler final
|
||||
: protected Interface::Fts::ModifyTemplateDataRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit TemplateHandler(MainHandler *mainHandler);
|
||||
~TemplateHandler();
|
||||
bool init();
|
||||
|
||||
void onModifyTemplateDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ModifyTemplateDataRequest &request) override;
|
||||
|
||||
private: // methods
|
||||
Core::FunctionReplyObject modifyTemplateDataRequest(const ParticipantManagement::ModifyTemplateDataRequest &request);
|
||||
std::vector<int32_t> inferiorIdsForTemplate(int32_t superiorTemplateId) const;
|
||||
|
||||
Core::FunctionReplyObject createNewTemplate(const TemplateData ¤tData,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
QVector<Template *> &templatesWithChanges);
|
||||
Core::FunctionReplyObject validateTemplateData(const QVector<ParticipantManagement::TemplateData> &dataVec,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
const ParticipantManagement::TemplateData &templateToValidate);
|
||||
|
||||
Core::FunctionReplyObject validateTemplateData(const QVector<ParticipantManagement::TemplateData> &dataVec,
|
||||
QHash<int32_t, int32_t> &modIdToTemplateId,
|
||||
int startIndex,
|
||||
int range);
|
||||
|
||||
Core::FunctionReplyObject deleteTemplateById(int32_t templateId, bool isTriggeredFromFtRequest = false);
|
||||
|
||||
private: // attributes
|
||||
MainHandler *m_mainHandler;
|
||||
QHash<int32_t, Template *> m_templates; // <templateId, Template>
|
||||
QMutex m_mutex;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
}; // class TemplateHandler
|
||||
} // namespace TemplateHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* The TypeDonator class is an interface for returning a Type to a given id.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-24
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class EquipmentType;
|
||||
class Type;
|
||||
namespace TypeHandling
|
||||
{
|
||||
class TypeDonator
|
||||
{
|
||||
public:
|
||||
virtual ~TypeDonator() = default;
|
||||
|
||||
virtual const Type *typeById(int typeId) const = 0;
|
||||
virtual bool isSupportType(int typeId) const = 0;
|
||||
virtual bool isParticipantType(int typeId) const = 0;
|
||||
virtual bool isUnitType(int typeId) const = 0;
|
||||
virtual bool isFiringUnitType(int typeId) const = 0;
|
||||
virtual bool isArtilleryParticipantType(int typeId) const = 0;
|
||||
|
||||
virtual const EquipmentType *equipmentTypeByTypeId(int typeId) = 0;
|
||||
}; // class TypeDonator
|
||||
} // namespace TypeHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* The ParticipantHandler class manages all type related function topics and holds classes for
|
||||
* further type data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-19
|
||||
*/
|
||||
#include "type_handler.h"
|
||||
#include "type_handler_exercise.h"
|
||||
#include "type_handler_global.h"
|
||||
#include "main_handler.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace TypeHandling
|
||||
{
|
||||
|
||||
TypeHandler::TypeHandler(MainHandler *mainHandler, LOGGER_T logger)
|
||||
: m_mainHandler(mainHandler)
|
||||
, m_logger(logger)
|
||||
{
|
||||
}
|
||||
|
||||
TypeHandler::~TypeHandler()
|
||||
{
|
||||
qDeleteAll(m_types);
|
||||
qDeleteAll(m_equipmentTypes);
|
||||
}
|
||||
|
||||
const ParticipantManagement::Type *TypeHandler::typeById(int32_t typeId) const
|
||||
{
|
||||
return m_types.value(typeId);
|
||||
}
|
||||
|
||||
bool TypeHandler::isSupportType(int typeId) const
|
||||
{
|
||||
const Type *type = typeById(typeId);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
switch (type->typeClass().underlying())
|
||||
{
|
||||
case TypeClass_def::SupportEntity:
|
||||
case TypeClass_def::SupportUnit:
|
||||
return true;
|
||||
case TypeClass_def::Unit:
|
||||
case TypeClass_def::Human:
|
||||
case TypeClass_def::GroundVehicle:
|
||||
case TypeClass_def::WeaponSystem:
|
||||
case TypeClass_def::Aircraft:
|
||||
case TypeClass_def::Vessel:
|
||||
case TypeClass_def::VehicleWithGear:
|
||||
case TypeClass_def::Unknown:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeHandler::isParticipantType(int typeId) const
|
||||
{
|
||||
const Type *type = typeById(typeId);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
switch (type->typeClass().underlying())
|
||||
{
|
||||
case TypeClass_def::SupportEntity:
|
||||
case TypeClass_def::SupportUnit:
|
||||
case TypeClass_def::Unknown:
|
||||
return false;
|
||||
case TypeClass_def::Unit:
|
||||
case TypeClass_def::Human:
|
||||
case TypeClass_def::GroundVehicle:
|
||||
case TypeClass_def::WeaponSystem:
|
||||
case TypeClass_def::Aircraft:
|
||||
case TypeClass_def::Vessel:
|
||||
case TypeClass_def::VehicleWithGear:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeHandler::isUnitType(int typeId) const
|
||||
{
|
||||
const Type *type = typeById(typeId);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
switch (type->typeClass().underlying())
|
||||
{
|
||||
case TypeClass_def::Unit:
|
||||
case TypeClass_def::SupportUnit:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeHandler::isFiringUnitType(int typeId) const
|
||||
{
|
||||
if (!isUnitType(typeId))
|
||||
return false;
|
||||
|
||||
return isArtilleryType(typeId);
|
||||
}
|
||||
|
||||
bool TypeHandler::isArtilleryParticipantType(int typeId) const
|
||||
{
|
||||
if (isUnitType(typeId))
|
||||
return false;
|
||||
|
||||
return isArtilleryType(typeId);
|
||||
}
|
||||
|
||||
const ParticipantManagement::EquipmentType *TypeHandler::equipmentTypeByTypeId(int32_t typeId)
|
||||
{
|
||||
const Type *type = typeById(typeId);
|
||||
return type ? m_equipmentTypes.value(type->equipmentTypeId()) : nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<TypeHandler> TypeHandler::createInstance(MainHandler *mainHandler, NGL::INGLLogger &logger)
|
||||
{
|
||||
int exerciseId = mainHandler->exerciseId();
|
||||
if (exerciseId <= 0)
|
||||
{
|
||||
DEBUG_LOG(logger) << "Creating TypeHandlerGlobal";
|
||||
return std::make_shared<TypeHandlerGlobal>(mainHandler);
|
||||
}
|
||||
DEBUG_LOG(logger) << "Creating TypeHandlerExercise for ex_"
|
||||
<< exerciseId;
|
||||
return std::make_shared<TypeHandlerExercise>(mainHandler);
|
||||
}
|
||||
|
||||
bool TypeHandler::isArtilleryType(int typeId) const
|
||||
{
|
||||
const Type *type = typeById(typeId);
|
||||
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
QJsonDocument typeProperties = QJsonDocument::fromJson(QByteArray::fromStdString(type->properties()));
|
||||
QJsonObject typePropertiesObject = typeProperties.object();
|
||||
|
||||
return typePropertiesObject.value(QStringLiteral("isArtillery")).toBool();
|
||||
}
|
||||
|
||||
} // namespace TypeHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* The abstract TypeHandler class is on the one hand the base class for all concrete TypeHandler... classes, on the
|
||||
* other hand it offers a static method to instantiate a concrete TypeHandler... child class.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-19
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <memory>
|
||||
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include "logger.h"
|
||||
#include "type_donator.h"
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace TypeHandling
|
||||
{
|
||||
class TypeHandler : public TypeDonator
|
||||
{
|
||||
public:
|
||||
~TypeHandler();
|
||||
|
||||
const Type *typeById(int32_t typeId) const override final;
|
||||
bool isSupportType(int typeId) const override final;
|
||||
bool isParticipantType(int typeId) const override final;
|
||||
bool isUnitType(int typeId) const override final;
|
||||
bool isFiringUnitType(int typeId) const override final;
|
||||
bool isArtilleryParticipantType(int typeId) const override final;
|
||||
const EquipmentType *equipmentTypeByTypeId(int32_t typeId) override final;
|
||||
|
||||
virtual bool init() = 0;
|
||||
|
||||
static std::shared_ptr<TypeHandler> createInstance(MainHandler *mainHandler, NGL::INGLLogger &logger);
|
||||
|
||||
protected:
|
||||
bool isArtilleryType(int typeId) const;
|
||||
explicit TypeHandler(MainHandler *mainHandler, LOGGER_T logger);
|
||||
protected:
|
||||
MainHandler *m_mainHandler;
|
||||
QHash<int32_t, Type *> m_types;
|
||||
QHash<int32_t, EquipmentType *> m_equipmentTypes;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
}; // class TypeHandler
|
||||
} // namespace TypeHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* The TypeHandlerExercise class is an abstract class for either an exercise dependent or an exercise independent
|
||||
* concrete class.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-19
|
||||
*/
|
||||
#include "type_handler_exercise.h"
|
||||
#include "main_handler.h"
|
||||
#include "convert_db_to_dds.h"
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
TypeHandling::TypeHandlerExercise::TypeHandlerExercise(MainHandler *mainHandler)
|
||||
: QObject()
|
||||
, TypeHandler(mainHandler, getLogger("TypeHandlerExercise"))
|
||||
{}
|
||||
|
||||
bool TypeHandling::TypeHandlerExercise::init()
|
||||
{
|
||||
m_dtc = ParticipantManagement::Interface::Dtc::create(m_mainHandler->dds());
|
||||
if (m_dtc == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC";
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::typeChanged,
|
||||
this, &TypeHandlerExercise::onTypeChanged);
|
||||
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::equipmentTypeChanged,
|
||||
this, &TypeHandlerExercise::onEquipmentTypeChanged);
|
||||
if (!m_dtc->enableType() ||
|
||||
!m_dtc->enableEquipmentType())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialize DTC";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Initialized DTC for receiving Type data";
|
||||
|
||||
std::shared_ptr<DatabaseInterface> dbEx0 = m_mainHandler->dbEx0();
|
||||
// pre-init from database
|
||||
auto cbType = [this](const Database::PpmType &t)
|
||||
{
|
||||
onTypeChanged(convert(t));
|
||||
};
|
||||
dbEx0->select(cbType);
|
||||
|
||||
auto cbEquipmentType = [this](const Database::PpmEquipmentType &et)
|
||||
{
|
||||
onEquipmentTypeChanged(convert(et));
|
||||
};
|
||||
dbEx0->select(cbEquipmentType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TypeHandling::TypeHandlerExercise::onTypeChanged(const ParticipantManagement::Type &data)
|
||||
{
|
||||
Type *changedType = m_types.value(data.id());
|
||||
if (changedType)
|
||||
{
|
||||
*changedType = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
changedType = new Type(data);
|
||||
m_types.insert(changedType->id(), changedType);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeHandling::TypeHandlerExercise::onEquipmentTypeChanged(const ParticipantManagement::EquipmentType &data)
|
||||
{
|
||||
EquipmentType *changedEquipmentType = m_equipmentTypes.value(data.id());
|
||||
if (changedEquipmentType)
|
||||
{
|
||||
*changedEquipmentType = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
changedEquipmentType = new EquipmentType(data);
|
||||
m_equipmentTypes.insert(changedEquipmentType->id(), changedEquipmentType);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* The TypeHandlerExercise class is an abstract class for either an exercise dependent or an exercise independent
|
||||
* concrete class.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-19
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "type_handler.h"
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
namespace TypeHandling
|
||||
{
|
||||
class TypeHandlerExercise final
|
||||
: public QObject
|
||||
, public TypeHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TypeHandlerExercise(MainHandler *mainHandler);
|
||||
|
||||
bool init() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onTypeChanged(const ParticipantManagement::Type &data);
|
||||
void onEquipmentTypeChanged(const ParticipantManagement::EquipmentType &data);
|
||||
private:
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
|
||||
}; // class TypeHandlerExercise
|
||||
} // namespace TypeHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* The ParticipantHandlerNonExercise class manages all type related function topics and holds classes for
|
||||
* further type data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-30
|
||||
*/
|
||||
|
||||
#include "type_handler_global.h"
|
||||
#include "main_handler.h"
|
||||
#include "convert_db_to_dds.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
static Database::PpmEquipmentType toDb(const EquipmentType &et)
|
||||
{
|
||||
Database::PpmEquipmentType db;
|
||||
db.id = et.id();
|
||||
db.name = QString::fromStdString(et.name());
|
||||
db.minEquipNo = et.minEquipNo();
|
||||
db.maxEquipNo = et.maxEquipNo();
|
||||
db.traVulnerabilityModelId = et.traVulnerabilityModelId();
|
||||
db.traPlayerTypeId = et.traPlayerTypeId();
|
||||
db.wmsTypeClassId = et.wmsTypeClass();
|
||||
db.deletedInWms = et.deletedInWms();
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
Database::PpmType toDb(const ParticipantManagement::Type &data)
|
||||
{
|
||||
Database::PpmType ret;
|
||||
|
||||
ret.id = data.id();
|
||||
ret.typeClassId = data.typeClass();
|
||||
if (data.equipmentTypeId() != 0)
|
||||
ret.equipmentTypeId = data.equipmentTypeId(); // QVariant
|
||||
ret.name = QString::fromStdString(data.name());
|
||||
ret.symbol = QString::fromStdString(data.symbol());
|
||||
ret.radioCount = data.radioCount();
|
||||
ret.hierarchyLevel = data.hierarchyLevel();
|
||||
ret.isDeleted = data.isDeleted();
|
||||
#ifdef Q_OS_WIN
|
||||
ret.disEntities = LtsUtils::BigintArray(data.disEntities());
|
||||
#else
|
||||
ret.disEntities = LtsUtils::BigintArray(LtsUtils::convert<std::vector<int64_t>>(data.disEntities()));
|
||||
#endif
|
||||
ret.properties = QString::fromStdString(data.properties());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TypeHandling::TypeHandlerGlobal::TypeHandlerGlobal(MainHandler *mainHandler)
|
||||
: TypeHandler(mainHandler, getLogger("TypeHandlerGlobal"))
|
||||
, Interface::Fts::ModifyTypeRequestHandler(mainHandler->exAnyFts())
|
||||
, Interface::Fts::RemoveTypeRequestHandler(mainHandler->exAnyFts())
|
||||
, Interface::Fts::ModifyEquipmentTypeDataRequestHandler(mainHandler->exAnyFts())
|
||||
{
|
||||
}
|
||||
|
||||
bool TypeHandling::TypeHandlerGlobal::init()
|
||||
{
|
||||
qDeleteAll(m_types);
|
||||
m_types.clear();
|
||||
qDeleteAll(m_equipmentTypes);
|
||||
m_equipmentTypes.clear();
|
||||
|
||||
if (m_mainHandler->db() == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "DatabaseInterface is nullptr";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_mainHandler->dds());
|
||||
if (m_exmDtc == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC";
|
||||
return false;
|
||||
}
|
||||
m_exmDtc->enableExercise();
|
||||
m_exmDtc->waitForHistoricalDataExercise();
|
||||
|
||||
m_mainHandler->exAnyFts()->enableModifyType();
|
||||
m_mainHandler->exAnyFts()->enableRemoveType();
|
||||
m_mainHandler->exAnyFts()->enableModifyEquipmentTypeData();
|
||||
|
||||
// get equipment types
|
||||
m_mainHandler->exAnyDts()->enableEquipmentType();
|
||||
auto cbEt = [this] (const Database::PpmEquipmentType &dbEquipmentType)
|
||||
{
|
||||
EquipmentType *newEquipmentType = new EquipmentType(convert(dbEquipmentType));
|
||||
m_equipmentTypes.insert(newEquipmentType->id(), newEquipmentType);
|
||||
m_mainHandler->exAnyDts()->publish(*newEquipmentType);
|
||||
};
|
||||
m_mainHandler->db()->select(cbEt);
|
||||
|
||||
// get types
|
||||
m_mainHandler->exAnyDts()->enableType();
|
||||
auto cbT = [this] (const Database::PpmType &dbType)
|
||||
{
|
||||
Type *newType = new Type(convert(dbType));
|
||||
m_types.insert(newType->id(), newType);
|
||||
m_mainHandler->exAnyDts()->publish(*newType);
|
||||
};
|
||||
m_mainHandler->db()->select(cbT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TypeHandling::TypeHandlerGlobal::onModifyTypeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::Type &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onModifyTypeRequest" << request;
|
||||
auto ret = (request.id() > 0 ? modifyTypeRequest(request) : createTypeRequest(request));
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
m_mainHandler->exAnyFts()->modifyTypeReply(cookie, ret);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TypeHandling::TypeHandlerGlobal::createTypeRequest(const ParticipantManagement::Type &request)
|
||||
{
|
||||
if (request.equipmentTypeId() != 0 && !m_equipmentTypes.contains(request.equipmentTypeId()))
|
||||
return Core::FunctionReplyObject(-1, tr_lts("dds", "Could not add new Type - equipmentTypeId %1 invalid")).arg(request.equipmentTypeId());
|
||||
|
||||
Database::PpmType newPpmType(toDb(request));
|
||||
if (!m_mainHandler->db()->insert(newPpmType))
|
||||
return Core::FunctionReplyObject(-1, tr_lts("dds", "Could not add new Type - insert statement failed"));
|
||||
|
||||
Type *newType = new Type(request);
|
||||
newType->id(newPpmType.id);
|
||||
// insert into map
|
||||
m_types.insert(newType->id(), newType);
|
||||
|
||||
// publish to dds
|
||||
m_mainHandler->exAnyDts()->publish(*newType);
|
||||
|
||||
DEBUG_LOG(m_logger) << "New type added: " << *newType;
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject TypeHandling::TypeHandlerGlobal::modifyTypeRequest(const ParticipantManagement::Type &request)
|
||||
{
|
||||
Type *typeToBeModified = m_types.value(request.id());
|
||||
if (!typeToBeModified)
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not add new Type - Type with id %1 not available")).arg(request.id());
|
||||
|
||||
if (typeToBeModified->equipmentTypeId() != request.equipmentTypeId())
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "It is not allowed to modify the Equipment Type of a Type"));
|
||||
|
||||
if (!m_mainHandler->db()->update(toDb(request)))
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not modify Type in database"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Old Type data:\n"
|
||||
<< *typeToBeModified
|
||||
<< "\nNew Type data:\n"
|
||||
<< request;
|
||||
*typeToBeModified = request;
|
||||
m_mainHandler->exAnyDts()->publish(*typeToBeModified);
|
||||
|
||||
return Core::FunctionReplyObject(request.id());
|
||||
}
|
||||
|
||||
void TypeHandling::TypeHandlerGlobal::onRemoveTypeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::RemoveTypeRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onRemoveTypeRequest " << request;
|
||||
|
||||
Core::FunctionReplyObject rep(request.typeId());
|
||||
Type *typeToBeRemoved = m_types.value(request.typeId());
|
||||
if (typeToBeRemoved)
|
||||
{
|
||||
if (isTypeUsed(typeToBeRemoved->id()))
|
||||
rep = Core::FunctionReplyObject(request.typeId(), tr_lts("dds", "Type '%1' with type id %2 cannot be removed, type is used")).arg(typeToBeRemoved->name()).arg(request.typeId());
|
||||
else
|
||||
{
|
||||
typeToBeRemoved->isDeleted(true);
|
||||
|
||||
if (!m_mainHandler->db()->update(toDb(*typeToBeRemoved)))
|
||||
rep = Core::FunctionReplyObject(request.typeId(), tr_lts("dds", "Could not mark type with id %1 as deleted in database")).arg(request.typeId());
|
||||
|
||||
m_mainHandler->exAnyDts()->publish(*typeToBeRemoved);
|
||||
}
|
||||
}
|
||||
else
|
||||
rep = Core::FunctionReplyObject(request.typeId(), tr_lts("dds", "RemoveTypeRequest for non existing type with id %1")).arg(request.typeId());
|
||||
|
||||
if (rep.error())
|
||||
WARNING_LOG(m_logger) << rep();
|
||||
|
||||
m_mainHandler->exAnyFts()->removeTypeReply(cookie, rep);
|
||||
}
|
||||
|
||||
void TypeHandling::TypeHandlerGlobal::onModifyEquipmentTypeDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::ModifyEquipmentTypeDataRequest &request)
|
||||
{
|
||||
Core::FunctionReplyObject rep;
|
||||
|
||||
INFO_LOG(m_logger) << "Got " << request.data().size() << " equipment types to modify";
|
||||
|
||||
QSet<int> activeIds;
|
||||
activeIds.reserve(request.data().size());
|
||||
|
||||
for (const EquipmentType ¤tData : request.data())
|
||||
{
|
||||
bool bPublishData = false;
|
||||
EquipmentType *existingEquipmentType = m_equipmentTypes.value(currentData.id(), nullptr);
|
||||
if (existingEquipmentType) // update existing equipment type
|
||||
{
|
||||
activeIds += currentData.id();
|
||||
|
||||
if (*existingEquipmentType != currentData)
|
||||
{
|
||||
bPublishData = true;
|
||||
*existingEquipmentType = currentData;
|
||||
if (!m_mainHandler->db()->update(toDb(currentData)))
|
||||
{
|
||||
rep = Core::FunctionReplyObject(currentData.id(), tr_lts("dds", "Error updating equipment type with %1 data in database")).arg(currentData.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Database::PpmEquipmentType dbEquipmentType(toDb(currentData));
|
||||
if (!m_mainHandler->db()->insert(dbEquipmentType))
|
||||
{
|
||||
rep = Core::FunctionReplyObject(currentData.id(), tr_lts("dds", "Error inserting equipment type with %1 data in database")).arg(currentData.id());
|
||||
break;
|
||||
}
|
||||
|
||||
existingEquipmentType = new EquipmentType(currentData);
|
||||
existingEquipmentType->id(dbEquipmentType.id);
|
||||
m_equipmentTypes.insert(existingEquipmentType->id(), existingEquipmentType);
|
||||
activeIds += existingEquipmentType->id();
|
||||
bPublishData = true;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Modified EquipmentType with id " << existingEquipmentType->id() << " ?: " << bPublishData;
|
||||
if (bPublishData)
|
||||
{
|
||||
if (!m_mainHandler->exAnyDts()->publish(*existingEquipmentType))
|
||||
{
|
||||
rep = Core::FunctionReplyObject(currentData.id(), tr_lts("dds", "Error publishing equipment type %1 to DDS")).arg(currentData.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request.deleteAll())
|
||||
{
|
||||
QHashIterator<int32_t,EquipmentType*> it(m_equipmentTypes);
|
||||
while (it.hasNext())
|
||||
{
|
||||
EquipmentType* et = it.next().value();
|
||||
if (activeIds.contains(et->id()))
|
||||
continue;
|
||||
|
||||
INFO_LOG(m_logger) << "Deleted in WHG " << et->id() << ", already marked as deleted?: " << et->deletedInWms();
|
||||
|
||||
// alle, die nicht behandelt wurden -> deletedInWms
|
||||
// über alle iterieren
|
||||
if (et->deletedInWms())
|
||||
continue;
|
||||
|
||||
et->deletedInWms(true);
|
||||
if (!m_mainHandler->db()->update(toDb(*et)))
|
||||
{
|
||||
rep = Core::FunctionReplyObject(et->id(), tr_lts("dds", "Error updating equipment type with %1 data in database")).arg(et->id());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_mainHandler->exAnyDts()->publish(*et))
|
||||
{
|
||||
rep = Core::FunctionReplyObject(et->id(), tr_lts("dds", "Error publishing equipment type %1 to DDS")).arg(et->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rep.error())
|
||||
WARNING_LOG(m_logger) << rep();
|
||||
|
||||
m_mainHandler->exAnyFts()->modifyEquipmentTypeDataReply(cookie, rep);
|
||||
}
|
||||
|
||||
bool TypeHandling::TypeHandlerGlobal::isTypeUsed(int typeId) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "typeId: " << typeId;
|
||||
|
||||
NSqlQuery q(m_mainHandler->db()->database());
|
||||
|
||||
const QString stmt = QStringLiteral("SELECT count(*) FROM %1 WHERE type_id = %2");
|
||||
|
||||
const auto exercises = m_exmDtc->exercises();
|
||||
for (const ExerciseManagement::Exercise &ex : exercises)
|
||||
{
|
||||
const QString tblName = DBCommon::getExerciseTableName(QStringLiteral("ppm_participant"), ex.id());
|
||||
//const QString stmt(QStringLiteral("SELECT count(*) FROM %1 WHERE type_id = %2").arg(tblName, QString::number(typeId)));
|
||||
|
||||
// Error occured => same as if type exists
|
||||
if (!q.execAndFetch(stmt.arg(tblName, QString::number(typeId))))
|
||||
return true;
|
||||
|
||||
int count = q.value(0).toInt();
|
||||
|
||||
DEBUG_LOG(m_logger) << "exercise: " << ex.id() << ", count: " << count;
|
||||
if (count > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString tblName(DBCommon::getTableName(QStringLiteral("ppm_participant"), QStringLiteral("ppm")));
|
||||
//const QString stmt(QStringLiteral("SELECT count(*) FROM %1 WHERE type_id = %2").arg(tblName, QString::number(typeId)));
|
||||
|
||||
// Error occured => same as if type exists
|
||||
if (!q.execAndFetch(stmt.arg(tblName, QString::number(typeId))))
|
||||
return true;
|
||||
|
||||
int count = q.value(0).toInt();
|
||||
|
||||
DEBUG_LOG(m_logger) << "schema: ppm , count: " << count;
|
||||
|
||||
return (count > 0);
|
||||
}
|
||||
|
||||
} // ParticipantManagement
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* The TypeHandlerGlobal class manages all type related function topics and holds classes for
|
||||
* further type data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 2016-05-30
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "type_handler.h"
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace TypeHandling
|
||||
{
|
||||
class TypeHandlerGlobal final
|
||||
: public TypeHandler
|
||||
, protected Interface::Fts::ModifyTypeRequestHandler
|
||||
, protected Interface::Fts::RemoveTypeRequestHandler
|
||||
, protected Interface::Fts::ModifyEquipmentTypeDataRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit TypeHandlerGlobal(MainHandler *mainHandler);
|
||||
|
||||
bool init() override;
|
||||
|
||||
void onModifyTypeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ParticipantManagement::Type &request) override;
|
||||
Core::FunctionReplyObject createTypeRequest(const ParticipantManagement::Type &request);
|
||||
Core::FunctionReplyObject modifyTypeRequest(const ParticipantManagement::Type &request);
|
||||
|
||||
void onRemoveTypeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const RemoveTypeRequest &request) override;
|
||||
void onModifyEquipmentTypeDataRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ModifyEquipmentTypeDataRequest &request) override;
|
||||
private:
|
||||
bool isTypeUsed(int typeId) const;
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
}; // class TypeHandlerGlobal
|
||||
} // namespace TypeHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,444 @@
|
||||
/**
|
||||
* The UasHandler class manages all Uas related function topics and holds classes for
|
||||
* further Uas data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Steve Kemayou, ESZS, 2025-06-02
|
||||
*/
|
||||
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include "main_handler.h"
|
||||
#include "ParticipantHandling/participant.h"
|
||||
|
||||
#include "mission_plan_handler.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
MissionPlanHandler::MissionPlanHandler(MainHandler *mainHandler)
|
||||
: Interface::Fts::ModifyMissionPlanRequestHandler(mainHandler->fts())
|
||||
, Interface::Fts::RemoveMissionPlanRequestHandler(mainHandler->fts())
|
||||
, Interface::Fts::SetMissionActionFulfilledRequestHandler(mainHandler->fts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("MissionPlanHandler"))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ParticipantManagement::UasHandling::MissionPlanHandler::~MissionPlanHandler()
|
||||
{
|
||||
qDeleteAll(m_objMissionPlans);
|
||||
}
|
||||
|
||||
bool MissionPlanHandler::init()
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" -- MissionPlanHandler init...";
|
||||
qDeleteAll(m_objMissionPlans);
|
||||
m_objMissionPlans.clear();
|
||||
if (!loadMissionPlansFromDb())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MissionPlanHandler::onModifyMissionPlanRequest(const rti::core::SampleIdentity &cookie, const ModifyMissionPlanRequest &request)
|
||||
{
|
||||
Core::FunctionReplyObject reply = request.id() == 0 ? createMissionPlanRequest(request)
|
||||
: modifyMissionPlanRequest(request);
|
||||
m_mainHandler->fts()->modifyMissionPlanReply(cookie, reply);
|
||||
}
|
||||
|
||||
void MissionPlanHandler::onRemoveMissionPlanRequest(const rti::core::SampleIdentity &cookie, const RemoveMissionPlanRequest &request)
|
||||
{
|
||||
Core::FunctionReplyObject reply = removeMissionPlanRequest(request.id());
|
||||
|
||||
m_mainHandler->ddsHandler()->fts()->removeMissionPlanReply(cookie, reply);
|
||||
}
|
||||
|
||||
void MissionPlanHandler::onSetMissionActionFulfilledRequest(const rti::core::SampleIdentity &cookie, const SetMissionActionFulfilledRequest &request)
|
||||
{
|
||||
//DEBUG_LOG(m_logger)<<">> -- onSetMissionActionFulfilledRequest -- ";
|
||||
Core::FunctionReplyObject reply = setMissionActionFulfilledRequest(request);
|
||||
m_mainHandler->ddsHandler()->fts()->setMissionActionFulfilledReply(cookie, reply);
|
||||
}
|
||||
|
||||
bool MissionPlanHandler::loadMissionPlansFromDb()
|
||||
{
|
||||
QVector<ParticipantManagement::Database::PpmMissionPlan> missionPlanVec;
|
||||
QVector<ParticipantManagement::Database::PpmMissionItem> missionItemVec;
|
||||
QVector<ParticipantManagement::Database::PpmMissionAction> missionActionVec;
|
||||
if (!m_mainHandler->db()->select(missionActionVec))
|
||||
{
|
||||
ERROR_LOG(m_logger)<<"Error reading data from database >> PpmMissionAction: "<<missionActionVec.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mainHandler->db()->select(missionItemVec))
|
||||
{
|
||||
ERROR_LOG(m_logger)<<"Error reading data from database >> missionItemVec"<<missionItemVec.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mainHandler->db()->select(missionPlanVec))
|
||||
{
|
||||
ERROR_LOG(m_logger)<<"Error reading data from database >> missionPlanVec"<<missionPlanVec.size();
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "load MissionPlans From Db Plans size = " << missionPlanVec.size()
|
||||
<<" Items size = "<<missionItemVec.size()
|
||||
<<" Actions size = "<<missionActionVec.size();
|
||||
// add to internal buffer
|
||||
for (const ParticipantManagement::Database::PpmMissionPlan &data : qAsConst(missionPlanVec))
|
||||
{
|
||||
ParticipantManagement::MissionPlan missionPlan;
|
||||
missionPlan.id(data.id);
|
||||
missionPlan.name(data.name.toStdString());
|
||||
missionPlan.participantId(data.participantId);
|
||||
missionPlan.missionStart(data.missionStart.toMSecsSinceEpoch());
|
||||
missionPlan.repeat(data.repeat);
|
||||
missionPlan.jumpToStart(data.jumpToStart);
|
||||
|
||||
|
||||
QMap <int, ParticipantManagement::Database::PpmMissionItem> itemsDbMap; // QMap to get it sorted
|
||||
QMultiMap <int, ParticipantManagement::Database::PpmMissionAction> actionsDbMap;
|
||||
//get mission items and actions for curr mission plan id
|
||||
|
||||
for (const ParticipantManagement::Database::PpmMissionItem &itemDb : qAsConst(missionItemVec))
|
||||
{
|
||||
if (itemDb.missionPlanId == data.id)
|
||||
{
|
||||
itemsDbMap.insert(itemDb.elementNumber, itemDb);
|
||||
for (const ParticipantManagement::Database::PpmMissionAction &actionDb : qAsConst(missionActionVec) )
|
||||
{
|
||||
if (actionDb.missionItemId == itemDb.id)
|
||||
actionsDbMap.insert(actionDb.missionItemId, actionDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
missionPlan.items().reserve(itemsDbMap.size());
|
||||
for (const ParticipantManagement::Database::PpmMissionItem &item : qAsConst(itemsDbMap))
|
||||
{
|
||||
ParticipantManagement::MissionItem msi;
|
||||
msi.actions().reserve(actionsDbMap.size());
|
||||
msi.name(item.name.toStdString());
|
||||
msi.location(Core::GeoPosition(item.location.x(), item.location.y(), item.location.z()));
|
||||
msi.itemNumber(item.elementNumber);
|
||||
int actionsFulfilled = 0;
|
||||
int64_t latestFulfilled = 0;
|
||||
for (const auto &action : actionsDbMap)
|
||||
{
|
||||
if (action.missionItemId == item.id)
|
||||
{
|
||||
ParticipantManagement::MissionAction msa;
|
||||
msa.planId(missionPlan.id());
|
||||
msa.actionType(action.missionActionTypeId);
|
||||
msa.duration(action.duration);
|
||||
msa.fulfilled(action.fulfilled.toMSecsSinceEpoch());
|
||||
msa.properties(action.properties.toStdString());
|
||||
msa.name(action.name.toStdString());
|
||||
msa.actionNumber(action.elementNumber);
|
||||
msa.itemNumber(msi.itemNumber());
|
||||
msi.actions().push_back(msa);
|
||||
|
||||
if (msa.fulfilled() > 0)
|
||||
actionsFulfilled++;
|
||||
|
||||
if (latestFulfilled < msa.fulfilled())
|
||||
latestFulfilled = msa.fulfilled();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
msi.actionsFulfilled(actionsFulfilled);
|
||||
msi.fulfilled(latestFulfilled);
|
||||
|
||||
missionPlan.items().push_back(msi);
|
||||
}
|
||||
|
||||
setLatestFulfilledItem(missionPlan); // update mission plan fulfillment count & fulfillemnt latest time
|
||||
|
||||
ObjectMissionPlan *obj = new ObjectMissionPlan(m_mainHandler->ddsHandler(), m_mainHandler->db(), missionPlan);
|
||||
obj->setDbMissionItems(itemsDbMap, actionsDbMap);
|
||||
m_objMissionPlans.insert(missionPlan.id(), obj);
|
||||
|
||||
// publish mission plan data
|
||||
m_mainHandler->ddsHandler()->dts()->publish(missionPlan);
|
||||
|
||||
}
|
||||
DEBUG_LOG(m_logger)<<" -- END load mission plan From Db -- ";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MissionPlanHandler::isUasInAutoMode(int participantId)
|
||||
{
|
||||
m_mainHandler->ddsHandler()->dtc()->waitForHistoricalDataUAS(3000);
|
||||
const auto uas = m_mainHandler->ddsHandler()->dtc()->getUasByParticipantId(participantId, m_mainHandler->exerciseId());
|
||||
|
||||
if (uas.id() < 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no uas for pid " << participantId;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "uas with pid " << participantId << " is in mode: " << (int)uas.uasState().underlying();
|
||||
|
||||
return (uas.uasState() == ProjectDataManagement::UasState::Auto);
|
||||
}
|
||||
|
||||
// stolen from Lts/Plugins/ParticipantManagement/Gui/ParticipantInfo/participant_info_dialog.cpp
|
||||
bool MissionPlanHandler::isUasCombatReady(int participantId)
|
||||
{
|
||||
m_mainHandler->ddsHandler()->dtc()->waitForHistoricalDataDynamicParticipantData(3000);
|
||||
const auto data = m_mainHandler->ddsHandler()->dtc()->dynamicParticipantData(participantId);
|
||||
|
||||
if (data.participantId() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Current State
|
||||
if (data.stateHistory().empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &history = data.stateHistory();
|
||||
|
||||
//LasState is the last "real" state, that has a VBG <=8 (Castastrophic)
|
||||
//It's not the last state received, as there can be other state changes like Sanitation, or NearMiss
|
||||
auto lastState = m_mainHandler->ddsHandler()->dtc()->youngestStateInformation(history/*, true*/ /* debug */);
|
||||
decltype(lastState) youngestState;
|
||||
youngestState.stateTime(0);
|
||||
for (const auto &si : history)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "StateInformation "
|
||||
<< " time=" << si.stateTime()
|
||||
<< " vulnerabilityBits=" << si.vulnerabilityBits()
|
||||
<< " vulnerabilityKindId=" << si.vulnerabilityKindId();
|
||||
if (youngestState.stateTime() < si.stateTime())
|
||||
youngestState = si;
|
||||
}
|
||||
|
||||
return (youngestState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CombatReady);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject MissionPlanHandler::createMissionPlanRequest(const ModifyMissionPlanRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) <<" >> -- createMissionPlanRequest -- ";
|
||||
if (request.participantId() > 0 && !isUasParticipant(request.participantId()))
|
||||
{
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Participant with id %1 is not a Uas participant.")).arg(request.participantId());
|
||||
}
|
||||
|
||||
if (!isUasInAutoMode(request.participantId()))
|
||||
{
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Uas with participant id %1 is not in auto mode - maybe the safety tablet is currently engaged.")).arg(request.participantId());
|
||||
}
|
||||
|
||||
if (!isUasCombatReady(request.participantId()))
|
||||
{
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Uas with participant id %1 ------ not combat ready.")).arg(request.participantId());
|
||||
}
|
||||
|
||||
/// 1- insert in DB Mission plan
|
||||
/// 2- insert in DB Mission Items
|
||||
/// 3- insert in DB Mission Actions
|
||||
|
||||
//1-) insert mission plan
|
||||
Database::PpmMissionPlan dbMissionPlan = ObjectMissionPlan::toDbMissionPlan(request);
|
||||
const MissionPlan missionPlan = ObjectMissionPlan::fillMissionPlanData(request);
|
||||
|
||||
ObjectMissionPlan *obj = new ObjectMissionPlan(m_mainHandler->ddsHandler(), m_mainHandler->db(), missionPlan);
|
||||
Core::FunctionReplyObject ret = obj->createMissionPlan(dbMissionPlan, request.items());
|
||||
if (ret.error())
|
||||
{
|
||||
delete obj;
|
||||
return ret;
|
||||
}
|
||||
m_objMissionPlans.insert(obj->id(), obj);
|
||||
|
||||
publishMissionPlan(obj->getMissionPlanData()); // publish mission plan
|
||||
return Core::FunctionReplyObject(dbMissionPlan.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject MissionPlanHandler::modifyMissionPlanRequest(const ModifyMissionPlanRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" >> -- modifyMissionPlanRequest -- ";
|
||||
/// 1- update Mission plan Table
|
||||
/// 2- remove first all mission items and their actions
|
||||
/// 3- add New mission items
|
||||
/// 4- add new mission actions
|
||||
ObjectMissionPlan *obj = m_objMissionPlans.value(request.id());
|
||||
if (!obj || request.id() < 0)
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Couldn't remove Mission plan with id %1")).arg(request.id());
|
||||
|
||||
const Database::PpmMissionPlan &dbMissionPlan = ObjectMissionPlan::toDbMissionPlan(request);
|
||||
|
||||
auto ret = obj->updateMissionPlan(dbMissionPlan, request.items());
|
||||
publishMissionPlan(obj->getMissionPlanData()); // publish mission plan
|
||||
return ret;
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject MissionPlanHandler::removeMissionPlanRequest(int id)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" >> -- removeMissionPlanRequest -- ";
|
||||
Core::FunctionReplyObject ret;
|
||||
ObjectMissionPlan *obj = m_objMissionPlans.value(id, nullptr);
|
||||
if (!obj)
|
||||
return ret;
|
||||
ret = obj->removeMissionPlan(id);
|
||||
if (ret.error())
|
||||
return ret;
|
||||
delete obj;
|
||||
m_objMissionPlans.remove(id);
|
||||
|
||||
m_mainHandler->ddsHandler()->dts()->removeMissionPlanByKey(id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool MissionPlanHandler::setCurrentMissionActionFulfilled(int participantId, const QString &nameOfTheMissionThatEnded)
|
||||
{
|
||||
// okay we somehow need to find the currently running mission for this participant..... the plan: filter mission plans by participant und by (start < now)
|
||||
bool found = false;
|
||||
for (const auto &missionPlan : m_objMissionPlans.values())
|
||||
{
|
||||
if (missionPlan->missionPlan().participantId() == participantId && missionPlan->missionPlan().missionStart() <= m_mainHandler->currentTimeMSec())
|
||||
{
|
||||
// get current action (stolen from Services/CentralEffectSimulation/Plugins/MissionPlan/ces_mission_plan_object.cpp)
|
||||
const std::vector< ParticipantManagement::MissionItem > items = missionPlan->missionPlan().items(); // copy !!
|
||||
for (const auto &item : items)
|
||||
{
|
||||
for (auto &msa : item.actions())
|
||||
{
|
||||
const QString thisMissionName(QStringLiteral("%1_%2_%3").arg(missionPlan->missionPlan().id()).arg(QString::fromStdString(missionPlan->missionPlan().name()), QString::fromStdString(item.name())));
|
||||
|
||||
INFO_LOG(m_logger) << ">> mission item: this mission name: " << thisMissionName << ", fulfilled: " << msa.fulfilled();
|
||||
|
||||
if (msa.fulfilled() > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thisMissionName != nameOfTheMissionThatEnded)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << ">> ######### setMissionActionFulfilledRequest !!! item = " << item.itemNumber() << ", name = " << item.name() << ", missionPlan = " << missionPlan->missionPlan().id();
|
||||
SetMissionActionFulfilledRequest req;
|
||||
req.actionNumber(msa.actionNumber());
|
||||
req.fulfilled(true);
|
||||
req.missionId(missionPlan->missionPlan().id());
|
||||
req.itemNumber(item.itemNumber());
|
||||
const auto res = setMissionActionFulfilledRequest(req);
|
||||
if (res.error())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "failed to set current mission action as fulfilled: " << res.str();
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// maybe okay? last mission action was already fulfilled? is this even possible at this point?
|
||||
DEBUG_LOG(m_logger) << "failed to set current mission action as fulfilled: no action found for pId " << participantId;
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject MissionPlanHandler::setMissionActionFulfilledRequest(const SetMissionActionFulfilledRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" -- [setMissionActionFulfilledRequest] req.missionId: "<<request.missionId();
|
||||
Core::FunctionReplyObject ret;
|
||||
ObjectMissionPlan *obj = m_objMissionPlans.value(request.missionId(), nullptr);
|
||||
if (!obj)
|
||||
return ret;
|
||||
ret = obj->setMissionActionFulfilled(request, m_mainHandler->currentTimeMSec());
|
||||
m_mainHandler->ddsHandler()->dts()->publish(obj->missionPlan());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MissionPlanHandler::publishMissionPlan(const MissionPlan &missionplan)
|
||||
{
|
||||
m_mainHandler->ddsHandler()->dts()->publish(missionplan);
|
||||
}
|
||||
|
||||
bool MissionPlanHandler::isUasParticipant(int participantId) const
|
||||
{
|
||||
const ParticipantManagement::ParticipantHandling::Participant *PARTICIPANT = m_mainHandler->participantHandler()->participantById(participantId);
|
||||
|
||||
if (PARTICIPANT == nullptr)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got invalid participantId " << participantId;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int TYPE_ID = PARTICIPANT->typeId();
|
||||
return m_mainHandler->ddsHandler()->dtc()->isTypeUas(TYPE_ID);
|
||||
}
|
||||
|
||||
int MissionPlanHandler::getNumberOfActionFulfilled(const MissionItem &msi) const
|
||||
{
|
||||
int count = 0;
|
||||
for (auto action : msi.actions())
|
||||
{
|
||||
if (action.fulfilled() > 0)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void MissionPlanHandler::setLatestFulfilledItem(MissionPlan &missionPlan)
|
||||
{
|
||||
int count = 0;
|
||||
int64_t latestTime = 0;
|
||||
for (auto item : missionPlan.items())
|
||||
{
|
||||
if (item.actionsFulfilled() > 0)
|
||||
count++;
|
||||
|
||||
if (latestTime < item.fulfilled())
|
||||
latestTime = item.fulfilled();
|
||||
|
||||
missionPlan.itemsFulfilled(count);
|
||||
missionPlan.fulfilled(latestTime);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t MissionPlanHandler::getLastestFulfilledAction(const MissionItem &msi) const
|
||||
{
|
||||
int64_t latestTime = 0;
|
||||
for (auto action : msi.actions())
|
||||
{
|
||||
if (action.fulfilled() > latestTime)
|
||||
latestTime = action.fulfilled();
|
||||
}
|
||||
|
||||
return latestTime;
|
||||
}
|
||||
|
||||
|
||||
}// namespace UasHandling
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* The UasHandler class manages all Uas related function topics and holds classes for
|
||||
* further Uas data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Steve Kemayou, ESZS, 2025-06-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QHash>
|
||||
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
#include <CentralEffectSimulation/dds_handler.h>
|
||||
#include "object_mission_plan.h"
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class ObjectMissionPlan;
|
||||
class MainHandler;
|
||||
namespace UasHandling
|
||||
{
|
||||
|
||||
class MissionPlanHandler final
|
||||
: protected Interface::Fts::ModifyMissionPlanRequestHandler
|
||||
, protected Interface::Fts::RemoveMissionPlanRequestHandler
|
||||
, protected Interface::Fts::SetMissionActionFulfilledRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit MissionPlanHandler(MainHandler *mainHandler);
|
||||
~MissionPlanHandler();
|
||||
|
||||
bool init();
|
||||
void onModifyMissionPlanRequest(const rti::core::SampleIdentity &cookie, const ModifyMissionPlanRequest &request) override final;
|
||||
void onRemoveMissionPlanRequest(const rti::core::SampleIdentity &cookie, const RemoveMissionPlanRequest &request) override final;
|
||||
void onSetMissionActionFulfilledRequest(const rti::core::SampleIdentity &cookie, const SetMissionActionFulfilledRequest &request) override final;
|
||||
bool loadMissionPlansFromDb();
|
||||
|
||||
bool setCurrentMissionActionFulfilled(int participantId, const QString &nameOfTheMissionThatEnded);
|
||||
|
||||
private:
|
||||
bool isUasCombatReady(int participantId);
|
||||
bool isUasInAutoMode(int participantId);
|
||||
Core::FunctionReplyObject createMissionPlanRequest(const ModifyMissionPlanRequest &request);
|
||||
Core::FunctionReplyObject modifyMissionPlanRequest(const ModifyMissionPlanRequest &request);
|
||||
Core::FunctionReplyObject removeMissionPlanRequest(int id);
|
||||
Core::FunctionReplyObject setMissionActionFulfilledRequest(const SetMissionActionFulfilledRequest &request);
|
||||
void publishMissionPlan(const MissionPlan &missionplan);
|
||||
bool isUasParticipant(int participantId) const;
|
||||
int getNumberOfActionFulfilled(const MissionItem &msi) const;
|
||||
void setLatestFulfilledItem(MissionPlan &missionPlan); /// update mission plan fulfillment count & fulfillemnt latest time
|
||||
int64_t getLastestFulfilledAction(const MissionItem &msi) const;
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
QHash<int32_t, ObjectMissionPlan *> m_objMissionPlans;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
}// namespace ParticipantManagement
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
/**
|
||||
* The ObjectMissionPlan class represents a ObjectMissionPlan. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Steve Kemayou, ESZS, 2025-04-08
|
||||
*/
|
||||
|
||||
#include "object_mission_plan.h"
|
||||
#include <ngldb/dbtransaction.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
|
||||
ObjectMissionPlan::ObjectMissionPlan(const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DatabaseInterface> &db,
|
||||
const ParticipantManagement::MissionPlan & missionPlan,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_ddsHandler(ddsHandler)
|
||||
, m_db(db)
|
||||
, m_missionplan(missionPlan)
|
||||
, m_logger(getLogger("ObjectMissionPlan"))
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" - ctor ObjectMissionPlan: planId: "<<m_missionplan.id();
|
||||
|
||||
}
|
||||
|
||||
int32_t ObjectMissionPlan::id() const
|
||||
{
|
||||
return m_missionplan.id();
|
||||
}
|
||||
|
||||
int32_t ObjectMissionPlan::participantId() const
|
||||
{
|
||||
return m_missionplan.participantId();
|
||||
}
|
||||
|
||||
Database::PpmMissionPlan ObjectMissionPlan::toDbMissionPlan(const ModifyMissionPlanRequest &mp)
|
||||
{
|
||||
Database::PpmMissionPlan result;
|
||||
result.id = mp.id();
|
||||
result.name = QString::fromStdString(mp.name());
|
||||
result.missionStart = QDateTime::fromMSecsSinceEpoch(mp.missionStart());
|
||||
result.repeat = mp.repeat();
|
||||
result.jumpToStart = mp.jumpToStart();
|
||||
result.participantId = mp.participantId();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
MissionPlan ObjectMissionPlan::fillMissionPlanData(const ModifyMissionPlanRequest &in)
|
||||
{
|
||||
MissionPlan out;
|
||||
out.id(in.id());
|
||||
out.name(in.name());
|
||||
out.missionStart(in.missionStart());
|
||||
out.properties(in.properties());
|
||||
out.items(in.items());
|
||||
out.participantId(in.participantId());
|
||||
out.jumpToStart(in.jumpToStart());
|
||||
out.repeat(in.repeat());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
MissionPlan ObjectMissionPlan::getMissionPlanData() const
|
||||
{
|
||||
return m_missionplan;
|
||||
}
|
||||
|
||||
void ObjectMissionPlan::setDbMissionItems(const QMap<int, ParticipantManagement::Database::PpmMissionItem> &dbItems,
|
||||
const QMap<int, Database::PpmMissionAction> &dbActions)
|
||||
{
|
||||
m_mapMissionItems.clear();
|
||||
m_dbMissionActions.clear();
|
||||
|
||||
for (const ParticipantManagement::Database::PpmMissionItem &item : qAsConst(dbItems))
|
||||
{
|
||||
ParticipantManagement::MissionItem msi;
|
||||
msi.actions().reserve(dbActions.size());
|
||||
msi.name(item.name.toStdString());
|
||||
msi.location(Core::GeoPosition(item.location.x(), item.location.y(), item.location.z()));
|
||||
msi.itemNumber(item.elementNumber);
|
||||
std::vector<Database::PpmMissionAction> actionsVec;
|
||||
for (const auto &action : dbActions)
|
||||
{
|
||||
if (action.missionItemId == item.id)
|
||||
{
|
||||
ParticipantManagement::MissionAction msa;
|
||||
msa.actionType(action.missionActionTypeId);
|
||||
msa.duration(action.duration);
|
||||
msa.fulfilled(action.fulfilled.toMSecsSinceEpoch());
|
||||
msa.properties(action.properties.toStdString());
|
||||
msa.name(action.name.toStdString());
|
||||
msa.actionNumber(action.elementNumber);
|
||||
msa.planId(item.missionPlanId);
|
||||
msi.actions().push_back(msa);
|
||||
actionsVec.push_back(action);
|
||||
}
|
||||
}
|
||||
|
||||
m_mapMissionItems.insert(item.id, msi);
|
||||
m_dbMissionActions.push_back(actionsVec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const MissionPlan &ObjectMissionPlan::missionPlan() const
|
||||
{
|
||||
return m_missionplan;
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectMissionPlan::createMissionPlan(Database::PpmMissionPlan newMissionPlan, const std::vector<MissionItem> &missionItems)
|
||||
{
|
||||
/// 1- insert in DB Mission plan
|
||||
/// 2- insert in DB Mission Items
|
||||
/// 3- insert in DB Mission Actions
|
||||
|
||||
DBTransaction trans(m_db->database());
|
||||
newMissionPlan.aborted = false;
|
||||
if (!m_db->insert(newMissionPlan))
|
||||
{
|
||||
QString error = QStringLiteral("Could not insert mission plan into database");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
std::vector<MissionItem> itemVec = missionItems;
|
||||
m_mapMissionItems.clear();
|
||||
m_mapMissionItems.reserve(itemVec.size());
|
||||
std::vector<std::vector<Database::PpmMissionAction>>itemsVec;
|
||||
m_dbMissionActions.clear();
|
||||
|
||||
for ( auto &item : itemVec)
|
||||
{
|
||||
Database::PpmMissionItem dbItem;
|
||||
dbItem.missionPlanId = newMissionPlan.id;
|
||||
dbItem.name = QString::fromStdString(item.name());
|
||||
dbItem.elementNumber = item.itemNumber();
|
||||
dbItem.location = LtsUtils::QPoint3D(item.location().lon(),item.location().lat(), item.location().z());
|
||||
|
||||
if (!m_db->insert(dbItem))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Item' to database"));
|
||||
|
||||
std::vector<Database::PpmMissionAction> actionsVec;
|
||||
actionsVec.reserve(item.actions().size());
|
||||
for (auto &action : item.actions())
|
||||
{
|
||||
action.planId(newMissionPlan.id);
|
||||
Database::PpmMissionAction dbAction;
|
||||
dbAction.missionActionTypeId = action.actionType();
|
||||
dbAction.missionItemId = dbItem.id;
|
||||
dbAction.duration = action.duration();
|
||||
dbAction.name = QString::fromStdString(action.name());
|
||||
dbAction.properties = QString::fromStdString(action.properties());
|
||||
dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(action.fulfilled());
|
||||
dbAction.elementNumber = action.actionNumber();
|
||||
if (!m_db->insert(dbAction))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Action' to database"));
|
||||
|
||||
actionsVec.push_back(dbAction);
|
||||
}//loop mission actions
|
||||
m_mapMissionItems.insert(dbItem.id, item);
|
||||
m_dbMissionActions.push_back(actionsVec); // [elNumber][actionNumber]
|
||||
}//loop mission items
|
||||
|
||||
m_missionplan.id(newMissionPlan.id);
|
||||
m_missionplan.name(newMissionPlan.name.toStdString());
|
||||
m_missionplan.missionStart(newMissionPlan.missionStart.toMSecsSinceEpoch());
|
||||
m_missionplan.participantId(newMissionPlan.participantId);
|
||||
m_missionplan.jumpToStart(newMissionPlan.jumpToStart);
|
||||
m_missionplan.repeat(newMissionPlan.repeat);
|
||||
m_missionplan.items(itemVec);
|
||||
m_missionplan.fulfilled(0);
|
||||
m_missionplan.itemsFulfilled(0);
|
||||
|
||||
for (auto &item : m_missionplan.items())
|
||||
{
|
||||
for (auto &action : item.actions())
|
||||
DEBUG_LOG(m_logger)<<"[CREATE] itemIdx: "<<item.itemNumber()
|
||||
<<" act.Num: "<<action.actionNumber()<<" act.ItemNum: "<<action.itemNumber()<<" itemFul:"<<action.fulfilled();
|
||||
}
|
||||
trans.commit();
|
||||
DEBUG_LOG(m_logger)<< ">> [NEW] mission plan with id( "<<newMissionPlan.id<<" ) inserted !!";
|
||||
return Core::FunctionReplyObject(newMissionPlan.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectMissionPlan::updateMissionPlan(Database::PpmMissionPlan newMissionPlan, const std::vector<MissionItem> &missionItems)
|
||||
{
|
||||
if (missionItems.size() == 0)
|
||||
return Core::FunctionReplyObject(newMissionPlan.id, tr_lts("dds", "Could not modify MissionPlan without segments."));
|
||||
|
||||
/// 1- update missipn plan table
|
||||
/// 2- remove items and their actions
|
||||
/// 3- insert new items and their actions
|
||||
DBTransaction trans(m_db->database());
|
||||
const auto tmpDbMissionItems = m_mapMissionItems;
|
||||
newMissionPlan.aborted = false;
|
||||
|
||||
/// update mission plan table
|
||||
if (!m_db->update(newMissionPlan))
|
||||
{
|
||||
QString error = QStringLiteral("Could not update mission plan! ");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
/// remove all items and their actions from the database
|
||||
for (const auto &itemId : tmpDbMissionItems.keys())
|
||||
{
|
||||
if (!m_db->removePpmMissionItem(itemId))
|
||||
{
|
||||
QString error = QStringLiteral("Could not remove mission plan from database");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Could not update mission plan into!"));
|
||||
}
|
||||
}
|
||||
|
||||
/// insert new items with their actions in the data base;
|
||||
m_mapMissionItems.clear();
|
||||
m_mapMissionItems.reserve(missionItems.size());
|
||||
m_dbMissionActions.clear();
|
||||
|
||||
std::vector<MissionItem> itemVec = missionItems;
|
||||
for (auto &item : itemVec)
|
||||
{
|
||||
Database::PpmMissionItem dbItem;
|
||||
dbItem.missionPlanId = newMissionPlan.id;
|
||||
dbItem.name = QString::fromStdString(item.name());
|
||||
dbItem.elementNumber = item.itemNumber();
|
||||
dbItem.location = LtsUtils::QPoint3D(item.location().lon(),item.location().lat(), item.location().z());
|
||||
if (!m_db->insert(dbItem))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Item' to database"));
|
||||
|
||||
std::vector<Database::PpmMissionAction> actionsVec;
|
||||
actionsVec.reserve(item.actions().size());
|
||||
for (auto &action : item.actions())
|
||||
{
|
||||
action.planId(newMissionPlan.id);
|
||||
Database::PpmMissionAction dbAction;
|
||||
dbAction.missionActionTypeId = action.actionType();
|
||||
dbAction.missionItemId = dbItem.id;
|
||||
dbAction.duration = action.duration();
|
||||
dbAction.name = QString::fromStdString(action.name());
|
||||
dbAction.properties = QString::fromStdString(action.properties());
|
||||
dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(action.fulfilled());
|
||||
dbAction.elementNumber = action.actionNumber();
|
||||
if (!m_db->insert(dbAction))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Action' to database"));
|
||||
|
||||
actionsVec.push_back(dbAction);
|
||||
}//loop mission actions
|
||||
m_mapMissionItems.insert(dbItem.id, item);
|
||||
m_dbMissionActions.push_back(actionsVec); // [elNumber][actionNumber]
|
||||
}//loop mission items
|
||||
|
||||
trans.commit();
|
||||
m_missionplan.id(newMissionPlan.id);
|
||||
m_missionplan.name(newMissionPlan.name.toStdString());
|
||||
m_missionplan.missionStart(newMissionPlan.missionStart.toMSecsSinceEpoch());
|
||||
m_missionplan.participantId(newMissionPlan.participantId);
|
||||
m_missionplan.jumpToStart(newMissionPlan.jumpToStart);
|
||||
m_missionplan.repeat(newMissionPlan.repeat);
|
||||
m_missionplan.items(itemVec);
|
||||
m_missionplan.itemsFulfilled(0); // on update items and action entries will be cleared
|
||||
m_missionplan.fulfilled(0);
|
||||
|
||||
DEBUG_LOG(m_logger)<< ">> [UPDATE] mission plan with id( "<<m_missionplan.id()<<" ) Updated !!";
|
||||
|
||||
return Core::FunctionReplyObject(m_missionplan.id());
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectMissionPlan::removeMissionPlan(int id)
|
||||
{
|
||||
DBTransaction trans(m_db->database());
|
||||
if (!m_db->removePpmMissionPlan(id))
|
||||
{
|
||||
QString error = QStringLiteral("Could not remove mission plan ! ");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
trans.commit();
|
||||
m_dbMissionActions.clear();
|
||||
m_mapMissionItems.clear();
|
||||
DEBUG_LOG(m_logger)<< ">> [REMOVE] mission Action with id( "<<id<<" ) deleted !!";
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectMissionPlan::setMissionActionFulfilled(SetMissionActionFulfilledRequest req, qint64 currentTimeMSec)
|
||||
{
|
||||
//0- if actionNumb and itemNumb are -1 -> missionplan is aborted. only update missionPlan table with status aborted = true
|
||||
//1- get db mission action from actionNumber
|
||||
//2- set mission action as fulfilled
|
||||
//3- set mission action save in db
|
||||
//4- update cache data
|
||||
|
||||
if (!m_db)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no init yet....";
|
||||
return Core::FunctionReplyObject("");
|
||||
}
|
||||
|
||||
if (req.missionId() != m_missionplan.id())
|
||||
{
|
||||
QString error = QStringLiteral("Wrong missionPlan Object caught Request: %1 / currPlanId: %2").arg(req.missionId()).arg(m_missionplan.id());
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Abort in case itemNumb=-1 && actionNumb=-1
|
||||
if (req.actionNumber() < 0 && req.itemNumber() < 0)
|
||||
{
|
||||
m_missionplan.aborted(true);
|
||||
return setMissionPlanAborted(true);
|
||||
}
|
||||
|
||||
auto &dbActions = m_dbMissionActions[req.itemNumber()]; //[elemNum][actionNum]
|
||||
|
||||
if (dbActions.empty()
|
||||
|| req.actionNumber() >= static_cast<int>(dbActions.size())
|
||||
|| req.actionNumber() < 0
|
||||
|| req.itemNumber() < 0) // actionNumber start by 0
|
||||
{
|
||||
QString error = QStringLiteral("Could not set mission action with id: %1 ! ").arg(req.actionNumber());
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
Database::PpmMissionAction &dbAction = dbActions[req.actionNumber()];
|
||||
dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(currentTimeMSec);
|
||||
|
||||
if (!m_db->update(dbAction))
|
||||
{
|
||||
QString error = QStringLiteral("Could not update mission action! ");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
//update item in case actions fulfilled
|
||||
//1- actions count
|
||||
//2- number of actions fulfilled
|
||||
//3- check if action count == item.actions.size()
|
||||
//4- if yes update missioPlan & missionItem fulfilled
|
||||
|
||||
MissionItem &msi = m_mapMissionItems[dbAction.missionItemId];
|
||||
msi.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch());
|
||||
msi.actionsFulfilled(msi.actionsFulfilled() + 1);
|
||||
MissionAction &msa = m_mapMissionItems[dbAction.missionItemId].actions()[dbAction.elementNumber];
|
||||
msa.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch());
|
||||
m_missionplan.items()[req.itemNumber()] = m_mapMissionItems[dbAction.missionItemId]; // item in MissionPlan updated through elementNumber
|
||||
|
||||
/// update fulfilled time for items and mission plan
|
||||
/// update fulfilled items count
|
||||
|
||||
int numbItemFulfilled = 0;
|
||||
for(const auto &item : m_mapMissionItems)
|
||||
{
|
||||
if (item.actionsFulfilled() == static_cast<int>(item.actions().size()))
|
||||
numbItemFulfilled++;
|
||||
}
|
||||
m_missionplan.itemsFulfilled(numbItemFulfilled);
|
||||
m_missionplan.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch());
|
||||
|
||||
|
||||
return Core::FunctionReplyObject(m_missionplan.id());
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectMissionPlan::setMissionPlanAborted(bool state)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" -- [setMissionPlanAborted] abort mission plan: "<<m_missionplan.id();
|
||||
Database::PpmMissionPlan dbMissionPlan;
|
||||
// m_db->selectPpmMissionPlan(m_missionplan.id(),dbMissionPlan);
|
||||
dbMissionPlan.missionStart = QDateTime::fromMSecsSinceEpoch(m_missionplan.missionStart());
|
||||
dbMissionPlan.jumpToStart = m_missionplan.jumpToStart();
|
||||
dbMissionPlan.id = m_missionplan.id();
|
||||
dbMissionPlan.name = QString::fromStdString(m_missionplan.name());
|
||||
dbMissionPlan.participantId = m_missionplan.participantId();
|
||||
dbMissionPlan.repeat = m_missionplan.repeat();
|
||||
dbMissionPlan.aborted = state;
|
||||
|
||||
|
||||
/// update mission plan table
|
||||
if (!m_db->update(dbMissionPlan))
|
||||
{
|
||||
QString error = QStringLiteral("Could not update mission plan! ");
|
||||
ERROR_LOG(m_logger)<< error;
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
return Core::FunctionReplyObject(m_missionplan.id());
|
||||
}
|
||||
|
||||
} // namespace UasHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* The ObjectMissionPlan class represents a ObjectMissionPlan. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Steve Kemayou, ESZS, 2025-04-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/logger.h>
|
||||
#include <ParticipantManagement/dds_handler.h>
|
||||
#include "logger.h"
|
||||
|
||||
#include <QObject>
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
class ObjectMissionPlan : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ObjectMissionPlan(const std::shared_ptr<ParticipantManagement::DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<ParticipantManagement::DatabaseInterface> &db,
|
||||
const ParticipantManagement::MissionPlan &missionPlan,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
|
||||
int32_t id() const;
|
||||
int32_t participantId() const;
|
||||
static Database::PpmMissionPlan toDbMissionPlan(const ParticipantManagement::ModifyMissionPlanRequest &mp);
|
||||
static MissionPlan fillMissionPlanData(const ModifyMissionPlanRequest &in);
|
||||
MissionPlan getMissionPlanData() const;
|
||||
void setDbMissionItems( const QMap <int, ParticipantManagement::Database::PpmMissionItem> &dbItems,
|
||||
const QMap <int, ParticipantManagement::Database::PpmMissionAction> &dbActions);
|
||||
const ParticipantManagement::MissionPlan &missionPlan() const;
|
||||
Core::FunctionReplyObject createMissionPlan(Database::PpmMissionPlan newMissionPlan, const std::vector<MissionItem> &missionItems);
|
||||
Core::FunctionReplyObject updateMissionPlan(Database::PpmMissionPlan newMissionPlan, const std::vector<MissionItem> &missionItems);
|
||||
Core::FunctionReplyObject removeMissionPlan(int id);
|
||||
|
||||
Core::FunctionReplyObject setMissionActionFulfilled(SetMissionActionFulfilledRequest req, qint64 currentTimeMSec);
|
||||
Core::FunctionReplyObject setMissionPlanAborted(bool state);
|
||||
private:
|
||||
std::shared_ptr<ParticipantManagement::DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<ParticipantManagement::DatabaseInterface> m_db;
|
||||
ParticipantManagement::MissionPlan m_missionplan;
|
||||
QHash<int /*dbItemId*/, ParticipantManagement::MissionItem > m_mapMissionItems; /// key:dbItemId | Value MissionItem
|
||||
|
||||
std::vector<std::vector<ParticipantManagement::Database::PpmMissionAction> > m_dbMissionActions; /// [ItemNumber][ActionNumber]
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
} // namespace UasHandling
|
||||
} // namespace ParticipantManagement
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* The Uas class represents a Uas. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2025-04-08
|
||||
*/
|
||||
|
||||
#include "uas.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
|
||||
bool Uas::hasChanges(const CreateModifyUasRequest &request)
|
||||
{
|
||||
bool hasChanges = request.deviceIdentifier() != m_data.deviceIdentifier.toStdString() ||
|
||||
request.participantId() != m_data.participantId ||
|
||||
request.exerciseId() != m_data.exerciseId ||
|
||||
request.hostname() != m_data.hostname.toStdString() ||
|
||||
request.hostport() != m_data.hostport ||
|
||||
request.useTcp() != m_data.useTcp;
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
m_data.deviceIdentifier = QString::fromStdString(request.deviceIdentifier());
|
||||
m_data.participantId = request.participantId();
|
||||
m_data.exerciseId = request.exerciseId();
|
||||
m_data.hostname = QString::fromStdString(request.hostname());
|
||||
m_data.hostport = request.hostport();
|
||||
m_data.useTcp = request.useTcp();
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
bool Uas::compareHostname( const QString &hostname)
|
||||
{
|
||||
return (m_data.hostname.compare(hostname, Qt::CaseInsensitive) == 0);
|
||||
}
|
||||
|
||||
bool Uas::compareHostPort(int hostport)
|
||||
{
|
||||
return (m_data.hostport == hostport);
|
||||
}
|
||||
|
||||
void Uas::unlinkUas()
|
||||
{
|
||||
m_data.participantId = 0;
|
||||
m_data.exerciseId = 0;
|
||||
}
|
||||
|
||||
void Uas::setState(const ProjectDataManagement::UasState &newState)
|
||||
{
|
||||
m_data.uasStateId = newState.underlying();
|
||||
}
|
||||
int32_t Uas::id() const
|
||||
{
|
||||
return m_data.id;
|
||||
}
|
||||
|
||||
int32_t Uas::participantId() const
|
||||
{
|
||||
return m_data.participantId;
|
||||
}
|
||||
|
||||
Database::PpmUas Uas::toDbUas() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
UAS Uas::toDdsUas() const
|
||||
{
|
||||
ParticipantManagement::UAS result;
|
||||
|
||||
result.id(m_data.id);
|
||||
result.deviceIdentifier(m_data.deviceIdentifier.toStdString());
|
||||
result.uasState(static_cast<ProjectDataManagement::UasState::inner_enum>(m_data.uasStateId));
|
||||
result.participantId(m_data.participantId);
|
||||
result.exerciseId(m_data.exerciseId);
|
||||
result.hostname(m_data.hostname.toStdString());
|
||||
result.hostport(m_data.hostport);
|
||||
result.sampleTime(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch());
|
||||
result.useTcp(m_data.useTcp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
} // namespace UasHandling
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* The Uas class represents a Uas. It holds the data and offers some conversion methods.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2025-04-08
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
class Uas
|
||||
{
|
||||
public:
|
||||
|
||||
explicit Uas(const Database::PpmUas &data)
|
||||
: m_data(data)
|
||||
{}
|
||||
|
||||
int32_t id() const;
|
||||
int32_t participantId() const;
|
||||
|
||||
Database::PpmUas toDbUas() const;
|
||||
UAS toDdsUas() const;
|
||||
|
||||
bool hasChanges(const CreateModifyUasRequest &request);
|
||||
void unlinkUas();
|
||||
void setState(const ProjectDataManagement::UasState &newState);
|
||||
bool compareHostname( const QString &hostname);
|
||||
bool compareHostPort(int hostport);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
Database::PpmUas m_data;
|
||||
};
|
||||
} // namespace UasHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* The UasHandler class manages all Uas related function topics and holds classes for
|
||||
* further Uas data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2025-04-08
|
||||
*/
|
||||
|
||||
#include "uas_handler.h"
|
||||
#include "uas.h"
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include "main_handler.h"
|
||||
#include "ParticipantHandling/participant.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
//------------------------------------------------------------------------------------------
|
||||
UasHandler::UasHandler(MainHandler *mainHandler)
|
||||
: QObject()
|
||||
, CreateModifyUasRequestHandler(mainHandler->exAnyFts())
|
||||
, RemoveUasRequestHandler(mainHandler->exAnyFts())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("UasHandler"))
|
||||
{
|
||||
m_mainHandler->exAnyFts()->enableCreateModifyUas();
|
||||
m_mainHandler->exAnyFts()->enableRemoveUas();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
UasHandler::~UasHandler()
|
||||
{
|
||||
qDeleteAll(m_uass);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
bool UasHandler::init()
|
||||
{
|
||||
qDeleteAll(m_uass);
|
||||
m_uass.clear();
|
||||
m_mainHandler->exAnyDts()->enableUAS();
|
||||
|
||||
QVector<Database::PpmUas> uasVec;
|
||||
|
||||
// read parties from db
|
||||
if (!m_mainHandler->db()->select(uasVec))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading Uas data from database";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const Database::PpmUas ¤tUas : qAsConst(uasVec))
|
||||
{
|
||||
UasHandling::Uas *newUas = new UasHandling::Uas(currentUas);
|
||||
|
||||
m_uass.insert(currentUas.id, newUas);
|
||||
|
||||
m_mainHandler->exAnyDts()->publish(newUas->toDdsUas());
|
||||
}
|
||||
|
||||
//now the exercise part
|
||||
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_mainHandler->dds());
|
||||
|
||||
connect(m_exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged,
|
||||
this, &UasHandler::onExerciseChanged);
|
||||
if (!m_exmDtc->enableExercise())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not enable Topic 'Exercise' of EXM DTC";
|
||||
return false;
|
||||
}
|
||||
|
||||
//now connect to ppm
|
||||
connect(m_mainHandler->ddsHandler()->dtc().get(), &Interface::Dtc::uASRadioLinkConnectionStatusChanged, this , &UasHandler::onUASRadioLinkConnectionStatusChanged);
|
||||
m_mainHandler->ddsHandler()->dtc()->enableUASRadioLinkConnectionStatus();
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
void UasHandler::onCreateModifyUasRequest(const rti::core::SampleIdentity &cookie, const CreateModifyUasRequest &request)
|
||||
{
|
||||
Core::FunctionReplyObject reply = request.id() == 0 ? createUas(request) : modifyUas(request);
|
||||
|
||||
m_mainHandler->exAnyFts()->createModifyUasReply(cookie, reply);
|
||||
}
|
||||
|
||||
void UasHandler::onRemoveUasRequest(const rti::core::SampleIdentity &cookie, const RemoveUasRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onRemoveUasRequest: " << request;
|
||||
auto ret = removeUas(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger) << ret();
|
||||
m_mainHandler->exAnyFts()->removeUasReply(cookie, ret);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject UasHandler::removeUas(const RemoveUasRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onRemoveUasRequest " << request;
|
||||
|
||||
if (request.id() < 0)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Got request to delete an UAS, but no valid UAS id to delete"));
|
||||
|
||||
UasHandling::Uas *uasToDelete = m_uass.value(request.id());
|
||||
if (!uasToDelete)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Could not delete UAS with id %1, because no UAS with that id exists"))
|
||||
.arg(request.id());
|
||||
|
||||
if (uasToDelete->participantId() > 0)
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Not possible to delete a UAS in use"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Removing UAS with ID " << request.id();
|
||||
|
||||
return removeUas(uasToDelete);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject UasHandler::removeUas(UasHandling::Uas *uasToDelete)
|
||||
{
|
||||
const int uasId = uasToDelete->id();
|
||||
// delete from db
|
||||
if (!m_mainHandler->db()->removePpmUas(uasId))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Error removing UAS with id %1 from database")).arg(uasId);
|
||||
// delete from dds
|
||||
m_mainHandler->exAnyDts()->removeUASByKey(uasId);
|
||||
|
||||
// delete from map
|
||||
m_uass.remove(uasId);
|
||||
delete uasToDelete;
|
||||
|
||||
return Core::FunctionReplyObject(uasId);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject UasHandler::createUas(const CreateModifyUasRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION;
|
||||
|
||||
// cant check here as we dont have access to all party participants
|
||||
/*
|
||||
if (request.participantId() > 0 && !isUasParticipant(request.participantId()))
|
||||
{
|
||||
QString error = QStringLiteral("Participant with id %1 is no Uas participant.").arg(request.participantId());
|
||||
|
||||
ERROR_LOG(m_logger) << error;
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}*/
|
||||
|
||||
Database::PpmUas dbUas;
|
||||
|
||||
dbUas.deviceIdentifier = QString::fromStdString(request.deviceIdentifier());
|
||||
dbUas.uasStateId = ProjectDataManagement::UasState::Undefined;
|
||||
dbUas.participantId = request.participantId();
|
||||
dbUas.exerciseId = request.exerciseId();
|
||||
dbUas.hostname = QString::fromStdString(request.hostname());
|
||||
dbUas.hostport = request.hostport();
|
||||
dbUas.useTcp = request.useTcp();
|
||||
|
||||
if (hostNameHostPortExists(dbUas.hostname, dbUas.hostport, -1))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Hostname with Port %1:%2 already exists"))
|
||||
.arg(dbUas.hostname).arg(dbUas.hostport);
|
||||
|
||||
if (!m_mainHandler->db()->insert(dbUas))
|
||||
{
|
||||
QString error = QStringLiteral("Could not insert Uas into database");
|
||||
|
||||
ERROR_LOG(m_logger) << error;
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
UasHandling::Uas *newUas = new UasHandling::Uas(dbUas);
|
||||
m_uass.insert(newUas->id(), newUas);
|
||||
|
||||
m_mainHandler->exAnyDts()->publish(newUas->toDdsUas());
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
Core::FunctionReplyObject UasHandler::modifyUas(const CreateModifyUasRequest &request)
|
||||
{
|
||||
if (!m_uass.contains(request.id()))
|
||||
{
|
||||
QString error = QStringLiteral("Uas topic with id %1 not present. Not possible to modify it.").arg(request.id());
|
||||
|
||||
ERROR_LOG(m_logger) << error;
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
Uas *uas = m_uass.value(request.id());
|
||||
|
||||
// Check if Hostname and Hostport already existing
|
||||
if (hostNameHostPortExists(QString::fromStdString(request.hostname()), request.hostport(), uas->id()))
|
||||
return Core::FunctionReplyObject(tr_lts("dds", "Hostname with Port %1:%2 already exists"))
|
||||
.arg(request.hostname()).arg(request.hostport());
|
||||
|
||||
if (!uas->hasChanges(request))
|
||||
{
|
||||
QString error = QStringLiteral("There are no changes in modify request.");
|
||||
|
||||
ERROR_LOG(m_logger) << error;
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
|
||||
//can't check here))
|
||||
/*
|
||||
if (request.participantId() > 0 && !isUasParticipant(request.participantId()))
|
||||
{
|
||||
QString error = QStringLiteral("Participant with id %1 is no Uas participant.").arg(request.participantId());
|
||||
|
||||
ERROR_LOG(m_logger) << error;
|
||||
|
||||
return Core::FunctionReplyObject(error.toStdString().c_str());
|
||||
}
|
||||
*/
|
||||
m_mainHandler->exAnyDts()->publish(uas->toDdsUas());
|
||||
m_mainHandler->db()->update(uas->toDbUas());
|
||||
|
||||
return Core::FunctionReplyObject();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
bool UasHandler::isUasParticipant(int participantId) const
|
||||
{
|
||||
const ParticipantManagement::ParticipantHandling::Participant *PARTICIPANT = m_mainHandler->participantHandler()->participantById(participantId);
|
||||
|
||||
if (PARTICIPANT == nullptr)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Got invalid participantId " << participantId;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const int TYPE_ID = PARTICIPANT->typeId();
|
||||
|
||||
return m_mainHandler->ddsHandler()->dtc()->isTypeUas(TYPE_ID);
|
||||
}
|
||||
|
||||
void UasHandler::onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification mod)
|
||||
{
|
||||
Q_UNUSED(mod)
|
||||
|
||||
if (data.state() != ExerciseManagement::ExerciseState::Stopped &&
|
||||
data.state() != ExerciseManagement::ExerciseState::Terminated &&
|
||||
data.state() != ExerciseManagement::ExerciseState::Unknown )
|
||||
return;
|
||||
|
||||
//Unlink
|
||||
for (auto uas : m_uass)
|
||||
{
|
||||
auto uasData = uas->toDdsUas();
|
||||
if (uasData.exerciseId() != data.id())
|
||||
continue;
|
||||
|
||||
uas->unlinkUas();
|
||||
m_mainHandler->exAnyDts()->publish(uas->toDdsUas());
|
||||
m_mainHandler->db()->update(uas->toDbUas());
|
||||
}
|
||||
}
|
||||
|
||||
void UasHandler::onUASRadioLinkConnectionStatusChanged(const UASRadioLinkConnectionStatus &data, DataModification mod)
|
||||
{
|
||||
if (data.id() <= 0)
|
||||
return;
|
||||
if (!m_uass.contains(data.id()))
|
||||
return;
|
||||
|
||||
auto uas = m_uass.value(data.id());
|
||||
if (mod == DataModification::eRemoved)
|
||||
uas->setState(ProjectDataManagement::UasState::Undefined);
|
||||
else
|
||||
uas->setState(data.uasState());
|
||||
m_mainHandler->exAnyDts()->publish(uas->toDdsUas());
|
||||
m_mainHandler->db()->update(uas->toDbUas());
|
||||
}
|
||||
|
||||
bool UasHandler::hostNameHostPortExists(const QString &hostname, int hostport, int uasId)
|
||||
{
|
||||
for (Uas *uas : qAsConst(m_uass))
|
||||
{
|
||||
if (uas->id() == uasId)
|
||||
continue;
|
||||
if (uas->compareHostname(hostname) && uas->compareHostPort(hostport))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace UasHandling
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* The UasHandler class manages all Uas related function topics and holds classes for
|
||||
* further Uas data.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2025-04-08
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace UasHandling
|
||||
{
|
||||
class Uas;
|
||||
class UasHandler final:
|
||||
public QObject
|
||||
, protected Interface::Fts::CreateModifyUasRequestHandler
|
||||
, protected Interface::Fts::RemoveUasRequestHandler
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UasHandler(MainHandler *mainHandler);
|
||||
~UasHandler();
|
||||
bool init();
|
||||
|
||||
void onCreateModifyUasRequest(const rti::core::SampleIdentity &cookie, const CreateModifyUasRequest &request) override final;
|
||||
void onRemoveUasRequest(const rti::core::SampleIdentity &cookie, const RemoveUasRequest &request) override final;
|
||||
|
||||
private slots:
|
||||
void onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification mod);
|
||||
void onUASRadioLinkConnectionStatusChanged(const UASRadioLinkConnectionStatus &data, DataModification mod);
|
||||
private:
|
||||
Core::FunctionReplyObject removeUas(const RemoveUasRequest &request);
|
||||
Core::FunctionReplyObject removeUas(UasHandling::Uas *uasToDelete);
|
||||
Core::FunctionReplyObject createUas(const CreateModifyUasRequest &request);
|
||||
Core::FunctionReplyObject modifyUas(const CreateModifyUasRequest &request);
|
||||
|
||||
bool isUasParticipant(int participantId) const;
|
||||
bool hostNameHostPortExists(const QString &host, int hostport, int uasId);
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
QHash<int32_t, Uas *> m_uass;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
} // namespace UasHandling
|
||||
} // namespace ParticipantManagement
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The ClientMessage class is an abstract base class for concrete ClientMessage objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#include "client_message.h"
|
||||
|
||||
#include "WebSocketInterface/Messages/reply_message.h"
|
||||
#include "WebSocketInterface/json_keys.h"
|
||||
#include "WebSocketInterface/data_manager.h"
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
namespace Messages
|
||||
{
|
||||
using namespace JsonKeys;
|
||||
|
||||
// ####### ClientMessageFactory begin #######
|
||||
ClientMessageFactory::ClientMessageFactory(DataManager *dataManager)
|
||||
: LtsWebSocket::AbstractClientMessageFactory(getLogger("ClientMessageFactory"))
|
||||
, m_dataManager(dataManager)
|
||||
{}
|
||||
|
||||
LtsWebSocket::AbstractClientMessage *ClientMessageFactory::createMessage(LtsWebSocket::ReplyHandler *client,
|
||||
const QString &message)
|
||||
{
|
||||
LtsWebSocket::AbstractClientMessage *result = checkAttributes(client, message);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (m_type == OcBaseDownload::WebSocketInterface::JsonKeys::BASE_DL_REQUEST())
|
||||
result = new BaseDlRequest(m_dataManager, client, m_type, m_typeId, m_uuid); // Todo: Check whether typeId is correct
|
||||
|
||||
if (m_type == ParticipantManagement::WebSocketInterface::JsonKeys::OC_POSITION_DATA()) // Todo: Check whether typeId is correct
|
||||
result = new OcPositionRequest(m_dataManager, client, m_type, m_typeId, m_uuid, QJsonDocument::fromJson(message.toUtf8()).object().value(QStringLiteral("data")).toObject() );
|
||||
|
||||
/********************************************************
|
||||
* Warning: 6006 has been negotiated with ESG for ADLER *
|
||||
********************************************************/
|
||||
if (m_type == ParticipantManagement::WebSocketInterface::JsonKeys::PARTY_BASE_DATA())
|
||||
result = new PartyRequest(m_dataManager, client, m_type, 6006, m_uuid); // Todo: Check whether typeId is correct
|
||||
|
||||
return checkResult(client, message, result);
|
||||
}
|
||||
// ####### ClientMessageFactory end #######
|
||||
|
||||
// ####### ClientMessage begin #######
|
||||
ClientMessage::ClientMessage(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid, const QJsonObject &data)
|
||||
: LtsWebSocket::AbstractClientMessage(client, type, typeId, uuid, data)
|
||||
, m_dataManager(dataManager)
|
||||
{}
|
||||
// ####### ClientMessage end #######
|
||||
|
||||
// ####### PartyRequest begin #######
|
||||
PartyRequest::PartyRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid)
|
||||
: ClientMessage(dataManager, client, type, typeId, uuid)
|
||||
{}
|
||||
|
||||
void PartyRequest::process()
|
||||
{
|
||||
m_client->addReply(m_dataManager->partyBaseData(m_uuid));
|
||||
}
|
||||
|
||||
bool PartyRequest::hasValidData() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ####### BaseDlRequest begin #######
|
||||
BaseDlRequest::BaseDlRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid)
|
||||
: ClientMessage(dataManager, client, type, typeId, uuid)
|
||||
{}
|
||||
|
||||
void BaseDlRequest::process()
|
||||
{
|
||||
if (m_dataManager->exerciseId() == 0) // equipment type, type and participant template only in ex_0
|
||||
{
|
||||
m_client->addReply(m_dataManager->equipmentTypeBaseData(m_uuid));
|
||||
m_client->addReply(m_dataManager->typeBaseData(m_uuid));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_client->addReply(m_dataManager->partyBaseData(m_uuid));
|
||||
m_client->addReply(m_dataManager->participantBaseData(m_uuid));
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseDlRequest::hasValidData() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
OcPositionRequest::OcPositionRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid, const QJsonObject &data)
|
||||
: ClientMessage(dataManager, client, type, typeId, uuid, data )
|
||||
{
|
||||
const auto val = data.value(EQUIPMENT_NR());
|
||||
if (val.toInt() > 0)
|
||||
m_equipmentNr = val.toInt();
|
||||
|
||||
}
|
||||
|
||||
void OcPositionRequest::process()
|
||||
{
|
||||
if (m_dataManager->exerciseId() != 0) // equipment type, type and participant template only in ex_0
|
||||
{
|
||||
m_client->addReply(m_dataManager->ocPositionData(m_equipmentNr, m_uuid));
|
||||
}
|
||||
}
|
||||
|
||||
bool OcPositionRequest::hasValidData() const
|
||||
{
|
||||
return m_equipmentNr > 0;
|
||||
}
|
||||
|
||||
// ####### BaseDlRequest end #######
|
||||
|
||||
} // namespace Messages
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The ClientMessage class is an abstract base class for concrete ClientMessage objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <LtsWebSocket/client_message_factory.h>
|
||||
#include <LtsWebSocket/client_message.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
class DataManager;
|
||||
|
||||
namespace Messages
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The ClientMessageFactory class creates ClientMessages which will then be processed
|
||||
*/
|
||||
class ClientMessageFactory final : public LtsWebSocket::AbstractClientMessageFactory
|
||||
{
|
||||
public:
|
||||
explicit ClientMessageFactory(DataManager *dataManager);
|
||||
|
||||
/**
|
||||
* @brief create Only way to create a ClientMessage object
|
||||
* @param message Text message which will be converted to a ClientMessage object
|
||||
* @return A ClientMessage object, which represents a concrete ClientMessage
|
||||
*/
|
||||
LtsWebSocket::AbstractClientMessage *createMessage(LtsWebSocket::ReplyHandler *client,
|
||||
const QString &message);
|
||||
|
||||
private:
|
||||
DataManager *m_dataManager;
|
||||
|
||||
}; // class ClientMessageFactory
|
||||
|
||||
/**
|
||||
* @brief The ClientMessage class is an abstract base class for concrete ClientMessage objects
|
||||
*/
|
||||
class ClientMessage : public LtsWebSocket::AbstractClientMessage
|
||||
{
|
||||
protected: // method
|
||||
explicit ClientMessage(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid, const QJsonObject &data = QJsonObject());
|
||||
|
||||
protected: // attributes
|
||||
DataManager *m_dataManager;
|
||||
}; // class ClientMessage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The PartyRequest class handles the party DL request and sends multiple all party data for the exercise
|
||||
*/
|
||||
class PartyRequest : public ClientMessage
|
||||
{
|
||||
public:
|
||||
explicit PartyRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid);
|
||||
|
||||
void process();
|
||||
bool hasValidData() const;
|
||||
}; // class BaseDlRequest
|
||||
|
||||
/**
|
||||
* @brief The BaseDlRequest class handles the base DL request and sends multiple replys depending on the data requested
|
||||
*/
|
||||
class BaseDlRequest : public ClientMessage
|
||||
{
|
||||
public:
|
||||
explicit BaseDlRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid);
|
||||
|
||||
void process();
|
||||
bool hasValidData() const;
|
||||
}; // class BaseDlRequest
|
||||
/**
|
||||
* @brief The BaseDlRequest class handles the base DL request and sends multiple replys depending on the data requested
|
||||
*/
|
||||
class OcPositionRequest : public ClientMessage
|
||||
{
|
||||
public:
|
||||
explicit OcPositionRequest(DataManager *dataManager, LtsWebSocket::ReplyHandler *client, const QString &type, const int typeId, const QString &uuid, const QJsonObject &data);
|
||||
|
||||
void process();
|
||||
bool hasValidData() const;
|
||||
private:
|
||||
int m_equipmentNr = 0;
|
||||
|
||||
}; // class BaseDlRequest
|
||||
|
||||
} // namespace Messages
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The ReplyMessage class is an abstract base class for all possible messages which are sent to the client
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#include "reply_message.h"
|
||||
|
||||
#include <LtsWebSocket/json_keys.h>
|
||||
#include "WebSocketInterface/json_keys.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
namespace Messages
|
||||
{
|
||||
using namespace JsonKeys;
|
||||
using namespace LtsWebSocket::JsonKeys;
|
||||
|
||||
// ####### EquipmentTypeBaseData begin #######
|
||||
EquipmentTypeBaseData::EquipmentTypeBaseData(const QJsonArray &data, const QString &uuid)
|
||||
: LtsWebSocket::ReplyMessage (EQUIPMENT_TYPE_BASE_DATA(), 1, uuid) // Todo: Check whether typeId is correct
|
||||
{
|
||||
m_jsonRepresentation.insert(DATA(), data);
|
||||
}
|
||||
// ####### EquipmentTypeBaseData end #######
|
||||
|
||||
// ####### TypeBaseData begin #######
|
||||
TypeBaseData::TypeBaseData(const QJsonArray &data, const QString &uuid)
|
||||
: LtsWebSocket::ReplyMessage (TYPE_BASE_DATA(), 2, uuid) // Todo: Check whether typeId is correct
|
||||
{
|
||||
m_jsonRepresentation.insert(DATA(), data);
|
||||
}
|
||||
// ####### TypeBaseData end #######
|
||||
|
||||
// ####### PartyBaseData begin #######
|
||||
/********************************************************
|
||||
* Warning: 6006 has been negotiated with ESG for ADLER *
|
||||
********************************************************/
|
||||
PartyBaseData::PartyBaseData(const QJsonArray &data, const QString &uuid)
|
||||
: LtsWebSocket::ReplyMessage (PARTY_BASE_DATA(), 6006, uuid) // Todo: Check whether typeId is correct
|
||||
{
|
||||
m_jsonRepresentation.insert(DATA(), data);
|
||||
}
|
||||
// ####### PartyBaseData end #######
|
||||
|
||||
// ####### ParticipantBaseData begin #######
|
||||
ParticipantBaseData::ParticipantBaseData(const QJsonArray &data, const QString &uuid)
|
||||
: LtsWebSocket::ReplyMessage (PARTICIPANT_BASE_DATA(), 4, uuid) // Todo: Check whether typeId is correct
|
||||
{
|
||||
m_jsonRepresentation.insert(DATA(), data);
|
||||
}
|
||||
|
||||
OcPositionData::OcPositionData(const QJsonObject &data, const QString &uuid)
|
||||
: LtsWebSocket::ReplyMessage (OC_POSITION_DATA(), 5, uuid) // Todo: Check whether typeId is correct
|
||||
{
|
||||
m_jsonRepresentation.insert(DATA(), data);
|
||||
}
|
||||
|
||||
// ####### ParticipantBaseData end #######
|
||||
|
||||
} // namespace Messages
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The ReplyMessage class is an abstract base class for all possible messages which are sent to the client
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <LtsWebSocket/reply_message.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QString>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
namespace Messages
|
||||
{
|
||||
/**
|
||||
* @brief The EquipmentTypeBaseData class equipment type data for base DL
|
||||
*/
|
||||
class EquipmentTypeBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit EquipmentTypeBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class EquipmentTypeBaseData
|
||||
|
||||
/**
|
||||
* @brief The TypeBaseData class type data for base DL
|
||||
*/
|
||||
class TypeBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit TypeBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class TypeBaseData
|
||||
|
||||
/**
|
||||
* @brief The ParticipantTemplateBaseData class participant template data for base DL
|
||||
*/
|
||||
class ParticipantTemplateBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit ParticipantTemplateBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class ParticipantTemplateBaseData
|
||||
|
||||
/**
|
||||
* @brief The PartyBaseData class party data for base DL
|
||||
*/
|
||||
class PartyBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit PartyBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class PartyBaseData
|
||||
|
||||
/**
|
||||
* @brief The ParticipantOrganisationBaseData class participant organisation data for base DL
|
||||
*/
|
||||
class ParticipantOrganisationBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit ParticipantOrganisationBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class ParticipantOrganisationBaseData
|
||||
|
||||
/**
|
||||
* @brief The ParticipantBaseData class participant data for base DL
|
||||
*/
|
||||
class ParticipantBaseData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit ParticipantBaseData(const QJsonArray &data, const QString &uuid);
|
||||
}; // class ParticipantBaseData
|
||||
|
||||
/**
|
||||
* @brief The ParticipantBaseData class participant data for base DL
|
||||
*/
|
||||
class OcPositionData : public LtsWebSocket::ReplyMessage
|
||||
{
|
||||
public:
|
||||
explicit OcPositionData(const QJsonObject &data, const QString &uuid);
|
||||
}; // class ParticipantBaseData
|
||||
|
||||
|
||||
} // namespace Messages
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The DataManager class takes strucure element data from the HandlerStructureElement,
|
||||
* offers an interface to get and set structure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#include "data_manager.h"
|
||||
#include "Messages/reply_message.h"
|
||||
#include "main_handler.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
DataManager::DataManager(int exerciseId, const std::shared_ptr<DatabaseInterface> &dbInterface, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc)
|
||||
: LtsWebSocket::DataManagerBaseDl<DatabaseInterface>(dbInterface, getLogger(QStringLiteral("DataManager")))
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_ppmDtc(dtc)
|
||||
{}
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
|
||||
LtsWebSocket::ReplyMessage *DataManager::equipmentTypeBaseData(const QString &uuid) const
|
||||
{
|
||||
return toBaseDataMessageFromDb<Database::PpmEquipmentType, Messages::EquipmentTypeBaseData>(uuid);
|
||||
}
|
||||
|
||||
LtsWebSocket::ReplyMessage *DataManager::typeBaseData(const QString &uuid) const
|
||||
{
|
||||
return toBaseDataMessageFromDb<Database::PpmType, Messages::TypeBaseData>(uuid);
|
||||
}
|
||||
|
||||
LtsWebSocket::ReplyMessage *DataManager::partyBaseData(const QString &uuid) const
|
||||
{
|
||||
return toBaseDataMessageFromDb<Database::PpmParty, Messages::PartyBaseData>(uuid);
|
||||
}
|
||||
|
||||
LtsWebSocket::ReplyMessage *DataManager::participantBaseData(const QString &uuid) const
|
||||
{
|
||||
return toBaseDataMessageFromDb<Database::PpmParticipant, Messages::ParticipantBaseData>(uuid);
|
||||
}
|
||||
|
||||
LtsWebSocket::ReplyMessage *DataManager::ocPositionData(int equipmentNr, const QString &uuid) const
|
||||
{
|
||||
if (!m_ppmDtc->isParticipantPositionEnabled() || !m_ppmDtc->isParticipantEnabled())
|
||||
{
|
||||
m_ppmDtc->enableParticipantPosition();
|
||||
m_ppmDtc->enableParticipant();
|
||||
}
|
||||
ParticipantPosition pos = m_ppmDtc->participantPosition(m_ppmDtc->participantIdByEquipmentNumber(equipmentNr));
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("participantId")] = pos.participantId();
|
||||
obj[QStringLiteral("lat")] = pos.pos().lat();
|
||||
obj[QStringLiteral("lon")] = pos.pos().lon();
|
||||
obj[QStringLiteral("height")] = pos.pos().z();
|
||||
obj[QStringLiteral("roomId")] = pos.roomId();
|
||||
obj[QStringLiteral("buildingId")] = pos.buildingId();
|
||||
|
||||
return new ParticipantManagement::WebSocketInterface::Messages::OcPositionData(obj, uuid);
|
||||
}
|
||||
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* The DataManager class is a convenience class for managing structure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <LtsWebSocket/data_manager_base_dl.h>
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The DataManager class is a convenience class for managing structure data
|
||||
*/
|
||||
class DataManager final : public LtsWebSocket::DataManagerBaseDl<DatabaseInterface>
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief DataManager Constructor
|
||||
* @param mainHandler Source for needed handlers
|
||||
*/
|
||||
explicit DataManager(int exerciseId,
|
||||
const std::shared_ptr<DatabaseInterface> &dbInterface,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc);
|
||||
|
||||
int exerciseId() const { return m_exerciseId; }
|
||||
|
||||
LtsWebSocket::ReplyMessage *equipmentTypeBaseData(const QString &uuid) const;
|
||||
LtsWebSocket::ReplyMessage *typeBaseData(const QString &uuid) const;
|
||||
LtsWebSocket::ReplyMessage *partyBaseData(const QString &uuid) const;
|
||||
LtsWebSocket::ReplyMessage *participantBaseData(const QString &uuid) const;
|
||||
LtsWebSocket::ReplyMessage *ocPositionData(int equipmentNr, const QString &uuid) const;
|
||||
|
||||
private:
|
||||
int m_exerciseId;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
}; // class DataManager
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Header file which holds all occuring JSON keys
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <OcBaseDownload/WebSocketInterface/json_keys.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
/**
|
||||
* @brief Namespace which holds all occuring JSON keys as const QString objects
|
||||
*/
|
||||
namespace JsonKeys
|
||||
{
|
||||
// types for client --> server messages
|
||||
inline QString EQUIPMENT_NR() { return QStringLiteral("equipmentNr"); }
|
||||
// types for server --> client messages
|
||||
inline QString EQUIPMENT_TYPE_BASE_DATA() { return QStringLiteral("equipmentTypeBaseData"); }
|
||||
inline QString TYPE_BASE_DATA() { return QStringLiteral("typeBaseData"); }
|
||||
inline QString PARTY_BASE_DATA() { return QStringLiteral("partyBaseData"); }
|
||||
inline QString PARTICIPANT_BASE_DATA() { return QStringLiteral("participantBaseData"); }
|
||||
inline QString OC_POSITION_DATA() { return QStringLiteral("ocPositionData"); }
|
||||
|
||||
} // namespace JsonKeys
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handler for the WebSocket Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#include "websocket_interface_handler.h"
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "data_manager.h"
|
||||
#include "WebSocketInterface/Messages/client_message.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
|
||||
WebSocketInterfaceHandler::WebSocketInterfaceHandler(MainHandler *mainHandler, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_webSocketServer(nullptr)
|
||||
, m_messageFactory(nullptr)
|
||||
, m_dataManager(nullptr)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("WebSocketInterfaceHandler"))
|
||||
{
|
||||
}
|
||||
|
||||
WebSocketInterfaceHandler::~WebSocketInterfaceHandler()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool WebSocketInterfaceHandler::init()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
|
||||
m_dataManager = new DataManager(m_mainHandler->exerciseId(), m_mainHandler->db(), m_mainHandler->ddsHandler()->dtc());
|
||||
|
||||
m_messageFactory = new Messages::ClientMessageFactory(m_dataManager);
|
||||
|
||||
m_webSocketServer = new LtsWebSocket::LtsWebSocketServer(m_messageFactory, this);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Initialising LtsWebSocketServer";
|
||||
if (!m_webSocketServer->init(QStringLiteral("PPM"), Settings::getWebSocketServerPortRange(1)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to initialise LtsWebSocketServer";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "... ok";
|
||||
|
||||
DEBUG_LOG(m_logger) << "Connection signals and slots";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketInterfaceHandler::cleanup()
|
||||
{
|
||||
delete m_webSocketServer;
|
||||
delete m_messageFactory;
|
||||
delete m_dataManager;
|
||||
}
|
||||
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handler for the WebSocket Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Dassow, SLST, 2017-12-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <LtsWebSocket/lts_web_socket_server.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class MainHandler;
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
namespace Messages
|
||||
{
|
||||
class ClientMessageFactory;
|
||||
}
|
||||
class DataManager;
|
||||
|
||||
/**
|
||||
* @brief The WebSocketInterfaceHandler class is the main class for the WebSocketInterface
|
||||
*/
|
||||
class WebSocketInterfaceHandler final : public QObject
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief WebSocketInterfaceHandler Constructor
|
||||
* @param mainHandler MainHandler to get the HandlerStructureElement from
|
||||
*/
|
||||
explicit WebSocketInterfaceHandler(MainHandler *mainHandler, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief ~WebSocketInterfaceHandler Destructor
|
||||
*/
|
||||
~WebSocketInterfaceHandler();
|
||||
|
||||
/**
|
||||
* @brief init Initialises all needed classes for the WebSocketInterface
|
||||
* @return True on success, otherwise false
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief webSocketPort returns the listen port
|
||||
* @return listen port
|
||||
*/
|
||||
unsigned short webSocketPort() { return m_webSocketServer->webSocketPort(); }
|
||||
|
||||
private:
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
LtsWebSocket::LtsWebSocketServer *m_webSocketServer;
|
||||
Messages::ClientMessageFactory *m_messageFactory;
|
||||
DataManager *m_dataManager;
|
||||
MainHandler *m_mainHandler;
|
||||
LOGGER_T m_logger;
|
||||
}; // class WebSocketInterfaceHandle
|
||||
|
||||
} // namespace WebSocketInterface
|
||||
} // namespace ParticipantManagement
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Convert db structures to dds structures
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-07-20
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <limits>
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Database
|
||||
{
|
||||
inline Type convert(const PpmType &data)
|
||||
{
|
||||
Type ddsData;
|
||||
|
||||
ddsData.id(data.id);
|
||||
ddsData.typeClass(data.typeClassId);
|
||||
ddsData.equipmentTypeId(data.equipmentTypeId.isNull() ? 0 : data.equipmentTypeId.toInt());
|
||||
ddsData.name(data.name.toStdString());
|
||||
ddsData.symbol(data.symbol.toStdString());
|
||||
ddsData.radioCount(data.radioCount);
|
||||
ddsData.hierarchyLevel(data.hierarchyLevel);
|
||||
ddsData.isDeleted(data.isDeleted);
|
||||
#ifdef Q_OS_WIN
|
||||
ddsData.disEntities(data.disEntities());
|
||||
#else
|
||||
ddsData.disEntities(LtsUtils::convert<std::vector<rti::core::int64>>(data.disEntities()));
|
||||
#endif
|
||||
ddsData.properties(data.properties.toStdString());
|
||||
|
||||
return ddsData;
|
||||
}
|
||||
inline EquipmentType convert(const PpmEquipmentType &db)
|
||||
{
|
||||
EquipmentType et;
|
||||
et.id(db.id);
|
||||
et.name(db.name.toStdString());
|
||||
{ // equipment value are save in the db as int, but in dds unsigned short is used.
|
||||
et.minEquipNo(db.minEquipNo < USHRT_MAX ? db.minEquipNo : USHRT_MAX);
|
||||
et.maxEquipNo(db.maxEquipNo < USHRT_MAX ? db.maxEquipNo : USHRT_MAX);
|
||||
}
|
||||
et.traVulnerabilityModelId(db.traVulnerabilityModelId);
|
||||
et.traPlayerTypeId(db.traPlayerTypeId);
|
||||
et.wmsTypeClass(db.wmsTypeClassId);
|
||||
et.deletedInWms(db.deletedInWms);
|
||||
return et;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* DdsHandler for PPM
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
|
||||
#include "dds_handler.h"
|
||||
|
||||
#include "exercise_time.h"
|
||||
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
#include <QThread>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
DdsHandler::DdsHandler(int domainId, int exerciseId)
|
||||
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(domainId, exerciseId <= 0 ? IDL::PartitionType::Global : IDL::PartitionType::Exercise, exerciseId))
|
||||
, m_logger(getLogger("DdsHandler"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "DdsHandler(" << domainId << ") for partition: " << m_ddsConnector->getDefaultPartition();
|
||||
}
|
||||
|
||||
DdsHandler::~DdsHandler()
|
||||
{
|
||||
m_exerciseTime = nullptr;
|
||||
m_pacemaker = nullptr;
|
||||
m_ddsAnyExDts = nullptr;
|
||||
m_ddsAnyExFts = nullptr;
|
||||
m_ddsFts = nullptr;
|
||||
m_ddsDts = nullptr;
|
||||
m_ddsDtc = nullptr;
|
||||
m_topicLockMaster = nullptr;
|
||||
m_ddsConnector = nullptr;
|
||||
}
|
||||
|
||||
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_ddsConnector->enableBatchedWriter(false);
|
||||
|
||||
// Pacemaker
|
||||
m_pacemaker = std::make_shared<Core::Pacemaker>(m_ddsConnector);
|
||||
m_topicLockMaster = std::make_shared<Core::TopicLockMaster>(m_ddsConnector);
|
||||
|
||||
// Core::PartitionTime -> ExerciseTime
|
||||
std::shared_ptr<DTS::PartitionTime> dtsPartitionTime;
|
||||
dtsPartitionTime.reset(m_ddsConnector->createDTS<DTS::PartitionTimeImpl>());
|
||||
m_exerciseTime = std::make_shared<ExerciseTime>(dtsPartitionTime);
|
||||
ERROR_LOG(m_logger) << "OKKKKK THIS THE NEW MAIN HANDLER DDS " << this->thread();
|
||||
m_ddsDts = ParticipantManagement::Interface::Dts::create(m_ddsConnector);
|
||||
m_ddsFts = ParticipantManagement::Interface::Fts::create(m_ddsConnector);
|
||||
m_ddsDtc = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
m_ddsDtc->enableEquipmentExerciseMapping(true);
|
||||
|
||||
const int exerciseId = m_ddsConnector->getPartitionId();
|
||||
|
||||
m_exAnyConnector = std::make_shared<DDSConnector::DdsConnector>(m_ddsConnector->getDomainParticipant(), IDL::PartitionType::Any);
|
||||
if (!m_exAnyConnector->init(qosFileList))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init Dds Connector with IDL::PartitionType::Any";
|
||||
return false;
|
||||
}
|
||||
m_exAnyConnector->initPublisherSubscriber();
|
||||
m_ddsAnyExDts = ParticipantManagement::Interface::Dts::create(m_exAnyConnector);
|
||||
m_ddsAnyExDts->enableEquipmentExerciseMapping(true);
|
||||
m_ddsAnyExDts->enableUASRadioLinkConnectionStatus(true);
|
||||
if (exerciseId <= 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating * FTS: " << m_exAnyConnector->getDefaultPartition();
|
||||
m_ddsAnyExFts = ParticipantManagement::Interface::Fts::create(m_exAnyConnector);
|
||||
// do not enable anything here - enable where it is used (inside type handling) to make sure
|
||||
// no other service get a subscription matched information without actually having data
|
||||
}
|
||||
|
||||
|
||||
const bool bExe = exerciseId > 0; // ex_N
|
||||
const bool bGlob = exerciseId <= 0; // ex_0
|
||||
if (!m_ddsDts->enableBite(true) ||
|
||||
!m_ddsDts->enableDynamicParticipantData(bExe) ||
|
||||
!m_ddsDts->enableEquipmentType(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsDts->enableParticipantGearEvent(bExe) ||
|
||||
!m_ddsDts->enableEquipmentExerciseMapping(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsDts->enableParticipant() ||
|
||||
!m_ddsDts->enableParticipantPosition(bExe) ||
|
||||
!m_ddsDts->enableParticipantOrganisation(bExe) ||
|
||||
!m_ddsDts->enableTargetInformation(bExe) ||
|
||||
!m_ddsDts->enableParty(bGlob || bExe) ||
|
||||
!m_ddsDts->enableTemplateParticipant(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsDts->enableType(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsDts->enableCtaError() ||
|
||||
!m_ddsDts->enableParticipantMode(bExe) ||
|
||||
!m_ddsDts->enableEquipmentSystemEvent(bExe) ||
|
||||
!m_ddsDts->enableHitLineInfo(bExe) ||
|
||||
!m_ddsDts->enableUnitPosition() ||
|
||||
!m_ddsDts->enableUAS(bGlob || bExe) ||
|
||||
!m_ddsDts->enableMissionPlan(bExe)
|
||||
)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing DTS";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_ddsFts->enableCallBite() ||
|
||||
!m_ddsFts->enableChangePartyUsedState(bExe) || // unused?
|
||||
!m_ddsFts->enableEquipmentSystemEventData() ||
|
||||
!m_ddsFts->enableGetParticipants() ||
|
||||
!m_ddsFts->enableInitParticipant() ||
|
||||
!m_ddsFts->enableModifyEquipmentTypeData(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsFts->enableModifyParticipantData() ||
|
||||
!m_ddsFts->enableModifyPartyData() ||
|
||||
!m_ddsFts->enableModifyTemplateData(bGlob) ||
|
||||
!m_ddsFts->enableModifyType(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsFts->enableModifyState() ||
|
||||
!m_ddsFts->enableRegisterParticipant() ||
|
||||
!m_ddsFts->enableModifyTargetInformation() ||
|
||||
!m_ddsFts->enableRemoveParty() ||
|
||||
!m_ddsFts->enableRemoveType(false) || // published in IDL::PartitionType::Any
|
||||
!m_ddsFts->enableSendMessage() ||
|
||||
!m_ddsFts->enableSetParticipantMode() ||
|
||||
!m_ddsFts->enableSyncParties(bExe) ||
|
||||
!m_ddsFts->enableSetSimulatedPosition(bExe) ||
|
||||
!m_ddsFts->enableSetSimulatedPositionRelative(bExe) ||
|
||||
!m_ddsFts->enableSetSimulatedParticipantFormation(bExe) ||
|
||||
!m_ddsFts->enableSetSanitation(bExe) ||
|
||||
!m_ddsFts->enableSelectiveReammunition(bExe) ||
|
||||
!m_ddsFts->enableSetAsSimulated(bExe) ||
|
||||
!m_ddsFts->enableOcCommand(bExe) ||
|
||||
!m_ddsFts->enableSetAsSimulated(bExe) ||
|
||||
!m_ddsFts->enableModifyMissionPlan(bExe)||
|
||||
!m_ddsFts->enableRemoveMissionPlan(bExe) ||
|
||||
!m_ddsFts->enableSetMissionActionFulfilled(bExe)||
|
||||
!m_ddsFts->enableModifyUasState(bExe)
|
||||
|
||||
)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing FTS";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pdmDtc->enableChargeType(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DdsHandler::longActionBreak()
|
||||
{
|
||||
// m_pacemaker->publishState(); //not threadSafe!
|
||||
// m_exerciseTime->publishPartitionTime();
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* DdsHandler for PPM
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <DDS/Core/topic_lock_master.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <ParticipantManagement/ppm_fts.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
#include "logger.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class Pacemaker;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class ExerciseTime;
|
||||
class DdsHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DdsHandler(int domainId, int exerciseId);
|
||||
~DdsHandler();
|
||||
|
||||
bool init(const QStringList &qosFileList = QStringList());
|
||||
|
||||
std::shared_ptr<Core::Pacemaker> pacemaker() const { return m_pacemaker; }
|
||||
std::shared_ptr<Core::TopicLockMaster> topicLockMaster() const { return m_topicLockMaster; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtc() const { return m_ddsDtc; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> dts() const { return m_ddsDts; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> fts() const { return m_ddsFts; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> exAnyDts() const { return m_ddsAnyExDts; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> exAnyFts() const { return m_ddsAnyExFts; }
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const { return m_pdmDtc; }
|
||||
std::shared_ptr<DDSConnector::DdsConnector> dds() const { return m_ddsConnector; }
|
||||
|
||||
// this should be called when a long action is in progress to
|
||||
// not run into a timeout. TODO: it would be much better to
|
||||
// move PaceMaker and ExerciseTime into an own thread instead this hack
|
||||
void longActionBreak();
|
||||
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_exAnyConnector;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> m_ddsDts;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ddsDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> m_ddsFts;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> m_ddsAnyExDts;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> m_ddsAnyExFts;
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
std::shared_ptr<Core::Pacemaker> m_pacemaker;
|
||||
std::shared_ptr<Core::TopicLockMaster> m_topicLockMaster;
|
||||
std::shared_ptr<ExerciseTime> m_exerciseTime;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Current Time for exercise
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-08-01
|
||||
*/
|
||||
|
||||
#include "exercise_time.h"
|
||||
#include "ppm_dts.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
ExerciseTime::ExerciseTime(const std::shared_ptr<DTS::PartitionTime> &partitionTime)
|
||||
: QObject(nullptr)
|
||||
, m_dtsPartitionTime(partitionTime)
|
||||
, m_exerciseTimer(new QTimer())
|
||||
, m_thread(new QThread())
|
||||
{
|
||||
m_exerciseTimer->moveToThread(m_thread);
|
||||
this->moveToThread(m_thread);
|
||||
m_exerciseTimer->setInterval(1000);
|
||||
connect(m_thread, &QThread::started, this, [this]()
|
||||
{
|
||||
m_exerciseTimer->start(1000);
|
||||
});
|
||||
connect(m_exerciseTimer, &QTimer::timeout, this, &ExerciseTime::publishPartitionTime);
|
||||
connect(m_exerciseTimer, &QTimer::destroyed, m_thread, &QThread::deleteLater);
|
||||
m_thread->start();
|
||||
//m_exerciseTimer->start(1000);
|
||||
}
|
||||
|
||||
ExerciseTime::~ExerciseTime()
|
||||
{
|
||||
// m_exerciseTimer->moveToThread(this->thread());
|
||||
m_exerciseTimer->deleteLater();
|
||||
//m_thread->quit();
|
||||
|
||||
// m_exerciseTimer->stop();
|
||||
}
|
||||
|
||||
void ExerciseTime::publishPartitionTime()
|
||||
{
|
||||
const qint64 exerciseTime = QDateTime::currentMSecsSinceEpoch();
|
||||
Core::PartitionTime currentTime(exerciseTime);
|
||||
m_dtsPartitionTime->write(currentTime);
|
||||
//m_exerciseTimer->start();
|
||||
//qWarning() << "This is thread " << this->thread() << " send time";
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Current Time for exercise
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-08-01
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#include <DDS/Core/core_dts_types.h>
|
||||
|
||||
#include "dds_handler.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class ExerciseTime final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ExerciseTime(const std::shared_ptr<DTS::PartitionTime> &partitionTime);
|
||||
~ExerciseTime();
|
||||
public Q_SLOTS:
|
||||
void publishPartitionTime();
|
||||
|
||||
private:
|
||||
std::shared_ptr<DTS::PartitionTime> m_dtsPartitionTime;
|
||||
QTimer *m_exerciseTimer;
|
||||
QThread *m_thread;
|
||||
};
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# Service: ParticipantManagement
|
||||
###########################################################
|
||||
#log4j.logger.PPM=DEBUG
|
||||
#log4j.logger.PPM.BiteHandler=DEBUG
|
||||
#log4j.logger.PPM.ClientMessageFactory=DEBUG
|
||||
#log4j.logger.PPM.DataManager=DEBUG
|
||||
#log4j.logger.PPM.DdsHandler=DEBUG
|
||||
#log4j.logger.PPM.EquipmentEventHandler=DEBUG
|
||||
#log4j.logger.PPM.GetParticipants=DEBUG
|
||||
#log4j.logger.PPM.MainHandler=DEBUG
|
||||
#log4j.logger.PPM.Participant=DEBUG
|
||||
#log4j.logger.PPM.ParticipantForReplay=DEBUG
|
||||
#log4j.logger.PPM.ParticipantHandler=DEBUG
|
||||
#log4j.logger.PPM.ParticipantHandlerForReplay=DEBUG
|
||||
#log4j.logger.PPM.PartyHandler=DEBUG
|
||||
#log4j.logger.PPM.ProxyListener=DEBUG
|
||||
#log4j.logger.PPM.TemplateHandler=DEBUG
|
||||
#log4j.logger.PPM.Test=DEBUG
|
||||
#log4j.logger.PPM.TypeHandler=DEBUG
|
||||
#log4j.logger.PPM.TypeHandlerExercise=DEBUG
|
||||
#log4j.logger.PPM.TypeHandlerGlobal=DEBUG
|
||||
#log4j.logger.PPM.UnitPositionCalculator=DEBUG
|
||||
#log4j.logger.PPM.WebSocketInterfaceHandler=DEBUG
|
||||
#log4j.logger.PPM.MissionPlanHandler=DEBUG
|
||||
#log4j.logger.PPM.ObjectMissionPlan=DEBUG
|
||||
|
||||
# File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "PPM.";
|
||||
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 ParticipantManagement
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for ParticipantManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "ppm_export.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
using LOGGER_T = NGL::INGLLogger &;
|
||||
|
||||
PPM_COMMON_EXPORT LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace ParticipantManagement
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for ParticipantManagement
|
||||
* $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("PPM", options.exerciseId());
|
||||
|
||||
ParticipantManagement::Settings::setIniFile(options.iniFile());
|
||||
|
||||
int iRet = -3;
|
||||
{
|
||||
std::unique_ptr<ParticipantManagement::MainHandler> mainHandler(new ParticipantManagement::MainHandler);
|
||||
|
||||
if (!mainHandler->init(options.domainId(), options.exerciseId()))
|
||||
return iRet;
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
iRet = app.exec();
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* MainHandler for ParticipantManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 19.05.2016
|
||||
*/
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "TypeHandling/type_handler.h"
|
||||
#include "UasHandling/mission_plan_handler.h"
|
||||
#include "UasHandling/uas_handler.h"
|
||||
#include "WebSocketInterface/websocket_interface_handler.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
#include <ngldb/db_service_handler.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
MainHandler::MainHandler() : m_logger(getLogger("MainHandler")) {}
|
||||
|
||||
MainHandler::~MainHandler()
|
||||
{
|
||||
m_getParticipants = nullptr;
|
||||
m_partyHandler = nullptr;
|
||||
m_templateHandler = nullptr;
|
||||
m_biteHandler = nullptr;
|
||||
m_participantHandler = nullptr;
|
||||
m_tabFtc = nullptr;
|
||||
m_tabDtc = nullptr;
|
||||
m_aesFtc = nullptr;
|
||||
m_equipmentEventHandler = nullptr;
|
||||
m_typeHandler = nullptr;
|
||||
m_websocketHandler = nullptr;
|
||||
m_uasHandler = nullptr;
|
||||
m_dbHandlerEx0 = nullptr;
|
||||
m_dbHandler = nullptr;
|
||||
m_ddsHandler = nullptr;
|
||||
}
|
||||
|
||||
bool MainHandler::init(int domainId, int exerciseId)
|
||||
{
|
||||
m_ddsHandler = std::make_shared<DdsHandler>(domainId, exerciseId);
|
||||
if (!m_ddsHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init DdsHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init DdsHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "DdsHandler initialized";
|
||||
|
||||
m_dbHandler = std::make_shared<DbHandler>();
|
||||
if (!m_dbHandler->init(exerciseId, Settings::settings()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init DbHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init DbHandler"));
|
||||
return false;
|
||||
}
|
||||
if (exerciseId > 0)
|
||||
{
|
||||
m_dbHandlerEx0 = std::make_shared<DbHandler>();
|
||||
if (!m_dbHandlerEx0->init(0, Settings::settings())) // need a second db connection due to username/password
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init DbHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init DbHandler"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dbHandlerEx0 = m_dbHandler;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "DbHandler initialized";
|
||||
|
||||
m_typeHandler = TypeHandling::TypeHandler::createInstance(this, m_logger);
|
||||
if (!m_typeHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init TypeHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init TypeHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "TypeHandler initialized";
|
||||
|
||||
m_partyHandler = std::make_shared<PartyHandling::PartyHandler>(this);
|
||||
if (!m_partyHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init PartyHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init PartyHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "PartyHandler initialized";
|
||||
|
||||
m_tabFtc = TrainingAreaBase::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
if (!m_tabFtc->enableAll())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init TrainingAreaBase FTC";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "TrainingAreaBase FTC initialized";
|
||||
|
||||
m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsHandler->dds());
|
||||
if (!m_aesFtc->enableChargeAdministrationModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init AreaEffectSimulation FTC";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_participantHandler = std::make_shared<ParticipantHandling::ParticipantHandlerForExercise>(this);
|
||||
if (!m_participantHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init ParticipantHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init ParticipantHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "ParticipantHandler initialized";
|
||||
m_ddsHandler->pacemaker()->addPort(m_participantHandler->getWebSocketPort(), Core::PortType::WebSocketPositionServer);
|
||||
|
||||
m_targetInformationHandler = std::make_shared<ParticipantManagement::HandlerTargetInformation>(this);
|
||||
if (!m_targetInformationHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init TargetInformationHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init TargetInformationHandler"));
|
||||
return false;
|
||||
}
|
||||
NOTICE_LOG(m_logger) << "Enabled TargetInformationHandler for ex " << exerciseId << " do= " << domainId;
|
||||
|
||||
m_biteHandler = std::make_shared<BiteHandling::BiteHandler>(this);
|
||||
if (!m_biteHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init BiteHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init BiteHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "BiteHandler initialized";
|
||||
|
||||
// template handler is not needed in exercise dependent PPM
|
||||
if (m_ddsHandler->dds()->getPartitionId() <= 0)
|
||||
{
|
||||
m_templateHandler = std::make_shared<TemplateHandling::TemplateHandler>(this);
|
||||
if (!m_templateHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init TemplateHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init TemplateHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "TemplateHandler initialized";
|
||||
}
|
||||
|
||||
m_getParticipants = std::make_shared<GetParticipants>(this);
|
||||
|
||||
m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->dds());
|
||||
m_equipmentEventHandler = std::make_shared<EquipmentEventHandling::EquipmentEventHandler>(this);
|
||||
if (!m_equipmentEventHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init EquipmentEventHandler";
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError, QStringLiteral("Could not init EquipmentEventHandler"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "EquipmentEventHandler initialized";
|
||||
|
||||
// WebSocketServer
|
||||
m_websocketHandler = std::make_shared<WebSocketInterface::WebSocketInterfaceHandler>(this);
|
||||
if (!m_websocketHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init WebSocketInterfaceHandler";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "WebSocketInterfaceHandler initialized";
|
||||
m_ddsHandler->pacemaker()->addPort(m_websocketHandler->webSocketPort(), Core::PortType::WebSocketServer);
|
||||
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::Running);
|
||||
|
||||
// UasHandler
|
||||
if (exerciseId == 0)
|
||||
{
|
||||
m_uasHandler = std::make_shared<UasHandling::UasHandler>(this);
|
||||
if (!m_uasHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init UasHandler";
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "UasHandler initialized";
|
||||
}
|
||||
|
||||
if (exerciseId != 0)
|
||||
{
|
||||
// init missionPlan
|
||||
m_missionPlanHandler = std::make_shared<UasHandling::MissionPlanHandler>(this);
|
||||
if (!m_missionPlanHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Couldn't init MissionPlanHandler";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<DatabaseInterface> MainHandler::db() const { return m_dbHandler->db(); }
|
||||
|
||||
std::shared_ptr<DatabaseInterface> MainHandler::dbEx0() const { return m_dbHandlerEx0->db(); }
|
||||
|
||||
qint64 MainHandler::currentTimeMSec() const { return QDateTime::currentMSecsSinceEpoch(); }
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* MainHandler for ParticipantManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Baeuerle, SLSE, 19.05.2016
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "BiteHandling/bite_handler.h"
|
||||
#include "EquipmentEventHandling/equipment_event_handler.h"
|
||||
#include "ParticipantHandling/get_participants.h"
|
||||
#include "ParticipantHandling/participant_handler.h"
|
||||
#include "ParticipantHandling/participant_handler_for_exercise.h"
|
||||
#include "PartyHandling/party_handler.h"
|
||||
#include "TargetHandling/handler_target_information.h"
|
||||
#include "TemplateHandling/template_handler.h"
|
||||
#include "TypeHandling/type_handler.h"
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
#include "ppm_db.h"
|
||||
#include <ParticipantManagement/ppm_db.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <TrainingAreaBase/tab_dtc.h>
|
||||
#include <TrainingAreaBase/tab_ftc.h>
|
||||
namespace NGLDB
|
||||
{
|
||||
template <typename DB> class DbServiceHandler;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace UasHandling
|
||||
{
|
||||
class UasHandler;
|
||||
class MissionPlanHandler;
|
||||
} // namespace UasHandling
|
||||
|
||||
namespace WebSocketInterface
|
||||
{
|
||||
class WebSocketInterfaceHandler;
|
||||
}
|
||||
|
||||
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
|
||||
|
||||
class MainHandler final : public ParticipantHandling::BaseDataProvider
|
||||
{
|
||||
public:
|
||||
explicit MainHandler();
|
||||
~MainHandler();
|
||||
|
||||
bool init(int domainId, int exerciseId);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> dts() const override { return m_ddsHandler->dts(); }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> fts() const { return m_ddsHandler->fts(); }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> exAnyDts() const { return m_ddsHandler->exAnyDts(); }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Fts> exAnyFts() const { return m_ddsHandler->exAnyFts(); }
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const override { return m_ddsHandler->pdmDtc(); }
|
||||
std::shared_ptr<DDSConnector::DdsConnector> dds() const { return m_ddsHandler->dds(); }
|
||||
std::shared_ptr<DdsHandler> ddsHandler() const { return m_ddsHandler; }
|
||||
std::shared_ptr<DatabaseInterface> db() const;
|
||||
std::shared_ptr<DatabaseInterface> dbEx0() const;
|
||||
std::shared_ptr<TypeHandling::TypeHandler> typeHandler() const { return m_typeHandler; }
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> tabFtc() const { return m_tabFtc; }
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> tabDtc() const { return m_tabDtc; }
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> aesFtc() const { return m_aesFtc; }
|
||||
std::shared_ptr<ParticipantHandling::ParticipantHandlerForExercise> participantHandler() const { return m_participantHandler; }
|
||||
std::shared_ptr<HandlerTargetInformation> targetInformationHandler() const { return m_targetInformationHandler; }
|
||||
std::shared_ptr<BiteHandling::BiteHandler> biteHandler() const { return m_biteHandler; }
|
||||
std::shared_ptr<TemplateHandling::TemplateHandler> templateHandler() const { return m_templateHandler; }
|
||||
std::shared_ptr<PartyHandling::PartyHandler> partyHandler() const { return m_partyHandler; }
|
||||
std::shared_ptr<EquipmentEventHandling::EquipmentEventHandler> equipmentEventHandler() const { return m_equipmentEventHandler; }
|
||||
std::shared_ptr<UasHandling::MissionPlanHandler> missionPlanHandler() const { return m_missionPlanHandler; }
|
||||
|
||||
int exerciseId() const { return dds()->getPartitionId(); }
|
||||
qint64 currentTimeMSec() const override;
|
||||
|
||||
private: // attributes
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandlerEx0;
|
||||
std::shared_ptr<TypeHandling::TypeHandler> m_typeHandler;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Ftc> m_tabFtc;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> m_tabDtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
|
||||
std::shared_ptr<ParticipantHandling::ParticipantHandlerForExercise> m_participantHandler;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::HandlerTargetInformation> m_targetInformationHandler;
|
||||
|
||||
std::shared_ptr<BiteHandling::BiteHandler> m_biteHandler;
|
||||
std::shared_ptr<TemplateHandling::TemplateHandler> m_templateHandler;
|
||||
std::shared_ptr<PartyHandling::PartyHandler> m_partyHandler;
|
||||
std::shared_ptr<GetParticipants> m_getParticipants;
|
||||
std::shared_ptr<EquipmentEventHandling::EquipmentEventHandler> m_equipmentEventHandler;
|
||||
std::shared_ptr<WebSocketInterface::WebSocketInterfaceHandler> m_websocketHandler;
|
||||
std::shared_ptr<UasHandling::UasHandler> m_uasHandler;
|
||||
std::shared_ptr<UasHandling::MissionPlanHandler> m_missionPlanHandler;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace ParticipantManagement
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom ppm functions (extends tab_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "ppm_common.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
StateInformation youngestStateInformation(const std::vector<ParticipantManagement::StateInformation> &stateList,
|
||||
bool bSkipVbgGreaterCatastrophicKill, bool bSkipSanitation, bool debug)
|
||||
{
|
||||
std::shared_ptr<int> _(nullptr, [debug](int *) { if (debug) qWarning() << "##############################################"; });
|
||||
|
||||
if (debug)
|
||||
qWarning() << "########## youngestStateInformation ##########";
|
||||
|
||||
ParticipantManagement::StateInformation ret;
|
||||
ret.vulnerabilityState(ProjectDataManagement::VulnerabilityState::NotReady);
|
||||
|
||||
if (stateList.empty())
|
||||
{
|
||||
if (debug)
|
||||
qWarning() << ">> stateList empty! not ready";
|
||||
return ret;
|
||||
}
|
||||
|
||||
// bool readyToDebug = false;
|
||||
// for (const ParticipantManagement::StateInformation &si : qAsConst(stateList))
|
||||
// {
|
||||
// if (si.originatorId() == 0
|
||||
// && si.originatorType() == ProjectDataManagement::StateChangeOriginator_def::ExerciseControl
|
||||
// && (si.vulnerabilityState() == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill
|
||||
// || si.vulnerabilityState() == ProjectDataManagement::VulnerabilityState_def::CombatReady)
|
||||
// )
|
||||
// readyToDebug = true;
|
||||
// }
|
||||
|
||||
/* NOTE: Participant::setState in PPM doesn't respect the vulnId sent by the TNE, but instead sets it to
|
||||
* the highest vuln (ignoring TemporarySeverance, NearMiss and HitWithNoEffect!) that was found in
|
||||
* the vulnerabilityBits. So the latest state in the history is always the state we are looking for.
|
||||
* NOTE: StateInformation's stateTime max resolution is seconds instead of milliseconds
|
||||
* NOTE: StateInformations can have the same stateTime, which means a CombatReady might be incorrectly
|
||||
* chosen because it has the same stateTime as a CatastrophicKill - if not sorted by time *and* state
|
||||
*/
|
||||
|
||||
std::vector<ParticipantManagement::StateInformation> sortedStateList(stateList); // copy list
|
||||
|
||||
// sort list by sample time, desc (highest time = youngest)
|
||||
std::sort(sortedStateList.begin(), sortedStateList.end(),
|
||||
[/*&debug,readyToDebug*/](const ParticipantManagement::StateInformation &left, const ParticipantManagement::StateInformation &right)
|
||||
{
|
||||
if (left.stateTime() == right.stateTime() && left.vulnerabilityState() != right.vulnerabilityState())
|
||||
{
|
||||
// if (readyToDebug)
|
||||
// debug = true;
|
||||
|
||||
// qWarning() << "WARNING: StateInformation with state" << (int)left.vulnerabilityState().underlying() << "has the same stateTime as StateInformation with state" << (int)right.vulnerabilityState().underlying();
|
||||
|
||||
// sort by state if time is the same (higher state = winner)
|
||||
return (left.vulnerabilityState() > right.vulnerabilityState());
|
||||
}
|
||||
|
||||
return (left.stateTime() > right.stateTime());
|
||||
});
|
||||
|
||||
|
||||
if (debug)
|
||||
{
|
||||
qWarning() << ">> printing all SIs";
|
||||
for (const ParticipantManagement::StateInformation &si : qAsConst(sortedStateList))
|
||||
qWarning() << ">>>> si" << "siVulnId" << (uint8_t)si.vulnerabilityState().underlying() << "bits" << si.vulnerabilityBits() << "time" << si.stateTime();
|
||||
|
||||
qWarning() << ">> checking SIs";
|
||||
}
|
||||
|
||||
|
||||
for (const ParticipantManagement::StateInformation &si : qAsConst(sortedStateList))
|
||||
{
|
||||
const uint8_t siVulnId = si.vulnerabilityState().underlying();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
qWarning() << "MWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMW";
|
||||
qWarning() << ">>>> si" << "siVulnId" << siVulnId;
|
||||
}
|
||||
|
||||
// we're only interested in 'visible' VBGs, don't care about near miss etc. here
|
||||
if (bSkipVbgGreaterCatastrophicKill && si.vulnerabilityState() > ProjectDataManagement::VulnerabilityState::CatastrophicKill)
|
||||
{
|
||||
if (debug)
|
||||
qWarning() << ">>>> vulnId is higher than CK!";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bSkipSanitation && si.originatorType() == ProjectDataManagement::StateChangeOriginator::Sanitation)
|
||||
{
|
||||
if (debug)
|
||||
qWarning() << ">>>> is sanitation!";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
qWarning() << ">>>> match! done!";
|
||||
return si;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
qWarning() << ">> no state found" << "bSkipVbgGreaterCatastrophicKill" << bSkipVbgGreaterCatastrophicKill << "bSkipSanitation" << bSkipSanitation;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
StateInformation youngestRealStateInformation(const std::vector<ParticipantManagement::StateInformation> &stateList,
|
||||
bool bSkipVbgGreaterCatastrophicKill)
|
||||
{
|
||||
if (stateList.size() == 0)
|
||||
{
|
||||
ParticipantManagement::StateInformation ret;
|
||||
ret.vulnerabilityState(ProjectDataManagement::VulnerabilityState::NotReady);
|
||||
return ret;
|
||||
}
|
||||
StateInformation youngestState = youngestStateInformation(stateList);
|
||||
size_t youngest = 0;
|
||||
for (size_t i = 1; i < stateList.size(); ++i)
|
||||
{
|
||||
const auto &tCurrent = stateList.at(i).stateTime();
|
||||
const auto &tYoungest = stateList.at(youngest).stateTime();
|
||||
|
||||
// we're only interested in 'visible' VBGs, don't care about near miss etc. here
|
||||
if (bSkipVbgGreaterCatastrophicKill && stateList.at(i).vulnerabilityState() > ProjectDataManagement::VulnerabilityState::CatastrophicKill)
|
||||
continue;
|
||||
if (stateList.at(i).originatorType() == ProjectDataManagement::StateChangeOriginator::Sanitation ||
|
||||
stateList.at(i).originatorType() == ProjectDataManagement::StateChangeOriginator::MedicalTimeout)
|
||||
continue;
|
||||
if (tCurrent > youngestState.stateTime())
|
||||
continue;
|
||||
|
||||
bool higherState = (stateList.at(i).vulnerabilityState() > stateList.at(youngest).vulnerabilityState() ) ||
|
||||
(stateList.at(i).vulnerabilityState() == stateList.at(youngest).vulnerabilityState() && (stateList.at(i).vitality() < stateList.at(youngest).vitality()));
|
||||
|
||||
if ((tCurrent > tYoungest && (stateList.at(i).originatorType() == ProjectDataManagement::StateChangeOriginator::ObserverController || stateList.at(i).originatorType() == ProjectDataManagement::StateChangeOriginator::ExerciseControl)) ||
|
||||
(tCurrent > tYoungest && higherState) ||
|
||||
(tCurrent == tYoungest && higherState))
|
||||
youngest = i;
|
||||
}
|
||||
if (youngest == 0)
|
||||
return youngestState;
|
||||
return stateList.at(youngest);
|
||||
}
|
||||
|
||||
ParticipantManagement::SanitationResult proceduresDone(const std::vector<StateInformation> &stateList)
|
||||
{
|
||||
// Empty List or 1 Entry ("CombatReady"): No Effect
|
||||
if (stateList.size() <= 1)
|
||||
return SanitationResult::NoEffect;
|
||||
|
||||
// If that guy is killed: NoEffect
|
||||
StateInformation youngestReal = youngestRealStateInformation(stateList);
|
||||
if (youngestReal.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CatastrophicKill)
|
||||
return SanitationResult::NoEffect;
|
||||
|
||||
|
||||
SanitationResult ret = SanitationResult::Unhandled;
|
||||
|
||||
for (size_t i = 1; i < stateList.size(); ++i)
|
||||
{
|
||||
// Better than "Unhandled" can only occur if this is done by Sanitation or O/C
|
||||
if (stateList.at(i).originatorType() != ProjectDataManagement::StateChangeOriginator::Sanitation
|
||||
&& stateList.at(i).originatorType() != ProjectDataManagement::StateChangeOriginator::ObserverController )
|
||||
continue;
|
||||
// Let's find the newest
|
||||
if (stateList.at(i).stateTime() < youngestReal.stateTime())
|
||||
continue;
|
||||
//
|
||||
if (ret == SanitationResult::Unhandled ) //we have a sanitation so at least 1
|
||||
ret = stateList.at(i).sanitationResult();
|
||||
|
||||
if (stateList.at(i).sanitationResult() == SanitationResult::Sufficient && ret != SanitationResult::Optimal )
|
||||
ret = SanitationResult::Sufficient;
|
||||
if (stateList.at(i).sanitationResult() == SanitationResult::Optimal)
|
||||
ret = SanitationResult::Optimal;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom ppm functions (extends tab_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
#include "ppm_export.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
PPM_COMMON_EXPORT StateInformation youngestStateInformation(const std::vector<ParticipantManagement::StateInformation> &stateList,
|
||||
bool bSkipVbgGreaterCatastrophicKill = true, bool bSkipSanitation = true,
|
||||
bool debug = false);
|
||||
StateInformation youngestRealStateInformation(const std::vector<ParticipantManagement::StateInformation> &stateList,
|
||||
bool bSkipVbgGreaterCatastrophicKill = true);
|
||||
PPM_COMMON_EXPORT SanitationResult proceduresDone(const std::vector<ParticipantManagement::StateInformation> &stateList);
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom db functions (extends ppm_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "ppm_db_impl_custom.h"
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/sql_query_janitor.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
// custom procs, body must be implemented by user
|
||||
bool DatabaseInterfaceImplCustom::removeEquipmentExerciseMapping(const Database::EquipmentExerciseMapping &equipmentExerciseMapping)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
|
||||
const QString tableName(getTableName(QStringLiteral("ppm_equipment_exercise_mapping")));
|
||||
const QString stmt(QStringLiteral("DELETE FROM ") + tableName +
|
||||
QStringLiteral(" WHERE equipment_number = ") +
|
||||
QString::number(equipmentExerciseMapping.equipmentNumber) +
|
||||
QStringLiteral(" AND participant_id = ") +
|
||||
QString::number(equipmentExerciseMapping.participantId) +
|
||||
QStringLiteral(" AND exercise_id = ") +
|
||||
QString::number(equipmentExerciseMapping.exerciseId));
|
||||
|
||||
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom db functions (extends ppm_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_db_impl.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
class DatabaseInterfaceImplCustom final : public DatabaseInterfaceImpl
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using DatabaseInterfaceImpl::DatabaseInterfaceImpl;
|
||||
|
||||
bool removeEquipmentExerciseMapping(const Database::EquipmentExerciseMapping &equipmentExerciseMapping) override final;
|
||||
};
|
||||
} // namespace ParticipantManagement
|
||||
+861
@@ -0,0 +1,861 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom ppm functions (extends tab_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "ppm_dtc_impl_custom.h"
|
||||
#include "ppm_common.h"
|
||||
#include <DDS/DTC/generic_dtc.h>
|
||||
#include <DDS/Generic/generic_data_reader.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QPolygonF>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
DtcImplCustom::DtcImplCustom(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: DtcImpl(ddsConnector)
|
||||
{
|
||||
}
|
||||
|
||||
bool DtcImplCustom::rootTemplates(QVector<TemplateParticipant> &templateVector) const
|
||||
{
|
||||
if (!m_dtcTemplateParticipant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error retrieving data topic TemplateParticipant";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &sample : m_dtcTemplateParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().superiorTemplateId() == 0)
|
||||
templateVector.append(sample.data());
|
||||
}
|
||||
|
||||
return !templateVector.isEmpty();
|
||||
}
|
||||
|
||||
bool DtcImplCustom::templateParticipantsFromTemplateId(int rootTemplateId, QVector<TemplateParticipant> &templateVector)
|
||||
{
|
||||
templateVector.append(inferiorTemplates(rootTemplateId));
|
||||
return !templateVector.isEmpty();
|
||||
}
|
||||
|
||||
TemplateData DtcImplCustom::convertFromParticipantTemplateToTemplateData(const TemplateParticipant &inputTemplate) const
|
||||
{
|
||||
TemplateData outputData;
|
||||
TemplateBase &out = outputData;
|
||||
out = inputTemplate;
|
||||
// in cases where the ids are not updated by the treeModel
|
||||
outputData.modId(inputTemplate.templateId());
|
||||
outputData.superiorModId(inputTemplate.superiorTemplateId());
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
ParticipantData Interface::DtcImplCustom::convertParticipantToParticipantData(const Participant &inputParticipant) const
|
||||
{
|
||||
ParticipantData outputData;
|
||||
ParticipantBase &out = outputData;
|
||||
out = inputParticipant;
|
||||
// in cases where the ids are not updated by the treeModel
|
||||
outputData.modId(inputParticipant.id());
|
||||
outputData.superiorModId(inputParticipant.superiorId());
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
ParticipantManagement::StateInformation DtcImplCustom::youngestStateInformation(
|
||||
const std::vector<ParticipantManagement::StateInformation> &stateList /*, bool debug*/) const
|
||||
{
|
||||
return ParticipantManagement::youngestStateInformation(stateList /*, true, true, debug*/);
|
||||
}
|
||||
|
||||
ParticipantManagement::SanitationResult DtcImplCustom::proceduresDone(const std::vector<StateInformation> &stateList) const
|
||||
{
|
||||
return ParticipantManagement::proceduresDone(stateList);
|
||||
}
|
||||
|
||||
QMap<int, Participant> DtcImplCustom::units() const
|
||||
{
|
||||
QMap<int, Participant> ret;
|
||||
if (!m_dtcType)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error retrieving data topic Type";
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!m_dtcParticipant)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error retrieving data topic Participant";
|
||||
return ret;
|
||||
}
|
||||
|
||||
QSet<int> unitTypeIds;
|
||||
for (const auto &sample : m_dtcType->readAlive())
|
||||
{
|
||||
if (sample.data().typeClass() == TypeClass::Unit || sample.data().typeClass() == TypeClass::SupportUnit)
|
||||
unitTypeIds.insert(sample.data().id());
|
||||
}
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (unitTypeIds.contains(sample.data().typeId()))
|
||||
ret.insert(sample.data().id(), sample.data());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::participantIdsByUnit(int unitId, const QMap<int, Participant> &participants, QSet<int> &participantIds)
|
||||
{
|
||||
const ParticipantManagement::Participant unit(participants.value(unitId));
|
||||
if (unit.id() != unitId)
|
||||
return false;
|
||||
|
||||
const ParticipantManagement::Type unitType(type(unit.typeId()));
|
||||
if (unitType.typeClass() != ParticipantManagement::TypeClass::Unit && unitType.typeClass() != ParticipantManagement::TypeClass::SupportUnit)
|
||||
return false;
|
||||
|
||||
participantIds += recursiveInferiosForParticipant(unitId, participants);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::visibleParties(QMap<int32_t, Party> &visibleParties, const QVector<int> &filter) const
|
||||
{
|
||||
if (!m_dtcParty)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error retrieving data topic Party";
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool bAll = (filter.size() == 1 && filter.first() == -1);
|
||||
for (const auto &sample : m_dtcParty->readAlive())
|
||||
if (bAll || filter.contains(sample.data().id()))
|
||||
visibleParties.insert(sample.data().id(), sample);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString DtcImplCustom::hierarchyFromParticipant(int participantId) { return lookUpHierachy(participantId, participants()); }
|
||||
|
||||
QString DtcImplCustom::hierarchyFromParticipant(int participantId, const QMap<int, Participant> &participants) const
|
||||
{
|
||||
return lookUpHierachy(participantId, participants);
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isEquipmentNumberInUse(int equipmentNumber, int &exerciseId) const
|
||||
{
|
||||
if (!m_dtcEquipmentExerciseMapping)
|
||||
return true; // we're not sure - return true ...
|
||||
|
||||
for (const auto &sample : m_dtcEquipmentExerciseMapping->readAlive())
|
||||
{
|
||||
for (const Equipment2ParticipantId &e2p : sample.data().mapping())
|
||||
{
|
||||
if (e2p.equipmentNumber() == equipmentNumber)
|
||||
{
|
||||
exerciseId = sample.data().exerciseId();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isTypeInUse(int typeId) const
|
||||
{
|
||||
if (!m_dtcParticipant)
|
||||
return true; // we're not sure - return true ...
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().typeId() == typeId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int DtcImplCustom::participantIdByEquipmentNumber(int equipmentNumber) const
|
||||
{
|
||||
if (!m_dtcParticipant)
|
||||
return -1;
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().equipmentNumber().is_set() && sample.data().equipmentNumber().get() == equipmentNumber)
|
||||
return sample.data().id();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DtcImplCustom::equipmentNumberByParticipantId(int participantId) const
|
||||
{
|
||||
if (!m_dtcParticipant)
|
||||
return -1;
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().id() == participantId)
|
||||
{
|
||||
if (sample.data().equipmentNumber().is_set())
|
||||
return sample.data().equipmentNumber().get();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DtcImplCustom::uasMissionIdByEquipmentNumber(int equipmentNumber) const
|
||||
{
|
||||
if (m_dtcMissionPlan == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int participantId = participantIdByEquipmentNumber(equipmentNumber);
|
||||
if (participantId < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (const auto &sample : m_dtcMissionPlan->readAlive())
|
||||
{
|
||||
if (sample.data().participantId() == participantId)
|
||||
{
|
||||
return sample.data().id();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DtcImplCustom::partyIdFromForceIdentifier(HlaForceIdentifierEnum inputForceIdentifier) const
|
||||
{
|
||||
if (!m_dtcParty)
|
||||
return -1;
|
||||
|
||||
for (const auto &sample : m_dtcParty->readAlive())
|
||||
{
|
||||
if (sample.data().hlaForceIdentifier() == inputForceIdentifier)
|
||||
return sample.data().id();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConnectState DtcImplCustom::saaConnectedState(const int partyId)
|
||||
{
|
||||
ConnectState ret = ConnectState::Undefined;
|
||||
if (!isPartyEnabled())
|
||||
{
|
||||
enableParty();
|
||||
waitForHistoricalDataParty(10);
|
||||
}
|
||||
|
||||
if (!m_dtcParty)
|
||||
return ret;
|
||||
|
||||
for (const auto &sample : m_dtcParty->readAlive())
|
||||
{
|
||||
if (partyId != sample.data().id())
|
||||
continue;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(sample.data().properties()));
|
||||
QJsonObject prop = doc.object();
|
||||
QJsonObject propAdler;
|
||||
if (prop.contains(QStringLiteral("Adler")))
|
||||
{
|
||||
propAdler = prop[QStringLiteral("Adler")].toObject();
|
||||
if (propAdler.contains(QStringLiteral("saaConnectedState")))
|
||||
return static_cast<ConnectState::inner_enum>(propAdler[QStringLiteral("saaConnectedState")].toInt());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<int> DtcImplCustom::getSubordinatesByParticipant(const int participantId)
|
||||
{
|
||||
QVector<int> result;
|
||||
if (!m_dtcParticipant)
|
||||
return result;
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().superiorId() == participantId)
|
||||
result.append(sample.data().id());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<int> DtcImplCustom::getParticipantsByPolygon(const QPolygonF &polygon, bool includeUnits, bool includeOc)
|
||||
{
|
||||
QVector<int> participantsInPolygon;
|
||||
QSet<int> unitTypeIds;
|
||||
|
||||
if (!isParticipantPositionEnabled())
|
||||
{
|
||||
enableParticipantPosition();
|
||||
waitForHistoricalDataParticipantPosition(10);
|
||||
}
|
||||
|
||||
if (!includeUnits)
|
||||
{
|
||||
if (!isTypeEnabled())
|
||||
{
|
||||
enableType();
|
||||
waitForHistoricalDataType(10);
|
||||
}
|
||||
for (const auto &sample : m_dtcType->readAlive())
|
||||
{
|
||||
if (sample.data().typeClass() == TypeClass::Unit || sample.data().typeClass() == TypeClass::SupportUnit)
|
||||
unitTypeIds.insert(sample.data().id());
|
||||
}
|
||||
}
|
||||
|
||||
participantsInPolygon.reserve(m_dtcParticipantPosition->readAlive().length());
|
||||
|
||||
for (const auto ¤tPosition : m_dtcParticipantPosition->readAlive())
|
||||
{
|
||||
if (!includeUnits && unitTypeIds.contains(currentPosition.data().participantTypeId()))
|
||||
continue;
|
||||
|
||||
if (!includeOc && currentPosition.data().partyId() == 1) // partyId 1 = OC
|
||||
continue;
|
||||
|
||||
const Core::GeoPosition ¤tGeoPosition = currentPosition.data().pos();
|
||||
const QPointF positionPoint(currentGeoPosition.lon(), currentGeoPosition.lat());
|
||||
|
||||
if (polygon.containsPoint(positionPoint, Qt::OddEvenFill))
|
||||
participantsInPolygon.append(currentPosition.data().participantId());
|
||||
}
|
||||
|
||||
return participantsInPolygon;
|
||||
}
|
||||
|
||||
// All Participant-Ids of Type UAS
|
||||
QVector<int> DtcImplCustom::getUasIds()
|
||||
{
|
||||
QVector<int> result;
|
||||
if (!m_dtcParticipant)
|
||||
return result;
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (isTypeUas(sample.data().typeId()))
|
||||
{
|
||||
result.append(sample.data().id());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UAS DtcImplCustom::getUasByParticipantId(int participantId, int exerciseId) const
|
||||
{
|
||||
ParticipantManagement::UAS uas;
|
||||
uas.id(-1); // if not found
|
||||
|
||||
for (const auto &sample : m_dtcUAS->readAlive())
|
||||
{
|
||||
if (sample.data().participantId() != participantId)
|
||||
continue;
|
||||
if (sample.data().exerciseId() != exerciseId)
|
||||
continue;
|
||||
uas = sample;
|
||||
break;
|
||||
}
|
||||
return uas;
|
||||
}
|
||||
|
||||
MissionAction DtcImplCustom::currentMissionAction(int missionPlanId) const
|
||||
{
|
||||
ParticipantManagement::MissionAction missionAction;
|
||||
missionAction.planId(0); // default compare value in case nothing found
|
||||
for (const auto &sample : m_dtcMissionPlan->readAlive())
|
||||
{
|
||||
if (sample.data().id() != missionPlanId)
|
||||
continue;
|
||||
const std::vector<ParticipantManagement::MissionItem> &items = sample.data().items();
|
||||
for (const auto &item : items)
|
||||
{
|
||||
if (item.fulfilled() > 0)
|
||||
continue;
|
||||
const std::vector<ParticipantManagement::MissionAction> &actions = item.actions();
|
||||
for (const auto &action : actions)
|
||||
{
|
||||
if (action.fulfilled() > 0)
|
||||
continue;
|
||||
return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
return missionAction;
|
||||
}
|
||||
|
||||
ParticipantManagement::Participant DtcImplCustom::getParticipantByInternalName(int partyId, const QString &unitName, const QString &internalName) const
|
||||
{
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().partyId() != partyId)
|
||||
continue;
|
||||
if (sample.data().isDeleted())
|
||||
continue;
|
||||
if (sample.data().name() != unitName.toStdString())
|
||||
continue;
|
||||
// Found Unit
|
||||
|
||||
// looking for Unit only?
|
||||
if (internalName.isEmpty())
|
||||
{
|
||||
return sample;
|
||||
}
|
||||
|
||||
for (auto inferiorId : sample.data().inferiorIds())
|
||||
{
|
||||
const auto &inferiorParticipant = m_participantCont.value(inferiorId);
|
||||
if (inferiorParticipant.id() <= 0 || inferiorParticipant.isDeleted())
|
||||
continue;
|
||||
if (inferiorParticipant.name() == internalName.toStdString())
|
||||
return inferiorParticipant;
|
||||
}
|
||||
}
|
||||
|
||||
return ParticipantManagement::Participant();
|
||||
}
|
||||
|
||||
QSet<int> DtcImplCustom::recursiveInferiosForParticipant(int32_t participantId, const QMap<int, Participant> &participants)
|
||||
{
|
||||
QSet<int> result;
|
||||
auto it = participants.find(participantId);
|
||||
if (it == participants.end())
|
||||
return result;
|
||||
|
||||
result += participantId;
|
||||
const Participant &p = it.value();
|
||||
for (int childId : p.inferiorIds())
|
||||
result += recursiveInferiosForParticipant(childId, participants);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString DtcImplCustom::lookUpHierachy(int participantId, const QMap<int, Participant> &participants)
|
||||
{
|
||||
if (participantId <= 0)
|
||||
return QString();
|
||||
|
||||
const auto itPart = participants.find(participantId);
|
||||
if (itPart == participants.end())
|
||||
return QString();
|
||||
const auto &part = itPart.value();
|
||||
|
||||
QString supStr = lookUpHierachy(part.superiorId(), participants);
|
||||
QString ret = QString::fromStdString(part.designator());
|
||||
// First separator is "./"
|
||||
if (part.superiorId() == 0)
|
||||
return (ret + QLatin1String("./"));
|
||||
|
||||
if (supStr.endsWith(QLatin1String("./")))
|
||||
return (supStr + ret);
|
||||
|
||||
return (supStr.isEmpty() ? ret : supStr + QLatin1Char(',') + ret);
|
||||
}
|
||||
|
||||
// private
|
||||
QVector<TemplateParticipant> DtcImplCustom::inferiorTemplates(int templateId)
|
||||
{
|
||||
QVector<TemplateParticipant> retVector;
|
||||
const TemplateParticipant participant = templateParticipant(templateId);
|
||||
retVector.append(participant);
|
||||
|
||||
if (participant.inferiorIds().is_set())
|
||||
{
|
||||
retVector.reserve(participant.inferiorIds().get().size() + retVector.size());
|
||||
for (int inferiorId : participant.inferiorIds().get())
|
||||
retVector.append(inferiorTemplates(inferiorId));
|
||||
}
|
||||
|
||||
return retVector;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isTypePatientSimulator(int typeId) const
|
||||
{
|
||||
if (!m_dtcParticipant)
|
||||
return false;
|
||||
|
||||
for (const auto &sample : m_dtcParticipant->readAlive())
|
||||
{
|
||||
if (sample.data().typeId() == typeId)
|
||||
{
|
||||
const std::string &str = sample.data().properties();
|
||||
if (str.size() > 0 && getNeedsIp(str) && getNeedsPort(str))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isAdlerType(int typeId) const
|
||||
{
|
||||
if (!m_dtcType)
|
||||
return false;
|
||||
|
||||
for (const Type &type : m_dtcType->readAlive())
|
||||
{
|
||||
if (type.id() != typeId)
|
||||
continue;
|
||||
const auto &prob = type.properties();
|
||||
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
const auto val = obj.value(QStringLiteral("isMovable"));
|
||||
if (val.isNull() || !val.isBool())
|
||||
return false;
|
||||
return !val.toBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isArtilleryType(int typeId) const
|
||||
{
|
||||
if (!m_dtcType)
|
||||
return false;
|
||||
|
||||
for (const Type &type : m_dtcType->readAlive())
|
||||
{
|
||||
if (type.id() != typeId)
|
||||
continue;
|
||||
const auto &prob = type.properties();
|
||||
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
const auto val = obj.value(QStringLiteral("isArtillery"));
|
||||
if (val.isNull() || !val.isBool())
|
||||
return false;
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isEditable(int typeId) const
|
||||
{
|
||||
if (!m_dtcType)
|
||||
return false;
|
||||
|
||||
for (const Type &type : m_dtcType->readAlive())
|
||||
{
|
||||
if (type.id() != typeId)
|
||||
continue;
|
||||
const auto &prob = type.properties();
|
||||
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
const auto val = obj.value(QStringLiteral("isEditable"));
|
||||
if (val.isNull() || !val.isBool())
|
||||
return true;
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isAdlerVerbund(int typeId) const
|
||||
{
|
||||
if (!m_dtcType)
|
||||
return false;
|
||||
|
||||
for (const Type &type : m_dtcType->readAlive())
|
||||
{
|
||||
if (type.id() != typeId)
|
||||
continue;
|
||||
const auto &prob = type.properties();
|
||||
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
const auto val = obj.value(QStringLiteral("isAdlerVerbund"));
|
||||
if (val.isNull() || !val.isBool())
|
||||
return false;
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::isPartyAdlerVerbund(int partyId) const
|
||||
{
|
||||
if (!m_dtcParty)
|
||||
return false;
|
||||
|
||||
for (const Party &party : m_dtcParty->readAlive())
|
||||
{
|
||||
if (party.id() != partyId)
|
||||
continue;
|
||||
const auto &prob = party.properties();
|
||||
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
if (!obj.contains(QStringLiteral("Adler")))
|
||||
return false;
|
||||
|
||||
const QJsonObject adlerObj = obj[QStringLiteral("Adler")].toObject();
|
||||
const auto val = adlerObj.value(QStringLiteral("isVerbund"));
|
||||
if (val.isNull() || !val.isBool())
|
||||
return false;
|
||||
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type DtcImplCustom::getTypeFromAdlerType(const QString &adlerTypeName, bool isUnit, bool isVerbund)
|
||||
{
|
||||
Type ret;
|
||||
|
||||
if (!m_dtcType)
|
||||
return ret;
|
||||
|
||||
for (const Type &type : m_dtcType->readAlive())
|
||||
{
|
||||
if (isUnit && type.typeClass() != TypeClass::Unit)
|
||||
continue;
|
||||
if (!isUnit && type.typeClass() != TypeClass::WeaponSystem)
|
||||
continue;
|
||||
const auto &prob = type.properties();
|
||||
QJsonParseError parserError;
|
||||
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
|
||||
if (parserError.error != QJsonParseError::NoError)
|
||||
continue;
|
||||
|
||||
const QJsonObject obj(doc.object());
|
||||
const auto val = obj.value(QStringLiteral("adlerType"));
|
||||
if (val.isNull() || !val.isString())
|
||||
continue;
|
||||
|
||||
if (val.toString() != adlerTypeName)
|
||||
continue;
|
||||
|
||||
if (isAdlerVerbund(type.id()) != isVerbund)
|
||||
continue;
|
||||
// Found exact Type
|
||||
DEBUG_LOG(m_logger) << "--- "
|
||||
<< "Found exact type --> typeId= " << type.id() << " ---";
|
||||
return type;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Properties in table ppm.ppm_type
|
||||
bool DtcImplCustom::isTypeUas(int typeId)
|
||||
{
|
||||
if (!m_dtcType)
|
||||
return false;
|
||||
|
||||
if (!isTypeEnabled())
|
||||
{
|
||||
enableType();
|
||||
waitForHistoricalDataType(10);
|
||||
}
|
||||
|
||||
for (const auto &sample : m_dtcType->readAlive())
|
||||
{
|
||||
// DEBUG_LOG(m_logger) << " sample equipmentTypeId=" << sample.data().equipmentTypeId();
|
||||
if (sample.data().id() == typeId)
|
||||
{
|
||||
const std::string &str = sample.data().properties();
|
||||
if (str.size() > 0 && getIsUAS(str))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UAS DtcImplCustom::getUasByParticipantId(int participantId, int exerciseId)
|
||||
{
|
||||
|
||||
if (!isUASEnabled())
|
||||
{
|
||||
enableUAS();
|
||||
waitForHistoricalDataUAS();
|
||||
}
|
||||
|
||||
if (!m_dtcUAS)
|
||||
return {};
|
||||
|
||||
for (const auto &sample : m_dtcUAS->readAlive())
|
||||
{
|
||||
if (sample.data().participantId() != participantId)
|
||||
continue;
|
||||
if (sample.data().exerciseId() != exerciseId)
|
||||
continue;
|
||||
return sample;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
int DtcImplCustom::getParticipantFromPrf(int prf) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getParticipantFromPrf prf=" << prf;
|
||||
|
||||
if (!m_dtcParticipant)
|
||||
return -1;
|
||||
|
||||
for (const DynamicParticipantData &sample : m_dtcDynamicParticipantData->readAlive())
|
||||
{
|
||||
for (const auto &designation : qAsConst(sample.designations()))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " code=" << designation.code();
|
||||
if (designation.code() == prf)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " return code=" << designation.code();
|
||||
return sample.participantId();
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DtcImplCustom::getPrfFromParticipant(int participantId) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getPrfFromParticipant participantId=" << participantId;
|
||||
if (!m_dtcParticipant)
|
||||
return -1;
|
||||
|
||||
for (const DynamicParticipantData &sample : m_dtcDynamicParticipantData->readAlive())
|
||||
{
|
||||
if (participantId == sample.participantId())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "participantId=" << sample.participantId() << " designations.size()=" << sample.designations().size();
|
||||
for (const auto &designation : qAsConst(sample.designations()))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " code=" << designation.code();
|
||||
if (designation.code() > 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " return code=" << designation.code();
|
||||
return designation.code();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::getNeedsIp(const std::string &s) const
|
||||
{
|
||||
QJsonParseError jError;
|
||||
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
|
||||
if (jError.error != QJsonParseError::NoError || !doc.isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QJsonObject obj(doc.object());
|
||||
return obj[QStringLiteral("needsIP")].toBool();
|
||||
}
|
||||
|
||||
bool DtcImplCustom::getNeedsPort(const std::string &s) const
|
||||
{
|
||||
QJsonParseError jError;
|
||||
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
|
||||
if (jError.error != QJsonParseError::NoError || !doc.isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QJsonObject obj(doc.object());
|
||||
return obj[QStringLiteral("needsPort")].toBool();
|
||||
}
|
||||
|
||||
QMap<double, int> DtcImplCustom::sortByDistance(const double lon, const double lat, const QVector<int> &participantIds)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " DtcImplCustom::sortByDistance";
|
||||
int zone = -1;
|
||||
|
||||
if (!isParticipantPositionEnabled())
|
||||
{
|
||||
enableParticipantPosition();
|
||||
waitForHistoricalDataParticipantPosition(10);
|
||||
}
|
||||
QMap<double, int> distanceMapSorted;
|
||||
|
||||
for (const auto ¤tPosition : m_dtcParticipantPosition->readAlive())
|
||||
{
|
||||
if (participantIds.contains(currentPosition.data().participantId()))
|
||||
{
|
||||
auto pOrigin = LtsCoordTrans::UtmCoordinate::fromGeographic(lon, lat, zone);
|
||||
auto pPos = LtsCoordTrans::UtmCoordinate::fromGeographic(currentPosition.data().pos().lon(), currentPosition.data().pos().lat(), zone);
|
||||
double distance = LtsCoordTrans::distance(pPos, pOrigin);
|
||||
DEBUG_LOG(m_logger) << distance;
|
||||
// Save distance and particiapnt Id into temporar map.
|
||||
// the map is sorted so we can use that later instead of writing a sort method vor a vec
|
||||
// for now
|
||||
distanceMapSorted.insert(distance, currentPosition.data().participantId());
|
||||
DEBUG_LOG(m_logger) << "insert distance=" << distance << ", participantId=" << currentPosition.data().participantId();
|
||||
}
|
||||
}
|
||||
|
||||
QMapIterator<double, int> it(distanceMapSorted);
|
||||
while (it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
DEBUG_LOG(m_logger) << "distance=" << it.key() << ", participantId=" << it.value();
|
||||
}
|
||||
|
||||
return distanceMapSorted;
|
||||
}
|
||||
|
||||
bool DtcImplCustom::getIsUAS(const std::string &s) const
|
||||
{
|
||||
QJsonParseError jError;
|
||||
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
|
||||
if (jError.error != QJsonParseError::NoError || !doc.isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QJsonObject obj(doc.object());
|
||||
return obj[QStringLiteral("isUAS")].toBool();
|
||||
}
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace ParticipantManagement
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom ppm functions (extends tab_db_impl.cpp/.h)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc_impl.h>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
|
||||
class DtcImplCustom final : public Interface::DtcImpl
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DtcImplCustom(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
bool rootTemplates(QVector<TemplateParticipant> &templateVector) const override;
|
||||
bool templateParticipantsFromTemplateId(int rootTemplateId, QVector<TemplateParticipant> &templateVector) override;
|
||||
TemplateData convertFromParticipantTemplateToTemplateData(const TemplateParticipant &inputTemplate) const override;
|
||||
ParticipantData convertParticipantToParticipantData(const Participant &inputParticipant) const override;
|
||||
ParticipantManagement::StateInformation youngestStateInformation(
|
||||
const std::vector<ParticipantManagement::StateInformation> &stateList /*, bool debug = false*/) const override;
|
||||
SanitationResult proceduresDone(const std::vector<ParticipantManagement::StateInformation> &stateList) const override;
|
||||
|
||||
/* To get this method working, the topics Type and Participant have to be enabled */
|
||||
QMap<int, Participant> units() const override;
|
||||
|
||||
/* To get this method working, the topics Type and Participant have to be enabled */
|
||||
bool participantIdsByUnit(int unitId, const QMap<int, Participant> &participants, QSet<int> &participantIds) override;
|
||||
|
||||
/* To get the visible parties, the topic Party has to be enabled */
|
||||
bool visibleParties(QMap<int32_t, Party> &visibleParties, const QVector<int> &filter) const override;
|
||||
|
||||
/* To get the hole hierarchy String of own and superior designators */
|
||||
QString hierarchyFromParticipant(int participantId) override;
|
||||
QString hierarchyFromParticipant(int participantId, const QMap<int, Participant> &participants) const override;
|
||||
|
||||
bool isEquipmentNumberInUse(int equipmentNumber, int &exerciseId) const override;
|
||||
bool isTypeInUse(int typeId) const override;
|
||||
bool isTypePatientSimulator(int typeId) const override;
|
||||
bool isAdlerType(int typeId) const override;
|
||||
bool isArtilleryType(int typeId) const override;
|
||||
bool isEditable(int typeId) const override;
|
||||
bool isAdlerVerbund(int typeId) const override;
|
||||
bool isPartyAdlerVerbund(int typeId) const override;
|
||||
|
||||
Type getTypeFromAdlerType(const QString &adlerTypeName, bool isUnit, bool isVerbund) override;
|
||||
|
||||
bool isTypeUas(int typeId) override;
|
||||
|
||||
UAS getUasByParticipantId(int participantId, int exerciseId) override;
|
||||
|
||||
int getParticipantFromPrf(int prf) const override;
|
||||
int getPrfFromParticipant(int participantId) const override;
|
||||
|
||||
/* Searching the participant ID for the given EquipmentNumber */
|
||||
int participantIdByEquipmentNumber(int equipmentNumber) const override;
|
||||
|
||||
/* Searching the EquipmentNumber for the given participant Id */
|
||||
int equipmentNumberByParticipantId(int participantId) const override;
|
||||
|
||||
/* Searching the UAS Middion ID for the given EquipmentNumber */
|
||||
int uasMissionIdByEquipmentNumber(int equipmentNumber) const override;
|
||||
|
||||
/* Searching to party ID from the HLA Force Identifier */
|
||||
int partyIdFromForceIdentifier(HlaForceIdentifierEnum inputForceIdentifier) const override;
|
||||
|
||||
/* returns true is SAA is connected for the party */
|
||||
ConnectState saaConnectedState(const int partyId) override;
|
||||
|
||||
// returns all participant IDs that have a position in the given polygon
|
||||
QVector<int> getParticipantsByPolygon(const QPolygonF &polygon, bool includeUnits, bool includeOc) override;
|
||||
|
||||
// returns all participants with superioId == participantId
|
||||
QVector<int> getSubordinatesByParticipant(const int participantId) override;
|
||||
|
||||
QMap<double, int> sortByDistance(const double lon, const double lat, const QVector<int> &participantIds) override;
|
||||
|
||||
// provides all participantIds of the drone type (type UAS)
|
||||
QVector<int> getUasIds() override;
|
||||
|
||||
// return uas entry by pariticpant id
|
||||
ParticipantManagement::UAS getUasByParticipantId(int participantId, int exerciseId) const override;
|
||||
|
||||
ParticipantManagement::MissionAction currentMissionAction(int missionPlanId) const override;
|
||||
|
||||
ParticipantManagement::Participant getParticipantByInternalName(int partyId, const QString &unitName, const QString &internalName) const override;
|
||||
|
||||
private: // methods
|
||||
static QSet<int> recursiveInferiosForParticipant(int participantId, const QMap<int, Participant> &participants);
|
||||
static QString lookUpHierachy(int participantId, const QMap<int, Participant> &participants);
|
||||
QVector<TemplateParticipant> inferiorTemplates(int templateId);
|
||||
bool getNeedsIp(const std::string &s) const;
|
||||
bool getNeedsPort(const std::string &s) const;
|
||||
bool getIsUAS(const std::string &s) const;
|
||||
};
|
||||
} // namespace Interface
|
||||
} // namespace ParticipantManagement
|
||||
+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 PPM_COMMON_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define PPM_COMMON_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCPPMCOMMON_LIB)
|
||||
# define PPM_COMMON_EXPORT Q_DECL_EXPORT
|
||||
# ifndef WIN32
|
||||
# ifdef NDDSUSERDllExport
|
||||
# undef NDDSUSERDllExport
|
||||
# endif
|
||||
# define NDDSUSERDllExport Q_DECL_EXPORT
|
||||
# endif
|
||||
# else
|
||||
# define PPM_COMMON_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PPM_CLIENT_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define PPM_CLIENT_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCPPMCLIENT_LIB)
|
||||
# define PPM_CLIENT_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define PPM_CLIENT_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PPM_SERVER_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define PPM_SERVER_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCPPMSERVER_LIB)
|
||||
# define PPM_SERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define PPM_SERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Generic technical areas for all exercises and all training areas (assuming 1 default technical area for each TA)
|
||||
|
||||
SET SEARCH_PATH TO ex_%ex_id%, PUBLIC;
|
||||
INSERT INTO ppm_party (id, role_id, name, color, fading_color, is_used_by, hla_force_identifier, properties ) SELECT id, role_id, name, color, fading_color, false, hla_force_identifier, '{}' FROM ppm.ppm_party;
|
||||
|
||||
-- for each ADLER chargeType and each party one entry with 10000 and effectSource = ADLER_STANDALONE(3)
|
||||
INSERT INTO aes_charge_administration( charge_type_id, party_id, effect_source_id, amount, planned, used, changed, amount_changed_by_operator) SELECT ct.id, p.id, 3, 10000, 0, 0, 0, false from pdm.pdm_charge_type ct CROSS JOIN ppm_party p where ct.properties->>'isAdlerChargeType' = 'true';
|
||||
|
||||
+1144
File diff suppressed because it is too large.
Load diff
+68
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Settings for ParticipantManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include "LtsUtilsCore/lts_portrange.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Settings::markVehiclesAsReservedFromExcon()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("PPM/markVehiclesAsReservedFromExcon"), true).toBool();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
uint Settings::maxParticipantsPerFiringUnit()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("PPM/maxParticipantsPerFiringUnit"), 8).toUInt();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QPair<quint16, quint16> Settings::getWebSocketServerPortRange(int type)
|
||||
{
|
||||
return LtsUtils::fromQPoint(settings()->settings()->value(QString(QStringLiteral("PPM/webSocketServerPortRange/%1")).arg(type), QPoint()).toPoint());
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Settings for ParticipantManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <QPair>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
//!< The real NGL::Settings - object
|
||||
NGL::Settings *settings();
|
||||
void setIniFile(const QString &ini);
|
||||
// guez hack - the guez warehouse automatically assigns an equipment number
|
||||
// for vehicles but this is not wanted. Therefore we have to mark them as
|
||||
// 'Reserved for Excon'
|
||||
bool markVehiclesAsReservedFromExcon();
|
||||
uint maxParticipantsPerFiringUnit();
|
||||
QPair<quint16, quint16> getWebSocketServerPortRange(int type);
|
||||
}
|
||||
|
||||
} // namespace ParticipantManagement
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Websocket interface to participant positions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Justus Hertel, SLSE, 2020-07-08
|
||||
*/
|
||||
|
||||
#include "web_socket_handler.h"
|
||||
|
||||
#include <QWebSocket>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
WebSocketHandler::WebSocketHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_webSocketServer(new QWebSocketServer(QStringLiteral("ParticipantPositionsSocket"), QWebSocketServer::NonSecureMode, this))
|
||||
, m_logger(getLogger(QStringLiteral("WebSocketHandler")))
|
||||
{}
|
||||
|
||||
WebSocketHandler::~WebSocketHandler()
|
||||
{
|
||||
for (const auto& ws : qAsConst(m_webSockets))
|
||||
{
|
||||
ws->disconnect(this);
|
||||
}
|
||||
m_webSockets.clear();
|
||||
}
|
||||
|
||||
bool WebSocketHandler::init(quint16 listenPort)
|
||||
{
|
||||
if (!m_webSocketServer->listen(QHostAddress::Any, listenPort))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not listen on port " << listenPort << " - aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(m_webSocketServer, &QWebSocketServer::newConnection,
|
||||
this, &WebSocketHandler::onNewConnection);
|
||||
|
||||
INFO_LOG(m_logger) << "Listening on port " << m_webSocketServer->serverPort();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketHandler::init(const QPair<quint16, quint16> &portRange)
|
||||
{
|
||||
for (quint16 currentPort = portRange.first; currentPort <= portRange.second; ++currentPort)
|
||||
{
|
||||
if (init(currentPort))
|
||||
return true;
|
||||
}
|
||||
|
||||
return init();
|
||||
}
|
||||
|
||||
bool WebSocketHandler::sendTelegramInternal(const ParticipantPosition &pos, int eqNo) const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("participantId")] = pos.participantId();
|
||||
obj[QStringLiteral("equipmentNumber")] = eqNo;
|
||||
obj[QStringLiteral("lat")] = pos.pos().lat();
|
||||
obj[QStringLiteral("lon")] = pos.pos().lon();
|
||||
obj[QStringLiteral("height")] = pos.pos().z();
|
||||
|
||||
const QString jsonStr = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
bool ret = false;
|
||||
for (const auto &wsw : qAsConst(m_webSockets))
|
||||
{
|
||||
if (wsw->sendTextMessage(jsonStr))
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WebSocketHandler::onNewConnection()
|
||||
{
|
||||
QWebSocket *ws = m_webSocketServer->nextPendingConnection();
|
||||
if (!ws)
|
||||
return;
|
||||
|
||||
connect(ws, &QWebSocket::disconnected,
|
||||
this, &WebSocketHandler::onWebSocketDisconnected);
|
||||
|
||||
m_webSockets += ws;
|
||||
|
||||
INFO_LOG(m_logger) << "New websocket connected";
|
||||
}
|
||||
|
||||
void WebSocketHandler::onWebSocketDisconnected()
|
||||
{
|
||||
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
|
||||
if (!ws)
|
||||
return;
|
||||
|
||||
m_webSockets.removeAll(ws);
|
||||
ws->deleteLater();
|
||||
|
||||
INFO_LOG(m_logger) << "A websocket disconnected";
|
||||
}
|
||||
|
||||
bool WebSocketHandler::sendPosition(const ParticipantPosition &participantPosition, int equipmentNumber) const
|
||||
{
|
||||
if (!isConnected() || m_webSockets.isEmpty())
|
||||
return false;
|
||||
|
||||
return sendTelegramInternal(participantPosition, equipmentNumber);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Websocket interface to participant positions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Justus Hertel, SLSE, 2017-01-11
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QWebSocketServer>
|
||||
#include <ParticipantManagement/ppm_common.h>
|
||||
#include "logger.h"
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
|
||||
class WebSocketHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WebSocketHandler(QObject *parent = nullptr);
|
||||
~WebSocketHandler();
|
||||
|
||||
bool init(quint16 listenPort = 0);
|
||||
bool init(const QPair<quint16, quint16> &portRange);
|
||||
bool isConnected() const { return !m_webSockets.isEmpty(); }
|
||||
quint16 listenPort() const { return m_webSocketServer->serverPort(); }
|
||||
bool sendPosition(const ParticipantPosition& participantPosition, int equipmentNumber) const;
|
||||
|
||||
private:
|
||||
bool sendTelegramInternal(const ParticipantPosition& pos, int eqNo) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onNewConnection();
|
||||
void onWebSocketDisconnected();
|
||||
|
||||
private:
|
||||
QWebSocketServer* m_webSocketServer = nullptr;
|
||||
QVector<QWebSocket*> m_webSockets;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user