Files
qt-migration-legatus/qt5-before/dlbo/Lts/Services/GuezIedManagement/handler_ied.cpp
T
torstenandCopilot 7173785915 Qt6 Migration: Complete migration with DDS/RTI support and build validation
Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list

Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF

Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
  - Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
  - Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)

Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified

Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-15 18:20:26 +00:00

368 lines
11 KiB
C++

/**
* 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 <Proxies/TrainingAreaBase/tab_dtc.h>
#include <QCoreApplication>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <ngldb/dbtransaction.h>
#include <ngldb/nsqlquery.h>
#include <GuezIedManagement/gim_record_replay_plugin.h>
namespace GuezIedManagement
{
HandlerIed::HandlerIed(MainHandler *mainHandler,
const std::shared_ptr<DdsHandler> &ddsHandler,
const std::shared_ptr<DatabaseInterface> &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<Database::GimIed> 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<qint64, GuezIedManagement::IedPosition> 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<IedType::inner_enum>(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<IedPairingState::inner_enum>(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<Small|Big> 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<int, ParticipantManagement::Participant> participants = m_ppmDtc->participants();
for (const auto &participant : participants)
{
if (participant.equipmentNumber() == equipmentNumber)
return participant.partyId();
}
return 0;
}
} // Namespace GuezIedManagement