Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Services/OcSituationServer/handler_oc_data.cpp
T
berrux-dev 3ec4208139 Migrates OcSituation and ServiceManagement to generated rtiddsgen API
Converts accessor calls to plain member access in osc, oss and obd services.
2026-09-21 02:46:47 +02:00

634 lines
20 KiB
C++
Executable File

/**
* Handler for all oc data at the server
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, NLST, 14-02-2018
*/
#include "handler_oc_data.h"
#include <QMutexLocker>
#include <LtsUtilsCore/dds_vector.h>
#include <LtsUtilsCore/qbytearray_byteaccess.h>
#include "main_handler.h"
#include "oc_situation.h"
#include "handler_oc_aes_data.h"
#include "handler_oc_situation_data.h"
#include "handler_oc_central_aes_data.h"
#include "settings.h"
#include "logger.h"
namespace OcSituationServer
{
HandlerOcData::HandlerOcData(MainHandler *mainHandler,
QObject *parent)
: QObject(parent)
, Interface::Fts::SendEquipmentMessageOcRequestHandler(mainHandler->dds()->fts())
, Interface::Fts::EquipmentErrorRequestHandler(mainHandler->dds()->fts())
, m_mainHandler(mainHandler)
, m_handlerOcAesData(new HandlerOcAesData(mainHandler, this))
, m_dts(mainHandler->dds()->dts())
, m_fts(mainHandler->dds()->fts())
, m_evlDtc(mainHandler->evlDtc())
, m_evlFtc(mainHandler->evlFtc())
, m_msgFtc(mainHandler->msgFtc())
, m_ppmDtc(mainHandler->ppmDtc())
, m_ppmFtc(mainHandler->ppmFtc())
, m_tabDtc(mainHandler->tabDtc())
, m_tabFtc(mainHandler->tabFtc())
, m_currentActiveEvaluationSchemaId(0)
, m_stateInformationTimer(new QTimer(this))
, m_logger(getLogger("HandlerOcData"))
{}
HandlerOcData::~HandlerOcData()
{}
bool HandlerOcData::init()
{
// EVL DTC enable
if (!m_evlDtc->enableEvaluationSchema())
{
ERROR_LOG(m_logger) << "Enabling EVL Data-Topics failed.";
return false;
}
connect(m_evlDtc.get(), &Evaluations::Interface::Dtc::evaluationSchemaChanged, this, &HandlerOcData::onEvaluationSchemaChanged);
auto cb = [this](const Evaluations::EvaluationSchema & schema)
{
onEvaluationSchemaChanged(schema, DataModification::eAdded);
};
m_evlDtc->evaluationSchemas(cb);
// EVL FTC enable
if (!m_evlFtc->enableEvlCommentModify())
{
ERROR_LOG(m_logger) << "Enabling EVL Function-Topics failed.";
return false;
}
// Msg FTC enable
if (!m_msgFtc->enableCreateOperatorMessage())
{
ERROR_LOG(m_logger) << "Enabling MSG Function-Topics failed.";
return false;
}
if (!m_ppmDtc->enableParticipant())
{
ERROR_LOG(m_logger) << "Enabling PPM Data-Topics failed.";
return false;
}
if (!m_ppmFtc->enableRegisterParticipant())
{
ERROR_LOG(m_logger) << "Enabling PPM FTC-Topics failed.";
return false;
}
// TAB DTC enable
if (!m_tabDtc->enableOcData())
{
ERROR_LOG(m_logger) << "Enabling TAB Data-Topics failed.";
return false;
}
// TAB DTC enable
if (!m_tabDtc->enableConnections())
{
ERROR_LOG(m_logger) << "Enabling TAB Data-Topics failed.";
return false;
}
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::ocDataChanged, this, &HandlerOcData::onOcDataChanged);
// TAB FTC enable
if (!m_tabFtc->enableSendOcData())
{
ERROR_LOG(m_logger) << "Enabling TAB Function-Topics failed.";
return false;
}
// Handler aes data
if (!m_handlerOcAesData->init())
{
ERROR_LOG(m_logger) << "Could not initialise HandlerOcAesData.";
return false;
}
connect(m_stateInformationTimer, &QTimer::timeout, this, &HandlerOcData::sendStateInformation);
m_stateInformationTimer->setInterval(Settings::stateInformationCycleTime());
INFO_LOG(m_logger) << "Starting StateInformation timer with interval: " << m_stateInformationTimer->interval();
m_stateInformationTimer->start();
INFO_LOG(m_logger) << "Initialisation HandlerOcData succesful.";
return true;
}
void HandlerOcData::onEvlCommentModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
ERROR_LOG(m_logger) << "Evaluation could not be transmitted to EVL: " << reply.translated();
else
DEBUG_LOG(m_logger) << "Evaluation successfully transmitted to EVL!";
}
void HandlerOcData::onCreateOperatorMessageReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
ERROR_LOG(m_logger) << "Message could not be created by MSG: " << reply.translated();
else
DEBUG_LOG(m_logger) << "Message created successfully by MSG!";
}
void HandlerOcData::onSendOcDataReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
ERROR_LOG(m_logger) << "Oc data could not be send: " << reply.translated();
else
DEBUG_LOG(m_logger) << "Oc data send successfully to TAB!";
}
void HandlerOcData::onRegisterParticipantReply(const ParticipantManagement::RegisterReply &reply)
{
if (reply.errorString.size())
ERROR_LOG(m_logger) << "Modify Participant data could not be send: " << reply.errorString;
else
DEBUG_LOG(m_logger) << "Modify Participant data send successfully to ppm!";
}
void HandlerOcData::onEvaluationSchemaChanged(const Evaluations::EvaluationSchema &data, DataModification modType)
{
if ((modType != DataModification::eAdded) && (modType != DataModification::eModified))
return;
if (data.sendToTa)
m_currentActiveEvaluationSchemaId = data.id;
}
void HandlerOcData::onOcDataChanged(const TrainingAreaBase::OcData &data, DataModification modType)
{
if ((modType != DataModification::eAdded) && (modType != DataModification::eModified))
return;
if (data.sampleTime < QDateTime::currentMSecsSinceEpoch() - 1000 * 60 * 10) // older than 10 mins -> ignore
return;
const QByteArray payload = LtsUtils::toQByteArray(data.payload);
unsigned int telegramId;
LtsUtils::get1Byte(payload, telegramId);
DEBUG_LOG(m_logger) << "New OcData telegramId: " << telegramId;
switch (telegramId)
{
case OcSituation::TelegramId::Message:
{
handleMessage(payload);
break;
}
case OcSituation::TelegramId::DemandEvaluationSchema:
{
handleDemandEvaluationSchema(payload, data.equipmentNumber);
break;
}
case OcSituation::TelegramId::Evaluation:
{
handleEvaluation(payload);
break;
}
case OcSituation::TelegramId::DemandSituation:
{
handleDemandSituation(payload, data.equipmentNumber);
break;
}
case OcSituation::TelegramId::DemandAesItems:
{
OcSituation::AesType aesType;
size_t pos = 1;
LtsUtils::get1Byte(payload, pos, aesType);
m_handlerOcAesData->demandAesItems(aesType, data.equipmentNumber);
break;
}
case OcSituation::TelegramId::EquipmentErrorRegistration:
{
handleEquipmentErrorRegistration(payload);
break;
}
case OcSituation::TelegramId::EquipmentRegistration:
{
handleEquipmentRegistration(payload);
break;
}
default:
{
INFO_LOG(m_logger) << "OC-data with telegram ID: " << telegramId << " is not by HandlerOcData OSS!";
break;
}
}
}
void HandlerOcData::onSendOcData(const TrainingAreaBase::SendOcDataRequest &req)
{
m_tabFtc->sendOcDataRequest(req, this);
}
void HandlerOcData::sendStateInformation()
{
QByteArray payload;
LtsUtils::set1Byte(OcSituation::TelegramId::StateInformation, payload);
LtsUtils::set2Byte(m_currentActiveEvaluationSchemaId, payload);
LtsUtils::set2Byte(m_handlerOcAesData->dangerAreaResetCnt(), payload);
LtsUtils::set2Byte(m_handlerOcAesData->iedResetCnt(), payload);
TrainingAreaBase::SendOcDataRequest out;
out.payload = LtsUtils::convert<std::vector<uint8_t>>(payload);
/*!
* \details Only if Tetra is connected, the OcData telegram will be send
* If we not check = A bunch of telegrams will be queued/stored until Tetra is connected, than Tetra is in Overload
*/
QMapIterator<qint32, TrainingAreaBase::Connections> conIt(m_tabDtc->connectionss());
while (conIt.hasNext())
{
conIt.next();
for (TrainingAreaBase::ConnectionState conState : conIt.value().connections)
{
if (conState.name == "TETRA" && conState.state == false)
return;
}
}
onSendOcData(out);
}
void HandlerOcData::onSituationThreadExit()
{
ThreadOcSituationData *t = qobject_cast<ThreadOcSituationData *>(sender());
INFO_LOG(m_logger) << "Exit O/C-Thread for O/C-Laptop-Id: " << m_situationThreads.key(t);
QMutexLocker l(&m_accessMutex);
m_situationThreads.remove(m_situationThreads.key(t));
t->deleteLater();
}
void HandlerOcData::onCentralAesThreadExit()
{
ThreadOcCentralAesData *t = qobject_cast<ThreadOcCentralAesData *>(sender());
INFO_LOG(m_logger) << "Exit CentralAesData-Thread for O/C-Laptop-Id: " << m_centralAesDataThreads.key(t);
QMutexLocker l(&m_accessMutex);
m_centralAesDataThreads.remove(m_centralAesDataThreads.key(t));
t->deleteLater();
}
void HandlerOcData::onSendEquipmentMessageOcRequest(const rti::core::SampleIdentity &cookie, const SendEquipmentMessageRequest &request)
{
QByteArray preparedPayload;
LtsUtils::set1Byte(OcSituation::TelegramId::Message, preparedPayload);
LtsUtils::set2Byte(0, preparedPayload); // dummy receiverId is individually set for each eqId in list
LtsUtils::set1Byte(Messaging::AddressType::ObserverController, preparedPayload);
LtsUtils::set2Byte(request.sender, preparedPayload);
LtsUtils::set1Byte(request.senderType, preparedPayload);
LtsUtils::set2Byte(m_mainHandler->exerciseId(), preparedPayload);
preparedPayload.append(QByteArray::fromStdString(request.subject));
preparedPayload.append('\n'); // separating subject from message
preparedPayload.append(QByteArray::fromStdString(request.message));
for (const auto equipmentNumber : request.equipmentNumbers)
{
TrainingAreaBase::SendOcDataRequest out;
out.equipmentNumber = equipmentNumber;
// replace 2 bytes with current receiver
QByteArray receiverId;
LtsUtils::set2Byte(equipmentNumber, receiverId);
QByteArray payload = preparedPayload.replace(1, 2, receiverId);
out.payload = LtsUtils::convert<std::vector<uint8_t>>(payload);
onSendOcData(out);
}
m_fts->sendEquipmentMessageOcReply(cookie, Core::FunctionReplyObject(request.requestId));
}
void HandlerOcData::onEquipmentErrorRequest(const rti::core::SampleIdentity &cookie, const EquipmentErrorRequest &request)
{
ERROR_LOG(m_logger) << "onEquipmentErrorRequest" << request.equipmentNumber;
EquipmentErrorRegistration out;
// out.id(request.requestId());
out.sampleTime = QDateTime::currentMSecsSinceEpoch();
out.participant = QString::number(request.equipmentNumber).toStdString();
out.device = request.device;
out.text = request.text;
m_dts->publish(out);
m_fts->equipmentErrorReply(cookie, Core::FunctionReplyObject(request.requestId));
}
void HandlerOcData::handleDemandSituation(const QByteArray &data, int equipmentId)
{
OcSituation::SituationCenterType centerType;
int centerEquipmentId = 0, radius = 0;
Core::GeoPosition2D position;
position.lon = std::nan("");
position.lat = std::nan("");
bool initial = false;
size_t pos = 1;
LtsUtils::get1Byte(data, pos, centerType);
if (centerType == OcSituation::SituationCenterType::Equipment)
{
LtsUtils::get2Byte(data, pos, centerEquipmentId);
LtsUtils::get2Byte(data, pos, radius);
DEBUG_LOG(m_logger) << "Request from O/C-Laptop-Id: " << equipmentId
<< " centerEquipmentId: " << centerEquipmentId << " radius: " << radius;
}
else
{
double tmp;
LtsUtils::get8Byte(data, pos, tmp);
position.lon = tmp;
LtsUtils::get8Byte(data, pos, tmp);
position.lat = tmp;
LtsUtils::get2Byte(data, pos, radius);
DEBUG_LOG(m_logger) << "Request from O/C-Laptop-Id: " << equipmentId
<< " center: " << position << " radius: " << radius;
}
bool filterActive = false;
LtsUtils::get1Byte(data, pos, initial);
LtsUtils::get1Byte(data, pos, filterActive);
QSet<ParticipantManagement::TypeClass> typeClassList{};
QSet<int> partyList{};
if (filterActive)
{
// get partyTypes
int pCount = 0;
LtsUtils::get1Byte(data, pos, pCount);
for (int i = 0; i < pCount; i++)
{
int partyId;
LtsUtils::get2Byte(data, pos, partyId);
partyList.insert(partyId);
}
//get types
int typeCount = 0;
LtsUtils::get1Byte(data, pos, typeCount);
for (int i = 0; i < typeCount; i++)
{
int typClass;
LtsUtils::get1Byte(data, pos, typClass);
typeClassList.insert((ParticipantManagement::TypeClass)typClass);
}
}
QMutexLocker l(&m_accessMutex);
// Situation Thread
ThreadOcSituationData *ocThread = m_situationThreads.value(equipmentId);
bool bInitialSituation;
if (!ocThread)
{
ocThread = new ThreadOcSituationData(m_mainHandler, equipmentId, centerEquipmentId, radius, filterActive, partyList, typeClassList);
m_situationThreads.insert(equipmentId, ocThread);
connect(ocThread, &QThread::finished, this, &HandlerOcData::onSituationThreadExit);
connect(ocThread, &ThreadOcSituationData::sendOcData, this, &HandlerOcData::onSendOcData);
ocThread->start();
bInitialSituation = true;
}
else
bInitialSituation = initial;
ocThread->requestOcSituationData(centerType, centerEquipmentId, position, radius, filterActive, partyList, typeClassList, bInitialSituation);
// Central AES Data Thread
bool bInitialAes;
ThreadOcCentralAesData *centralAesDataThread = m_centralAesDataThreads.value(equipmentId);
if (!centralAesDataThread)
{
centralAesDataThread = new ThreadOcCentralAesData(m_mainHandler, equipmentId, centerEquipmentId, radius);
m_centralAesDataThreads.insert(equipmentId, centralAesDataThread);
connect(centralAesDataThread, &QThread::finished, this, &HandlerOcData::onCentralAesThreadExit);
connect(centralAesDataThread, &ThreadOcCentralAesData::sendOcData, this, &HandlerOcData::onSendOcData);
centralAesDataThread->start();
bInitialAes = true;
}
else
bInitialAes = initial;
centralAesDataThread->requestOcCentralAesData(centerType, centerEquipmentId, position, radius, bInitialAes);
}
void HandlerOcData::handleDemandEvaluationSchema(const QByteArray &data, int equipmentNumber)
{
Q_UNUSED(data);
// ignoring requested schema ID, as we only have one active schema to be send to TA
Evaluations::EvaluationSchema schema = m_evlDtc->evaluationSchema(m_currentActiveEvaluationSchemaId);
DEBUG_LOG(m_logger) << "Sending to equipmentnumber: " << equipmentNumber << " evaluation schmema: " << m_currentActiveEvaluationSchemaId;
TrainingAreaBase::SendOcDataRequest out;
out.equipmentNumber = equipmentNumber;
QByteArray payload;
LtsUtils::set1Byte(OcSituation::TelegramId::EvaluationSchema, payload);
LtsUtils::set2Byte(schema.id, payload);
QByteArray compressed = qCompress(QByteArray::fromStdString(schema.schemadata));
payload.append(compressed);
out.payload = LtsUtils::convert<std::vector<uint8_t>>(payload);
onSendOcData(out);
}
void HandlerOcData::handleEvaluation(const QByteArray &data)
{
Evaluations::EvlCommentModifyRequest out;
size_t pos = 1;
unsigned int tmp;
// get schema id
LtsUtils::get2Byte(data, pos, tmp);
out.schemaId = tmp;
// get sender operator id
LtsUtils::get4Byte(data, pos, tmp);
out.senderOperatorId = tmp;
// get receiver operator id
LtsUtils::get4Byte(data, pos, tmp);
if (tmp > 0)
out.receiverOperatorId = dds::core::optional<int32_t>(tmp);
// get timeStamp
int64_t timeStamp;
LtsUtils::get8Byte(data, pos, timeStamp);
out.ts = timeStamp;
// get hierarchy string
unsigned int hierarchyLength;
LtsUtils::get2Byte(data, pos, hierarchyLength);
out.hierarchy = QByteArray(data.mid(pos, hierarchyLength)).toStdString();
pos += hierarchyLength;
// get text string
unsigned int textLength;
LtsUtils::get2Byte(data, pos, textLength);
out.text = QByteArray(data.mid(pos, textLength)).toStdString();
DEBUG_LOG(m_logger) << "Got new evl comment: " << out;
m_evlFtc->evlCommentModifyRequest(out, this);
}
void HandlerOcData::handleMessage(const QByteArray &data)
{
Messaging::CreateOperatorMessageRequest out;
size_t pos = 1;
unsigned int tmp = 0;
unsigned int addressType;
// get receiver
LtsUtils::get2Byte(data, pos, tmp);
std::vector<int32_t> recipientIds;
recipientIds.push_back(tmp);
// get address type
LtsUtils::get1Byte(data, pos, addressType);
out.recipientType = static_cast<Messaging::AddressType>(addressType);
if (addressType == static_cast<int>(Messaging::AddressType::ObserverController))
{
int participantId = m_ppmDtc->participantIdByEquipmentNumber(tmp);
if (participantId > 0)
recipientIds[0] = participantId;
else
{
ERROR_LOG(m_logger) << "Recipient equipment number: " << tmp << " is unknown. Aborting creating message.";
return;
}
}
out.recipientIds = recipientIds;
// get sender
LtsUtils::get2Byte(data, pos, tmp);
LtsUtils::get1Byte(data, pos, addressType);
out.senderType = static_cast<Messaging::AddressType>(addressType);
if (addressType == static_cast<int>(Messaging::AddressType::ObserverController))
{
int participantId = m_ppmDtc->participantIdByEquipmentNumber(tmp);
if (participantId > 0)
out.senderId = participantId;
else
{
WARNING_LOG(m_logger) << "Sender equipment number: " << tmp << " is unknown. Setting senderId to 0.";
out.senderId = 0;
out.senderType = Messaging::AddressType::ObserverController;
}
}
else
{
// no need to check if operator still exists, there is no harm if not
out.senderId = tmp;
}
// get exerciseId
LtsUtils::get2Byte(data, pos, tmp);
if (tmp == 0)
WARNING_LOG(m_logger) << "Could'n set ExerciseId" << " " << tmp << " set to 0";
out.exerciseId = tmp;
// get address type
const QByteArray msg(data.right(data.size() - pos));
int idx = msg.indexOf('\n');
if (idx < 0)
{
out.subject = (tr("Message from %1").arg(out.senderId)).toStdString();
out.message = msg.constData();
}
else
{
out.subject = msg.left(idx).constData();
out.message = msg.mid(idx + 1).constData();
}
DEBUG_LOG(m_logger) << "Got new message: " << out;
m_msgFtc->createOperatorMessageRequest(out, this);
}
void HandlerOcData::handleEquipmentErrorRegistration(const QByteArray &data)
{
EquipmentErrorRegistration out;
size_t pos = 1;
unsigned int tmp;
// equipmentNumber
LtsUtils::get2Byte(data, pos, tmp);
out.equipmentNumber = tmp;
// participant
out.participant = data.mid(pos, 36).toStdString();
pos += 36;
// device
out.device = data.mid(pos, 36).toStdString();
pos += 36;
// length
LtsUtils::get1Byte(data, pos, tmp);
// text
out.text = data.mid(pos, tmp).toStdString();
out.sampleTime = QDateTime::currentMSecsSinceEpoch();
DEBUG_LOG(m_logger) << "Got new error registration: " << out;
m_dts->publish(out);
}
void HandlerOcData::handleEquipmentRegistration(const QByteArray &data)
{
size_t pos = 1;
unsigned int tmp;
// participantID
LtsUtils::get2Byte(data, pos, tmp);
int participantId = tmp;
// equipmentNumber
LtsUtils::get2Byte(data, pos, tmp);
int equipmentNumber = tmp;
ParticipantManagement::Participant part = m_ppmDtc->participant(participantId);
if (part.equipmentNumber.is_set() && equipmentNumber > 0)
{
// we need a deregistration first!
ParticipantManagement::RegisterParticipantRequest dereq;
dereq.assignState = ParticipantManagement::ParticipantAssignState::NotAssigned;
dereq.equipmentNumber = 0;
dereq.participantId = participantId;
dereq.info = part.info;
dereq.identification = part.identification;
m_ppmFtc->registerParticipantRequest(dereq, this);
}
ParticipantManagement::RegisterParticipantRequest req;
if (equipmentNumber > 0)
req.assignState = ParticipantManagement::ParticipantAssignState::HandoutExcon;
else
req.assignState = ParticipantManagement::ParticipantAssignState::NotAssigned;
req.equipmentNumber = equipmentNumber;
req.participantId = participantId;
req.info = part.info;
req.identification = part.identification;
DEBUG_LOG(m_logger) << "Try to register part with id: " << req.participantId << " and eqNumeber " << req.equipmentNumber;
m_ppmFtc->registerParticipantRequest(req, this);
}
} // Namespace OcSituationServer