Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Services/ParticipantManagement/UasHandling/mission_plan_handler.cpp
T
berrux-dev 598fc2560e Complete Qt6 migration: full clean build green across groups G1-G12 incl. runtime plugin set
new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
2026-10-20 09:36:57 +02:00

446 lines
15 KiB
C++
Executable File

/**
* 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 <utility>
#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 : std::as_const(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 : std::as_const(missionItemVec))
{
if (itemDb.missionPlanId == data.id)
{
itemsDbMap.insert(itemDb.elementNumber, itemDb);
for (const ParticipantManagement::Database::PpmMissionAction &actionDb : std::as_const(missionActionVec) )
{
if (actionDb.missionItemId == itemDb.id)
actionsDbMap.insert(actionDb.missionItemId, actionDb);
}
}
}
missionPlan.items.reserve(itemsDbMap.size());
for (const ParticipantManagement::Database::PpmMissionItem &item : std::as_const(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;
return (uas.uasState == ProjectDataManagement::UasState::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::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
}