Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Services/ParticipantManagement/ParticipantHandling/participant_handler.cpp
T
berrux-dev 598fc2560e Complete Qt6 migration: full clean build green across groups G1-G12 incl. runtime plugin set
new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
2026-10-20 09:36:57 +02:00

780 lines
29 KiB
C++
Executable File

/**
* The ParticipantHandler class manages all participant related function topics and holds classes for
* further participant data.
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-05-12
*/
#include "participant_handler.h"
#include <utility>
#include "participant.h"
#include "ppm_common.h"
#include "settings.h"
#include "unit_position_calculator.h"
#include <Buildings/bld.hpp>
#include <ProjectDataManagement/pdm_dtc.h>
#include <LtsUtilsCore/outdated_position.h>
namespace ParticipantManagement
{
namespace ParticipantHandling
{
//
// ParticipantHandler
//
ParticipantHandler::ParticipantHandler(BaseDataProvider *bdp, const char *loggerName) : QObject(), m_hitLineId(0), m_bdp(bdp), m_logger(getLogger(loggerName)) {}
ParticipantHandler::~ParticipantHandler()
{
if (m_unitPositionCalculator)
m_unitPositionCalculator->stopCalculation();
clearParticipants();
}
void ParticipantHandler::clearParticipants()
{
// clear maps
for (auto it = m_hitLineInfoMap.cbegin(); it != m_hitLineInfoMap.cend(); ++it)
dts()->removeHitLineInfoByKey(it.value().id);
m_hitLineInfoMap.clear();
for (auto p : std::as_const(m_participants))
{
p->removeFromDds();
delete p;
}
m_participants.clear();
}
bool ParticipantHandler::init()
{
clearParticipants();
m_unitPositionCalculator.reset(new UnitPositionCalculator(this));
m_webSocketHandler = std::make_shared<WebSocketHandler>(this);
if (!m_webSocketHandler->init(Settings::getWebSocketServerPortRange(2)))
{
ERROR_LOG(m_logger) << "could not init websockethandler";
return false;
}
return true;
}
void ParticipantHandler::setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId)
{
DEBUG_LOG(m_logger) << "setEquipmentNumberForParticipant, old: " << oldEqNo << ", new: " << newEqNo << ", participant: " << participantId;
if (oldEqNo > 0)
m_equipNumber2ParticipantId.remove(oldEqNo);
if (newEqNo > 0)
{
int &val = m_equipNumber2ParticipantId[newEqNo];
if (val != 0 && val != participantId)
WARNING_LOG(m_logger) << "Another participant (" << val << ") already has the equipment number " << newEqNo << " - overriding it with participant "
<< participantId;
val = participantId;
}
}
Participant *ParticipantHandler::participantById(int32_t participantId) const { return m_participants.value(participantId); }
Participant *ParticipantHandler::participantByEquipmentNumber(int32_t equipmentNumber)
{
const int participantId = m_equipNumber2ParticipantId.value(equipmentNumber);
DEBUG_LOG(m_logger) << " >>>>>> [ParticipantHandler] participantByEquipmentNumber participantId: " << participantId << " | equipNumb: " << equipmentNumber;
return participantById(participantId);
}
void ParticipantHandler::onNewGearEvent(const TrainingAreaBase::EquipmentGearEvent &gearEvent)
{
if (isTelegramInFuture(gearEvent))
{
WARNING_LOG(m_logger) << "Got an EquipmentGearEvent which has a timestamp in the future: " << gearEvent.sampleTime;
return;
}
// NOTE: gearEvent.chargeAmount() is not used because there is no usecase for this value ... atm
Participant *participantToBeChanged = participantByEquipmentNumber(gearEvent.equipmentNumber);
if (!participantToBeChanged)
{
WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << gearEvent.equipmentNumber;
return;
}
participantToBeChanged->setGearCharge(gearEvent.charge, gearEvent.sampleTime);
participantToBeChanged->publishDynamicData();
// publish gear event
dts()->publish(
ParticipantGearEvent(participantToBeChanged->id(),
gearEvent.sampleTime,
gearEvent.chargeAmount,
GearCharge(gearEvent.charge.gearId, gearEvent.charge.gearTypeId, gearEvent.charge.chargeTypeId, gearEvent.charge.remain)));
}
void ParticipantHandler::onNewGearChargeStateFromProxy(const TrainingAreaBase::EquipmentGearChargeState &chargeState)
{
if (isTelegramInFuture(chargeState))
{
WARNING_LOG(m_logger) << "Got an EquipmentGearChargeState which has a timestamp in the future: " << chargeState.sampleTime;
return;
}
const int equipNo = chargeState.equipmentNumber;
Participant *participantToBeChanged = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo);
if (!participantToBeChanged)
{
WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << chargeState.equipmentNumber;
return;
}
for (const TrainingAreaBase::GearCharge &charge : chargeState.charge)
participantToBeChanged->setGearCharge(charge, chargeState.sampleTime);
participantToBeChanged->publishDynamicData();
emit gearChargeChanged(participantToBeChanged->id(), participantToBeChanged->partyId());
}
void ParticipantHandler::onNewGearAssignmentFromProxy(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment)
{
if (isTelegramInFuture(gearAssignment))
{
WARNING_LOG(m_logger) << "Got an EquipmentGearAssignment which has a timestamp in the future: " << gearAssignment.sampleTime;
return;
}
Participant *participantToBeChanged = participantByEquipmentNumber(gearAssignment.equipmentNumber);
if (!participantToBeChanged)
{
WARNING_LOG(m_logger) << "Got gear assignment for unknown equipment number " << gearAssignment.equipmentNumber;
return;
}
participantToBeChanged->setGear(gearAssignment);
participantToBeChanged->publishDynamicData();
}
void ParticipantHandler::onNewStateFromProxy(const TrainingAreaBase::EquipmentState &data)
{
if (isTelegramInFuture(data))
{
WARNING_LOG(m_logger) << "Got an EquipmentState which has a timestamp in the future: " << data.sampleTime;
return;
}
// 1. handle included EquipmentPosition:
TrainingAreaBase::EquipmentPosition pos;
pos.equipmentNumber = data.equipmentNumber;
pos.sampleTime = data.sampleTime;
if (data.position.has_value())
{
pos.position = data.position.get();
onNewPositionFromProxy(pos);
}
// 2. handle EquipmentState
Participant *participantToBeChanged = participantByEquipmentNumber(data.equipmentNumber);
if (!participantToBeChanged)
{
WARNING_LOG(m_logger) << "Got equipment state for unknown equipment number " << data.equipmentNumber;
return;
}
// convert eqNo to participantId if originator was a participant and data.originatorId() is an equipment number
int originatorId = data.originatorId;
Participant *originParticipant = nullptr;
if (data.originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_Participant)
{
originParticipant = participantByEquipmentNumber(data.originatorId);
if (originParticipant)
originatorId = originParticipant->id();
else
originatorId = -originatorId;
}
// Make Laser Designations to Laser Designations
auto dtcPdm = m_bdp->pdmDtc();
if (dtcPdm && dtcPdm->getChargeTypeSpecialProperty(data.originatorChargeTypeId, 0, 0) == ProjectDataManagement::ChargeTypeProperty::LTD && originParticipant)
{
QSet<int> ldGearTypes{1043}; // Need Property for LTD...
DynamicParticipantData dpd = originParticipant->dynamicParticipantData();
auto it = std::find_if(dpd.gear.cbegin(), dpd.gear.cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId); });
if (it != dpd.gear.cend())
{
for (auto &ld : dpd.designations)
{
if (ld.gearId != it->gearId)
continue;
ld.spotLocation = pos.position.position;
ld.outputPower = 1.0;
originParticipant->setDynamicData(dpd);
originParticipant->publishDynamicData();
break;
}
}
}
if (!participantToBeChanged->setState(data, originatorId))
return; // outdated - ignore
participantToBeChanged->publishDynamicData();
createHitlineInfo(originatorId, originParticipant, participantToBeChanged, pos, data.originatorChargeTypeId, data.sampleTime);
}
void ParticipantHandler::createHitlineInfo(int, Participant *, Participant *, const TrainingAreaBase::EquipmentPosition &, int, qint64)
{
// replay participant is filled with setHitlineInfoFromReplay
return;
}
void ParticipantHandler::onNewPositionFromProxy(const TrainingAreaBase::EquipmentPosition &position)
{
if (isTelegramInFuture(position))
{
WARNING_LOG(m_logger) << "Got an EquipmentPosition which has a timestamp in the future: " << position.sampleTime;
return;
}
if (isTelegramOutdated(position) && position.position.reportingSource != Core::PositionReportingSource::SetByOperator)
{
INFO_LOG(m_logger) << "position is outdated: " << position;
return;
}
DEBUG_LOG(m_logger) << "Got new position from proxy: " << position;
const int equipNo = position.equipmentNumber;
// negative - treat as participantId
Participant *participantWithNewPosition = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo);
if (!participantWithNewPosition)
{
WARNING_LOG(m_logger) << "Got EquipmentPosition " << position << " for unknown equipment number: " << equipNo;
return;
}
if (participantWithNewPosition->setPosition(position))
participantWithNewPosition->publishPosition();
}
void ParticipantHandler::onNewEquipmentOperationalStateFromProxy(const TrainingAreaBase::EquipmentOperationalState &operationalState)
{
if (isTelegramInFuture(operationalState))
{
WARNING_LOG(m_logger) << "Got an EquipmentOperationalState which has a timestamp in the future: " << operationalState.sampleTime;
return;
}
Participant *participantToUpdate = participantByEquipmentNumber(operationalState.equipmentNumber);
if (!participantToUpdate)
{
WARNING_LOG(m_logger) << "Got EquipmentOperationalState for unknown equipment number: " << operationalState;
return;
}
participantToUpdate->setOperationalState(operationalState);
participantToUpdate->publishDynamicData();
}
void ParticipantHandler::onNewBiteFromProxy(const TrainingAreaBase::EquipmentBite &bite)
{
if (isTelegramInFuture(bite))
{
WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the future: " << bite.sampleTime;
return;
}
if (isTelegramOutdated(bite))
{
WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the past: " << bite.sampleTime;
return;
}
Bite biteData;
Participant *p = participantByEquipmentNumber(bite.equipmentNumber);
biteData.participantId = p ? p->id() : -1;
biteData.equipmentNumber = bite.equipmentNumber;
biteData.sampleTime = bite.sampleTime;
biteData.registerType = bite.registerType;
biteData.biteState = bite.biteState;
biteData.configState = bite.configState;
biteData.batteryState = bite.batteryState;
biteData.configError = bite.configError;
biteData.biteErrors.reserve(bite.biteErrors.size());
for (const TrainingAreaBase::EquipmentBiteError &error : bite.biteErrors)
biteData.biteErrors.emplace_back(error.errorNumber, error.canDeviceNumber, error.subdeviceNumber, error.uniqueId);
dts()->publish(biteData);
}
void ParticipantHandler::onNewCtaDataErrorFromProxy(const TrainingAreaBase::CtaDataError &error)
{
CtaError ctasErrorData;
ctasErrorData.equipmentNumber = error.equipmentNumber;
ctasErrorData.timeReceipt = currentTimeMSec();
ctasErrorData.timePlayerUnit = error.sampleTime;
ctasErrorData.errorReason = error.reason;
ctasErrorData.telegramId = error.originTelegramId;
dts()->publish(ctasErrorData);
}
void ParticipantHandler::onNewParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &report)
{
if (isTelegramInFuture(report))
{
WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the future: " << report.sampleTime;
return;
}
if (isTelegramOutdated(report))
{
WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the past: " << report.sampleTime;
return;
}
Participant *participant = participantByEquipmentNumber(report.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << report.equipmentNumber;
return;
}
ParticipantMode ddsData;
ddsData.participantId = participant->id();
ddsData.language = report.language;
ddsData.opMode = report.operationMode;
ddsData.reactivationDecontamination = report.reactivationDetoxication;
ddsData.reactivationMaintenance = report.reactivationMaintenance;
ddsData.reactivationMedic = report.reactivationMedic;
ddsData.modeVest = report.protectionModeVest;
ddsData.modeHelmet = report.protectionModeHelmet;
ddsData.modePersonalProtection = report.personellProtectionMode;
ddsData.protectionLevel = report.protectionLevel;
ddsData.handgrenadeSearchMode = report.handgrenadeSearchMode;
ddsData.internationalMode = report.internationalMode;
ddsData.abcProtectionMode = report.abcProtectionMode;
ddsData.sampleTime = report.sampleTime;
participant->setMode(ddsData);
participant->publishMode();
}
void ParticipantHandler::onNewSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data)
{
if (isTelegramInFuture(data))
{
WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the future: " << data.sampleTime;
return;
}
if (isTelegramOutdated(data))
{
WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the past: " << data.sampleTime;
return;
}
Participant *participant = data.equipmentNumber < 0 ? participantById(-data.equipmentNumber) : participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
TrainingAreaBase::EquipmentPosition pos;
pos.equipmentNumber = data.equipmentNumber;
pos.sampleTime = data.sampleTime;
if (data.position.has_value())
{
Core::GeoPosition geoPos(data.position.get().lon, data.position.get().lat, 0);
pos.position.position = geoPos;
if (participant->setPosition(pos))
participant->publishPosition();
}
participant->setSpecialSensorData(data);
participant->publishDynamicData();
}
void ParticipantHandler::onNewLaserDesignation(const TrainingAreaBase::LaserDesignation &data)
{
DEBUG_LOG(m_logger) << "New Laser Designation: "
<< "Code: " << data.code << ", GearID: " << data.gearId << ", EqNo: " << data.equipmentNumber << ", Lon: " << data.spotLocation.lon
<< ", Lat: " << data.spotLocation.lat << ", Power: " << data.outputPower;
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
DynamicParticipantData dpd = participant->dynamicParticipantData();
DEBUG_LOG(m_logger) << "Begin Update Laser Designation: ";
updateLaserDesignation(dpd, data);
DEBUG_LOG(m_logger) << "End Update Laser Designation: ";
DEBUG_LOG(m_logger) << "Set DPD and publish ";
participant->setDynamicData(dpd);
participant->publishDynamicData();
}
void ParticipantHandler::onLaserDesignationRemoved(int equipmentNumber, int gearId)
{
DEBUG_LOG(m_logger) << "On Remove Laser Designation: ";
Participant *participant = participantByEquipmentNumber(equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << equipmentNumber;
return;
}
DynamicParticipantData dpd = participant->dynamicParticipantData();
DEBUG_LOG(m_logger) << "Begin Remove Laser Designation: ";
removeLaserDesignation(dpd, gearId);
DEBUG_LOG(m_logger) << "End Remove Laser Designation: ";
DEBUG_LOG(m_logger) << "Set DPD and publish ";
participant->setDynamicData(dpd);
participant->publishDynamicData();
}
void ParticipantHandler::onBuildingHitLineInfo(const Buildings::BuildingHitLineInfo &data)
{
DEBUG_LOG(m_logger) << "onBuildingHitLineInfo "
<< "BuildingId=" << data.buildingId << " originatorParticipantId=" << data.originatorParticipantId;
auto dtcPdm = m_bdp->pdmDtc();
// NOTE: igniterTypeId/IgniterFunction = 0 as long as BuildingHitLineInfo does not contain values
if (dtcPdm->getChargeTypeSpecialProperty(data.chargeTypeId, 0, 0) != ProjectDataManagement::ChargeTypeProperty::LTD)
return;
Participant *participant = participantById(data.originatorParticipantId);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with participantId: " << data.originatorParticipantId;
return;
}
DynamicParticipantData dpd = participant->dynamicParticipantData();
DEBUG_LOG(m_logger) << "Begin Update Laser Designation: ";
updateLaserDesignation(dpd, data);
DEBUG_LOG(m_logger) << "End Update Laser Designation: ";
DEBUG_LOG(m_logger) << "setDynamicData";
participant->setDynamicData(dpd);
DEBUG_LOG(m_logger) << "publishDynamicData"
<< " dpd.designations().size()=" << dpd.designations.size();
participant->publishDynamicData();
}
void ParticipantHandler::onSanitaryMaterialStockReport(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data)
{
DEBUG_LOG(m_logger) << "onSanitaryMaterialStockReport";
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
if (data.qualification == TrainingAreaBase::Qualification::NotDefined)
{
DEBUG_LOG(m_logger) << "!!! Clear Materials : equipment number " << data.equipmentNumber;
DEBUG_LOG(m_logger) << "!!! Clear Materials : sample time " << data.sampleTime;
participant->setSanitationMaterial(0,
std::vector<int>(),
data.uniqueId,
data.sampleTime,
Qualification::NotAssigned,
data.originatorEquipmentNumber); // this is a deassociation so clear material
}
else
{
DEBUG_LOG(m_logger) << "!!! Set Materials : equipment number " << data.equipmentNumber;
DEBUG_LOG(m_logger) << "!!! Set Materials : sample time " << data.sampleTime;
participant->setSanitationMaterial(data.sanitaryMaterialCount,
data.sanitaryMaterialStock,
data.uniqueId,
data.sampleTime,
static_cast<ParticipantManagement::Qualification>(data.qualification),
data.originatorEquipmentNumber);
}
participant->publishDynamicData();
}
void ParticipantHandler::onParticipantSanitation(const TrainingAreaBase::ParticipantSanitation &data)
{
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
Participant *participantOrig = participantByEquipmentNumber(data.originatorEquipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
int participantOrigId = data.originatorEquipmentNumber;
if (participantOrig)
participantOrigId = participantOrig->id();
if (data.qualification == TrainingAreaBase::Qualification::NotDefined && data.proceduresTaken == 0)
{
DEBUG_LOG(m_logger) << "!!! Clear Sanitation = " << data.sampleTime;
DEBUG_LOG(m_logger) << "!!! Clear Sanitation: equipNo = " << data.equipmentNumber;
participant->setSanitationMaterial(0, std::vector<int>(), 0, data.sampleTime, Qualification::NotAssigned, 0); // this is a deassociation so clear material
}
else
{
DEBUG_LOG(m_logger) << "!!! SetSanitation: sample time = " << data.sampleTime;
DEBUG_LOG(m_logger) << "!!! SetSanitation: equipNo = " << data.equipmentNumber;
participant->setSanitation(data.proceduresTaken, data.sanitationResult, data.sanitationEvaluation, participantOrigId, data.qualification, data.sampleTime);
}
participant->publishDynamicData();
}
void ParticipantHandler::onOperatorAction(const TrainingAreaBase::OperatorAction &data)
{
// maybe use other commands later?!
if (data.action != 8 && data.action != 35)
return;
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
if (participant->setOperatorAction(data.action, data.operatorId, data.sampleTime))
participant->publishDynamicData();
}
void ParticipantHandler::onEquipmentEvent(const TrainingAreaBase::EquipmentEvent &data)
{
// maybe use other commands later?!
if (data.source.subDeviceId != 14 || data.source.equipmentFunctionId != 5)
return;
if (data.code == 1 || data.code == 2) // 1: 9Liner 2: Transport
{
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
return;
if (participant->setEquipmentEvent(data.code, data.sampleTime))
participant->publishDynamicData();
}
}
void ParticipantHandler::onNewFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data)
{
Participant *participant = participantByEquipmentNumber(data.equipmentNumber);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber;
return;
}
TrainingAreaBase::EquipmentPosition pos;
pos.equipmentNumber = data.equipmentNumber;
pos.sampleTime = data.sampleTime;
Core::GeoPosition geoPos(data.position.lon, data.position.lat, 0);
pos.position.position = geoPos;
if (participant->setPosition(pos))
participant->publishPosition();
StateInformation oldState = youngestStateInformation(participant->dynamicParticipantData().stateHistory, false);
TrainingAreaBase::EquipmentState state;
state.equipmentNumber = data.equipmentNumber;
state.originatorId = data.aesItemId;
state.originatorType = ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_FunctionalArea;
state.sampleTime = data.sampleTime;
state.vulnerabilityState = ProjectDataManagement::VulnerabilityState::VulnerabilityState_HitWithNoEffect; // no effect - it's an entry into a functional area
state.vulnerabilityBits = oldState.vulnerabilityBits;
state.vulnerabilityKindId = oldState.vulnerabilityKindId;
state.vitality = oldState.vitality;
participant->setState(state, data.aesItemId);
participant->publishDynamicData();
}
inline bool isOutdated(qint64 curTime, qint64 posTime)
{
// maxDisplayDuration = 2min -> use 3min
return curTime > (posTime + 3 * 60 * 1000);
}
void ParticipantHandler::onHitLineInfoTimeout()
{
const qint64 tNow = currentTimeMSec();
auto it = m_hitLineInfoMap.begin();
while (it != m_hitLineInfoMap.end())
{
if (!isOutdated(tNow, it.value().sampleTime))
break;
dts()->removeHitLineInfoByKey(it.value().id);
it = m_hitLineInfoMap.erase(it);
}
}
void ParticipantHandler::setPosition(const ParticipantManagement::ParticipantPosition &data)
{
Participant *participant = participantById(data.participantId);
if (!participant)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with id " << data.participantId;
return;
}
participant->setPosition(data, true);
}
void ParticipantHandler::setHitlineInfoFromReplay(const HitLineInfo &data)
{
if (!dts()->publish(data))
return;
m_hitLineInfoMap.insert(data.id, data);
}
void ParticipantHandler::setUASFromReplay(const UAS &data)
{
dts()->publish(data);
}
bool ParticipantHandler::isSupportTypeClass(const ParticipantManagement::TypeClass &typeClass)
{
return (typeClass == TypeClass::SupportUnit || typeClass == TypeClass::SupportEntity);
}
bool ParticipantHandler::isSampleTimeOutdated(qint64 sampleTime) const
{
const qint64 curTime = currentTimeMSec();
return sampleTime < curTime - 11 * 60 * 1000;
}
bool ParticipantHandler::isSampleTimeInFuture(qint64 sampleTime) const
{
const qint64 curTime = currentTimeMSec();
return sampleTime > curTime + 1 * 60 * 1000;
}
std::shared_ptr<Interface::Dts> ParticipantHandler::dts() const { return m_bdp->dts(); }
qint64 ParticipantHandler::currentTimeMSec() const { return m_bdp->currentTimeMSec(); }
quint16 ParticipantHandler::getWebSocketPort() const { return m_webSocketHandler->listenPort(); }
void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &data, const TrainingAreaBase::LaserDesignation &newLaserDesignation)
{
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
DEBUG_LOG(m_logger) << "-Update Laser Designation - Start ";
for (LaserDesignation &laserDesignation : data.designations)
{
if (laserDesignation.gearId != newLaserDesignation.gearId)
continue;
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << laserDesignation.gearId << " found in designations";
laserDesignation.code = newLaserDesignation.code;
if (!qFuzzyIsNull(laserDesignation.outputPower) && !qFuzzyIsNull(newLaserDesignation.spotLocation.lat)
&& !qFuzzyIsNull(newLaserDesignation.spotLocation.lon))
laserDesignation.spotLocation = Core::GeoPosition(newLaserDesignation.spotLocation.lon, newLaserDesignation.spotLocation.lat, 0.0);
// If Laser was on before and now is turned off, we have to reset spot Location
if (!qFuzzyIsNull(laserDesignation.outputPower) && qFuzzyIsNull(newLaserDesignation.outputPower))
laserDesignation.spotLocation = Core::GeoPosition(0.0, 0.0, 0.0);
laserDesignation.outputPower = newLaserDesignation.outputPower;
DEBUG_LOG(m_logger) << "-Update Laser Designation - Data updated, returning";
return;
}
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " NOT found in designations";
int gearId = newLaserDesignation.gearId;
auto it = std::find_if(data.gear.cbegin(), data.gear.cend(), [gearId](const GearInformation &gi) { return gearId == gi.gearId; });
if (it == data.gear.cend()) // No gear, no designation...
{
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " NOT found in Gears";
return;
}
DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " found in Gears";
DEBUG_LOG(m_logger) << "-Update Laser Designation - Adding new designation";
data.designations.emplace_back(newLaserDesignation.gearId,
Core::GeoPosition(newLaserDesignation.spotLocation.lon, newLaserDesignation.spotLocation.lat, 0.0),
newLaserDesignation.code,
newLaserDesignation.outputPower);
}
void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &dataInOut, const Buildings::BuildingHitLineInfo &newLaserDesignation)
{
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
// Todo: Die erste vorhandene LaserDesignation wird angepasst. Ein Laser On muss vorher gekommen sein, damit das Element da ist.
// Mehrere Designatoren pro Teilnehmer werden nicht unterstützt.
DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info";
for (LaserDesignation &laserDesignation : dataInOut.designations)
{
DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Updating (first) Designation with GearId " << laserDesignation.gearId;
laserDesignation.outputPower = 1.0;
laserDesignation.spotLocation = newLaserDesignation.buildingPos;
return;
}
QSet<int> ldGearTypes{1043}; // Need Property for LTD...
auto it = std::find_if(dataInOut.gear.cbegin(), dataInOut.gear.cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId); });
if (it != dataInOut.gear.cend())
{
LaserDesignation ld;
ld.gearId = it->gearId;
ld.code = 0;
ld.spotLocation = newLaserDesignation.buildingPos;
ld.outputPower = 1.0;
dataInOut.designations.emplace_back(ld);
ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Added Designation";
}
ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - No laserDesignation available participantId="
<< newLaserDesignation.originatorParticipantId;
}
void ParticipantHandler::removeLaserDesignation(DynamicParticipantData &data, qint32 gearId)
{
LOGGER_T m_logger = getLogger("ParticipantHandler.Laser");
DEBUG_LOG(m_logger) << "-Remove Laser Designation: Start";
auto validationFunction = [gearId](ParticipantManagement::LaserDesignation laserDesignation) { return laserDesignation.gearId == gearId; };
auto eraseIterator = std::find_if(data.designations.begin(), data.designations.end(), validationFunction);
if (eraseIterator == data.designations.end())
{
DEBUG_LOG(m_logger) << "-Remove Laser Designation: GearId NOT found";
return;
}
DEBUG_LOG(m_logger) << "-Remove Laser Designation: Removing Designation";
data.designations.erase(eraseIterator);
}
} // namespace ParticipantHandling
} // namespace ParticipantManagement