Files
qt5-legatus-legacy/Lts/Services/ParticipantManagement/ParticipantHandling/participant_handler.cpp
T
2026-08-13 18:33:10 +02:00

779 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 "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 : qAsConst(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().is_set())
{
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::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_def::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().is_set())
{
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_def::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_def::type>(data.qualification().underlying()),
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::FunctionalArea);
state.sampleTime(data.sampleTime());
state.vulnerabilityState(ProjectDataManagement::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