Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+297
View File
@@ -0,0 +1,297 @@
/**
* Handle an impact from nasat aircraft and create single explosion
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-30
*/
#include "handler_nasat_impact.h"
#include "initialization.h"
#include "dds_handler.h"
#include "handler_participant.h"
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsCoordTrans/lts_coord_trans.h>
// #define TRIGGER_DUMMY_IMPACT
#ifdef TRIGGER_DUMMY_IMPACT
# include <QTimer>
#endif // TRIGGER_DUMMY_IMPACT
namespace GuezNasat
{
HandlerNasatImpact::HandlerNasatImpact(Initialization *mainHandler)
: AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler()
, m_mainHandler(mainHandler)
, m_logger(getLogger("HandlerNasatImpact"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
auto pdmDtc = m_mainHandler->dds()->pdmDtc();
connect(pdmDtc.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged,
this, &HandlerNasatImpact::onChargeTypeChanged);
pdmDtc->chargeTypes([this](const ProjectDataManagement::ChargeType &ct) { onChargeTypeChanged(ct);});
#ifdef TRIGGER_DUMMY_IMPACT
FATAL_LOG(m_logger) << LOGFUNCTION << " prepare singleShot...";
QTimer *timer = new QTimer;
timer->setInterval(30000);
connect(timer, &QTimer::timeout, [this] () {
FATAL_LOG(m_logger) << LOGFUNCTION << " singleShot...";
NasatWeaponRelease wr;
wr.aircraftId = 1;
GeoPosition2D geoPos;
geoPos.lon = 11.56; // degree
geoPos.lat = 52.46; // degree
wr.impactPosition = geoPos;
wr.flightTime = 5;
wr.munition = Munition::MSL_AGM_114K; // MSL_AGM_114K : 29 -> 499
// wr.munition = Munition::Missile_MK_24; // Missile_MK_24: 41 -> 511
wr.fuseType = FuseType::Instant;
wr.releaseMode = ReleaseMode::Undefined;
this->nasatWeaponRelease(wr);
FATAL_LOG(m_logger) << LOGFUNCTION << " singleShot...DONE";
});
timer->start();
#endif // TRIGGER_DUMMY_IMPACT
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void HandlerNasatImpact::onAirSupportImpactModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
WARNING_LOG(m_logger) << "Could not create single explosion for nasat impact: " << reply();
#ifdef NLDEVCTRL_844
testing.replyCounter++;
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this
<< " - replyCounter=" << testing.replyCounter;
#else
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this;
#endif // NLDEVCTRL_844
}
void HandlerNasatImpact::onExplosionClusterModifyReply(const Core::FunctionReplyObject &reply)
{
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this
<< ", reply.error()=" << reply.error();
if (reply.error())
ERROR_LOG(m_logger) << "onExplosionClusterModifyReply: Got reply: " << reply() << "(id=" << reply.id() << ")"
<< " '" << reply.translated() << "'";
}
void HandlerNasatImpact::nasatWeaponRelease(const GuezNasat::NasatWeaponRelease &weaponRelease)
{
const Core::GeoPosition geoPos(weaponRelease.impactPosition.lon * LtsCoordTrans::deg2rad(),
weaponRelease.impactPosition.lat * LtsCoordTrans::deg2rad(),
0); // z == 0? Ground... TODO
double tsWeaponRelease = weaponRelease.timestamp < 0 ? QDateTime::currentSecsSinceEpoch() : weaponRelease.timestamp;
// AES needs time to execute a) calculations of trajectory and b) intersections ('preStartTimer')
// add 5sec, an additional period of time:
tsWeaponRelease += 5;
qint64 impactTimeMsec = qRound64((tsWeaponRelease + weaponRelease.flightTime) * 1000);
qint64 weaponReleaseMsec = qRound64(weaponRelease.flightTime * 1000);
nasatImpact(weaponRelease.aircraftId, geoPos, weaponReleaseMsec, impactTimeMsec, static_cast<int>(weaponRelease.munition), weaponRelease.fuseType);
}
void HandlerNasatImpact::nasatImpact(int nasatId, const Core::GeoPosition &pos, qint64 flightTimeMsec, qint64 impactTimeMsec, int munitionCode, FuseType fuseType)
{
#ifdef NLDEVCTRL_844
static bool bEnable = true;
if (!bEnable)
return;
#endif // NLDEVCTRL_844
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId
<< ", pos=" << pos
<< ", flightTimeMsec = " << flightTimeMsec
<< ", impactTimeMsec = " << impactTimeMsec;
const auto participants = m_mainHandler->handlerParticipant()->participantsForNasatId(nasatId);
if (participants.isEmpty())
{
WARNING_LOG(m_logger) << "Can not find a valid participant for nasat aircraft with id " << nasatId;
return;
}
const int chargeTypeIdVal = chargeTypeFromMunitionCode(munitionCode);
if (chargeTypeIdVal < 0)
return;
const QDateTime dtNow = QDateTime::currentDateTime();
const qint64 tNow = dtNow.toMSecsSinceEpoch() + 5000; // 5s for Tetra - really needed?
AreaEffectSimulation::ExplosionClusterSingleEffectOnlyRequest ecReq;
ecReq.id(0);
ecReq.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow); // msec
ecReq.name(QStringLiteral("NASAT_%1_%2_%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
ecReq.element(ecReq.name());
ecReq.impactPosition(Core::GeoPosition2D(pos.lon(), pos.lat()));
ecReq.chargeTypeId(chargeTypeIdVal);
// ecReq.externalId(815);
// ecReq.flightTime(flightTime);
if (m_logger.isDebugEnabled())
{
const Core::GeoPosition &nasatPos = m_mainHandler->handlerParticipant()->nasatPosition(nasatId);
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId
<< ", pos=" << nasatPos
<< ", flightTimeMsec = " << flightTimeMsec
<< ", impactTimeMsec=" << impactTimeMsec;
}
AreaEffectSimulation::ExplosionClusterModifyRequest ecCommonModifyRequest;
ecCommonModifyRequest.id(0);
ecCommonModifyRequest.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow); // msec
ecCommonModifyRequest.effectDuration(1000);
ecCommonModifyRequest.effectSourceId(ProjectDataManagement::EffectSource::ES_Internal);
// charge and geometry:
ecCommonModifyRequest.explosionGeometry(AreaEffectSimulation::AesExplosionGeometry_def::EgPoint);
// ecCommonModifyRequest.zog(0);
ecCommonModifyRequest.chargeStruct().chargeTypeId(chargeTypeIdVal);
ecCommonModifyRequest.chargeStruct().igniterTypeId(fuseTypeToPdmIgniterType(fuseType));
ecCommonModifyRequest.area().cornerBottomLeft(Core::GeoPosition2D(pos.lon(), pos.lat()));
ecCommonModifyRequest.name(QStringLiteral("NASAT_%1_%2_%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
ecCommonModifyRequest.element(ecReq.name());
ecCommonModifyRequest.mhpCount(1);
ecCommonModifyRequest.impactCount(1);
// ecCommonModifyRequest.partyId(request.partyId());
// ecCommonModifyRequest.participantId(-1); // -1 -> avoid trajectory
ecCommonModifyRequest.flightDuration(flightTimeMsec); // request.flightDuration in msec
// AreaEffectSimulation::AirSupportImpactModifyRequest asi;
// asi.name(QStringLiteral("NASAT_a%1_m%2_t%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
// asi.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow);
// asi.chargeTypeId(chargeTypeFromMunitionCode(munitionCode));
// if (asi.chargeTypeId() < 0)
// return;
// asi.impactPosition(Core::GeoPosition2D(pos.lon(), pos.lat()));
// asi.flightTime(flightTime);
DEBUG_LOG(m_logger) << " Sending air support impact: number of participant= " << participants.size();
for (const NasatAircraftParticipantEx *nap : participants)
{
// asi.partyId(nap->partyId());
// asi.participantId(nap->participantId());
ecReq.partyId(nap->partyId());
ecCommonModifyRequest.partyId(nap->partyId());
ecCommonModifyRequest.participantId(nap->participantId());
// ecCommonModifyRequest.externalId(nap->participantId()); // externalId -> would be like like HLA and means no trajectory
int success = nap->publisher()->publish(ecCommonModifyRequest, this);
if (success)
DEBUG_LOG(m_logger) << "Sending air support impact create request: " << ecReq << " to exercise " << nap->exerciseId()
<< ", nap=" << nap->participant()
<< " -> success = " << success;
else
ERROR_LOG(m_logger) << "Error on Sending air support impact create request: " << ecReq << " to exercise " << nap->exerciseId()
<< ", nap=" << nap->participant()
<< " -> success = " << success;
#ifdef NLDEVCTRL_844
testing.requestCounter++;
INFO_LOG(m_logger) << " requestCounter = " << testing.requestCounter;
#endif // NLDEVCTRL_844
}
#ifdef NLDEVCTRL_844
bool bOk = (testing.requestCounter - testing.replyCounter) < 23;
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< ", replyCounter = " << testing.replyCounter;
if (!bOk)
{
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< " -> DISABLE";
bEnable = false;
abort();
}
if (testing.requestCounter > 70)
{
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< " -> RESTART";
exit(42); // trigger restart
}
#endif // NLDEVCTRL_844
}
void HandlerNasatImpact::onChargeTypeChanged(const ProjectDataManagement::ChargeType &ct)
{
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray::fromRawData(ct.properties().c_str(), ct.properties().size())));
const QJsonObject obj(doc.object());
if (!obj.contains(QLatin1String("nasatId")))
return;
int nasatId = obj.value(QLatin1String("nasatId")).toInt();
if (nasatId == 0)
{
WARNING_LOG(m_logger) << "Found charge with an invalid property 'nasatId', id: " << ct.id();
return;
}
m_chargeMapping.insert(nasatId, ct.id());
}
int HandlerNasatImpact::chargeTypeFromMunitionCode(int nasatChargeCode) const
{
auto it = m_chargeMapping.find(nasatChargeCode);
if (it != m_chargeMapping.end())
return it.value();
WARNING_LOG(m_logger) << "Got unmapped nasat charge code " << nasatChargeCode;
Q_ASSERT(false);
return -1;
}
int HandlerNasatImpact::fuseTypeToPdmIgniterType(FuseType fusetype) const
{
// return = igniterTypeId from table pdm_igniter_type
switch (fusetype) {
case FuseType::Instant:
return 102; // Impact Default
case FuseType::Delay:
return 103; // Delay Default
case GuezNasat::FuseType::AirBurst:
return 101; // Proxmimity Default
default:
return 102;
}
}
} // namespace GuezNasat