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
780 lines
29 KiB
C++
Executable File
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
|