Files
qt5-legatus-legacy/Lts/Services/AreaEffectSimulation/ModuleTests/aes_test_explosion_cluster.cpp
T
2026-08-13 18:33:10 +02:00

480 lines
15 KiB
C++
Executable File

/**
* @RDE_HEADER@
* AES Function Topic Client test executable
* $Id$
* $HeadURL$
* $Author$
*/
#include "aes_test_explosion_cluster.h"
#include <ProjectDataManagement/pdm.hpp>
#include <QCoreApplication>
#include <QTimer>
#include <QTest>
namespace AreaEffectSimulation
{
// must be in pdm.pdm_charge_type
static const int s_ChargeTypeId1 = 371;
static const int s_ChargeTypeId2 = 372;
static const int s_IgniterTypeProximity = 101;
static const int s_IgniterTypeImpact = 102;
TestExplosionCluster::TestExplosionCluster(QObject *parent)
: TestBase("Test.ExplosionCluster", parent)
{}
bool TestExplosionCluster::init(int domainId, int exerciseId, int testId)
{
if (!TestBase::init(domainId, exerciseId, testId))
return false;
m_dtc->waitForHistoricalDataExplosionCluster();
m_ecData.id(-1);
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionClusterChanged,
this, &TestExplosionCluster::explosionClusterChanged);
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
this, &TestExplosionCluster::triggeredImpactsChanged);
return true;
}
bool TestExplosionCluster::checkBaseData(const AreaEffectSimulation::ExplosionCluster &a,
const AreaEffectSimulation::ExplosionCluster &b) const
{
if (!checkAesItem(a, b))
return false;
if (a.area() != b.area())
{
WARNING_LOG(m_logger) << "area does not match: " << a.area() << " - " << b.area();
return false;
}
return true;
}
void TestExplosionCluster::tryCreateExplosionCluster()
{
INFO_LOG(m_logger) << "tryCreateExplosionCluster start";
m_ecData = AreaEffectSimulation::ExplosionCluster();
AreaEffectSimulation::ExplosionCluster eaData;
eaData.id(0);
eaData.effectStart((time(nullptr) + 30) * 1000); // msec
QString name(QStringLiteral("ec__"));
name += QString::number(eaData.effectStart().get());
eaData.name(name.toStdString());
eaData.effectDuration(10000); // 10 seconds
eaData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
eaData.chargeStruct().igniterTypeId(s_IgniterTypeImpact);
// 32 U MD 93860 79903 -> 0.155484041, 0.92622146
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202560, 0.91611), 200, 50, 20)); // width, height, rotation
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202561, 0.916111), 200, 50, 20)); // width, height, rotation
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916112), 200, 50, 20)); // width, height, rotation
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202564, 0.916112), 200, 50, 20)); // width, height, rotation
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916115), 200, 50, 20)); // width, height, rotation
eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916114), 30, 20, 20)); // width, height, rotation
eaData.mhPoints({{0.2025611, 0.9161111}, {0.2025611, 0.9161111}, {0.2025611, 0.9161111}}); // 3
eaData.partyId(3);
eaData.participantId(5);
eaData.externalId(0);
INFO_LOG(m_logger) << "trying to send explosionClusterCreateRequest()";
m_replyError = false;
m_bExpectedFailure = true;
m_bIsCreatedRequest = true;
int igniterTypeId = s_IgniterTypeImpact;
if ((m_testId >= 0) && (m_testId <= 2) )
igniterTypeId = m_testId;
INFO_LOG(m_logger) << "m_testId " << m_testId << ", igniterType = " << igniterTypeId;
const std::string& properties = "{}";
if (!m_ftc->explosionClusterModifyRequest(
ExplosionClusterModifyRequest(
0,
eaData.name(),
eaData.element(),
eaData.effectStart(),
eaData.effectDuration(),
eaData.effectSourceId(),
eaData.area(),
AreaEffectSimulation::AesExplosionGeometry_def::EgArea,
0, // zog
eaData.mhPoints().size(), // mhpCount;
dds::core::optional<double>(), // mhpRotation for ExplosionClusterOcModify only
3, // impactCount
{ 12345, // eaData.chargeTypeId(),
igniterTypeId, // eaData.igniterTypeId(),
0 // eaData.igniterFunctionId()
},
3, // firePurpose 3=Blenden mit Wirkung
// 25, // firing_elevation_angle
123, // peakHeight,
10 * 1000, // flightDuration [msec],
eaData.partyId(),
eaData.participantId(),
{}, // esmParticipantIds
eaData.externalId(),
-1, // eaData.launchVelocity(),
-1, // eaData.launchAngleDeg(),
-1, // eaData.dropAngle(),
-1, // eaData.tapTime(), // msec since epoch
-1, // eaData.lcAttack(), // fka lcPrf
-1, // eaData.lcTermination(),
-1, // eaData.cloudBase(), // Wolkenuntergrenze
eaData.effectMarkingInTa(),
properties),
this))
{
ERROR_LOG(m_logger) << "Error during explosionClusterCreateRequest()";
failExit();
return;
}
// since the chargeTypeId is not valid, we should get an error
if (!waitForData([this]() { return m_replyError == true; }))
{
ERROR_LOG(m_logger) << "Error creating area explosion object (try with error)";
failExit();
return;
}
failExit();
/*
// now with correct charge type
m_bExpectedFailure = false;
m_expectedAesId = -1;
eaData.chargeTypeId(s_ChargeTypeId1);
m_bIsCreatedRequest = true;
if (!m_ftc->explosionClusterModifyRequest(
ExplosionClusterModifyRequest(
0,
eaData.name(),
eaData.effectStart(),
eaData.effectDuration(),
eaData.chargeTypeId(),
eaData.area(),
eaData.partyId(),
eaData.participantId(),
1, // eaData.cannonCount(),
1, // eaData.cannonRounds(),
123,// eaData.fireRequestTime(),
// eaData.altitude(),
// eaData.purpose(),
// eaData.effectMarkingInTa(),
eaData.externalId()),
this))
{
ERROR_LOG(m_logger) << "Error during explosionClusterCreateRequest()";
failExit();
return;
}
if (!waitForData([this]() { return m_ecData.id() == m_expectedAesId; }))
{
ERROR_LOG(m_logger) << "Error creating area explosion object";
failExit();
return;
}
if (!checkBaseData(m_ecData, eaData))
{
ERROR_LOG(m_logger) << "Creation data does not match published data";
failExit();
return;
}
// QTimer::singleShot(0, this, &TestExplosionCluster::tryModifyExplosionCluster);
INFO_LOG(m_logger) << "tryCreateExplosionCluster successful";
*/
}
/*
void TestExplosionCluster::tryModifyExplosionCluster()
{
INFO_LOG(m_logger) << "tryModifyExplosionCluster start";
m_ecData.name("af2");
m_ecData.effectStart(m_ecData.effectStart().get() + 3000);
m_ecData.effectDuration(9000); // 9 sec
m_ecData.chargeTypeId(s_ChargeTypeId2);
// 32 U MD 93860 79903 -> 0.155484041, 0.92622146
m_ecData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.155484041, 0.92622146), 50, 60, 70));
waitForData
m_ecData.partyId(3);
m_ecData.participantId(5);
// m_ecData.cannonCount(2);
// m_ecData.cannonRounds(2);
m_ecData.effectMarkingInTa(true);
const AreaEffectSimulation::ExplosionCluster eaData(m_ecData);
m_ecData = AreaEffectSimulation::ExplosionCluster();
m_ecData.id(eaData.id());
m_bIsCreatedRequest = false;
if (!m_ftc->explosionClusterModifyRequest(
ExplosionClusterModifyRequest(
eaData.id(),
eaData.name(),
eaData.effectStart(),
eaData.effectDuration(),
eaData.chargeTypeId(),
eaData.area(),
eaData.partyId(),
eaData.participantId(),
1,// eaData.cannonCount(),
1, // eaData.cannonRounds(),
123,// eaData.fireRequestTime(),
123,// eaData.fireRequestTime(),
eaData.subAreaCount(),
// eaData.altitude(),
// eaData.purpose(),
// eaData.effectMarkingInTa(),
eaData.externalId()),
this))
{
ERROR_LOG(m_logger) << "Error requesting modify data";
failExit();
return;
}
if (!waitForData([this]() { return m_ecData.chargeTypeId() == s_ChargeTypeId2; }))
{
ERROR_LOG(m_logger) << "Error updating area explosion object";
failExit();
return;
}
if (!checkBaseData(m_ecData, eaData))
{
ERROR_LOG(m_logger) << "Modify data does not match published data";
failExit();
return;
}
QTimer::singleShot(0, this, &TestExplosionCluster::tryWaitForActivationExplosionCluster);
INFO_LOG(m_logger) << "tryModifyExplosionCluster successful";
}
*/
void TestExplosionCluster::tryWaitForActivationExplosionCluster()
{
INFO_LOG(m_logger) << "tryWaitForActivationExplosionCluster start";
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
{
DEBUG_LOG(m_logger) << "Effect State = " << m_ecData.effectStateId();
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
failExit();
return;
}
QTimer::singleShot(0, this, &TestExplosionCluster::tryPauseResumeExplosionCluster);
INFO_LOG(m_logger) << "tryWaitForActivationExplosionCluster end";
}
void TestExplosionCluster::tryPauseResumeExplosionCluster()
{
INFO_LOG(m_logger) << "tryPauseResumeExplosionCluster start";
// try to resume but is already active -> expected error
m_replyError = false;
m_bExpectedFailure = true;
if (!m_ftc->explosionClusterPauseResumeRequest(
ExplosionClusterPauseResumeRequest(
m_ecData.id(),
true,
dds::core::optional<rti::core::int64>(),
dds::core::optional<int32_t>(),
dds::core::optional<int32_t>()),
this))
{
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(true)";
failExit();
return;
}
if (!waitForData([this]() { return m_replyError == true; }))
{
ERROR_LOG(m_logger) << "Error waiting for reply error while switching to pause of area explosion";
failExit();
return;
}
// and now pause
m_bExpectedFailure = false;
if (!m_ftc->explosionClusterPauseResumeRequest(
ExplosionClusterPauseResumeRequest(
m_ecData.id(),
false,
dds::core::optional<rti::core::int64>(),
dds::core::optional<int32_t>(),
dds::core::optional<int32_t>()),
this))
{
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(false)";
failExit();
return;
}
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsPaused; }))
{
ERROR_LOG(m_logger) << "Error while waiting for pause of area explosion";
failExit();
return;
}
// pause again -> expected error
m_replyError = false;
m_bExpectedFailure = true;
if (!m_ftc->explosionClusterPauseResumeRequest(
ExplosionClusterPauseResumeRequest(
m_ecData.id(),
false,
dds::core::optional<rti::core::int64>(),
dds::core::optional<int32_t>(),
dds::core::optional<int32_t>()),
this))
{
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(false)";
failExit();
return;
}
if (!waitForData([this]() { return m_replyError == true; }))
{
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
failExit();
return;
}
// and resume execution
m_bExpectedFailure = false;
if (!m_ftc->explosionClusterPauseResumeRequest(
ExplosionClusterPauseResumeRequest(
m_ecData.id(),
true,
dds::core::optional<rti::core::int64>(),
dds::core::optional<int32_t>(),
dds::core::optional<int32_t>()),
this))
{
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(true)";
failExit();
return;
}
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
{
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
failExit();
return;
}
INFO_LOG(m_logger) << "tryPauseResumeExplosionCluster end";
QTimer::singleShot(0, this, &TestExplosionCluster::checkTriggeredExplosions);
}
void TestExplosionCluster::checkTriggeredExplosions()
{
INFO_LOG(m_logger) << "checkTriggeredExplosions start";
// first we should wait for Activation
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
{
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
failExit();
return;
}
// attn: msb is bit 7
checkTriggeredExplosionsHelper(0x70); // 0b01110000
checkTriggeredExplosionsHelper(0x30); // 0b00110000
checkTriggeredExplosionsHelper(0x10); // 0b00010000
checkTriggeredExplosionsHelper(0x00); // 0b00000000
// last step: wait for expiry
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired; }))
{
ERROR_LOG(m_logger) << "Error while waiting for expiring of area explosion";
failExit();
return;
}
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
INFO_LOG(m_logger) << "checkTriggeredExplosions end";
}
void TestExplosionCluster::checkTriggeredExplosionsHelper(int bitfield)
{
// since we've 9 seconds duration and the first hit is at 0, every 2.5sec should be a new TriggeredExplosions telegram
QElapsedTimer et;
et.start();
if (!waitForData([this, bitfield]() { return m_tiData.bitfield()[0] == bitfield; }))
{
ERROR_LOG(m_logger) << "Error while waiting for triggered explosison telegram with bitfield 0x" << QByteArray::number(bitfield, 16);
failExit();
return;
}
// 500ms delay through dds allowed :)
if (et.elapsed() > 3000)
{
ERROR_LOG(m_logger) << "Something went wrong - waited more than 3 seconds for next impact trigger";
failExit();
}
}
void TestExplosionCluster::explosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType)
{
if (m_ecData.id() == -1)
return;
onAesChanged(data, modType, m_ecData);
}
void TestExplosionCluster::triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
{
if (m_ecData.id() != data.aesItemId() || modType == DataModification::eRemoved)
return;
INFO_LOG(m_logger) << "Got TriggeredImpacts data - bitfield[0] = 0x" << QByteArray::number(static_cast<int>(data.bitfield()[0]), 16);
m_tiData = data;
}
void TestExplosionCluster::onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject)
{
if (m_bIsCreatedRequest)
onAesCreateReply(replyObject);
else
onAesModifyReply(replyObject);
}
void TestExplosionCluster::onExplosionClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject)
{
INFO_LOG(m_logger) << "Got pause/resume reply explosion area with id " << replyObject.id()
<< ", error = " << replyObject.error()
<< " and errorString = '" << replyObject.translated() << "'";
m_replyError = replyObject.error();
if (m_replyError && !m_bExpectedFailure)
ERROR_LOG(m_logger) << "Got pause/resume reply explosion area error: " << replyObject();
}
} // namespace AreaEffectSimulation
// ------------------------------------------------------------------
int main(int argc, char **argv)
{
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestExplosionCluster; });
}