454 lines
14 KiB
C++
Executable File
454 lines
14 KiB
C++
Executable File
/**
|
|
* Handler for aes data to be send to the oc-laptop transparent
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Philipp Dassow, NLST, 18-04-2018
|
|
*/
|
|
|
|
#include "handler_oc_aes_data.h"
|
|
#include <functional>
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <LtsUtilsCore/dds_vector.h>
|
|
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
|
|
|
#include "settings.h"
|
|
|
|
namespace OcSituationServer
|
|
{
|
|
|
|
HandlerOcAesData::HandlerOcAesData(MainHandler *mainHandler,
|
|
QObject *parent)
|
|
: QObject(parent)
|
|
, m_aesDtc(mainHandler->aesDtc())
|
|
, m_gimDtc(mainHandler->gimDtc())
|
|
, m_tabFtc(mainHandler->tabFtc())
|
|
, m_dbHandler(mainHandler->db())
|
|
, m_positionConverter(mainHandler->positionConverter())
|
|
, m_dangerAreaResetCnt(0)
|
|
, m_iedResetCnt(0)
|
|
, m_collectionTimer(QMap<OcSituation::AesType, QTimer*>())
|
|
, m_demandingEquipments(QMap<OcSituation::AesType, QSet<int>>())
|
|
, m_iedPositionsToBeSend(QMap<int, GuezIedManagement::IedPosition>())
|
|
, m_iedPositionCycleTimer(new QTimer(this))
|
|
, m_logger(getLogger("HandlerOcAesData"))
|
|
{}
|
|
|
|
HandlerOcAesData::~HandlerOcAesData()
|
|
{}
|
|
|
|
bool HandlerOcAesData::init()
|
|
{
|
|
// create collectionTimer
|
|
m_collectionTimer[OcSituation::AesType::DangerArea] = new QTimer(this);
|
|
m_collectionTimer[OcSituation::AesType::DangerArea]->setSingleShot(true);
|
|
m_collectionTimer[OcSituation::AesType::DangerArea]->setInterval(Settings::aesDemandCollectionTime());
|
|
connect(m_collectionTimer[OcSituation::AesType::DangerArea], &QTimer::timeout, this, &HandlerOcAesData::onCollectionTimeOutDemandDangerAreas);
|
|
|
|
m_collectionTimer[OcSituation::AesType::Ied] = new QTimer(this);
|
|
m_collectionTimer[OcSituation::AesType::Ied]->setSingleShot(true);
|
|
m_collectionTimer[OcSituation::AesType::Ied]->setInterval(Settings::aesDemandCollectionTime());
|
|
connect(m_collectionTimer[OcSituation::AesType::Ied], &QTimer::timeout, this, &HandlerOcAesData::onCollectionTimeOutDemandIeds);
|
|
|
|
// set reset counter
|
|
QVector<Database::OssResetCounter> dataVec;
|
|
// read all Ieds from database
|
|
if (!m_dbHandler->select(dataVec))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading reset counter from database!";
|
|
return false;
|
|
}
|
|
|
|
for (const auto &data : qAsConst(dataVec))
|
|
{
|
|
switch (data.aesTypeId)
|
|
{
|
|
case OcSituation::AesType::DangerArea:
|
|
{
|
|
m_dangerAreaResetCnt = data.resetCounter;
|
|
break;
|
|
}
|
|
case OcSituation::AesType::Ied:
|
|
{
|
|
m_iedResetCnt = data.resetCounter;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
WARNING_LOG(m_logger) << "Reset counter for aes type: " << data.aesTypeId << " read from db is not handled.";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// AES DTC enable
|
|
if (!m_aesDtc->enableDangerArea())
|
|
{
|
|
ERROR_LOG(m_logger) << "Enabling AES Data-Topics failed.";
|
|
return false;
|
|
}
|
|
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaChanged, this, &HandlerOcAesData::onDangerAreaChanged);
|
|
|
|
// GIM DTC enable
|
|
if (!m_gimDtc->enableIed() ||
|
|
!m_gimDtc->enableIedPosition())
|
|
{
|
|
ERROR_LOG(m_logger) << "Enabling GIM Data-Topics failed.";
|
|
return false;
|
|
}
|
|
connect(m_gimDtc.get(), &GuezIedManagement::Interface::Dtc::iedChanged, this, &HandlerOcAesData::onIedChanged);
|
|
connect(m_gimDtc.get(), &GuezIedManagement::Interface::Dtc::iedPositionChanged, this, &HandlerOcAesData::onIedPositionChanged);
|
|
|
|
connect(m_iedPositionCycleTimer, &QTimer::timeout, this, &HandlerOcAesData::sendIedPositions);
|
|
m_iedPositionCycleTimer->setInterval(Settings::iedPositionCycleTime());
|
|
DEBUG_LOG(m_logger) << "Starting ied position timer with interval: " << m_iedPositionCycleTimer->interval();
|
|
m_iedPositionCycleTimer->start();
|
|
|
|
return true;
|
|
}
|
|
|
|
void HandlerOcAesData::demandAesItems(OcSituation::AesType aesType, int eqNumber)
|
|
{
|
|
switch (aesType)
|
|
{
|
|
case OcSituation::AesType::DangerArea:
|
|
case OcSituation::AesType::Ied:
|
|
{
|
|
DEBUG_LOG(m_logger) << "Got demand for aes type: " << aesType << " from equipment: " << eqNumber;
|
|
|
|
if (!m_collectionTimer[aesType]->isActive())
|
|
m_collectionTimer[aesType]->start();
|
|
|
|
m_demandingEquipments[aesType].insert(eqNumber);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
WARNING_LOG(m_logger) << "Aes type: " << aesType << " is currently not handled.";
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerOcAesData::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 HandlerOcAesData::onDangerAreaChanged(const AreaEffectSimulation::DangerArea &data, DataModification mod)
|
|
{
|
|
Q_UNUSED(data);
|
|
Q_UNUSED(mod);
|
|
incrementResetCnt(OcSituation::AesType::DangerArea);
|
|
}
|
|
|
|
void HandlerOcAesData::onIedChanged(const GuezIedManagement::Ied &data, DataModification mod)
|
|
{
|
|
Q_UNUSED(data);
|
|
Q_UNUSED(mod);
|
|
incrementResetCnt(OcSituation::AesType::Ied);
|
|
}
|
|
|
|
void HandlerOcAesData::onIedPositionChanged(const GuezIedManagement::IedPosition &data, DataModification mod)
|
|
{
|
|
if (mod == DataModification::eRemoved)
|
|
return;
|
|
|
|
GuezIedManagement::Ied ied = m_gimDtc->ied(data.id());
|
|
if (ied.id() > 0)
|
|
{
|
|
if (ied.pairingState().underlying() != GuezIedManagement::IedPairingState::NotPaired)
|
|
m_iedPositionsToBeSend.insert(data.id(), data);
|
|
}
|
|
else
|
|
ERROR_LOG(m_logger) << "Got ied position for not existing ID: " << data.id();
|
|
}
|
|
|
|
void HandlerOcAesData::onCollectionTimeOutDemandDangerAreas()
|
|
{
|
|
std::function<void (int)> f = std::bind(&HandlerOcAesData::sendDangerAreasToTab, this, std::placeholders::_1);
|
|
collectionTimeout(OcSituation::AesType::DangerArea, f);
|
|
}
|
|
|
|
void HandlerOcAesData::onCollectionTimeOutDemandIeds()
|
|
{
|
|
std::function<void (int)> f = std::bind(&HandlerOcAesData::sendIedsToTab, this, std::placeholders::_1);
|
|
collectionTimeout(OcSituation::AesType::Ied, f);
|
|
}
|
|
|
|
void HandlerOcAesData::sendIedPositions()
|
|
{
|
|
if (m_iedPositionsToBeSend.size() == 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "No new ied positions to be send.";
|
|
return;
|
|
}
|
|
|
|
TrainingAreaBase::SendOcDataRequest req;
|
|
req.equipmentNumber(0); // ied positions are always send broadcast
|
|
|
|
QByteArray data, payload;
|
|
int cnt = 0;
|
|
|
|
// set "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::IedPositions, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
|
|
for (const auto &pos : qAsConst(m_iedPositionsToBeSend))
|
|
{
|
|
LtsUtils::set2Byte(m_gimDtc->ied(pos.id()).equipmentNumber(), data);
|
|
const QPointF relCoord(m_positionConverter->relativeFromGeographic(pos.position()));
|
|
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
|
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
|
|
|
data[1] = ++cnt;
|
|
|
|
QByteArray ba = qCompress(data);
|
|
DEBUG_LOG(m_logger) << "Added ied position " << pos
|
|
<< " data size: " << data.size()
|
|
<< " compressed size: " << ba.size();
|
|
|
|
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
|
payload.append(ba);
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
|
|
cnt = 0;
|
|
data.clear();
|
|
payload.clear();
|
|
|
|
// set new "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::IedPositions, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
}
|
|
}
|
|
|
|
if (cnt > 0) // is still data to be send?
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
|
payload.append(qCompress(data));
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
}
|
|
|
|
m_iedPositionsToBeSend.clear();
|
|
}
|
|
|
|
void HandlerOcAesData::collectionTimeout(OcSituation::AesType type, const std::function<void (int)> &sendFunction)
|
|
{
|
|
DEBUG_LOG(m_logger) << "There are " << m_demandingEquipments[type].size() << " requests for aes type: " << type
|
|
<< " sending Items as " << ((m_demandingEquipments[type].size() > 5) ? QStringLiteral("broadcast") : QStringLiteral("direct")) << " telegram(s)";
|
|
|
|
if (m_demandingEquipments[type].size() > 5)
|
|
sendFunction(0); // broadcast
|
|
else
|
|
for (int eqNumber : qAsConst(m_demandingEquipments[type]))
|
|
sendFunction(eqNumber);
|
|
|
|
//cleanup
|
|
m_demandingEquipments[type].clear();
|
|
}
|
|
|
|
void HandlerOcAesData::sendDangerAreasToTab(int eqNumber)
|
|
{
|
|
TrainingAreaBase::SendOcDataRequest req;
|
|
req.equipmentNumber(eqNumber);
|
|
|
|
const QMap<int, AreaEffectSimulation::DangerArea> dangerAreas = m_aesDtc->dangerAreas();
|
|
QByteArray data, payload;
|
|
int cnt = 0;
|
|
|
|
// set "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::DangerArea, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
|
|
for (const auto &dangerArea : dangerAreas)
|
|
{
|
|
if (dangerArea.effectStateId() >= AreaEffectSimulation::AesEffectState::EsCreated) // do not transfer ended or deleted areas
|
|
{
|
|
LtsUtils::set2Byte(dangerArea.id(), data);
|
|
QByteArray name(QByteArray::fromStdString(dangerArea.name()));
|
|
name.resize(8);
|
|
data.append(name);
|
|
if (dangerArea.effectStart().is_set())
|
|
LtsUtils::set4Byte(dangerArea.effectStart().get() / 1000, data);
|
|
else
|
|
LtsUtils::set4Byte(0, data);
|
|
LtsUtils::set1Byte(dangerArea.segments().size(), data);
|
|
for (const auto &segment : dangerArea.segments())
|
|
{
|
|
const QPointF relCoord(m_positionConverter->relativeFromGeographic(segment));
|
|
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
|
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
|
}
|
|
|
|
data[1] = ++cnt;
|
|
|
|
QByteArray ba = qCompress(data);
|
|
DEBUG_LOG(m_logger) << "Added danger area " << dangerArea
|
|
<< " data size: " << data.size()
|
|
<< " compressed size: " << ba.size();
|
|
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
|
payload.append(ba);
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
|
|
cnt = 0;
|
|
data.clear();
|
|
payload.clear();
|
|
|
|
// set new "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::DangerArea, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cnt > 0) // is still data to be send?
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
|
payload.append(qCompress(data));
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
}
|
|
}
|
|
|
|
void HandlerOcAesData::sendIedsToTab(int eqNumber)
|
|
{
|
|
TrainingAreaBase::SendOcDataRequest req;
|
|
req.equipmentNumber(eqNumber);
|
|
|
|
const QMap<int, GuezIedManagement::Ied> ieds = m_gimDtc->ieds();
|
|
QByteArray data, payload;
|
|
int cnt = 0;
|
|
|
|
// set "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::Ied, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
|
|
for (const auto &ied : ieds)
|
|
{
|
|
LtsUtils::set2Byte(ied.equipmentNumber(), data);
|
|
LtsUtils::set1Byte(ied.type().underlying(), data);
|
|
uint8_t trigger = (uint8_t(ied.tautWireTrigger()) << 3) |
|
|
(uint8_t(ied.lightBarrierTrigger()) << 2) |
|
|
(uint8_t(ied.switchTrigger()) << 1) |
|
|
(uint8_t(ied.remoteTrigger()));
|
|
LtsUtils::set1Byte(trigger, data);
|
|
LtsUtils::set1Byte(ied.explosiveForce(), data);
|
|
LtsUtils::set1Byte(ied.partyId(), data);
|
|
LtsUtils::set1Byte(ied.tacticalState().underlying(), data);
|
|
|
|
// set an initial position, as only paired ieds are updated concurrently
|
|
const auto pos = m_gimDtc->iedPosition(ied.id());
|
|
const QPointF relCoord(m_positionConverter->relativeFromGeographic(pos.position()));
|
|
LtsUtils::set3Byte(qRound(relCoord.x()), data);
|
|
LtsUtils::set3Byte(qRound(relCoord.y()), data);
|
|
|
|
data[1] = ++cnt;
|
|
|
|
QByteArray ba = qCompress(data);
|
|
DEBUG_LOG(m_logger) << "Added ied " << ied
|
|
<< " data size: " << data.size()
|
|
<< " compressed size: " << ba.size();
|
|
|
|
if (ba.size() > Settings::maxNumOfBytePerAesTxCycle()) // one cycle is full -> send
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << ba.toHex(' ');
|
|
payload.append(ba);
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
|
|
cnt = 0;
|
|
data.clear();
|
|
payload.clear();
|
|
|
|
// set new "header" data
|
|
LtsUtils::set1Byte(OcSituation::TelegramId::AesItems, payload);
|
|
LtsUtils::set1Byte(OcSituation::AesType::Ied, data);
|
|
LtsUtils::set1Byte(cnt, data);
|
|
}
|
|
}
|
|
|
|
if (cnt > 0) // is still data to be send?
|
|
{
|
|
DEBUG_LOG(m_logger) << "Uncompressed Data: " << data.toHex(' ');
|
|
DEBUG_LOG(m_logger) << "Compressed Data: " << qCompress(data).toHex(' ');
|
|
payload.append(qCompress(data));
|
|
req.payload(LtsUtils::convert<std::vector<uint8_t>>(payload));
|
|
m_tabFtc->sendOcDataRequest(req, this);
|
|
}
|
|
}
|
|
|
|
void HandlerOcAesData::incrementResetCnt(OcSituation::AesType aesType)
|
|
{
|
|
switch (aesType)
|
|
{
|
|
case OcSituation::AesType::DangerArea:
|
|
{
|
|
setResetCnt(aesType, m_dangerAreaResetCnt + 1);
|
|
break;
|
|
}
|
|
case OcSituation::AesType::Ied:
|
|
{
|
|
setResetCnt(aesType, m_iedResetCnt + 1);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
WARNING_LOG(m_logger) << "Reset counter for aes type: " << aesType << " is not handled in incrementResetCnt.";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerOcAesData::setResetCnt(OcSituation::AesType aesType, int resetCnt)
|
|
{
|
|
Database::OssResetCounter data;
|
|
data.aesTypeId = aesType;
|
|
data.resetCounter = resetCnt;
|
|
|
|
switch (aesType)
|
|
{
|
|
case OcSituation::AesType::DangerArea:
|
|
{
|
|
m_dangerAreaResetCnt = resetCnt;
|
|
break;
|
|
}
|
|
case OcSituation::AesType::Ied:
|
|
{
|
|
m_iedResetCnt = resetCnt;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
WARNING_LOG(m_logger) << "Reset counter for aes type: " << aesType << " is not handled in setResetCnt.";
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update db
|
|
if (!m_dbHandler->update(data))
|
|
ERROR_LOG(m_logger) << "Error updating reset counter in db.";
|
|
}
|
|
|
|
} // namespace OcSituationServer
|