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