/** * @RDE_HEADER@ * AES Function Topic Client test executable * $Id$ * $HeadURL$ * $Author$ */ #include "aes_test_explosion_cluster.h" #include #include #include #include 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(), // 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(), dds::core::optional(), dds::core::optional()), 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(), dds::core::optional(), dds::core::optional()), 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(), dds::core::optional(), dds::core::optional()), 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(), dds::core::optional(), dds::core::optional()), 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(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; }); }