/** * Handle the single building instances * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-02-06 */ #include "building_control_handler.h" #include "building_process.h" #include "main_handler.h" #include #include #include #include #include #include namespace Buildings { BuildingControlHandler::BuildingControlHandler(MainHandler *mainHandler) : QObject() , Interface::Fts::SetBuildingStatesRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::SetBuildingContaminationStateRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::SetFortifyFactorRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::SendCesHitOnBuildingRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::SendCesHit3DonBuildingRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::TriggerBsmFlashRequestHandler(mainHandler->ddsHandler()->fts()) , Interface::Fts::SwitchRelayRequestHandler(mainHandler->ddsHandler()->fts()) , m_mainHandler(mainHandler) , m_logger(getLogger("BuildingControlHandler")) {} BuildingControlHandler::~BuildingControlHandler() { for (BuildingProcess *bldg : qAsConst(m_buildings)) { bldg->shutdown(); delete bldg; } m_buildings.clear(); } bool BuildingControlHandler::init() { DEBUG_LOG(m_logger)<<"BuildingControlHandler::init exerciseId="<exerciseId(); const QString bcuName = QStringLiteral("BuildingControlUnit"); m_bcuExecutableName = QStandardPaths::findExecutable(bcuName, { QCoreApplication::applicationDirPath()}); if (m_bcuExecutableName.isEmpty()) { WARNING_LOG(m_logger) << "Executable " << bcuName << " not found - can not start building control unit processes!"; return false; } if (m_mainHandler->exerciseId() > 0) { // Initialize RecordReplay to get initial participantPosition RecordReplayPlugin recordReplay; // no ddsconnector - we don't want to publish data here recordReplay.initDtc(nullptr, m_mainHandler->exerciseId()); NSqlQuery q(m_mainHandler->db()->database()); recordReplay.readHistoryStateAt(q, QDateTime::currentMSecsSinceEpoch()); // key is sampleTime -> multiMap const QMultiMap latestStates = recordReplay.getHistoryStateMap(); DEBUG_LOG(m_logger) << "Starting to read HistoryStatedata from record replay. Size: " << latestStates.size(); for (auto it = latestStates.begin(); it != latestStates.end(); ++it) { const Buildings::HistoryState &historyState = it.value(); if (!m_mainHandler->ismHandler()->isElementAssignedToExercise(historyState.mseId(),m_mainHandler->exerciseId() )) { DEBUG_LOG(m_logger)<<"[INIT] [recordReplay]>>>>>>> mseId=" << historyState.mseId() << " not in execise"; continue; } m_historyStates.insert(historyState.mseId(), historyState); DEBUG_LOG(m_logger)<<"[INIT] [recordReplay]>>>>>>> "<shutdown(); bldg->deleteLater(); m_buildings.erase(it); m_historyStates.remove(buildingId); } void BuildingControlHandler::onBuildingChanged(const BuildingInfo &buildingInfo, bool damageInit = false) { DEBUG_LOG(m_logger) << "onBuildingChanged damageInit=" << damageInit << " mseId=" << buildingInfo.mseId; auto it = m_buildings.find(buildingInfo.mseId); BuildingProcess *bldg = nullptr; if (it == m_buildings.end()) { bldg = new BuildingProcess(m_mainHandler, m_bcuExecutableName, buildingInfo, damageInit, this); DEBUG_LOG(m_logger) << "onBuildingChanged m_buildings.insert mseId=" << buildingInfo.mseId; m_buildings.insert(buildingInfo.mseId, bldg); bldg->newRelayInfos(m_relayInfos); bldg->start(); } else { bldg = it.value(); bldg->setBuildingInfo(buildingInfo); bldg->newRelayInfos(m_relayInfos); } Buildings::HistoryState historyState; if ( m_historyStates.contains(buildingInfo.mseId)) { historyState = m_historyStates.value(buildingInfo.mseId); DEBUG_LOG(m_logger) << "onBuildingChanged setHistoryState contains historyState.mseId=" << historyState.mseId() << " buildingInfo.mseId=" << buildingInfo.mseId; } else { historyState.mseId (buildingInfo.mseId); DEBUG_LOG(m_logger) << "onBuildingChanged setHistoryState insert historyState.mseId=" << historyState.mseId() << " buildingInfo.mseId=" << buildingInfo.mseId; m_historyStates.insert(historyState.mseId(), historyState); } DEBUG_LOG(m_logger) << "onBuildingChanged setHistoryState historyState.mseId=" << historyState.mseId() << " buildingInfo.mseId=" << buildingInfo.mseId; bldg->setHistoryState(m_historyStates.value(buildingInfo.mseId)); } void BuildingControlHandler::onSetBuildingContaminationStateRequest(const rti::core::SampleIdentity &cookie, const SetBuildingContaminationStateRequest &request) { DEBUG_LOG(m_logger) << "onSetBuildingContaminationStateRequest " << request; const Core::FunctionReplyObject fro = onSetBuildingContaminationStateRequestInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->setBuildingContaminationStateReply(cookie, fro); } void BuildingControlHandler::onSetBuildingStatesRequest(const rti::core::SampleIdentity &cookie, const SetBuildingStatesRequest &request) { DEBUG_LOG(m_logger) << "onSetBuildingStatesRequest " << request; const Core::FunctionReplyObject fro = onSetBuildingStatesRequestInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->setBuildingStatesReply(cookie, fro); } void BuildingControlHandler::onSetFortifyFactorRequest(const rti::core::SampleIdentity &cookie, const SetFortifyFactorRequest &request) { DEBUG_LOG(m_logger) << "onSetFortifyFactorRequest " << request; const Core::FunctionReplyObject fro = onSetFortifyFactorRequestInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->setFortifyFactorReply(cookie, fro); } void BuildingControlHandler::onSendCesHitOnBuildingRequest(const rti::core::SampleIdentity &cookie, const SendCesHitOnBuildingRequest &request) { DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingRequest " << request; const Core::FunctionReplyObject fro = onSendCesHitOnBuildingRequestInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->sendCesHitOnBuildingReply(cookie, fro); } void BuildingControlHandler::onSendCesHit3DonBuildingRequest(const rti::core::SampleIdentity &cookie, const SendCesHit3DonBuildingRequest &request) { DEBUG_LOG(m_logger) << "onSendCesHit3DonBuildingRequest " << request; const Core::FunctionReplyObject fro = onSendCesHit3DonBuildingRequestInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->sendCesHit3DonBuildingReply(cookie, fro); } void BuildingControlHandler::onTriggerBsmFlashRequest(const rti::core::SampleIdentity &cookie, const TriggerBsmFlashRequest &request) { DEBUG_LOG(m_logger) << "onTriggerBsmFlashRequest " << request; const Core::FunctionReplyObject fro = onTriggerBsmFlashInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->triggerBsmFlashReply(cookie, fro); } Core::FunctionReplyObject BuildingControlHandler::onSetBuildingContaminationStateRequestInternal(const SetBuildingContaminationStateRequest &data) { const auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); BuildingProcess *bldg = it.value(); if (!bldg->setContaminationState(data.buildingId(), data.contaminationState())) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not send contamination state to building control process.")); return Core::FunctionReplyObject(); } Core::FunctionReplyObject BuildingControlHandler::onSetBuildingStatesRequestInternal(const SetBuildingStatesRequest &data) { std::vector roomIds; // prefer std::vector here since building.roomIds() has also std::vector, so it´s easier for (const auto &building : data.buildings()) { const auto it = m_buildings.find(building.buildingId()); if (it == m_buildings.end()) return Core::FunctionReplyObject(building.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(building.buildingId()); BuildingProcess *bldg = it.value(); if (data.resetContamination().is_set()) { if (data.resetContamination().get() && !bldg->resetContaminationState()) return Core::FunctionReplyObject(building.buildingId(), tr_lts("dds", "reset contamination of building with id %1 failed.")).arg(building.buildingId()); } if (data.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::NoChange) continue; if (data.vulnerabilityState() != ProjectDataManagement::VulnerabilityState::CatastrophicKill && data.vulnerabilityState() != ProjectDataManagement::VulnerabilityState::CombatReady ) return Core::FunctionReplyObject(building.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(building.buildingId()); if (building.roomIds().is_set()) roomIds = building.roomIds().get(); if (!bldg->setVulnerabilityState(data.vulnerabilityState(), roomIds)) return Core::FunctionReplyObject(building.buildingId(), tr_lts("dds", "Can not send vulnerability state to building control process.")); } return Core::FunctionReplyObject(); } Core::FunctionReplyObject BuildingControlHandler::onSetFortifyFactorRequestInternal(const SetFortifyFactorRequest &data) { auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); BuildingProcess *bldg = it.value(); if (!bldg->setFortifyFactors(data.fortifyFactors())) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not send fortify factors to building control process.")); return Core::FunctionReplyObject(); } void BuildingControlHandler::setEffectStates(const int buildingId, const int assetId, const QByteArray &properties) { DEBUG_LOG(m_logger) << "BuildingControlHandler::setEffectStates" << " buildingId=" << buildingId << " assetId=" << assetId << " properties=" << properties; auto it = m_buildings.find(buildingId); if (it == m_buildings.end()) return; BuildingProcess *bldg = it.value(); if (bldg) bldg->setEffectStates( assetId, properties); } void BuildingControlHandler::onRelayInfoChanged(const AssetManagement::RelayInfo &info, const DataModification mod) { if (mod != DataModification::eRemoved) m_relayInfos.insert(info.id(), info); else m_relayInfos.remove(info.id()); for(auto *bldg : qAsConst(m_buildings)) bldg->newRelayInfos(m_relayInfos); } Core::FunctionReplyObject BuildingControlHandler::onSendCesHitOnBuildingRequestInternal(const SendCesHitOnBuildingRequest &data) { DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingRequestInternal"; auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) { DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingRequestInternal return"; return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); } BuildingProcess *bldg = it.value(); if (!bldg->sendCesHitOnBuilding(data.effectTime(), data.chargeTypeId(), data.destructiveFactor(), data.penetrationFactor(), data.aesId(), data.impactPosition(), QString::fromStdString(data.properties()))) { DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingRequestInternal return Can not send ces hit to building control process"; return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not send ces hit to building control process.")); } DEBUG_LOG(m_logger) << "FunctionReplyObject"; return Core::FunctionReplyObject(); } Core::FunctionReplyObject BuildingControlHandler::onSendCesHit3DonBuildingRequestInternal(const SendCesHit3DonBuildingRequest &data) { DEBUG_LOG(m_logger) << "onSendCesHit3DonBuildingRequestInternal"; auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) { DEBUG_LOG(m_logger) << "onSendCesHit3DonBuildingRequestInternal return"; return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); } BuildingProcess *bldg = it.value(); if (!bldg->sendCesHit3DonBuilding(data.effectTime(), data.chargeTypeId(), data.destructiveFactor(), data.penetrationFactor(), data.aesId(), data.impactPosition(), data.detonationLocation(), data.detonationDistance(), QString::fromStdString(data.properties()))) { DEBUG_LOG(m_logger) << "onSendCesHit3DonBuildingRequestInternal return Can not send ces hit to building control process"; return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not send ces hit to building control process.")); } DEBUG_LOG(m_logger) << "FunctionReplyObject"; return Core::FunctionReplyObject(); } Core::FunctionReplyObject BuildingControlHandler::onTriggerBsmFlashInternal(const TriggerBsmFlashRequest &data) { DEBUG_LOG(m_logger) << "onTriggerBsmFlashInternal"; { auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); BuildingProcess *bldg = it.value(); BuildingInfo buildingInfo= bldg->buildingInfo(); BsmInfo bsmInfo = buildingInfo.bsms.value(data.assetId()); DEBUG_LOG(m_logger) << " BuildingId=" << data.buildingId() << " assetId=" << bsmInfo.assetId << " hostname=" << bsmInfo.hostname; if (!bldg->triggerFlashlight(data)) { DEBUG_LOG(m_logger) << "onTriggerBsmFlashInternal return Can not send trigger flashlight to building control process"; return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not send trigger flashlight to building control process")); } } DEBUG_LOG(m_logger) << "FunctionReplyObject"; return Core::FunctionReplyObject(); } void BuildingControlHandler::onSwitchRelayRequest(const rti::core::SampleIdentity &cookie, const SwitchRelayRequest &request) { DEBUG_LOG(m_logger) << "SwitchRelayRequest " << request; // Request als Json-Telegramm an den entsprechenden Gebaeudeprozess wer websocket weiterleiten. const Core::FunctionReplyObject fro = onSwitchRelayInternal(request); if (fro.error()) WARNING_LOG(m_logger) << fro(); m_mainHandler->ddsHandler()->fts()->switchRelayReply(cookie, fro); } Core::FunctionReplyObject BuildingControlHandler::onSwitchRelayInternal(const SwitchRelayRequest &data) { DEBUG_LOG(m_logger) << "onSwitchRelayInternal " << data; auto it = m_buildings.find(data.buildingId()); if (it == m_buildings.end()) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Building with id %1 not found.")).arg(data.buildingId()); BuildingProcess *bldg = it.value(); if (!bldg->switchRelay(data)) return Core::FunctionReplyObject(data.buildingId(), tr_lts("dds", "Can not set relay to building control process.")); return Core::FunctionReplyObject(); } } // namespace Buildings