309 lines
11 KiB
C++
Executable File
309 lines
11 KiB
C++
Executable File
/**
|
|
* Plugin CES Mission Plan
|
|
* $Id: $
|
|
* $HeadURL: svn://slssvn/TDS/branches/product/features/25_03_etb_uas/Lts/Services/CentralEffectSimulation/Plugins/MissionPlan/ces_mission_plan_object.cpp $
|
|
* $Author: Kemayou_s $
|
|
* Created by Steve Kemayou, ESZS, 2025-06-25
|
|
*/
|
|
|
|
#include "ces_mission_plan_object.h"
|
|
#include "qobject.h"
|
|
#include <QJsonObject>
|
|
#include <QJsonDocument>
|
|
#include <ngltools/ngltools_dtg.h>
|
|
namespace CES_MISSIONPLAN
|
|
{
|
|
|
|
CesMissionPlanObject::CesMissionPlanObject(const ParticipantManagement::MissionPlan &missionPlan,
|
|
const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
|
|
QObject *parent)
|
|
: QObject(parent)
|
|
, m_missionStartimer(new QTimer(this))
|
|
, m_loiterTimer(new QTimer(this))
|
|
, m_ddsHandler(ddsHandler)
|
|
, m_missionPlan(missionPlan)
|
|
, m_logger(CentralEffectSimulation::getLogger("Plugin.MissionPlan.CesMissionPlanObject"))
|
|
{
|
|
///1- set missionStartTimer for mission start
|
|
///2- set loiterTimer: he is use when a mission action requires it
|
|
|
|
m_missionStartimer->setSingleShot(true);
|
|
connect(m_missionStartimer, &QTimer::timeout, this, &CesMissionPlanObject::sendNextMissionAction);
|
|
if (missionPlan.missionStart() > m_ddsHandler->currentPartitionTime())
|
|
{
|
|
const int time = m_missionPlan.missionStart() - m_ddsHandler->currentPartitionTime();
|
|
// DEBUG_LOG(m_logger)<<" -- [CesMissionPlanObject] start mission after << "<<time/1000<<" sec.";
|
|
m_missionStartimer->start(time);
|
|
}
|
|
|
|
m_loiterTimer->setSingleShot(true);
|
|
connect(m_loiterTimer, &QTimer::timeout, this, [this]()
|
|
{
|
|
setMissionActionFulfilled(getNextAction());
|
|
});
|
|
}
|
|
|
|
void CesMissionPlanObject::setMissionActionFulfilled(const ParticipantManagement::MissionAction &msa)
|
|
{
|
|
///1- set mission action param fulfilled
|
|
///2- send setFulfillment request to svcParticipantManagement
|
|
///3- get next action ready for TAB
|
|
///4- if no actions left send misson plan completed signal
|
|
///5- else send next mission action to TAB
|
|
|
|
//DEBUG_LOG(m_logger)<<" -- [setMissionActionFullfiled] -> msa.number: "<<msa.actionNumber()<<" planId: "<<msa.planId();
|
|
// actionNumb=-1 && itemNumb=-1 |-> mission will be aborted
|
|
if (msa.itemNumber() < 0 && msa.actionNumber() < 0)
|
|
{
|
|
ParticipantManagement::SetMissionActionFulfilledRequest abortReq(m_missionPlan.id(),
|
|
m_ddsHandler->currentPartitionTime(),
|
|
-1,
|
|
-1);
|
|
if ( !m_ddsHandler->ftcPpm()->setMissionActionFulfilledRequest(abortReq))
|
|
WARNING_LOG(m_logger) << " -- unable to abort mission with planId:"<<abortReq.missionId();
|
|
|
|
return;
|
|
}
|
|
|
|
if (msa.itemNumber() >= static_cast<int>(m_missionPlan.items().size()) )
|
|
{
|
|
//WARNING_LOG(m_logger)<<" -- [setMissionActionFulfilled] item size invalid !!";
|
|
return;
|
|
}
|
|
|
|
const int actionCount = m_missionPlan.items()[msa.itemNumber()].actions().size();
|
|
if (msa.actionNumber() >= actionCount)
|
|
{
|
|
//WARNING_LOG(m_logger)<<" -- [setMissionActionFulfilled] actions size invalid !!";
|
|
return;
|
|
}
|
|
|
|
auto &action = m_missionPlan.items()[msa.itemNumber()].actions()[msa.actionNumber()];
|
|
action.fulfilled(m_ddsHandler->currentPartitionTime());
|
|
ParticipantManagement::SetMissionActionFulfilledRequest req;
|
|
req.actionNumber(action.actionNumber());
|
|
req.fulfilled(action.fulfilled());
|
|
req.itemNumber(action.itemNumber());
|
|
req.missionId(m_missionPlan.id());
|
|
|
|
if (!m_ddsHandler->ftcPpm()->setMissionActionFulfilledRequest(req))
|
|
WARNING_LOG(m_logger) << " -- unable to setMissionActionFulfilledRequest: planId:"<<req.missionId();
|
|
|
|
}
|
|
|
|
int CesMissionPlanObject::planId() const
|
|
{
|
|
return m_missionPlan.id();
|
|
}
|
|
|
|
int CesMissionPlanObject::participantId() const
|
|
{
|
|
return m_missionPlan.participantId();
|
|
}
|
|
|
|
bool CesMissionPlanObject::isMissionFulfilled(const ParticipantManagement::MissionPlan &mission)
|
|
{
|
|
int itemCount = 0;
|
|
int actionCount = 0;
|
|
for (const auto &item : mission.items())
|
|
{
|
|
actionCount = 0;
|
|
for (const auto &a : item.actions())
|
|
{
|
|
//DEBUG_LOG(m_logger)<<" -- [setMissionPlan] action.Num : "<<a.actionNumber()<<" itemNum: "<<a.itemNumber()<<" fulfilled: "<<a.fulfilled();
|
|
if (a.fulfilled() > 0)
|
|
actionCount++;
|
|
else
|
|
return false;
|
|
}
|
|
if (actionCount == (int) item.actions().size())
|
|
itemCount++;
|
|
}
|
|
|
|
return (itemCount == (int)mission.items().size());
|
|
}
|
|
|
|
void CesMissionPlanObject::sendActionAttact()
|
|
{
|
|
//1- set aes element
|
|
//2- send request
|
|
//3- setActionFulfilled
|
|
int ret = m_ddsHandler->ftcAes()->explosionClusterSingleEffectOnlyModifyRequest(getExplosionCluster());
|
|
if (!ret)
|
|
WARNING_LOG(m_logger)<<" -- sendActionAttact ret error for planId: "<<m_missionPlan.id();
|
|
|
|
setMissionActionFulfilled(getNextAction());
|
|
}
|
|
|
|
AreaEffectSimulation::ExplosionClusterSingleEffectOnlyRequest CesMissionPlanObject::getExplosionCluster()
|
|
{
|
|
auto msa = getNextAction();
|
|
|
|
QJsonObject jsobj = QJsonDocument::fromJson(QByteArray::fromStdString(msa.properties())).object();
|
|
const int chargeTypeId = jsobj.value(QStringLiteral("chargeTypeId")).toInt();
|
|
|
|
|
|
const ParticipantManagement::Participant participant = m_ddsHandler->dtcPpm()->participant(m_missionPlan.participantId());
|
|
const ParticipantManagement::UAS uas = m_ddsHandler->dtcPpm()->getUasByParticipantId(m_missionPlan.participantId(),
|
|
m_ddsHandler->dds()->getPartitionId());
|
|
|
|
QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(m_ddsHandler->currentPartitionTime());
|
|
timeStamp = timeStamp.addSecs(10);
|
|
const QString exploName = QStringLiteral("%1_%2").arg(QString::fromStdString(uas.deviceIdentifier())).arg(DTG::toStringMSec(timeStamp.toMSecsSinceEpoch(), DTG::DisplayFormat::Short));
|
|
Core::GeoPosition geoPos(jsobj.value(QStringLiteral("location_x")).toDouble(),
|
|
jsobj.value(QStringLiteral("location_y")).toDouble(), 0.0);
|
|
|
|
AreaEffectSimulation::ExplosionClusterSingleEffectOnlyRequest ecReq;
|
|
ecReq.id(0);
|
|
ecReq.effectStart(timeStamp.toMSecsSinceEpoch());
|
|
ecReq.name(exploName.toStdString());
|
|
ecReq.element(ecReq.name());
|
|
ecReq.impactPosition(geoPos);
|
|
ecReq.chargeTypeId(chargeTypeId);
|
|
ecReq.partyId(participant.partyId());
|
|
// ecReq.externalId(0); // not used!!
|
|
|
|
return ecReq;
|
|
}
|
|
|
|
|
|
void CesMissionPlanObject::sendNextMissionAction()
|
|
{
|
|
///1- get next mission action to fulfill
|
|
///2- if there is no mission action left send mission plan completed
|
|
///3- check what the next action is.
|
|
///4- if actionType is loiter start Timer. On timeout setMissionActionFulfilled
|
|
///5- send mission action to mission handler
|
|
|
|
ParticipantManagement::MissionAction action = getNextAction();
|
|
|
|
//DEBUG_LOG(m_logger)<<" -- ########## ###### SEND NEXT ACTION ###### #############";
|
|
|
|
// set mission plan completed! or aborted
|
|
if (isMissionFulfilled(m_missionPlan) || m_missionPlan.aborted())
|
|
{
|
|
DEBUG_LOG(m_logger)<<" -- [sendNextMissionAction] No action mission Completed for plan id: "<<m_missionPlan.id();
|
|
deleteMissionPlanObject();
|
|
return;
|
|
}
|
|
|
|
switch (action.actionType().underlying()) {
|
|
case ParticipantManagement::MissionActionType::MoveTo:
|
|
{
|
|
emit ready2SendNextAction(action);
|
|
break;
|
|
}
|
|
case ParticipantManagement::MissionActionType::Loiter:
|
|
{
|
|
m_loiterTimer->start(action.duration() * 1000); // duration is in sec -> in msec: x * 1000
|
|
return;
|
|
}
|
|
case ParticipantManagement::MissionActionType::Attack:
|
|
{
|
|
sendActionAttact();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CesMissionPlanObject::setMissionPlan(const ParticipantManagement::MissionPlan &plan)
|
|
{
|
|
///1- update mission plan
|
|
///2- if plan fulfilled delete object
|
|
///3- send Next Mission Action
|
|
|
|
m_missionPlan = plan;
|
|
if (plan.missionStart() > m_ddsHandler->currentPartitionTime())
|
|
{
|
|
//DEBUG_LOG(m_logger)<<" -- [setMissionPlan] restart Timer for plan.id: "<<plan.id();
|
|
m_missionStartimer->start(m_missionPlan.missionStart() - m_ddsHandler->currentPartitionTime());
|
|
return;
|
|
}
|
|
|
|
if (isMissionFulfilled(plan) || plan.aborted())
|
|
{
|
|
DEBUG_LOG(m_logger) << "setMissionPlan deleteMissionPlanObject";
|
|
deleteMissionPlanObject();
|
|
return;
|
|
}
|
|
|
|
sendNextMissionAction();
|
|
}
|
|
|
|
ParticipantManagement::MissionPlan &CesMissionPlanObject::missionPlan()
|
|
{
|
|
return m_missionPlan;
|
|
}
|
|
|
|
const ParticipantManagement::MissionAction CesMissionPlanObject::getNextAction()
|
|
{
|
|
|
|
DEBUG_LOG(m_logger)<<" -- [getNextAction]: planId: "<<m_missionPlan.id()<<" itemSize: "<<m_missionPlan.items().size();
|
|
std::vector<ParticipantManagement::MissionItem> items = m_missionPlan.items();
|
|
|
|
// std::sort(items.begin(), items.end(), [](const ParticipantManagement::MissionItem &itemA, const ParticipantManagement::MissionItem &itemB){ return (itemA.itemNumber() < itemB.itemNumber()); });
|
|
|
|
for (auto &item : m_missionPlan.items())
|
|
{
|
|
for (auto &msa : item.actions())
|
|
{
|
|
if (msa.fulfilled() > 0)
|
|
{
|
|
continue;
|
|
}
|
|
DEBUG_LOG(m_logger)<<" -- [getNextActopm]mission with planId: " << m_missionPlan.id() << " // action_number " << msa.actionNumber()
|
|
<< " // action_type " << msa.actionType();
|
|
|
|
return msa;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
|
|
void CesMissionPlanObject::setMissionCompleted()
|
|
{
|
|
const ParticipantManagement::MissionPlan &msp = m_missionPlan;
|
|
ParticipantManagement::ModifyMissionPlanRequest req;
|
|
req.missionStart(msp.missionStart());
|
|
req.jumpToStart(msp.jumpToStart());
|
|
req.id(msp.id());
|
|
req.items(msp.items());
|
|
req.name(msp.name());
|
|
req.participantId(msp.participantId());
|
|
req.properties(msp.properties());
|
|
req.repeat(msp.repeat());
|
|
|
|
if (!m_ddsHandler->ftcPpm()->modifyMissionPlanRequest(req))
|
|
ERROR_LOG(m_logger)<<" -- couldn't modify mission plan ";
|
|
|
|
// delete object object is connected with handler
|
|
// it will be automatically removed from object list in handler
|
|
deleteMissionPlanObject();
|
|
|
|
}
|
|
|
|
/*!
|
|
* \brief CesMissionPlanObject::abortMission
|
|
* Mission is aborted when uas switched to manual mode.
|
|
* Notification to PPM is done by setting actionNumb and itemNumb to -1
|
|
*/
|
|
void CesMissionPlanObject::abortMission()
|
|
{
|
|
DEBUG_LOG(m_logger)<<" -- [abortMission] abord mission with planId: "<<m_missionPlan.id()<<" // uas id: "<<m_missionPlan.participantId();
|
|
ParticipantManagement::MissionAction msa = getNextAction();
|
|
msa.actionNumber(-1);
|
|
msa.itemNumber(-1);
|
|
setMissionActionFulfilled(msa);
|
|
}
|
|
|
|
void CesMissionPlanObject::deleteMissionPlanObject()
|
|
{
|
|
DEBUG_LOG(m_logger)<<" -- [DELETE OBJECT] plan fullfiled: delete Object planId: "<<m_missionPlan.id();
|
|
deleteLater();
|
|
}
|
|
|
|
}
|