Files
qt5-legatus-legacy/Lts/Proxies/TrainingAreaBase/Plugins/AdlerJson/ppm_handler.cpp
T
2026-08-13 18:33:10 +02:00

1099 lines
41 KiB
C++
Executable File

/**
* @RDE_HEADER@
* PpmHandler for AdlerJson Plugin
* $Id: ppm_handler.cpp 62899 2024-05-29 11:08:50Z ewert_j $
* $HeadURL: svn://slssvn/TDS/branches/product/features/ufom/Lts/Proxies/TrainingAreaBase/Plugins/AdlerJson/ppm_handler.cpp $
* $Author: ewert_j $
* Created by Julius Ewert, ESIM, 2024-03-20
*/
#include "ppm_handler.h"
#include "Core/core.hpp"
#include <QJsonDocument>
#include "json_dispatcher.h"
#include <QRandomGenerator>
#include <LtsUtilsCore/dds_vector.h>
#include <ParticipantManagement/ppm.hpp>
namespace AdlerJson
{
// See PPM::SpecialSensorStatus
static const int ADLER_OPERATIONAL = 125;
// static const int ADLER_CONDITIONALLY_OPERATIONAL = 126;
static const int ADLER_NOT_OPERATIONAL = 127;
PpmHandler::PpmHandler(QObject *parent)
: QObject(parent)
, m_logger(getLogger("PpmHandler"))
, m_sendParticipantDataTimer(new QTimer(this))
{
}
bool PpmHandler::init(MainDispatcher *mainDispatcher)
{
m_mainDispatcher = mainDispatcher;
m_ftcPpm = ParticipantManagement::Interface::Ftc::create(m_mainDispatcher->ddsHandler()->ddsConnector());
m_ftcPpm->enableModifyParticipantData();
m_ftcPpm->enableModifyPartyData();
m_ftcPpm->enableSetSimulatedPosition();
m_dtcPpm = ParticipantManagement::Interface::Dtc::create(m_mainDispatcher->ddsHandler()->ddsConnector());
DEBUG_LOG(m_logger) << "-------------<><><>------" << m_mainDispatcher->exerciseId();
if (!m_dtcPpm->enableParticipant() || !m_dtcPpm->enableDynamicParticipantData() || !m_dtcPpm->enableParticipantPosition())
{
ERROR_LOG(m_logger) << "Can not read data from Ppm";
return false;
}
m_dtcPpm->enableType();
m_dtcPpm->waitForHistoricalDataParticipant(2000);
m_dtcPpm->waitForHistoricalDataDynamicParticipantData(1000);
m_dtcPpm->waitForHistoricalDataParticipantPosition(1000);
m_sendParticipantDataTimer->setInterval(2 * 1000);
connect(m_sendParticipantDataTimer, &QTimer::timeout, this, &PpmHandler::onSendParticipantDataTimeout);
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::partyChanged, this, &PpmHandler::onPartyChanged);
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantChanged, this, &PpmHandler::onParticipantChanged);
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged, this, &PpmHandler::onParticipantPositionChanged);
connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged, this, &PpmHandler::onDynamicParticipantDataChanged);
return true;
}
void PpmHandler::modifyPartyAdlerProperties(const int wsId,
const int assetId,
const int partyId,
const QString &saaName,
const QString &szenarName,
const ParticipantManagement::ConnectState &connectState,
const bool isVerbund)
{
DEBUG_LOG(m_logger) << "modifyParty"
<< " assetId=" << assetId << " partyId=" << partyId << " saaName=" << saaName << " szenarName=" << szenarName << " connectState=" << connectState
<< " isVerbund=" << isVerbund;
ParticipantManagement::Party requestParty;
requestParty = m_dtcPpm->party(partyId);
// Get old properties and then update them
QJsonObject origObj = QJsonDocument::fromJson(requestParty.properties().c_str()).object();
// This might be empty after creation, but it's okay
QJsonObject adlerPropertiesObj = origObj[QStringLiteral("Adler")].toObject();
adlerPropertiesObj[QStringLiteral("saaConnectedState")] = connectState.underlying();
adlerPropertiesObj[QStringLiteral("szenarName")] = szenarName;
adlerPropertiesObj[QStringLiteral("saaName")] = saaName;
adlerPropertiesObj[QStringLiteral("wsId")] = wsId;
adlerPropertiesObj[QStringLiteral("assetId")] = ((connectState == ParticipantManagement::ConnectState::Connected) ? assetId : -1); // sicherung
adlerPropertiesObj[QStringLiteral("isVerbund")] = isVerbund;
const QByteArray &propertiesBa = requestParty.properties().c_str();
QJsonParseError parserError;
QJsonDocument doc(QJsonDocument::fromJson(propertiesBa, &parserError));
if (parserError.error != QJsonParseError::NoError)
{
ERROR_LOG(m_logger) << "Error parsing json document: " << parserError.errorString() << " '" << propertiesBa << "'";
doc = QJsonDocument();
}
DEBUG_LOG(m_logger) << "json to parse: " << doc.toJson();
QJsonObject obj(doc.object());
obj[QStringLiteral("Adler")] = adlerPropertiesObj;
const QByteArray propertiesStr = QJsonDocument(obj).toJson(QJsonDocument::Compact);
requestParty.properties() = propertiesStr.data();
m_ftcPpm->modifyPartyDataRequest(requestParty);
}
void PpmHandler::parseSQFS(const Feuerstellungsdaten &exSQFS, const int wsId)
{
DEBUG_LOG(m_logger) << "Start parse SQFS";
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId);
if (!saa)
{
ERROR_LOG(m_logger) << "SQ WS from SAA but SAA with id " << wsId << " not found";
return;
}
const QString &verein = exSQFS.feuereinheit.verein;
const ProjectDataManagement::L26_EffectingSystemType &internalType = exSQFS.typ;
// The random number helps us identifying this message and its content inside the temp maps
int rndNmbr = QRandomGenerator::global()->generate();
ParticipantManagement::ParticipantData pUdata = findParticipantDataByInternalName(rndNmbr, verein, saa->getIsVerbund());
// Here we Need to save the charges
auto chargeMap = m_tempChargesMap.value(rndNmbr);
chargeMap.insert(verein, QVector<Geschoss>(exSQFS.geschosse));
m_tempChargesMap.insert(rndNmbr, chargeMap);
QMap<QString, ProjectDataManagement::L28_Status> readyMap;
readyMap.insert(verein, exSQFS.status);
m_tempReadyMessage.insert(rndNmbr, readyMap);
// we will use the mid point coordinate for the unit position
auto posdMap = m_tempPositionMap.value(rndNmbr);
AdlerJson::KoordinateMitHoehe middle;
middle.koordinate.longitude = exSQFS.mittelpunkt.koordinate.longitude;
middle.koordinate.latitude = exSQFS.mittelpunkt.koordinate.latitude;
posdMap.insert(verein, middle);
m_tempPositionMap.insert(rndNmbr, posdMap);
// add custom function to get participant for own party!
int superiorModId = 1000000007;
ParticipantManagement::Participant pUnit = findParticipantByInternalName(verein, saa->getPartyId(), saa->getIsVerbund());
// We already had a "fake" Unit, we just need the tempmaps
if (pUdata.modId() > 0)
{
m_sendParticipantDataTimer->start();
return;
}
// We have either an existing unit or not even a fake unit: then we will update or create one
if (pUnit.id() > 0)
{
// Update UnitPos //what about others?
// Nothing to do as we dont Update Unit Symbols by itself.
// But Update Charges
// It still applies, that units never publsh their positions..
// see Lts/Services/ParticipantManagement/ParticipantHandling/participant.cpp:37
sendChargesFromTempMap(rndNmbr, saa->getPartyId(), saa->getIsVerbund());
sendReadyMessageFromTempMap(rndNmbr, saa->getPartyId(), saa->getIsVerbund());
sendPositionFromTempMap(rndNmbr, saa->getPartyId(), saa->getIsVerbund());
// then remove again here
m_tempChargesMap.remove(rndNmbr);
m_tempPositionMap.remove(rndNmbr);
m_tempinternalNameMap.remove(rndNmbr);
m_tempReadyMessage.remove(rndNmbr);
}
else
{
std::vector<ParticipantManagement::ParticipantData> list;
// Get UnitType
const ParticipantManagement::Type unitType = m_dtcPpm->getTypeFromAdlerType(waffensystemtypMap.key(internalType.underlying()), true, saa->getIsVerbund());
// find parent First
// modId will be 0 if not found and set if found
// append root if set
const auto root = findRootUnit(saa->getPartyId());
if (root.id() > 0)
{
DEBUG_LOG(m_logger) << "Append FS Unit to root Unit";
list.push_back(root);
}
ParticipantManagement::ParticipantData data = findParticipantDataByInternalName(rndNmbr, verein, saa->getIsVerbund()); // update
data.id(0);
data.partyId(saa->getPartyId());
data.externalId(0);
data.hierarchyNumber(1);
data.name(verein.toStdString());
data.designator(verein.toStdString());
data.symbol(unitType.symbol());
data.tacticalIdentifier(verein.toStdString());
data.typeId(unitType.id());
data.modId(superiorModId);
data.isDeleted(false);
data.isSimulated(false);
data.superiorModId(root.modId());
list.push_back(data);
ParticipantManagement::ModifyParticipantDataRequest newRequest;
newRequest.requestId(rndNmbr); // we store the random number here to adress later for the postion
newRequest.data(list);
// add to m_tempPartDataList
m_tempPartDataList.insert(rndNmbr, list);
// Send Request
m_ftcPpm->modifyParticipantDataRequest(newRequest, this);
}
}
void PpmHandler::parseSQWS(const Waffensystemdaten &exSQWS, const int wsId)
{
DEBUG_LOG(m_logger) << "Start parse SQWS";
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId);
if (!saa)
{
ERROR_LOG(m_logger) << "SQ WS from SAA but SAA with id " << wsId << " not found";
return;
}
const ProjectDataManagement::L27_EffectorId &internalName = exSQWS.kenner;
const ProjectDataManagement::L26_EffectingSystemType &internalType = exSQWS.typ;
const auto &charges = exSQWS.geschosse;
const QString &verein = exSQWS.einheit.verein;
// The random number helps us identifying this message and its content inside the temp maps
int currentRandomNumber = QRandomGenerator::global()->generate();
// overrides currentRandomNumber if the verin is already inside
ParticipantManagement::ParticipantData pUdata = findParticipantDataByInternalName(currentRandomNumber, verein, saa->getIsVerbund());
// Save Name for later
auto nameVec = m_tempinternalNameMap.value(currentRandomNumber);
nameVec.append(waffensystemkennerMap.key(internalName));
m_tempinternalNameMap.insert(currentRandomNumber, nameVec);
QMap<QString, QVector<Geschoss>> map = m_tempChargesMap.value(currentRandomNumber);
map.insert(waffensystemkennerMap.key(internalName), charges);
m_tempChargesMap.insert(currentRandomNumber, map);
// add custom function to get participant for own party!
ParticipantManagement::Participant pp = findParticipantByInternalName(waffensystemkennerMap.key(internalName), saa->getPartyId(), saa->getIsVerbund());
// Save Position and internal name in temp Maps:
auto posMap = m_tempPositionMap.value(currentRandomNumber);
posMap.insert(waffensystemkennerMap.key(internalName), exSQWS.koordinate);
m_tempPositionMap.insert(currentRandomNumber, posMap);
if (pp.id() > 0)
{
// Update
DEBUG_LOG(m_logger) << "Found Participant only update pos";
sendPositionFromTempMap(currentRandomNumber, saa->getPartyId(), saa->getIsVerbund());
sendChargesFromTempMap(currentRandomNumber, saa->getPartyId(), saa->getIsVerbund());
// then remove again here
m_tempChargesMap.remove(currentRandomNumber);
m_tempPositionMap.remove(currentRandomNumber);
m_tempinternalNameMap.remove(currentRandomNumber);
m_randomNumbers.removeAll(currentRandomNumber);
}
else
{
// need to map those inside the ppmdtc
const ParticipantManagement::Type type = m_dtcPpm->getTypeFromAdlerType(waffensystemtypMap.key(internalType.underlying()), false, saa->getIsVerbund());
DEBUG_LOG(m_logger) << "found type with id: " << type.id() << " for name: " << waffensystemtypMap.key(internalType);
if (type.id() <= 0)
{
ERROR_LOG(m_logger) << "NO Type Found";
return;
}
std::vector<ParticipantManagement::ParticipantData> list = m_tempPartDataList.value(currentRandomNumber);
// Find Unit first)
uint superiorModId = QRandomGenerator::global()->generate() / 2;
ParticipantManagement::Participant pUnit = findParticipantByInternalName(verein, saa->getPartyId(), saa->getIsVerbund());
DEBUG_LOG(m_logger) << "Looking for Verein: " << verein << " found Unit: " << pUnit.id() << " foundData: " << pUdata.modId();
if (pUdata.modId() > 0)
{
superiorModId = pUdata.modId();
DEBUG_LOG(m_logger) << "FOUND UNIT in list use their modId " << superiorModId << " RND: " << currentRandomNumber;
}
else if (pUnit.id() > 0)
{
// Mod Unit
ParticipantManagement::ParticipantData pUData = m_dtcPpm->convertParticipantToParticipantData(pUnit);
pUData.modId(superiorModId);
pUData.hierarchyNumber(1);
list.push_back(pUData);
m_tempPartDataList.insert(currentRandomNumber, list);
DEBUG_LOG(m_logger) << "CREATE Uit from ppm " << superiorModId << " RND: " << currentRandomNumber;
ParticipantManagement::Participant tmp = pUnit;
while (tmp.superiorId() > 0)
{
tmp = m_dtcPpm->participant(tmp.superiorId());
pUData = m_dtcPpm->convertParticipantToParticipantData(tmp);
list.push_back(pUData);
}
}
else
{
// create new
// find parent First
// modId will be 0 if not found and set if found
// append root if set
const auto root = findRootUnit(saa->getPartyId());
if (root.id() > 0)
{
DEBUG_LOG(m_logger) << "Append to Unit" << superiorModId << " RND: " << currentRandomNumber;
list.push_back(root);
}
const ParticipantManagement::Type unitType = m_dtcPpm->getTypeFromAdlerType(waffensystemtypMap.key(internalType), true, saa->getIsVerbund());
DEBUG_LOG(m_logger) << "CREATE NEW Unit use supId" << superiorModId << " RND: " << currentRandomNumber;
ParticipantManagement::ParticipantData data;
data.id(0);
data.partyId(saa->getPartyId());
data.externalId(0);
data.hierarchyNumber(1);
data.name(verein.toStdString());
data.designator(verein.toStdString());
data.symbol(unitType.symbol());
data.tacticalIdentifier(verein.toStdString());
data.typeId(unitType.id()); // use korrect type
data.modId(superiorModId);
data.isDeleted(false);
data.isSimulated(false);
data.superiorModId(root.modId());
// Add to request List
list.push_back(data);
}
// Create
DEBUG_LOG(m_logger) << "Create new Participant"
<< " RND: " << currentRandomNumber;
ParticipantManagement::ParticipantData data;
data.id(0);
data.partyId(saa->getPartyId());
data.externalId(0);
data.hierarchyNumber(list.size());
data.name(waffensystemkennerMap.key(internalName).toStdString());
data.designator(waffensystemkennerMap.key(internalName).toStdString());
data.symbol(type.symbol());
data.tacticalIdentifier(verein.toStdString());
data.typeId(type.id()); // use korrect type
data.modId(QRandomGenerator::global()->generate() / 2);
data.isDeleted(false);
data.isSimulated(false);
data.superiorModId(superiorModId);
// ParticipantManagement::ModifyParticipantDataRequest *newRequest = new ParticipantManagement::ModifyParticipantDataRequest();
// newRequest->requestId(rndNmbr); //we store the random number here to adress later for the postion
list.push_back(data);
m_tempPartDataList.insert(currentRandomNumber, list);
m_randomNumbers.append(currentRandomNumber);
m_sendParticipantDataTimer->start();
}
}
void PpmHandler::parseSQLP(const Ladeplatzdaten &exSQLP, const int wsId)
{
DEBUG_LOG(m_logger) << "START parse SQLP";
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId);
if (!saa)
{
ERROR_LOG(m_logger) << "SQ LP from SAA but SAA with id " << wsId << " not found";
return;
}
const QString &verein = exSQLP.einheit.verein;
// lets assume that there is no "unit for that and can be added manualy
int rndNmbr = QRandomGenerator::global()->generate();
// Save Position and internal name in temp Maps:
auto posdMap = m_tempPositionMap.value(rndNmbr);
posdMap.insert(verein, exSQLP.koordinate);
m_tempPositionMap.insert(rndNmbr, posdMap);
QMap<QString, QVector<Geschoss>> map;
map.insert(verein, QVector<Geschoss>(exSQLP.geschosse));
m_tempChargesMap.insert(rndNmbr, map);
auto nameVec = m_tempinternalNameMap.value(rndNmbr);
nameVec.append(verein);
m_tempinternalNameMap.insert(rndNmbr, nameVec);
// add custom function to get participant for own party!
ParticipantManagement::Participant pp = findParticipantByInternalName(verein, saa->getPartyId(), saa->getIsVerbund());
const ParticipantManagement::Type type = m_dtcPpm->getTypeFromAdlerType(QStringLiteral("LP"), false, saa->getIsVerbund());
if (pp.id() > 0)
{
// Update pos
sendPositionFromTempMap(rndNmbr, saa->getPartyId(), saa->getIsVerbund());
// update charge
sendChargesFromTempMap(rndNmbr, saa->getPartyId(), saa->getIsVerbund());
// then remove again here
m_tempChargesMap.remove(rndNmbr);
m_tempPositionMap.remove(rndNmbr);
m_tempinternalNameMap.remove(rndNmbr);
}
else
{
// Create new Participant
// Create
DEBUG_LOG(m_logger) << "Create new Participant LP";
std::vector<ParticipantManagement::ParticipantData> list;
// find parent First
// modId will be 0 if not found and set if found
// append root if set
const auto root = findRootUnit(saa->getPartyId());
if (root.id() > 0)
{
DEBUG_LOG(m_logger) << "Append LP to Unit";
list.push_back(root);
}
ParticipantManagement::ParticipantData data;
data.id(0);
data.partyId(saa->getPartyId());
data.externalId(0);
data.hierarchyNumber(1);
data.name(verein.toStdString());
data.designator(verein.toStdString());
data.symbol(type.symbol());
data.tacticalIdentifier(verein.toStdString());
data.typeId(type.id()); // use korrect type
data.modId(1000000001);
data.isDeleted(false);
data.isSimulated(false);
data.superiorModId(root.modId());
ParticipantManagement::ModifyParticipantDataRequest *newRequest = new ParticipantManagement::ModifyParticipantDataRequest();
newRequest->requestId(rndNmbr); // we store the random number here to adress later for the postion
list.push_back(data);
newRequest->data(list);
// add to m_tempPartDataList
m_tempPartDataList.insert(rndNmbr, list);
m_ftcPpm->modifyParticipantDataRequest(*newRequest, this);
}
}
void PpmHandler::removeAllSAAParticipants(const int partyId)
{
// find all participants frpom this SAA
const auto &participants = findAllSAAParticipants(partyId);
if (participants.isEmpty())
return;
ParticipantManagement::ModifyParticipantDataRequest req;
std::vector<ParticipantManagement::ParticipantData> list;
for (const auto &part : qAsConst(participants))
{
const ParticipantManagement::Type &participantType = m_dtcPpm->type(part.typeId());
bool isUnitType
= (participantType.typeClass() == ParticipantManagement::TypeClass::Unit) || (participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
if (isUnitType)
continue;
ParticipantManagement::ParticipantData pToDel;
pToDel.id() = part.id();
pToDel.isDeleted() = true;
list.push_back(pToDel);
}
req.data(list);
DEBUG_LOG(m_logger) << "Remove all participants (without Units): " << list.size();
m_ftcPpm->modifyParticipantDataRequest(req, this);
}
// void PpmHandler::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType)
// {
// }
void PpmHandler::onCreateParticipant()
{
ParticipantManagement::ParticipantData data;
data.id(0);
data.partyId(3);
data.externalId(0);
data.hierarchyNumber(1);
data.name("Noah Thiering");
data.designator("Hund");
data.symbol("AP6D|CMPL|10011000001308000000");
data.tacticalIdentifier("14");
data.typeId(177);
data.modId(1000000001);
data.isDeleted(false);
data.isSimulated(false);
data.superiorModId(0);
ParticipantManagement::ModifyParticipantDataRequest *newRequest = new ParticipantManagement::ModifyParticipantDataRequest();
newRequest->requestId(2);
std::vector<ParticipantManagement::ParticipantData> liste;
liste.push_back(data);
newRequest->data(liste);
// ParticipantManagement::ParticipantData data;
// int32_t id,
// int32_t partyId,
// int32_t hierarchyNumber,
// const ::dds::core::optional< int32_t >& equipmentNumber,
// int32_t typeId,
// ::rti::core::int64 externalId,
// const std::string& symbol,
// const std::string& name,
// const std::string& identification,
// const std::string& designator,
// const std::string& tacticalIdentifier,
// const std::string& info,
// const ParticipantManagement::ParticipantAssignState& assignState,
// bool isSimulated,
// bool isDeleted,
// const std::string& properties,
// int32_t modId,
// int32_t superiorModId);
// data.id(0);
// data.partyId(1);
// data.typeId(5);
// ParticipantManagement::ModifyParticipantDataRequest *newRequest = new ParticipantManagement::ModifyParticipantDataRequest();
// newRequest->requestId(9999);
// std::vector<ParticipantManagement::ParticipantData> liste;
// liste.push_back(data);
// newRequest->data(liste);
// m_ftcPpm->modifyParticipantDataRequest(*newRequest);
m_ftcPpm->modifyParticipantDataRequest(*newRequest);
}
void PpmHandler::getParticipants()
{
if (!m_dtcPpm)
return;
for (const auto &participant : m_dtcPpm->participants())
{
onParticipantChanged(participant, DataModification::eAdded);
}
}
bool PpmHandler::isEqNumberInExercise(const int equipmentNumber) const
{
bool result = m_dtcPpm->participantIdByEquipmentNumber(equipmentNumber) > 0;
return result;
}
void PpmHandler::onParticipantChanged(const ParticipantManagement::Participant &participant, DataModification modType)
{
if (!participant.equipmentNumber().is_set())
{
for (auto it = m_participantIdsByEqNo.begin(); it != m_participantIdsByEqNo.end(); ++it)
if (it.value() == participant.id())
{
m_participantIdsByEqNo.remove(it.key());
break;
}
return;
}
if (participant.externalId() > 0)
return;
QJsonObject headerJson;
headerJson[QStringLiteral("equipmentNumber")] = participant.equipmentNumber().get();
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
if (modType == DataModification::eRemoved)
{
m_participantIdsByEqNo.remove(participant.equipmentNumber().get());
QJsonObject telegram;
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
telegram[QStringLiteral("data")] = data;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaRemoveParticipant");
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_REMOVE_PARTICIPANT;
emit participantChanged(telegram);
return;
}
if (m_participantIdsByEqNo.contains(participant.equipmentNumber().get()))
{
if (m_participantIdsByEqNo[participant.equipmentNumber().get()] != participant.id())
{
for (auto it = m_participantIdsByEqNo.begin(); it != m_participantIdsByEqNo.end(); ++it)
if (it.value() == participant.id())
{
m_participantIdsByEqNo.remove(it.key());
break;
}
m_participantIdsByEqNo[participant.equipmentNumber().get()] = participant.id();
}
}
else
m_participantIdsByEqNo[participant.equipmentNumber().get()] = participant.id();
ParticipantManagement::DynamicParticipantData dynamicData = m_dtcPpm->dynamicParticipantData(participant.id());
ParticipantManagement::Party party = m_dtcPpm->party(participant.partyId());
ParticipantManagement::Type type = m_dtcPpm->type(participant.typeId());
ParticipantManagement::ParticipantPosition partPos = m_dtcPpm->participantPosition(participant.id());
QJsonObject telegram;
QJsonObject geoPositionObj;
geoPositionObj[QStringLiteral("lon")] = partPos.pos().lon();
geoPositionObj[QStringLiteral("lat")] = partPos.pos().lat();
geoPositionObj[QStringLiteral("z")] = partPos.pos().z();
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
data[QStringLiteral("status")] = static_cast<int>(m_dtcPpm->youngestStateInformation(dynamicData.stateHistory()).vulnerabilityState().underlying());
data[QStringLiteral("forceIdentifier")] = static_cast<int>(party.hlaForceIdentifier().underlying());
data[QStringLiteral("geoPosition")] = geoPositionObj;
telegram[QStringLiteral("data")] = data;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaAddParticipant");
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_ADD_PARTICIPANT;
emit participantChanged(telegram);
}
void PpmHandler::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &position, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
const bool participantIsExternal = m_dtcPpm->participant(position.participantId()).externalId() > 0;
if (participantIsExternal)
{
handleParticipantPositionChangedExternal(position);
}
else
{
handleParticipantPositionChangedInternal(position);
}
}
void PpmHandler::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &dynPartData, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
ParticipantManagement::Participant part = m_dtcPpm->participant(dynPartData.participantId());
if (part.externalId() > 0 || !part.equipmentNumber().is_set())
return;
QJsonObject telegram;
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_VULNERABILITY_STATE_CHANGED;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaVulnerabilityStateChanged");
QJsonObject headerJson;
headerJson[QStringLiteral("equipmentNumber")] = part.equipmentNumber().get();
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
data[QStringLiteral("status")] = static_cast<int>(m_dtcPpm->youngestStateInformation(dynPartData.stateHistory()).vulnerabilityState().underlying());
telegram[QStringLiteral("data")] = data;
emit participantChanged(telegram);
}
void PpmHandler::onSendParticipantDataTimeout()
{
m_sendParticipantDataTimer->stop();
if (m_randomNumbers.empty())
ERROR_LOG(m_logger) << "Cant Send ParticipantData RandomNumbers is empty";
ParticipantManagement::ModifyParticipantDataRequest *newRequest = new ParticipantManagement::ModifyParticipantDataRequest();
int currentRandomNumber = m_randomNumbers.first();
newRequest->requestId(currentRandomNumber); // we store the random number here to adress later for the postion
newRequest->data(m_tempPartDataList.value(currentRandomNumber));
m_ftcPpm->modifyParticipantDataRequest(*newRequest, this);
}
void PpmHandler::handleParticipantPositionChangedExternal(const ParticipantManagement::ParticipantPosition &position)
{
ParticipantManagement::Participant part = m_dtcPpm->participant(position.participantId());
const bool participantPreviouslyMounted = m_mountedParticipants.contains(part.equipmentNumber().get());
if (!participantPreviouslyMounted)
return;
const bool mountedOnOtherParticipant = position.mountedOn().is_set();
if (!mountedOnOtherParticipant)
{
sendParticipantUnmount(part);
return;
}
const bool newMountedParticipantIsExternal = m_dtcPpm->participant(position.mountedOn().get()).externalId() != 0;
if (newMountedParticipantIsExternal)
{ // If the new mounted participant is internal the entry in the Hashmap is still used. So dont remove it!
m_mountedParticipants.remove(part.equipmentNumber().get());
}
}
void PpmHandler::handleParticipantPositionChangedInternal(const ParticipantManagement::ParticipantPosition &position)
{
DEBUG_LOG(m_logger) << "handleParticipantPositionChangedInternal";
ParticipantManagement::Participant part = m_dtcPpm->participant(position.participantId());
const bool hasMountedParticipants = position.mountedParticipants().is_set() && position.mountedParticipants().get().size() > 0;
if (hasMountedParticipants)
{
const QVector<int32_t> mountedParticipantIds(position.mountedParticipants().get().begin(), position.mountedParticipants().get().end());
for (int mountedParticipantId : qAsConst(mountedParticipantIds))
{
ParticipantManagement::Participant mountedParticipant = m_dtcPpm->participant(mountedParticipantId);
const bool isExternal = mountedParticipant.externalId() > 0;
const bool wasMountedOnThisPart = m_mountedParticipants.contains(mountedParticipant.equipmentNumber().get())
&& m_mountedParticipants[mountedParticipant.equipmentNumber().get()] == part.equipmentNumber().get();
if (!isExternal || wasMountedOnThisPart)
continue;
if (!part.equipmentNumber().is_set())
continue;
sendParticipantMount(mountedParticipant, part);
}
if (part.equipmentNumber().is_set())
{
sendParticipantPositionChanged(position);
}
}
}
void PpmHandler::sendParticipantMount(const ParticipantManagement::Participant &part, const ParticipantManagement::Participant &partToBeMounted) // Passanger, Vehicle
{
m_mountedParticipants.insert(part.equipmentNumber().get(), partToBeMounted.equipmentNumber().get());
ERROR_LOG(m_logger) << "Mount Participant";
QJsonObject telegram;
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_PARTICIPANT_MOUNT;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaParticipantMount");
QJsonObject headerJson;
headerJson[QStringLiteral("equipmentNumber")] = part.equipmentNumber().get();
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
data[QStringLiteral("mountedOn")] = QJsonValue(partToBeMounted.equipmentNumber().get());
telegram[QStringLiteral("data")] = data;
emit participantMount(telegram);
}
void PpmHandler::sendParticipantUnmount(const ParticipantManagement::Participant &participant)
{
m_mountedParticipants.remove(participant.equipmentNumber().get());
DEBUG_LOG(m_logger) << "Unmount Participant";
QJsonObject telegram;
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_PARTICIPANT_UNMOUNT;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaParticipantUnmount");
QJsonObject headerJson;
headerJson[QStringLiteral("equipmentNumber")] = participant.equipmentNumber().get();
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
telegram[QStringLiteral("data")] = data;
emit participantUnmount(telegram);
}
void PpmHandler::sendParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &position)
{
ParticipantManagement::Participant part = m_dtcPpm->participant(position.participantId());
QJsonObject telegram;
// telegram[QStringLiteral("typeId")] = TrainingAreaBase::TetraIcd::TelegramId::UFOMHLA_POSITION_CHANGED;
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaPositionChanged");
QJsonObject headerJson;
headerJson[QStringLiteral("equipmentNumber")] = part.equipmentNumber().get();
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
QJsonObject data;
data[QStringLiteral("header")] = headerJson;
data[QStringLiteral("lon")] = position.pos().lon();
data[QStringLiteral("lat")] = position.pos().lat();
data[QStringLiteral("z")] = position.pos().z();
telegram[QStringLiteral("data")] = data;
emit participantChanged(telegram);
}
void PpmHandler::onModifyParticipantDataReply(const Core::FunctionReplyObject &reply)
{
DEBUG_LOG(m_logger) << "Got Function Reply " << reply.str();
if (!reply.error())
{
if (!m_tempPartDataList.contains(reply.id()))
return;
const int partyId = m_tempPartDataList.value(reply.id()).data()->partyId();
if (!m_mainDispatcher->jsonDispatcher()->getSAAByParty(partyId))
return;
const bool isVerbund = m_mainDispatcher->jsonDispatcher()->getSAAByParty(partyId)->getIsVerbund();
DEBUG_LOG(m_logger) << "Got ModifyParticipant Reply SEND from temp Maps (partyId: " << partyId << " , isVerbund: " << isVerbund << ")";
if (m_tempPositionMap.contains(reply.id()))
sendPositionFromTempMap(reply.id(), partyId, isVerbund);
if (m_tempChargesMap.contains(reply.id()))
sendChargesFromTempMap(reply.id(), partyId, isVerbund);
if (m_tempReadyMessage.contains(reply.id()))
sendReadyMessageFromTempMap(reply.id(), partyId, isVerbund);
}
else
{
ERROR_LOG(m_logger) << "GOT ModifyParticipant Replay with error " << reply.translated();
}
// then remove any entries from Map
m_tempChargesMap.remove(reply.id());
m_tempPositionMap.remove(reply.id());
m_tempinternalNameMap.remove(reply.id());
m_tempReadyMessage.remove(reply.id());
if (m_randomNumbers.contains(reply.id()))
{
m_randomNumbers.removeAll(reply.id());
if (!m_randomNumbers.isEmpty() && !m_sendParticipantDataTimer->isActive())
m_sendParticipantDataTimer->start();
}
m_tempPartDataList.remove(reply.id());
}
void PpmHandler::onModifyPartyDataReply(const Core::FunctionReplyObject &reply) { DEBUG_LOG(m_logger) << "Got Function Reply " << reply.str(); }
QList<ParticipantManagement::Participant> PpmHandler::findAllSAAParticipants(const int partyId)
{
QList<ParticipantManagement::Participant> ret;
const auto &list = m_dtcPpm->participants();
for (const auto &part : qAsConst(list))
{
if (part.partyId() != partyId || part.isDeleted())
continue;
if (!m_dtcPpm->isArtilleryType(part.typeId()))
continue;
if (part.name().empty())
continue;
ret.append(part);
}
return ret;
}
ParticipantManagement::ParticipantData PpmHandler::findParticipantDataByInternalName(int &randomNumberInOut, const QString &internalName, const bool isVerbund)
{
ParticipantManagement::ParticipantData ret;
for (const auto &randomNumber : m_tempPartDataList.keys())
{
for (const auto &part : m_tempPartDataList.value(randomNumber))
{
if (part.name() != internalName.toStdString())
continue;
if (m_dtcPpm->isAdlerVerbund(part.typeId()) != isVerbund)
continue;
randomNumberInOut = randomNumber;
return part;
}
}
return ret;
}
ParticipantManagement::ParticipantData PpmHandler::findRootUnit(const int partyId)
{
ParticipantManagement::ParticipantData ret;
const auto &list = m_dtcPpm->participants();
for (const auto &part : qAsConst(list))
{
if (part.partyId() != partyId || part.isDeleted())
continue;
if (m_dtcPpm->type(part.typeId()).typeClass() != ParticipantManagement::TypeClass::Unit)
continue;
if (m_dtcPpm->isArtilleryType(part.typeId()))
continue;
if (part.superiorId() > 0)
continue;
ret = m_dtcPpm->convertParticipantToParticipantData(part);
}
return ret;
}
ParticipantManagement::Participant PpmHandler::findParticipantByInternalName(const QString &internalName, const int partyId, const bool isVerbund)
{
ParticipantManagement::Participant pp;
DEBUG_LOG(m_logger) << "START find participant: " << internalName;
auto participantMap = m_dtcPpm->participants();
for (const auto &part : qAsConst(participantMap))
{
if (part.partyId() != partyId || part.isDeleted())
continue;
if (!m_dtcPpm->isArtilleryType(part.typeId()))
continue;
if (m_dtcPpm->isAdlerVerbund(part.typeId()) != isVerbund)
continue;
if (part.name() != internalName.toStdString())
continue;
pp = part;
}
return pp;
}
void PpmHandler::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ", modType: " << modType;
if (modType == DataModification::eRemoved)
return;
const ParticipantManagement::ConnectState connectState = m_dtcPpm->saaConnectedState(data.id());
DEBUG_LOG(m_logger) << "++++ connectState: " << connectState;
// only in connect state disconnecting: delete all ADLER objects and force the disconnection
if (connectState != ParticipantManagement::ConnectState::Disconnecting)
return;
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByParty(data.id());
if (!saa)
return;
DEBUG_LOG(m_logger) << "++++ szenarName: " << saa->getSzenarName() << ", wsId: " << saa->getWsId();
EXStatus status;
status.status = Szenarstatus::Gestoppt;
m_mainDispatcher->jsonDispatcher()->onSAAStatus(saa->getWsId(), status);
m_mainDispatcher->jsonDispatcher()->onSAADeregistration(saa->getWsId(), data.id());
}
void PpmHandler::sendPositionFromTempMap(int rndNmbr, const int partyId, const bool isVerbund)
{
const QMap<QString, KoordinateMitHoehe> posMap = m_tempPositionMap.value(rndNmbr);
const QList<QString> partList;
// we need the participant Id now
const auto &nameVec = m_tempinternalNameMap.value(rndNmbr);
QMapIterator<QString, KoordinateMitHoehe> it(posMap);
while (it.hasNext())
{
it.next();
ParticipantManagement::Participant pp = findParticipantByInternalName(it.key(), partyId, isVerbund);
if (pp.id() <= 0)
return;
TrainingAreaBase::EquipmentPosition equipPosReq;
Core::GeoPosition tlnPos;
TrainingAreaBase::TabPosition tabPos;
tlnPos.lat(it.value().koordinate.latitude * (M_PI / 180.0));
tlnPos.lon(it.value().koordinate.longitude * (M_PI / 180.0));
// Ignore Adler Z Value due to different elevation maps
// tlnPos.z(it.value().hoehe);
tabPos.position(tlnPos);
tabPos.reportingSource(Core::PositionReportingSource::SetByOperator);
equipPosReq.sampleTime(m_mainDispatcher->ddsHandler()->partitionTime());
equipPosReq.position(tabPos);
equipPosReq.equipmentNumber(-1 * pp.id());
// equipPosReq.mountedParticipants();
// equipPosReq.orientation();
m_mainDispatcher->ddsHandler()->dtsTab()->publish(equipPosReq);
}
}
void PpmHandler::sendChargesFromTempMap(const int rndNmbr, const int partyId, const bool isVerbund)
{
// No ammunition supply is displayed in ADLER standalone mode
if (!isVerbund)
return;
const auto &charges = m_tempChargesMap.value(rndNmbr);
const ParticipantManagement::Type type = m_dtcPpm->getTypeFromAdlerType(QStringLiteral("LP"), false, isVerbund);
for (const auto &charge : charges.toStdMap())
{
TrainingAreaBase::EquipmentGearChargeState gearChargeState;
TrainingAreaBase::GearCharge gc;
ParticipantManagement::Participant participant = findParticipantByInternalName(charge.first, partyId, isVerbund);
const QVector<Geschoss> geschosse = sumUpAnzahlForSameGeschoss(charge.second);
for (auto c : geschosse)
{
int chargeTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(c.geschosssorte);
// if geschosssorte is null, we cannot get a valid chargeTypeId for it
// this happens when the SAA is sending "Ladung" without a valid geschosssorte)
if (chargeTypeId <= 0)
continue;
DEBUG_LOG(m_logger) << "---- participant.id:" << participant.id() << (participant.typeId() == type.id() ? " (Ladeplatz)" : "");
QVector<int> gearTypesIds = m_mainDispatcher->pdmHandler()->getDtc()->gearTypeIdFromChargeTypeId(chargeTypeId);
// Here only one gearType should be found
gc.gearTypeId() = !gearTypesIds.isEmpty() ? gearTypesIds.first() : 0;
gc.gearId(participant.id());
gc.chargeTypeId(chargeTypeId);
gc.remain() = c.anzahl;
gearChargeState.charge().push_back(gc);
}
gearChargeState.sampleTime(m_mainDispatcher->ddsHandler()->partitionTime());
gearChargeState.equipmentNumber(-1 * participant.id());
m_mainDispatcher->ddsHandler()->dtsTab()->publish(gearChargeState);
}
m_tempChargesMap.remove(rndNmbr);
}
void PpmHandler::sendReadyMessageFromTempMap(int rndNmbr, const int partyId, const bool isVerbund)
{
const auto &readyMap = m_tempReadyMessage.value(rndNmbr);
for (const auto &readyMsg : readyMap.toStdMap())
{
ParticipantManagement::Participant participant = findParticipantByInternalName(readyMsg.first, partyId, isVerbund);
TrainingAreaBase::SpecialSensorData ssData;
ssData.sampleTime(m_mainDispatcher->ddsHandler()->partitionTime());
ssData.operationalState(convertStatus_L28(readyMsg.second));
ssData.equipmentNumber(-1 * participant.id());
m_mainDispatcher->ddsHandler()->dtsTab()->publish(ssData);
}
m_tempReadyMessage.remove(rndNmbr);
}
int PpmHandler::convertStatus_L28(const ProjectDataManagement::L28_Status &status)
{
switch (status.underlying())
{
case ProjectDataManagement::L28_Status::Einsatzbereit:
return ADLER_OPERATIONAL;
case ProjectDataManagement::L28_Status::NichtEinsatzbereit:
return ADLER_NOT_OPERATIONAL;
default:
WARNING_LOG(m_logger) << "Status " << status << " not handled in switch";
break;
}
return -1;
}
QVector<Geschoss> PpmHandler::sumUpAnzahlForSameGeschoss(const QVector<Geschoss> &geschosse) const
{
using GeschossInfo = std::tuple<QString, QString, QString>;
QMap<GeschossInfo, Geschoss> summedUpGeschosseMap;
for (const Geschoss &geschoss : geschosse)
{
const GeschossInfo geschossInfo(geschoss.geschosssorte, geschoss.ladung, geschoss.zuender);
if (summedUpGeschosseMap.contains(geschossInfo))
{
summedUpGeschosseMap[geschossInfo].anzahl += geschoss.anzahl;
continue;
}
summedUpGeschosseMap.insert(geschossInfo, geschoss);
}
return summedUpGeschosseMap.values().toVector();
}
} // namespace AdlerJson