1003 lines
35 KiB
C++
Executable File
1003 lines
35 KiB
C++
Executable File
/**
|
|
* Send Participant data to NGS
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Ehrlicher, SLSE, 2017-04-07
|
|
*/
|
|
|
|
#include "ppm_handler.h"
|
|
#include "ngs_handler.h"
|
|
#include <Common/participantinformation.h>
|
|
|
|
#include <LtsUtilsGuiDds/request_helper.h>
|
|
#include <EntityTypeStruct.h>
|
|
#include <Proxies/TrainingAreaBase/tab.hpp>
|
|
|
|
namespace HighLevelArchitecture
|
|
{
|
|
|
|
PpmHandler::PpmHandler(NgsHandler *ngsHandler)
|
|
: m_ngsHandler(ngsHandler)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_logger(getLogger("PpmHandler"))
|
|
{}
|
|
|
|
PpmHandler::~PpmHandler()
|
|
{
|
|
m_dtcPpm.reset();
|
|
m_ftcPpm.reset();
|
|
m_dtcPdm.reset();
|
|
m_dtsTab.reset();
|
|
m_ftcTab.reset();
|
|
m_dtcAes.reset();
|
|
}
|
|
|
|
bool PpmHandler::init()
|
|
{
|
|
m_dtcPpm = ParticipantManagement::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
m_ftcPpm = ParticipantManagement::Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
m_dtcPdm = ProjectDataManagement::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
m_dtsTab = TrainingAreaBase::Interface::Dts::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
m_ftcTab = TrainingAreaBase::Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
m_dtcAes = AreaEffectSimulation::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector());
|
|
|
|
// PPM DTC
|
|
|
|
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::typeChanged,
|
|
this, &PpmHandler::onTypeChanged);
|
|
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
|
|
this, &PpmHandler::onDynamicParticipantDataChanged);
|
|
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
|
this, &PpmHandler::onParticipantChanged);
|
|
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
|
|
this, &PpmHandler::onParticipantPositionChanged);
|
|
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::partyChanged,
|
|
this, &PpmHandler::onPartyChanged);
|
|
|
|
m_dtcPpm->enableType();
|
|
m_dtcPpm->enableDynamicParticipantData();
|
|
m_dtcPpm->enableParticipant();
|
|
m_dtcPpm->enableParticipantPosition();
|
|
m_dtcPpm->enableParty();
|
|
m_dtcPpm->enableParticipantGearEvent();
|
|
m_dtcPdm->enableGearTypeChargeType();
|
|
m_dtcPpm->waitForHistoricalDataParticipant();
|
|
|
|
|
|
// PPM FTC
|
|
|
|
m_ftcPpm->enableModifyParticipantData();
|
|
|
|
// PDM DTC
|
|
|
|
connect(m_dtcPdm.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged,
|
|
this, &PpmHandler::onChargeTypeChanged);
|
|
|
|
m_dtcPdm->enableChargeType();
|
|
|
|
// TAB DTS
|
|
if (!(m_dtsTab->enableEquipmentPosition() &&
|
|
m_dtsTab->enableEquipmentGearEvent() &&
|
|
m_dtsTab->enableEquipmentState() &&
|
|
m_dtsTab->enableLaserDesignation() &&
|
|
m_dtsTab->enableSpecialSensorData() &&
|
|
m_dtsTab->enableGearCharge() &&
|
|
m_dtsTab->enableEquipmentGearChargeState() &&
|
|
m_dtsTab->enableEquipmentGearAssignment())
|
|
)
|
|
{
|
|
ERROR_LOG(m_logger) << "Enabling TAB DTS Data-Topics failed.";
|
|
return false;
|
|
}
|
|
|
|
|
|
// TAB FTC
|
|
m_ftcTab->enableDemandInit();
|
|
m_ftcTab->enableDemandVulnerabilityStateChange();
|
|
m_ftcTab->enableSendCesHitInformation();
|
|
|
|
|
|
// AES DTC
|
|
// Nothing to do as only aesItemIdFromExternalId is called.
|
|
|
|
// Connect Connector signals to slots here.
|
|
NgsConnector *conn = m_ngsHandler->ngsConnector().get();
|
|
|
|
connect(conn, &NgsConnector::firstTickFinished, this, &PpmHandler::startPublishToNgs);
|
|
connect(conn, &NgsConnector::spatialChanged, this, &PpmHandler::onSpatialChanged);
|
|
connect(conn, &NgsConnector::markingChanged, this, &PpmHandler::onMarkingChanged);
|
|
connect(conn, &NgsConnector::exconEngagement, this, &PpmHandler::onExconEngagement);
|
|
connect(conn, &NgsConnector::weaponFire, this, &PpmHandler::onWeaponFire);
|
|
connect(conn, &NgsConnector::gearChargeState, this, &PpmHandler::onGearChargeState);
|
|
connect(conn, &NgsConnector::cesHitInformation, this, &PpmHandler::onParticipantCesHit);
|
|
connect(conn, &NgsConnector::equipmentState, this, &PpmHandler::onEquipmentState);
|
|
connect(conn, &NgsConnector::laserDesignation, this, &PpmHandler::onLaserDesignation);
|
|
connect(conn, &NgsConnector::sensorChanged, this, &PpmHandler::onSensorDataChanged);
|
|
|
|
return true;
|
|
}
|
|
|
|
ParticipantManagement::Role PpmHandler::roleForPartyId(int partyId)
|
|
{
|
|
if (partyId <= 0)
|
|
return ParticipantManagement::Role_def::Unknown;
|
|
auto it = m_partyData.constFind(partyId);
|
|
if (it == m_partyData.constEnd())
|
|
{
|
|
m_dtcPpm->waitForHistoricalDataParty();
|
|
m_partyData = m_dtcPpm->partys();
|
|
it = m_partyData.constFind(partyId);
|
|
if (it == m_partyData.constEnd())
|
|
return ParticipantManagement::Role_def::Unknown;
|
|
}
|
|
return it.value().role();
|
|
}
|
|
|
|
// DDS -> own memory
|
|
void PpmHandler::onTypeChanged(const ParticipantManagement::Type &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
m_types[data.id()] = data;
|
|
break;
|
|
case DataModification::eRemoved:
|
|
m_types.remove(data.id());
|
|
break;
|
|
}
|
|
}
|
|
|
|
int PpmHandler::getEquipmentNo(int participantId) const
|
|
{
|
|
if (!m_partData.contains(participantId))
|
|
return 0;
|
|
|
|
const ParticipantManagement::Participant &p = m_partData[participantId];
|
|
if (!p.equipmentNumber().is_set())
|
|
return 0;
|
|
|
|
return p.equipmentNumber().get();
|
|
}
|
|
|
|
int PpmHandler::getParticipantIdByExternalId(int externalId) const
|
|
{
|
|
for(const auto &part : qAsConst(m_partData))
|
|
{
|
|
if (part.externalId() == externalId)
|
|
return part.id();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// DDS -> HLA
|
|
void PpmHandler::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType)
|
|
{
|
|
int equipmentNo = getEquipmentNo(data.participantId());
|
|
if (equipmentNo == 0)
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not find EquipmentNo for Participant " << data.participantId() << ". Cannot send Dynamic Participant Data Modification to HLA.";
|
|
return;
|
|
}
|
|
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
{
|
|
if (!m_ngsHandler->ngsConnector()->canPublishData())
|
|
break;
|
|
|
|
std::shared_ptr<NgsConnector> conn = m_ngsHandler->ngsConnector();
|
|
|
|
const ParticipantManagement::StateInformation oldStateInfo = currentParticipantStateInformation(m_dynPartData.value(data.participantId()));
|
|
const ParticipantManagement::StateInformation newStateInfo = currentParticipantStateInformation(data);
|
|
// Improvement: Pass Originator to Connector, so the source can also be AES.
|
|
if (oldStateInfo != newStateInfo)
|
|
{
|
|
m_dynPartData[data.participantId()] = data;
|
|
if (newStateInfo.originatorType() == ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation)
|
|
{
|
|
// Aes hit
|
|
conn->setParticipantHit(equipmentNo,
|
|
newStateInfo,
|
|
getParticipantPosition(data.participantId()),
|
|
newStateInfo.originatorChargeTypeId(),
|
|
newStateInfo.originatorType(),
|
|
newStateInfo.originatorId());
|
|
}
|
|
else if (newStateInfo.originatorType() == ProjectDataManagement::StateChangeOriginator::Participant)
|
|
{
|
|
// direct hit
|
|
conn->setParticipantHit(equipmentNo,
|
|
newStateInfo,
|
|
getParticipantPosition(data.participantId()),
|
|
newStateInfo.originatorChargeTypeId(),
|
|
newStateInfo.originatorType(),
|
|
getEquipmentNo(newStateInfo.originatorId()));
|
|
}
|
|
else
|
|
{
|
|
// TODO: ProjectDataManagement::StateChangeOriginator::OperatorController, ExerciseControl, WoundTreatmentDevice, MaintainanceDevice
|
|
// reactivation or something similar
|
|
conn->setParticipantHit(equipmentNo,
|
|
newStateInfo,
|
|
getParticipantPosition(data.participantId()),
|
|
newStateInfo.originatorChargeTypeId(),
|
|
newStateInfo.originatorType(),
|
|
newStateInfo.originatorId());
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case DataModification::eRemoved:
|
|
m_dynPartData.remove(data.participantId());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// DDS -> HLA
|
|
void PpmHandler::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onParticipantChanged: " << data;
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
createParticipant(data);
|
|
m_partData[data.id()] = data;
|
|
break;
|
|
case DataModification::eModified:
|
|
{
|
|
// Participant has been deleted
|
|
if (data.isDeleted() && !m_partData[data.id()].isDeleted())
|
|
{
|
|
removeParticipant(m_partData[data.id()]); // Remove the old Equipment No
|
|
removeParticipant(data); // If it has a new Equipment No, kill it also.
|
|
m_partData[data.id()] = data;
|
|
break;
|
|
}
|
|
|
|
// Participant is new // Shouldn't happen, as it is the Added case
|
|
if (!m_partData.contains(data.id()))
|
|
{
|
|
createParticipant(data);
|
|
m_partData[data.id()] = data;
|
|
break;
|
|
}
|
|
|
|
// Only create/remove if Equipment Number changed...
|
|
int oldEqNo = m_partData[data.id()].equipmentNumber().is_set() ? m_partData[data.id()].equipmentNumber().get() : 0;
|
|
int newEqNo = data.equipmentNumber().is_set() ? data.equipmentNumber().get() : 0;
|
|
if (oldEqNo != newEqNo)
|
|
{
|
|
removeParticipant(m_partData[data.id()]);
|
|
createParticipant(data);
|
|
}
|
|
|
|
if (m_partData[data.id()].designator() != data.designator() && data.equipmentNumber().is_set())
|
|
m_ngsHandler->ngsConnector()->setParticipantName(data.equipmentNumber().get(), QString::fromStdString(data.designator()));
|
|
|
|
m_partData[data.id()] = data;
|
|
break;
|
|
}
|
|
case DataModification::eRemoved:
|
|
removeParticipant(data);
|
|
m_partData.remove(data.id());
|
|
break;
|
|
}
|
|
|
|
auto it = m_externalEquipmentNumbers.find(data.id());
|
|
if (it == m_externalEquipmentNumbers.end())
|
|
{
|
|
// not found
|
|
if (modType == DataModification::eRemoved || !data.equipmentNumber().is_set() || data.externalId() <= 0)
|
|
return;
|
|
int equipNo = data.equipmentNumber().get();
|
|
m_externalEquipmentNumbers.insert(data.id(), equipNo);
|
|
emit externalEquipmentNumberAdded(equipNo);
|
|
}
|
|
else
|
|
{
|
|
// found
|
|
int oldEquipNo = it.value();
|
|
if (modType == DataModification::eRemoved || !data.equipmentNumber().is_set() || data.externalId() <= 0)
|
|
{
|
|
m_externalEquipmentNumbers.erase(it);
|
|
emit externalEquipmentNumberRemoved(oldEquipNo);
|
|
return;
|
|
}
|
|
if (oldEquipNo != data.equipmentNumber().get())
|
|
{
|
|
emit externalEquipmentNumberRemoved(oldEquipNo);
|
|
emit externalEquipmentNumberAdded(data.equipmentNumber().get());
|
|
it.value() = data.equipmentNumber().get();
|
|
}
|
|
}
|
|
}
|
|
|
|
// DDS -> HLA
|
|
void PpmHandler::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onParticipantPositionChanged: " << data;
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
{
|
|
if (m_ngsHandler->ngsConnector()->canPublishData())
|
|
{
|
|
int eqNo = getEquipmentNo(data.participantId());
|
|
if (eqNo == 0)
|
|
return;
|
|
ParticipantPosition pos(data.pos(), data.sampleTime());
|
|
m_ngsHandler->ngsConnector()->setWorldLocation(eqNo, pos);
|
|
}
|
|
m_partPosData[data.participantId()] = data;
|
|
break;
|
|
}
|
|
case DataModification::eRemoved:
|
|
m_partPosData.remove(data.participantId());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// HLA -> DDS
|
|
void PpmHandler::onSpatialChanged(int eqId, const ParticipantPosition &pos, qint64 simTimeMSecs)
|
|
{
|
|
// NGSConnector already checked that the position changed significantly
|
|
|
|
TrainingAreaBase::EquipmentPosition &position = m_observerPositions[eqId];
|
|
|
|
position.position().position() = pos.toGeoPosition();
|
|
position.equipmentNumber(eqId); // With SAAB, ExternalId and EqId are the same!
|
|
position.sampleTime(simTimeMSecs);
|
|
m_dtsTab->publish(position);
|
|
}
|
|
|
|
|
|
void PpmHandler::onSensorDataChanged(const TrainingAreaBase::SpecialSensorData &event)
|
|
{
|
|
m_dtsTab->publish(event);
|
|
}
|
|
|
|
bool PpmHandler::onMarkingChanged(int eqId, const QString &marking, qint64 simTimeMSecs)
|
|
{
|
|
Q_UNUSED(simTimeMSecs);
|
|
// According to Ulli, the external (fixed) designation shall be the tactIdentifier. The designator thus is freely changeable.
|
|
ParticipantManagement::ParticipantData p = m_dtcPpm->convertParticipantToParticipantData(m_dtcPpm->participant(m_dtcPpm->participantIdByEquipmentNumber(eqId)));
|
|
if (p.tacticalIdentifier() == marking.toStdString())
|
|
return true;
|
|
p.tacticalIdentifier(marking.toStdString());
|
|
ParticipantManagement::ModifyParticipantDataRequest req;
|
|
req.data().push_back(std::move(p));
|
|
return m_requestHelper->startSingleRequest([this, req]()
|
|
{
|
|
return m_ftcPpm->modifyParticipantDataRequest(req, this);
|
|
});
|
|
}
|
|
|
|
// DDS -> own memory
|
|
void PpmHandler::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
m_partyData[data.id()] = data;
|
|
break;
|
|
case DataModification::eRemoved:
|
|
m_partyData.remove(data.id());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// DDS -> own memory
|
|
void PpmHandler::onChargeTypeChanged(const ProjectDataManagement::ChargeType &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
m_chargeTypes[data.id()] = data;
|
|
break;
|
|
case DataModification::eRemoved:
|
|
m_chargeTypes.remove(data.id());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PpmHandler::startPublishToNgs()
|
|
{
|
|
INFO_LOG(m_logger) << "Recreating all players from scratch due to structure / exercise change";
|
|
|
|
// 1. Cleanup
|
|
m_createdParticipantIds.clear();
|
|
|
|
// 2. Remove all virtual Players from database
|
|
// not yet supporteed
|
|
|
|
// 4. Recreate players
|
|
INFO_LOG(m_logger) << "(Re)Adding all players, size: " << m_partData.size();
|
|
|
|
for (const ParticipantManagement::Participant &participant : qAsConst(m_partData))
|
|
createParticipant(participant);
|
|
}
|
|
|
|
void PpmHandler::participantInitRequest(const TrainingAreaBase::TetraIcd::Init &request)
|
|
{
|
|
m_ngsHandler->ngsConnector()->sendParticipantInitRequest(request.header.equipmentNumber, request.resetManipulation, request.resetVulnerabilityState, request.restockCharges, request.header.timeStamp);
|
|
}
|
|
|
|
rpr2::DetonationResultCodeEnum8::ET PpmHandler::rpr2DetonationResultFromVulnerabilityState(TrainingAreaBase::TetraIcd::VulnerabilityState vulnerabilityState)
|
|
{
|
|
// ICE only cares about EntityImpact and EntotyProximateDetonation. Everything else will be discarded
|
|
rpr2::DetonationResultCodeEnum8::ET status = rpr2::DetonationResultCodeEnum8::None;
|
|
switch(vulnerabilityState)
|
|
{
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady:
|
|
status = rpr2::DetonationResultCodeEnum8::None;
|
|
break;
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::LightDamage:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::MediumDamage:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::HeavyDamage:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::MobilityKill:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::VisibleMobilityKill:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::WeaponSystemDamage:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::VisibleWeaponSystemDamage:
|
|
status = rpr2::DetonationResultCodeEnum8::AirHit;
|
|
break;
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::CatastrophicKill:
|
|
status = rpr2::DetonationResultCodeEnum8::EntityImpact;
|
|
break;
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::TemporarySeverance:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::NearMiss:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::HitWithNoEffect:
|
|
status = rpr2::DetonationResultCodeEnum8::EntityProximateDetonation;
|
|
break;
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::VulnerabilityBitsChanged:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::Reserved:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::NContamination:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::BContamination:
|
|
case TrainingAreaBase::TetraIcd::VulnerabilityState::CContamination:
|
|
status = rpr2::DetonationResultCodeEnum8::Other;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
rpr2::DetonationResultCodeEnum8::ET PpmHandler::rpr2DetonationResultFromPercentage(int percentage)
|
|
{
|
|
rpr2::DetonationResultCodeEnum8::ET status = rpr2::DetonationResultCodeEnum8::EntityProximateDetonation;
|
|
if (percentage > 0)
|
|
status = rpr2::DetonationResultCodeEnum8::AirHit;
|
|
if (percentage > 50)
|
|
status = rpr2::DetonationResultCodeEnum8::EntityImpact;
|
|
return status;
|
|
}
|
|
|
|
void PpmHandler::participantVulnerabilityStateRequest(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Participant Vulnerability State Request";
|
|
|
|
rpr2::DetonationResultCodeEnum8::ET resCode = rpr2DetonationResultFromVulnerabilityState(request.reqestedState);
|
|
m_ngsHandler->ngsConnector()->sendMunitionDetonation(request.header.equipmentNumber,
|
|
ProjectDataManagement::ChargeType(),
|
|
0,
|
|
resCode,
|
|
request.header.timeStamp);
|
|
}
|
|
|
|
void PpmHandler::participantCesHitInformationRequest(const TrainingAreaBase::TetraIcd::CesHitInformation &request)
|
|
{
|
|
rpr2::DetonationResultCodeEnum8::ET resCode = rpr2DetonationResultFromPercentage(request.effectPercent);
|
|
ProjectDataManagement::ChargeType ct = chargeTypeFromTasCodeDirect(request.chargeTasCodeDirect);
|
|
m_ngsHandler->ngsConnector()->sendMunitionDetonation(request.header.equipmentNumber,
|
|
ct,
|
|
request.originatorEquipmentNumber,
|
|
resCode,
|
|
request.header.timeStamp);
|
|
}
|
|
|
|
void PpmHandler::createParticipant(const ParticipantManagement::Participant &participant)
|
|
{
|
|
// Only create participants that have no external ID.
|
|
if (participant.externalId() > 0 || participant.equipmentNumber() == 0 || participant.isDeleted())
|
|
return;
|
|
|
|
if (!m_ngsHandler->ngsConnector()->canPublishData())
|
|
{
|
|
WARNING_LOG(m_logger) << "Can not publish data ... :(";
|
|
return;
|
|
}
|
|
|
|
if (m_createdParticipantIds.contains(participant.id()))
|
|
return;
|
|
|
|
const ParticipantManagement::Type partType = getParticipantType(participant.typeId());
|
|
bool bCreated;
|
|
switch (partType.typeClass().underlying())
|
|
{
|
|
case ParticipantManagement::TypeClass_def::Human:
|
|
bCreated = createHuman(participant);
|
|
break;
|
|
case ParticipantManagement::TypeClass_def::GroundVehicle:
|
|
case ParticipantManagement::TypeClass_def::VehicleWithGear:
|
|
case ParticipantManagement::TypeClass_def::WeaponSystem:
|
|
bCreated = createGroundVehicle(participant);
|
|
break;
|
|
case ParticipantManagement::TypeClass_def::Aircraft:
|
|
bCreated = createAircraft(participant);
|
|
break;
|
|
case ParticipantManagement::TypeClass_def::SupportEntity:
|
|
case ParticipantManagement::TypeClass_def::Unit:
|
|
// bCreated = createUnit(participant);
|
|
// break;
|
|
case ParticipantManagement::TypeClass_def::Vessel:
|
|
// bCreated = createVessel(participant);
|
|
// break;
|
|
default:
|
|
bCreated = false;
|
|
}
|
|
|
|
if (!bCreated)
|
|
return;
|
|
|
|
m_createdParticipantIds += participant.id();
|
|
}
|
|
|
|
bool PpmHandler::removeParticipant(const ParticipantManagement::Participant &participant)
|
|
{
|
|
if (!participant.equipmentNumber().is_set() || participant.equipmentNumber().get() == 0)
|
|
return false;
|
|
|
|
return m_ngsHandler->ngsConnector()->removeBaseEntity(participant.equipmentNumber().get());
|
|
}
|
|
|
|
//bool PpmHandler::createUnit(const ParticipantManagement::Participant &participant)
|
|
//{
|
|
// const ParticipantInformation pi(participant2ParticipantInformation(participant));
|
|
// return m_ngsHandler->ngsConnector()->addAggregateEntity(pi, participant.inferiorIds());
|
|
//}
|
|
|
|
bool PpmHandler::createHuman(const ParticipantManagement::Participant &participant)
|
|
{
|
|
const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id()));
|
|
return m_ngsHandler->ngsConnector()->addHuman(pi, currentVulnerabilityState(participant.id()));
|
|
}
|
|
|
|
bool PpmHandler::createGroundVehicle(const ParticipantManagement::Participant &participant)
|
|
{
|
|
const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id()));
|
|
return m_ngsHandler->ngsConnector()->addGroundVehicle(pi, currentVulnerabilityState(participant.id()));
|
|
}
|
|
|
|
bool PpmHandler::createAircraft(const ParticipantManagement::Participant &participant)
|
|
{
|
|
const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id()));
|
|
return m_ngsHandler->ngsConnector()->addLongBowApache(pi, currentVulnerabilityState(participant.id()));
|
|
}
|
|
|
|
TypeStruct PpmHandler::getTypestruct(int typeId)
|
|
{
|
|
dds::core::vector<rti::core::int64> disEntities = getParticipantType(typeId).disEntities();
|
|
if (disEntities.size())
|
|
return TypeStruct::fromDisInt(disEntities.at(0)); // First is relevant for sending
|
|
|
|
return TypeStruct();
|
|
}
|
|
|
|
ParticipantManagement::Type PpmHandler::getParticipantType(int typeId)
|
|
{
|
|
auto it = m_types.constFind(typeId);
|
|
if (it == m_types.constEnd())
|
|
{
|
|
m_dtcPpm->waitForHistoricalDataType();
|
|
m_types = m_dtcPpm->types();
|
|
it = m_types.constFind(typeId);
|
|
if (it == m_types.constEnd())
|
|
return ParticipantManagement::Type();
|
|
}
|
|
return it.value();
|
|
}
|
|
|
|
ProjectDataManagement::VulnerabilityState PpmHandler::currentVulnerabilityState(int participantId) const
|
|
{
|
|
ProjectDataManagement::VulnerabilityState ts;
|
|
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
{
|
|
const auto &sh = itPartData.value().stateHistory();
|
|
if (sh.size() != 0)
|
|
{
|
|
size_t idxCurrent = 0;
|
|
for (size_t i = 1; i < sh.size(); ++i)
|
|
{
|
|
if (sh.at(idxCurrent).stateTime() < sh.at(i).stateTime())
|
|
idxCurrent = i;
|
|
}
|
|
ts = sh.at(idxCurrent).vulnerabilityState();
|
|
return ts;
|
|
}
|
|
}
|
|
ts = ProjectDataManagement::VulnerabilityState_def::TemporarySeverance;
|
|
return ts;
|
|
}
|
|
|
|
ParticipantManagement::StateInformation PpmHandler::currentParticipantStateInformation(int participantId) const
|
|
{
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
return currentParticipantStateInformation(itPartData.value());
|
|
return ParticipantManagement::StateInformation();
|
|
}
|
|
|
|
ParticipantManagement::StateInformation PpmHandler::currentParticipantStateInformation(const ParticipantManagement::DynamicParticipantData &data)
|
|
{
|
|
const auto &sh = data.stateHistory();
|
|
if (sh.size() == 0)
|
|
return ParticipantManagement::StateInformation();
|
|
|
|
size_t idxCurrent = 0;
|
|
for (size_t i = 1; i < sh.size(); ++i)
|
|
{
|
|
if (sh.at(idxCurrent).stateTime() < sh.at(i).stateTime())
|
|
idxCurrent = i;
|
|
}
|
|
return sh.at(idxCurrent);
|
|
}
|
|
|
|
dds::core::vector<ParticipantManagement::GearInformation> PpmHandler::currentParticipantGearInformation(int participantId) const
|
|
{
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
return itPartData.value().gear();
|
|
return dds::core::vector<ParticipantManagement::GearInformation>();
|
|
}
|
|
|
|
dds::core::vector<ParticipantManagement::ManipulationInformation> PpmHandler::currentParticipantManipulationInformation(int participantId) const
|
|
{
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
return itPartData.value().manipulation();
|
|
return dds::core::vector<ParticipantManagement::ManipulationInformation>();
|
|
}
|
|
|
|
ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromId(int chargeTypeId)
|
|
{
|
|
auto it = m_chargeTypes.constFind(chargeTypeId);
|
|
if (it == m_chargeTypes.constEnd() && m_dtcPdm)
|
|
{
|
|
m_dtcPdm->waitForHistoricalDataChargeType();
|
|
m_chargeTypes = m_dtcPdm->chargeTypes();
|
|
it = m_chargeTypes.constFind(chargeTypeId);
|
|
}
|
|
return (it == m_chargeTypes.constEnd()) ? ProjectDataManagement::ChargeType() : it.value();
|
|
}
|
|
|
|
ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromDisEntity(const std::string &disEntity)
|
|
{
|
|
if (m_chargeTypes.isEmpty() && m_dtcPdm)
|
|
{
|
|
m_dtcPdm->waitForHistoricalDataChargeType();
|
|
m_chargeTypes = m_dtcPdm->chargeTypes();
|
|
}
|
|
|
|
for (const auto &item : qAsConst(m_chargeTypes))
|
|
{
|
|
if (item.disEntity() == disEntity)
|
|
return item;
|
|
}
|
|
return ProjectDataManagement::ChargeType();
|
|
}
|
|
|
|
ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromTasCodeDirect(int32_t tasCode)
|
|
{
|
|
if (m_chargeTypes.isEmpty() && m_dtcPdm)
|
|
{
|
|
m_dtcPdm->waitForHistoricalDataChargeType();
|
|
m_chargeTypes = m_dtcPdm->chargeTypes();
|
|
}
|
|
|
|
for (const auto &item : qAsConst(m_chargeTypes))
|
|
{
|
|
if (item.legacyId() == tasCode)
|
|
return item;
|
|
}
|
|
return ProjectDataManagement::ChargeType();
|
|
}
|
|
|
|
int PpmHandler::gearTypeIdFromChargeTypeId(int chargeTypeId)
|
|
{
|
|
if (m_gearTypeChargeTypes.isEmpty() && m_dtcPdm)
|
|
{
|
|
m_dtcPdm->waitForHistoricalDataGearTypeChargeType();
|
|
m_gearTypeChargeTypes = m_dtcPdm->gearTypeChargeTypes();
|
|
}
|
|
|
|
int gearTypeId = 999999999;
|
|
for (const auto &item : qAsConst(m_gearTypeChargeTypes))
|
|
{
|
|
if (item.chargeTypeId() == chargeTypeId)
|
|
if (item.gearTypeId() < gearTypeId)
|
|
gearTypeId = item.gearTypeId();
|
|
}
|
|
if (gearTypeId == 999999999)
|
|
return 0;
|
|
return gearTypeId;
|
|
}
|
|
|
|
|
|
rpr2::ForceIdentifierEnum8::ET PpmHandler::getRprForceIdentifierFromPpmForceIdentifier(const ParticipantManagement::HlaForceIdentifierEnum& ppmForceIdentifier) const
|
|
{
|
|
rpr2::ForceIdentifierEnum8::ET eqfi = rpr2::ForceIdentifierEnum8::Other;
|
|
switch (ppmForceIdentifier.underlying()) {
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_1:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_2:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_2;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_3:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_3;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_4:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_4;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_5:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_5;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_6:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_6;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_7:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_7;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_8:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_8;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_9:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_9;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_10:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Friendly_10;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_1:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_2:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_2;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_3:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_3;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_4:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_4;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_5:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_5;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_6:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_6;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_7:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_7;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_8:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_8;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_9:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_9;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_10:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Opposing_10;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_1:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_2:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_2;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_3:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_3;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_4:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_4;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_5:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_5;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_6:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_6;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_7:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_7;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_8:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_8;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_9:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_9;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_10:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Neutral_10;
|
|
break;
|
|
case ParticipantManagement::HlaForceIdentifierEnum_def::Other:
|
|
eqfi = rpr2::ForceIdentifierEnum8::Other;
|
|
break;
|
|
}
|
|
return eqfi;
|
|
}
|
|
|
|
int PpmHandler::partyIdFromForceIdentifier(rpr2::ForceIdentifierEnum8::ET fi)
|
|
{
|
|
if (m_partyData.isEmpty() && m_dtcPpm)
|
|
{
|
|
m_dtcPpm->waitForHistoricalDataParty();
|
|
m_partyData = m_dtcPpm->partys();
|
|
}
|
|
|
|
for (const ParticipantManagement::Party &item : qAsConst(m_partyData))
|
|
{
|
|
if (fi == getRprForceIdentifierFromPpmForceIdentifier(item.hlaForceIdentifier()))
|
|
return item.id();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
rpr2::ForceIdentifierEnum8::ET PpmHandler::forceIdentifierFromPartyId(int partyId)
|
|
{
|
|
if (m_partyData.isEmpty() && m_dtcPpm)
|
|
{
|
|
m_dtcPpm->waitForHistoricalDataParty();
|
|
m_partyData = m_dtcPpm->partys();
|
|
}
|
|
|
|
if (!m_partyData.contains(partyId))
|
|
return rpr2::ForceIdentifierEnum8::Other;
|
|
|
|
return getRprForceIdentifierFromPpmForceIdentifier(m_partyData[partyId].hlaForceIdentifier());
|
|
}
|
|
|
|
void PpmHandler::onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
m_requestHelper->requestReply(replyObject);
|
|
}
|
|
|
|
void PpmHandler::onDemandInitReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
m_requestHelper->requestReply(reply);
|
|
}
|
|
|
|
void PpmHandler::onDemandVulnerabilityStateChangeReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
m_requestHelper->requestReply(reply);
|
|
}
|
|
|
|
void PpmHandler::onSendCesHitInformationReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
m_requestHelper->requestReply(reply);
|
|
}
|
|
|
|
ParticipantPosition PpmHandler::getParticipantPosition(int participantId) const
|
|
{
|
|
auto itPartPos = m_partPosData.find(participantId);
|
|
if (itPartPos == m_partPosData.end())
|
|
return ParticipantPosition();
|
|
|
|
ParticipantPosition pp(itPartPos.value().pos());
|
|
pp.msec = itPartPos.value().sampleTime();
|
|
|
|
return pp;
|
|
}
|
|
|
|
void PpmHandler::onParticipantHit(const GuezHitStruct &hitStruct)
|
|
{
|
|
const auto ct = chargeTypeFromDisEntity(hitStruct.originatorChargeTypeEtsString.toStdString());
|
|
|
|
TrainingAreaBase::TabPosition pos;
|
|
pos.position(hitStruct.position);
|
|
pos.reportingSource(Core::PositionReportingSource_def::External);
|
|
|
|
TrainingAreaBase::EquipmentState es;
|
|
es.equipmentNumber(hitStruct.targetId);
|
|
es.originatorChargeTypeId(ct.id());
|
|
if (hitStruct.originatorType.underlying() == ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation)
|
|
{
|
|
int aesItemId = 0;
|
|
if (m_dtcAes->aesItemIdFromExternalId(hitStruct.originatorId, aesItemId) == AreaEffectSimulation::AesType_def::AtUnknown)
|
|
es.originatorId(hitStruct.originatorId % 10); // Not found, therefore it is our AesItem that is sent with (AesItemId * 10)
|
|
else
|
|
es.originatorId(aesItemId);
|
|
}
|
|
else
|
|
{
|
|
es.originatorId(hitStruct.originatorId);
|
|
}
|
|
es.originatorType(hitStruct.originatorType);
|
|
es.sampleTime(hitStruct.sampleTime);
|
|
es.vulnerabilityBits(hitStruct.vulnerabilityBits);
|
|
es.vulnerabilityKindId(hitStruct.vulnerabilityKind);
|
|
es.vulnerabilityState(hitStruct.vulnerabilityState);
|
|
if (!qIsNull(hitStruct.position.lat()) || !qIsNull(hitStruct.position.lon()))
|
|
es.position(pos);
|
|
m_dtsTab->publish(es);
|
|
// Damage Model recognizes change of Manipulation for itself and calls the Slot all by itself.
|
|
// onManipulationChanged(hitStruct.targetId, hitStruct.vulnerabilityBits & rpr2::TotalStatusEnum32::Manipulation, es.sampleTime());
|
|
}
|
|
|
|
void PpmHandler::onParticipantInit(int eqNo, bool resetManipulation, bool resupplyAmmo, bool resetVulnerabilityState)
|
|
{
|
|
TrainingAreaBase::DemandInitRequest dir;
|
|
dir.equipmentNumbers().push_back(eqNo);
|
|
dir.requestId(1);
|
|
dir.resetManipulation(resetManipulation);
|
|
dir.restockCharges(resupplyAmmo);
|
|
dir.resetVulnerabilityState(resetVulnerabilityState);
|
|
|
|
m_requestHelper->startSingleRequest([this, dir]()
|
|
{
|
|
return m_ftcTab->demandInitRequest(dir, this);
|
|
});
|
|
|
|
}
|
|
|
|
void PpmHandler::onParticipantCesHit(const TrainingAreaBase::SendCesHitInformation &request)
|
|
{
|
|
m_ftcTab->sendCesHitInformationRequest(request, this);
|
|
}
|
|
|
|
void PpmHandler::onLaserDesignation(const TrainingAreaBase::LaserDesignation &request)
|
|
{
|
|
m_dtsTab->publish(request);
|
|
}
|
|
|
|
void PpmHandler::onWeaponFire(const TrainingAreaBase::EquipmentGearEvent &event)
|
|
{
|
|
m_dtsTab->publish(event);
|
|
}
|
|
|
|
void PpmHandler::onGearChargeState(const TrainingAreaBase::EquipmentGearChargeState &event)
|
|
{
|
|
m_dtsTab->publish(event);
|
|
}
|
|
|
|
void PpmHandler::onGearAssignment(const TrainingAreaBase::EquipmentGearAssignment &event)
|
|
{
|
|
m_dtsTab->publish(event);
|
|
}
|
|
|
|
void PpmHandler::onEquipmentState(const TrainingAreaBase::EquipmentState &event)
|
|
{
|
|
m_dtsTab->publish(event);
|
|
}
|
|
|
|
bool PpmHandler::onExconEngagement(int eqNo, const ProjectDataManagement::VulnerabilityState &state)
|
|
{
|
|
if (state != ProjectDataManagement::VulnerabilityState_def::CombatReady)
|
|
{
|
|
TrainingAreaBase::DemandVulnerabilityStateChangeRequest req;
|
|
req.equipmentNumbers().push_back(eqNo);
|
|
req.requestId(1); // irrelevant
|
|
req.vulnerabilityState(state);
|
|
|
|
return m_requestHelper->startSingleRequest([this, req]()
|
|
{
|
|
return m_ftcTab->demandVulnerabilityStateChangeRequest(req, this);
|
|
});
|
|
}
|
|
|
|
TrainingAreaBase::DemandInitRequest req;
|
|
req.equipmentNumbers().push_back(eqNo);
|
|
req.resetVulnerabilityState(true);
|
|
|
|
return m_requestHelper->startSingleRequest([this, req]()
|
|
{
|
|
return m_ftcTab->demandInitRequest(req, this);
|
|
});
|
|
}
|
|
|
|
} // namespace HighLevelArchitecture
|