/** * Handler definition and state IED * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Dassow, SLEA, 2017-07-20 */ #include "handler_ied.h" #include "object_ied.h" #include "main_handler.h" #include "gim_db.h" #include #include #include #include #include #include namespace GuezIedManagement { HandlerIed::HandlerIed(MainHandler *mainHandler, const std::shared_ptr &ddsHandler, const std::shared_ptr &db, QObject *parent) : QObject(parent) , Interface::Fts::PairIedRequestHandler(ddsHandler->fts()) , m_mainHandler(mainHandler) , m_ddsHandler(ddsHandler) , m_tabDtc(nullptr) , m_ppmDtc(nullptr) , m_db(db) , m_logger(getLogger("HandlerIed")) {} HandlerIed::~HandlerIed() { qDeleteAll(m_iedObjMap); m_db = nullptr; m_tabDtc = nullptr; m_ppmDtc = nullptr; m_ddsHandler = nullptr; } bool HandlerIed::init() { // initialize PPM DTC m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->dds()); if (!m_ppmDtc->enableParticipantPosition()) { ERROR_LOG(m_logger) << "PPM DTC enableParticipantPosition() failed."; return false; } if (!m_ppmDtc->enableParticipant()) { ERROR_LOG(m_logger) << "PPM DTC enableParticipant() failed."; return false; } if (!m_ppmDtc->enableParty()) { ERROR_LOG(m_logger) << "PPM DTC enableParty() failed."; return false; } QVector dataVec; // read all Ieds from database if (!m_db->select(dataVec)) { ERROR_LOG(m_logger) << "Error reading data from database!"; return false; } // create Ied objects for (const Database::GimIed &data : qAsConst(dataVec)) { ObjectIed *ifs(new ObjectIed(m_ddsHandler, m_db, m_ppmDtc, this)); Core::FunctionReplyObject ret = ifs->createObject(data); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); return false; } m_iedObjMap.insert(ifs->getId(), ifs); } DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_iedObjMap.size(); // Initialize RecordReplay to get initial IedPosition RecordReplayPlugin recordReplay; // no ddsconnector - we don't want to publish data here recordReplay.initDtc(nullptr, m_mainHandler->exerciseId()); NSqlQuery q(m_db->database()); recordReplay.readIedPositionAt(q, QDateTime::currentMSecsSinceEpoch()); // key is sampleTime -> multiMap QMultiMap latestPositions = recordReplay.getIedPositionMap(); DEBUG_LOG(m_logger) << "Starting to read IED positions from record replay. Size: " << latestPositions.size(); for (auto it = latestPositions.begin(); it != latestPositions.end(); ++it) { const auto &pos = it.value(); ObjectIed *currentIed = m_iedObjMap.value(pos.id()); if (currentIed == nullptr) { INFO_LOG(m_logger) << "Got position for non existing IED-Id: " << pos.id(); continue; } DEBUG_LOG(m_logger) << "Setting position for IED-Id " << pos.id(); currentIed->setPosition(it.value()); } m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->dds()); if (!m_tabDtc->enableDefinitionIed() || !m_tabDtc->enableStateIed()) { ERROR_LOG(m_logger) << "Could not initialize TraininAreaBase data topic client"; return false; } connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::definitionIedChanged, this, &HandlerIed::onDefinitionIed); connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::stateIedChanged, this, &HandlerIed::onStateIed); return true; } static inline IedTacticalState toTacticalState(int tacticalState) { switch (tacticalState) { case 0: return IedTacticalState::NotActive; case 1: return IedTacticalState::Active; case 2: return IedTacticalState::Defused; case 3: return IedTacticalState::TriggeredBySwitch; case 4: return IedTacticalState::TriggeredByRemote; case 5: return IedTacticalState::TriggeredByLightBarrier; case 6: return IedTacticalState::TriggeredByTautWire; case 7: return IedTacticalState::TriggeredByControlDevice; case 255: break; default: Q_ASSERT(false); break; } return IedTacticalState::Unknown; } static void assignBaseData(const TrainingAreaBase::IedBaseData &inData, Database::GimIed &outData) { outData.equipmentNumber = inData.iedId(); outData.tacticalStateId = toTacticalState(inData.tacticalState()); outData.pyrotechnics = inData.statePyrotechnics(); outData.sampleTime = inData.sampleTime(); } void HandlerIed::onDefinitionIed(const TrainingAreaBase::DefinitionIed &data, DataModification modType) { if (modType != DataModification::eAdded && modType != DataModification::eModified) return; DEBUG_LOG(m_logger) << "onDefinitionIed: " << data; Database::GimIed newData; assignBaseData(data, newData); newData.typeId = static_cast(data.type()); newData.remoteTrigger = data.remoteTrigger(); newData.switchTrigger = data.switchTrigger(); newData.lightBarrierTrigger = data.lightBarrierTrigger(); newData.tautWireTrigger = data.tautWireTrigger(); newData.explosiveForce = data.explosiveForce(); if (m_ppmDtc->party(data.partyId()).id() > 0) newData.partyId = data.partyId(); // use party from telegram else newData.partyId = getPartyIdFromParticipantEquipmentNumber(data.equipmentNumber()); // use party from equipmentNumber newData.pairingStateId = static_cast(data.pairingState()); switch (newData.pairingStateId.underlying()) { case IedPairingState_def::PairedToParticipant: newData.pairedParticipantId.setValue(data.pairedId().get()); break; case IedPairingState_def::PairedToOps: newData.pairedOpsId.setValue(data.pairedId().get()); break; case IedPairingState_def::NotPaired: break; } // set symbol / sidc // Note: // Special: triggered Ied has seperate SIDC: // "M25D|CMPL|10014000001103000000"); // SIDC for IED (OHNE ZickZack) // "M25D|CMPL|10014000001103010000"); // SIDC for IED (MIT ZickZack) // ^ // | -> Therefore suppress Injury // handled at guez_ied_to_map.cpp and gim_info_dialog.cpp switch (newData.typeId.underlying()) { case IedType_def::SuicideIed: newData.symbol = QStringLiteral("AP6D|CMPL|10014000001103040000"); //SIDC for suicide bomber break; case IedType_def::IedSmallPyro: case IedType_def::IedBigPyro: newData.symbol = QStringLiteral("AP6D|CMPL|10014000001103000000"); // SIDC for IED (OHNE ZickZack) break; } // switch int id = getIdByEquipmentnumber(newData.equipmentNumber); if (m_iedObjMap.contains(id)) m_iedObjMap[id]->updateDefinition(newData); else { ObjectIed *ifs(new ObjectIed(m_ddsHandler, m_db, m_ppmDtc, this)); Core::FunctionReplyObject ret = ifs->createObject(newData); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); return; } m_iedObjMap.insert(ifs->getId(), ifs); auto it = m_orphanedStateIed.find(data.iedId()); if (it != m_orphanedStateIed.end()) { auto defState = it.value(); m_orphanedStateIed.erase(it); defState.tacticalState(data.tacticalState()); defState.statePyrotechnics(data.statePyrotechnics()); defState.sampleTime(data.sampleTime()); onStateIed(defState, DataModification::eAdded); } id = ifs->getId(); } m_iedObjMap[id]->setPosition(newData.sampleTime, Core::GeoPosition(data.position().lon(), data.position().lat(), 0)); } static inline IedError toIedError(int err) { switch (err) { case 0: return IedError::NoError; case 1: return IedError::DeviceMissing; } Q_ASSERT(false); return IedError::DeviceMissing; } void HandlerIed::onStateIed(const TrainingAreaBase::StateIed &data, DataModification modType) { if (modType != DataModification::eAdded && modType != DataModification::eModified) return; DEBUG_LOG(m_logger) << "onStateIed: " << data; // only overwrite state for existing IEDs if (m_iedObjMap.contains(getIdByEquipmentnumber(data.iedId()))) { Database::GimIed newData; assignBaseData(data, newData); newData.batterywarnings = data.batteryWarnings(); newData.electronicsErrorStateId = toIedError(data.errorStateElectronics()); newData.pyrotechnics1ErrorStateId = toIedError(data.errorStatePyrotechnics1()); newData.pyrotechnics2ErrorStateId = toIedError(data.errorStatePyrotechnics2()); newData.pyrotechnics3ErrorStateId = toIedError(data.errorStatePyrotechnics3()); m_iedObjMap[getIdByEquipmentnumber(newData.equipmentNumber)]->updateState(newData); } else { WARNING_LOG(m_logger) << "StateIed without an existing IED - got no DefinitionIED? " << data; m_orphanedStateIed.insert(data.iedId(), data); } } void HandlerIed::onPairIedRequest(const rti::core::SampleIdentity &cookie, const PairIedRequest &request) { Core::FunctionReplyObject ret; INFO_LOG(m_logger) << "onPairIedRequest id = " << request.id(); ObjectIed *ifs = m_iedObjMap.value(request.id()); if (ifs == nullptr) { ret = Core::FunctionReplyObject(request.id(), tr_lts("dds", "IED with id %1 not found")).arg(request.id()); m_ddsHandler->fts()->pairIedReply(cookie, ret); return; } Database::GimIed data; data.pairingStateId = request.pairingState(); switch (request.pairingState().underlying()) { case IedPairingState_def::PairedToParticipant: { data.pairedParticipantId.setValue(request.pairedParticipantId().get()); data.partyId = m_ppmDtc->participant(request.pairedParticipantId().get()).partyId(); break; } case IedPairingState_def::PairedToOps: { data.pairedOpsId.setValue(request.pairedOpsId().get()); break; } case IedPairingState_def::NotPaired: break; } ret = ifs->updatePairingState(data); if (ret.error()) ERROR_LOG(m_logger) << ret(); m_ddsHandler->fts()->pairIedReply(cookie, ret); } int HandlerIed::getIdByEquipmentnumber(const int number) const { for (const auto &obj : m_iedObjMap) { if (obj->getEquipmentnumber() == number) return obj->getId(); } return -1; } int HandlerIed::getPartyIdFromParticipantEquipmentNumber(const int equipmentNumber) const { const QMap participants = m_ppmDtc->participants(); for (const auto &participant : participants) { if (participant.equipmentNumber() == equipmentNumber) return participant.partyId(); } return 0; } } // Namespace GuezIedManagement