Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

@@ -0,0 +1,48 @@
#
# Commmunication with WlsProxy
# $Id$
# $HeadURL$
# $Author$
#
SET(SRCS
logger.cpp
logger.h
main_dispatcher.cpp
main_dispatcher.h
main_handler_tx.cpp
main_handler_tx.h
plugin.cpp
plugin.h
tetra_dispatcher.cpp
tetra_dispatcher.h
tetra_handler_rx.cpp
tetra_handler_rx.h
tetra_handler_tx.cpp
tetra_handler_tx.h
tetra_prtcnv.cpp
tetra_prtcnv.h
wls_dispatcher.cpp
wls_dispatcher.h
wls_handler_rx.cpp
wls_handler_rx.h
wls_handler_tx.cpp
wls_handler_tx.h
)
QT5_ADD_RESOURCES(SRCS tetra.qrc)
NGL_ADD_LIBRARY(AAR SV tabPluginWlsTetra MODULE ${SRCS})
NGL_INSTALL_TARGET(tabPluginWlsTetra)
NGL_TARGET_LINK_LIBRARIES(tabPluginWlsTetra
CoPrtCnv
NGLLogger
nglsettings
PrtCnvLib
Qt5::Core
Qt5::Network
Qt5::Sql
Qt5::WebSockets
tabPluginInterface
tabTelegrams
)
+101
View File
@@ -0,0 +1,101 @@
[Common]
LogCentralTelegrams=1
LogRadioTelegrams=1
LogTelegramPath=logdata
LogTelegramPrefix=PrtCnv_
; virtual TeilnehmerId of protocol-converter
VirtualIdPrtCnv=90
MaxEqID=50000
;or max unsigned short: 65535
[Db]
DatabaseFileName=db/telegrams.db
[Central]
UseSocketsInsteadFiles=1
HostName=EXCTDS01
Port=9600
; Milliseconds
AckTimeout=900
ConnectTimeout=2000
DisconnectTimeout=10000
AliveTimeout=3000
; nbr of unsuccessful send-attempts, before telegram will be deleted without sending it
NbrOfAttempts=5
[Radio]
UseScrambling=1
EmergencyCallISSI=9000
BroadcastISSI=5000
ConnectTimeout=2000
HostName=CCSTSW01
Port=52010
HostName1=CCSTSW02
Port1=52010
HostISSI=9998
; Seconds
CyclicEnvironmentTime=30
HostISSI=9999
; Milliseconds
DisconnectTimeout=10000
AliveTimeout=3000
; 1 - UseSDS_TL
UseSDS_TL=0
DumpReceivedTelegrams=1
DumpSentTelegrams=1
; GSSIs which we would like to subscribe to - make sure to not subscribe to our own BroadcastISSI !
ListenGroups=5001
[Login]
LoginFilePathWithPrefix=login/pk_
DoLicenseDespiteSelftestOrConfigFailure=0
DoCheckPlayerId=1
LowestPlayerId=500
HighestPlayerId=65535
PlayerIdFilePath=playerIds.dat
[Broadcast]
; Count, how often a Broadcast telegram will be send (minimum 1, 0 will be ignored and the telegram is sent anyway)
MaxBroadcastSendCount=1
; In seconds, delay between sending 1st and 2nd broadcast (< 0 -> disable)
BroadcastDelay2=10
; In seconds, delay between sending 2nd and 3rd broadcast (< 0 -> disable)
BroadcastDelay3=20
; the time to wait for NachforderungBroadcast from TNEs, before begin sending the broadcasts
ClaimWindow=30
; factor for extend the claimwindow when we have full load in downlink
FullLoadFactor=3
; if less TNEs ask for broadcasts, they will be send directed
BroadcastLimit=10
; the time to wait before sending next broadcast in milliseconds
SendGap=500
; minimum id of DUS-Mines to be able to get reactivated
MinimumDusMineId=2048
[TrafficControl]
; from PrtCnv to Tetra (Telegram-Counting)
; Number of telegrams (0..255) reported by air-interface-report telegram when we have high load
SendQueueHighLoad=150
; Number of telegrams that will be sent per second, when we have high-load
SendTelegramsHighLoad=50
; Number of telegrams (0..255) reported by air-interface-report telegram when we have full load
SendQueueFullLoad=200
; Number of telegrams that will be sent per second, when we have full-load
SendTelegramsFullLoad=10
; from Tetra to PrtCnv (Byte-Counting)
; high load in percent (0 .. 100)
ReceiveQueueHighLoad=50
; full load in percent (ReceiveQueueHighLoad .. 100)
ReceiveQueueFullLoad=75
; hysteresis in percent (0 .. 10)
ReceiveQueueHysteresis=5
; Averaging time in seconds
ReceiveAveragingTime=5
; Throughput in KB/s per Transceiver
ReceiveThroughput=3.6
; Transceiver count
TransceiverCount=6
[Injection]
Enable=true
Port=46666
+38
View File
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace WlsTetra
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "TAB.WLS.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace WlsTetra
+23
View File
@@ -0,0 +1,23 @@
/**
* @RDE_HEADER@
* Logging for TrainingAreaBase
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace WlsTetra
{
using LOGGER_T = NGL::INGLLogger&;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace WlsTetra
@@ -0,0 +1,75 @@
/**
* Send / Receive telegrams to/from Wls
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "main_dispatcher.h"
#include "main_handler_tx.h"
#include "wls_dispatcher.h"
#include "wls_handler_tx.h"
#include "tetra_dispatcher.h"
#include "tetra_handler_tx.h"
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
#include <QSettings>
namespace WlsTetra
{
MainDispatcher::MainDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
NGL::Settings *settings)
: m_wlsDispatcher(new WlsDispatcher(pdp, recvFromTabCb, settings))
, m_tetraDispatcher(new TetraDispatcher(pdp, recvFromTabCb))
, m_recvFromTabCb(recvFromTabCb)
, m_mainHandlerTx(std::make_shared<MainHandlerTx>(std::dynamic_pointer_cast<WlsHandlerTx>(m_wlsDispatcher->sendToTab()),
std::dynamic_pointer_cast<TetraHandlerTx>(m_tetraDispatcher->sendToTab())))
, m_logger(getLogger("MainDispatcher"))
{
N_CoPrtCnv::CoPrtCnvTelegramConverter::setUse2BytesForSingleFireDiameter(
settings->settings()->value(QLatin1String("AES/use2BytesForSingleFireDiameter"), true).toBool());
connect(m_wlsDispatcher, &WlsDispatcher::broadcastTelegramsRequest,
m_tetraDispatcher, &TetraDispatcher::onBroadcastTelegramsRequest);
connect(m_wlsDispatcher, &WlsDispatcher::wlsTelegramReceived,
m_tetraDispatcher, &TetraDispatcher::onWlsTelegramReceived);
connect(m_wlsDispatcher, &WlsDispatcher::wlsTelegramSent,
m_tetraDispatcher, &TetraDispatcher::onWlsTelegramSent);
connect(m_wlsDispatcher, &WlsDispatcher::connectionState,
this, &MainDispatcher::connectionState);
connect(m_tetraDispatcher, &TetraDispatcher::connectionState,
this, &MainDispatcher::connectionState);
connect(m_tetraDispatcher, &TetraDispatcher::participantLicenseChange,
m_wlsDispatcher, &WlsDispatcher::onParticipantLicenseChange);
}
MainDispatcher::~MainDispatcher()
{
m_mainHandlerTx = nullptr;
m_recvFromTabCb = nullptr;
delete m_wlsDispatcher;
delete m_tetraDispatcher;
}
bool MainDispatcher::init()
{
return m_wlsDispatcher->init() && m_tetraDispatcher->init();
}
std::shared_ptr<TrainingAreaBase::SendToTab> MainDispatcher::sendToTab()
{
return m_mainHandlerTx;
}
bool MainDispatcher::canSendData() const
{
return m_wlsDispatcher->canSendData() || m_tetraDispatcher->canSendData();
}
void MainDispatcher::exerciseChanged()
{
m_wlsDispatcher->exerciseChanged();
m_tetraDispatcher->exerciseChanged();
}
} // namespace WlsTetra
@@ -0,0 +1,48 @@
/**
* Send / Receive telegrams to/from Wls
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <TrainingAreaBase/tab_plugin_interface.h>
#include <DDS/Core/function_reply_object.h> // tr_lts
#include "logger.h"
namespace WlsTetra
{
class WlsDispatcher;
class TetraDispatcher;
class MainDispatcher final : public TrainingAreaBase::Plugin::Interface
{
Q_OBJECT
public:
MainDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
NGL::Settings *settings);
~MainDispatcher();
public Q_SLOTS:
bool init() override;
public:
std::shared_ptr<TrainingAreaBase::SendToTab> sendToTab() override;
bool isDebugInterface() const override { return false; }
bool canSendData() const override;
void exerciseChanged() override;
const char *name() const override { return tr_lts("dds", "WlsTetra"); }
private:
WlsDispatcher *m_wlsDispatcher;
TetraDispatcher *m_tetraDispatcher;
std::shared_ptr<TrainingAreaBase::RecvFromTab> m_recvFromTabCb;
std::shared_ptr<TrainingAreaBase::SendToTab> m_mainHandlerTx;
NGL::INGLLogger &m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,299 @@
/**
* Convert telegrams to Json and sent to WLS proxy
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "main_handler_tx.h"
#include "tetra_handler_tx.h"
#include "wls_handler_tx.h"
using namespace TrainingAreaBase;
namespace WlsTetra
{
template<typename T>
struct HasHeaderStruct
{
struct Fallback { TetraIcd::Header header; };
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<TetraIcd::Header Fallback::*, &C::header> *))[1];
template<typename C> static char (&f(...))[2];
public:
static bool const value = sizeof(f<Derived>(nullptr)) == 2;
};
template <typename T, typename std::enable_if<HasHeaderStruct<T>::value, int>::type = 0>
static inline int getEquipNo(const T *data)
{
return data->header.equipmentNumber;
}
template < typename T, typename std::enable_if < !HasHeaderStruct<T>::value, int >::type = 0 >
static inline int getEquipNo(const T *)
{
return -1;
}
MainHandlerTx::MainHandlerTx(const std::shared_ptr<WlsHandlerTx> &wlsTx,
const std::shared_ptr<TetraHandlerTx> &tetraTx)
: m_wlsHandlerTx(wlsTx)
, m_tetraHandlerTx(tetraTx)
, m_logger(getLogger("MainHandlerTx"))
{}
SendToTab::HandleState MainHandlerTx::canHandleTelegram(int equipmentNumber, int telegramId) const
{
SendToTab::HandleState hsWls = m_wlsHandlerTx->canHandleTelegram(equipmentNumber, telegramId);
if (hsWls == SendToTab::HandleState::YesConsume ||
hsWls == SendToTab::HandleState::YesShare)
return hsWls;
SendToTab::HandleState hsTetra = m_tetraHandlerTx->canHandleTelegram(equipmentNumber, telegramId);
if (hsTetra == SendToTab::HandleState::YesConsume ||
hsTetra == SendToTab::HandleState::YesShare)
return hsTetra;
if (hsWls == SendToTab::HandleState::YesFallback)
return hsWls;
if (hsTetra == SendToTab::HandleState::YesFallback)
return hsTetra;
if (hsWls == SendToTab::HandleState::Debug)
return hsWls;
if (hsTetra == SendToTab::HandleState::Debug)
return hsTetra;
return SendToTab::HandleState::No;
}
void MainHandlerTx::resetSendCounter()
{
m_wlsHandlerTx->resetSendCounter();
}
bool MainHandlerTx::txData(const TetraIcd::Acknowledge &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DemandBite &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::Init &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::SetVulnerabilityModel &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DemandEquipmentConfigurationReport &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DemandVulnerabilityStateChange &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::LanguageSelection &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::EquipmentMessage &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::EquipmentMessageOC &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateSingleExplosion &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateAreaExplosion &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateMineArea &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::MineAreaSingleMineState &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateNContamination &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateCContamination &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DeactivateEffectSimulation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ModifyAreaEffectSimulationName &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::PauseEffectSimulation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ResumeEffectSimulation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::MineTriggered &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DusMineReactivation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateFunctionalArea &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CreateDusSingleMine &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ExerciseEnvironmentData &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ExerciseStateData &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::OpaquePayloadDataOut &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ParticipantSwVersionsRequest &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::TechnicalArea &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CesHitInformation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::CesHitRequest &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ParticipantMode &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DemandParticipantMode &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ParticipantConfiguration &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::DemandParticipantConfiguration &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::ExerciseEquipmentAssignmentComplete &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::Sanitation &data)
{
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::SelectiveReammunition &data)
{
DEBUG_LOG(m_logger) << "MainHandlerTx::txData SelectiveReammunition";
return sendToTxMixin(&data);
}
bool MainHandlerTx::txData(const TetraIcd::SetDevicePowerRequest &data)
{
return sendToTxMixin(&data);
}
template <typename T>
bool MainHandlerTx::sendToTxMixin(const T *data)
{
const int equipmentNumber = getEquipNo(data);
SendToTab::HandleState hsWls = m_wlsHandlerTx->canHandleTelegram(equipmentNumber, data->id());
SendToTab::HandleState hsTetra = m_tetraHandlerTx->canHandleTelegram(equipmentNumber, data->id());
if (hsWls == SendToTab::HandleState::Debug)
m_wlsHandlerTx->txData(*data);
if (hsTetra == SendToTab::HandleState::Debug)
m_tetraHandlerTx->txData(*data);
if (hsWls == SendToTab::HandleState::YesConsume)
return m_wlsHandlerTx->txData(*data);
if (hsTetra == SendToTab::HandleState::YesConsume)
return m_tetraHandlerTx->txData(*data);
bool bRet = false;
if (hsWls == SendToTab::HandleState::YesShare)
bRet |= m_wlsHandlerTx->txData(*data);
if (hsTetra == SendToTab::HandleState::YesShare)
bRet |= m_tetraHandlerTx->txData(*data);
if (bRet)
return bRet;
if (hsWls == SendToTab::HandleState::YesFallback)
return m_wlsHandlerTx->txData(*data);
if (hsTetra == SendToTab::HandleState::YesFallback)
return m_tetraHandlerTx->txData(*data);
return false;
}
} // namespace WlsTetra
@@ -0,0 +1,79 @@
/**
* Convert telegrams to Json and sent to WLS proxy
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include "logger.h"
#include <TrainingAreaBase/send_to_tab.h>
#include <memory>
class QWebSocket;
namespace WlsTetra
{
class WlsHandlerTx;
class TetraHandlerTx;
class MainHandlerTx final : public QObject, public TrainingAreaBase::SendToTab
{
Q_OBJECT
public:
explicit MainHandlerTx(const std::shared_ptr<WlsHandlerTx> &wlsTx,
const std::shared_ptr<TetraHandlerTx> &tetraTx);
const char *name() const override { return "WlsTetra"; }
HandleState canHandleTelegram(int equipmentNumber, int telegramId) const override;
void resetSendCounter() override;
bool txData(const TrainingAreaBase::TetraIcd::Acknowledge &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandBite &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Init &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data) override;
bool txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data) override;
bool txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineTriggered &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Sanitation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data) override;
private:
template <typename T>
bool sendToTxMixin(const T *data);
private:
std::shared_ptr<WlsHandlerTx> m_wlsHandlerTx;
std::shared_ptr<TetraHandlerTx> m_tetraHandlerTx;
LOGGER_T m_logger;
};
}
@@ -0,0 +1 @@
1-65535
+27
View File
@@ -0,0 +1,27 @@
/**
* Send / Receive telegrams to/from TX/RX directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "plugin.h"
#include "main_dispatcher.h"
#include <nglsettings/nglsettings_settings.h>
namespace WlsTetra
{
//
// TetraXdrPlugin
//
std::shared_ptr<TrainingAreaBase::Plugin::Interface> TabWlsPlugin::createInterface(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
const std::shared_ptr<TrainingAreaBase::TxMixin> &sendToTabCb,
NGL::Settings *settings)
{
Q_UNUSED(sendToTabCb);
return std::make_shared<MainDispatcher>(pdp, recvFromTabCb, settings);
}
} // namespace WlsTetra
+30
View File
@@ -0,0 +1,30 @@
/**
* Send / Receive telegrams to/from TX/RX directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <TrainingAreaBase/tab_plugin_interface.h>
namespace WlsTetra
{
class TabWlsPlugin : public QObject, public TrainingAreaBase::Plugin::Plugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "special:3:tab.wls")
Q_INTERFACES(TrainingAreaBase::Plugin::Plugin)
public:
TabWlsPlugin() = default;
~TabWlsPlugin() = default;
std::shared_ptr<TrainingAreaBase::Plugin::Interface> createInterface(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
const std::shared_ptr<TrainingAreaBase::TxMixin> &sendToTabCb,
NGL::Settings *settings) override;
};
} // namespace WlsTetra
+6
View File
@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>playerIds.dat</file>
<file>PrtCnv.dat</file>
</qresource>
</RCC>
@@ -0,0 +1,116 @@
/**
* Send / Receive telegrams to/from PrtCnv
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "tetra_dispatcher.h"
#include "tetra_handler_rx.h"
#include "tetra_handler_tx.h"
namespace WlsTetra
{
//
// TetraDispatcher
//
TetraDispatcher::TetraDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb)
: TrainingAreaBase::Plugin::Interface()
, m_rxHandler(std::make_shared<TetraHandlerRx>(recvFromTabCb))
, m_txHandler(std::make_shared<TetraHandlerTx>())
, m_tetraPrtCnv(new TetraPrtCnv(pdp, this))
, m_dataProvider(pdp)
, m_logger(getLogger("TetraDispatcher"))
{
connect(m_tetraPrtCnv, &TetraPrtCnv::tetraConnectionChanged,
this, &TetraDispatcher::onTetraConnectionChanged);
connect(m_rxHandler.get(), &TetraHandlerRx::tetraConnectionChanged,
this, &TetraDispatcher::onTetraConnectionChanged);
connect(m_rxHandler.get(), &TetraHandlerRx::participantLicenseChange,
this, &TetraDispatcher::participantLicenseChange);
connect(m_tetraPrtCnv, &TetraPrtCnv::textMessageFromPrtCnv,
m_rxHandler.get(), &TetraHandlerRx::handleTelegram);
connect(m_rxHandler.get(), &TetraHandlerRx::initialAckReceived,
this, &TetraDispatcher::onSendInitialData);
connect(m_rxHandler.get(), &TetraHandlerRx::txData,
m_txHandler.get(), QOverload<const TrainingAreaBase::TetraIcd::Acknowledge &>::of(&TetraHandlerTx::txData));
connect(m_txHandler.get(), &TetraHandlerTx::outgoingMessage,
m_tetraPrtCnv, &TetraPrtCnv::textMessageToPrtCnv);
}
bool TetraDispatcher::init()
{
onTetraConnectionChanged(false);
if (!m_tetraPrtCnv->init())
return false;
return true;
}
void TetraDispatcher::onBroadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter)
{
emit m_tetraPrtCnv->broadcastTelegramsRequest(equipmentNumber, broadcastIndex, resetCounter);
}
void TetraDispatcher::onWlsTelegramReceived(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele)
{
m_tetraPrtCnv->logWlsTelegram(tele, false);
}
void TetraDispatcher::onWlsTelegramSent(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele)
{
m_tetraPrtCnv->logWlsTelegram(tele, true);
}
std::shared_ptr<TrainingAreaBase::SendToTab> TetraDispatcher::sendToTab()
{
return std::static_pointer_cast<TrainingAreaBase::SendToTab>(m_txHandler);
}
bool TetraDispatcher::canSendData() const
{
return m_txHandler->isConnected();
}
void TetraDispatcher::exerciseChanged()
{
m_tetraPrtCnv->onExerciseChanged();
}
void TetraDispatcher::onTetraConnectionChanged(bool bConnected)
{
NOTICE_LOG(m_logger) << "onTetraConnectionChanged: " << bConnected;
m_txHandler->setConnected(false);
if (!bConnected)
{
m_txHandler->resetSendCounter();
m_rxHandler->resetConnection();
}
emit connectionState(QString::fromUtf8(name()), bConnected);
}
void TetraDispatcher::onSendInitialData()
{
m_txHandler->setConnected(true);
if (m_dataProvider)
{
INFO_LOG(m_logger) << "sending initial data";
// on connect we must send:
if (m_dataProvider->exerciseId() > 0)
{
// - Umgebungsmeldung
m_txHandler->txData(m_dataProvider->exerciseEnvironmentData());
}
// - Betriebszustandsmeldung
m_txHandler->txData(m_dataProvider->exerciseStateData());
m_txHandler->txData(m_dataProvider->exerciseEquipmentAssignment());
const auto &aesTeles = m_dataProvider->aesTelegrams();
for (TrainingAreaBase::TetraIcd::TrainingAreaTelegram *aesTele : aesTeles)
m_txHandler->sendToTx(aesTele);
}
}
} // namespace WlsTetra
@@ -0,0 +1,65 @@
/**
* Send / Receive telegrams to/from PrtCnv
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <QWebSocketServer>
#include <QWebSocket>
#include <QTimer>
#include <TrainingAreaBase/tab_plugin_interface.h>
#include <PrtCnv/PrtCnvApplication.hpp>
#include <DDS/Core/function_reply_object.h> // tr_lts
#include "tetra_prtcnv.h"
#include "logger.h"
namespace WlsTetra
{
class TetraHandlerRx;
class TetraHandlerTx;
class TetraDispatcher final : public TrainingAreaBase::Plugin::Interface
{
Q_OBJECT
public:
explicit TetraDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb);
public Q_SLOTS:
bool init() override;
void onBroadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter);
void onWlsTelegramReceived(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele);
void onWlsTelegramSent(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele);
Q_SIGNALS:
void participantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc);
public:
std::shared_ptr<TrainingAreaBase::SendToTab> sendToTab() override;
bool isDebugInterface() const override { return false; }
bool canSendData() const override;
void exerciseChanged() override;
const char *name() const override { return tr_lts("dds", "TETRA"); }
private:
bool init(PrtCnv::PrtCnvApplication *prtCnvApp);
private Q_SLOTS:
void onTetraConnectionChanged(bool bConnected);
void onSendInitialData();
private:
void disconnectSocket(QWebSocket *s);
private:
std::shared_ptr<TetraHandlerRx> m_rxHandler;
std::shared_ptr<TetraHandlerTx> m_txHandler;
TetraPrtCnv *m_tetraPrtCnv;
TrainingAreaBase::Plugin::DataProvider *m_dataProvider;
NGL::INGLLogger &m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,226 @@
/**
* Read XDR telegrams from a directory and convert it to EtsTetraIcd structures
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#include "tetra_handler_rx.h"
#include <TrainingAreaBase/training_area_telegrams.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
namespace WlsTetra
{
TetraHandlerRx::TetraHandlerRx(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &rxHandler)
: m_rxHandler(rxHandler)
, m_ackTimer(new QTimer(this))
, m_receiveCounter(0)
, m_bWarnedOnce(false)
, m_bWaitForInitialAck(true)
, m_logger(getLogger("TetraHandlerRx"))
{
m_ackTimer->setInterval(1000);
m_ackTimer->setSingleShot(false);
connect(m_ackTimer, &QTimer::timeout,
this, &TetraHandlerRx::onAckTimeout);
}
bool TetraHandlerRx::handleTelegram(const QByteArray &baJson)
{
using namespace TrainingAreaBase::TetraIcd;
if (baJson.isEmpty())
return false;
const QJsonObject obj = QJsonDocument::fromJson(baJson).object();
const QJsonValue sendCounter = obj.value(QStringLiteral("counter"));
if (!sendCounter.isUndefined())
{
if (!sendCounter.isDouble())
return false;
m_receiveCounter = sendCounter.toInt(-1);
DEBUG_LOG(m_logger) << "Incoming telegram with Id " << obj.value(QStringLiteral("type")).toString();
if (m_receiveCounter < 0)
return false;
}
const QJsonValue typeId = obj.value(QStringLiteral("typeId"));
if (!typeId.isDouble())
{
ERROR_LOG(m_logger) << "Can not read type id: " << baJson;
return false;
}
const QJsonObject data = obj.value(QStringLiteral("data")).toObject();
try
{
switch (typeId.toInt())
{
case Constraints<Acknowledge>::id(): // 0
{
auto ack = TrainingAreaBase::TetraIcd::Acknowledge::fromJson(data);
handleAcknowledge(ack.timeStamp, ack.ackCounter);
break;
}
case Constraints<ManipulationReport>::id(): // 2
rxData(ManipulationReport::fromJson(data));
break;
case Constraints<EquipmentOperationalState>::id(): // 7
rxData(EquipmentOperationalState::fromJson(data));
break;
case Constraints<EquipmentConfigurationReport>::id(): // 11
rxData(EquipmentConfigurationReport::fromJson(data));
break;
case Constraints<CtaDataError>::id(): // 12
rxData(CtaDataError::fromJson(data));
break;
case Constraints<PositionReport>::id(): // 21
rxData(PositionReport::fromJson(data));
break;
case Constraints<PositionReportWithMountedEquipments>::id(): // 22
rxData(PositionReportWithMountedEquipments::fromJson(data));
break;
case Constraints<MineTriggered>::id(): // 40
rxData(MineTriggered::fromJson(data));
break;
case Constraints<DefinitionIed>::id(): // 43
rxData(DefinitionIed::fromJson(data));
break;
case Constraints<StateIed>::id(): // 44
rxData(StateIed::fromJson(data));
break;
case Constraints<DusSingleMineState>::id(): // 45
rxData(DusSingleMineState::fromJson(data));
break;
case Constraints<StateChangeDirect>::id(): // 52
rxData(StateChangeDirect::fromJson(data));
break;
case Constraints<StateChangeIndirect>::id(): // 53
rxData(StateChangeIndirect::fromJson(data));
break;
case Constraints<OperatorAction>::id(): // 55
rxData(OperatorAction::fromJson(data));
break;
case Constraints<SelectiveReammunition>::id(): // 56
rxData(SelectiveReammunition::fromJson(data));
break;
case Constraints<StateChange>::id(): // 61
rxData(StateChange::fromJson(data));
break;
case Constraints<FunctionalAreaEntry>::id(): // 63
rxData(FunctionalAreaEntry::fromJson(data));
break;
case Constraints<OpaquePayloadDataIn>::id(): // 71
rxData(OpaquePayloadDataIn::fromJson(data));
break;
case Constraints<SpecialSensorData>::id(): // 92
rxData(SpecialSensorData::fromJson(data));
break;
case Constraints<MinelayerTrailerData>::id(): // 95
rxData(MinelayerTrailerData::fromJson(data));
break;
case Constraints<MinelayerThrowerData>::id(): // 96
rxData(MinelayerThrowerData::fromJson(data));
break;
case Constraints<MinelayerTrailerPosition>::id(): // 97
rxData(MinelayerTrailerPosition::fromJson(data));
break;
case Constraints<EquipmentEvent>::id(): // 185
rxData(EquipmentEvent::fromJson(data));
break;
case Constraints<EquipmentGearAssignment>::id(): // 200
rxData(EquipmentGearAssignment::fromJson(data));
break;
case Constraints<EquipmentGearChargeState>::id(): // 202
rxData(EquipmentGearChargeState::fromJson(data));
break;
case Constraints<BiteReport>::id(): // 205
rxData(BiteReport::fromJson(data));
break;
case Constraints<EquipmentGearEvent>::id(): // 210
rxData(EquipmentGearEvent::fromJson(data));
break;
case Constraints<ParticipantSwVersions>::id(): // 213
rxData(ParticipantSwVersions::fromJson(data));
break;
case Constraints<ParticipantModeReport>::id(): // 231
rxData(ParticipantModeReport::fromJson(data));
break;
case Constraints<ParticipantConfigurationReport>::id(): // 233
rxData(ParticipantConfigurationReport::fromJson(data));
break;
case Constraints<EmergencyCall>::id(): // 1120
rxData(EmergencyCall::fromJson(data));
break;
case Constraints<SanitationRepair>::id(): // 240
rxData(SanitationRepair::fromJson(data));
break;
case Constraints<SanitaryMaterialStockReport>::id(): // 241
rxData(SanitaryMaterialStockReport::fromJson(data));
break;
case Constraints<Sanitation>::id(): // 242
rxData(Sanitation::fromJson(data));
break;
case Constraints<ApacheLaserDesignation>::id():
rxData(ApacheLaserDesignation::fromJson(data));
break;
case Constraints<ProxyConnectionState>::id(): // 2013
emit tetraConnectionChanged(ProxyConnectionState::fromJson(data).connectedToSystem);
break;
case Constraints<ParticipantLicenseChange>::id(): // 2014
emit participantLicenseChange(ParticipantLicenseChange::fromJson(data));
break;
default:
WARNING_LOG(m_logger) << "Handler for telegram Id " << typeId.toInt()
<< " not yet implemented (" << baJson << ")";
return false;
}
}
catch (const std::exception &e)
{
WARNING_LOG(m_logger) << "Could not parse json: " << e.what() << " (" << baJson << ")";
return false;
}
return true;
}
void TetraHandlerRx::handleAcknowledge(qint64 timeStamp, int counter)
{
TRACE_LOG(m_logger) << "Ack from Socket for time " << timeStamp
<< " with counter " << counter
<< ", initial: " << m_bWaitForInitialAck;
if (m_bWaitForInitialAck)
{
m_bWaitForInitialAck = false;
emit initialAckReceived();
m_ackTimer->start();
}
}
void TetraHandlerRx::onAckTimeout()
{
TrainingAreaBase::TetraIcd::Acknowledge ack;
ack.timeStamp = time(nullptr) * 1000;
ack.ackCounter = m_receiveCounter;
emit txData(ack);
}
template<typename T>
void TetraHandlerRx::rxData(const T &data)
{
if (!m_rxHandler)
{
if (!m_bWarnedOnce)
{
ERROR_LOG(m_logger) << "No RecvFromTab available";
m_bWarnedOnce = true;
}
return;
}
return m_rxHandler->rxData(data);
}
} // namespace WlsTetra
@@ -0,0 +1,49 @@
/**
* Read XDR telegrams from a directory and convert it to EtsTetraIcd structures
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#pragma once
#include <TrainingAreaBase/recv_from_tab.h>
#include <QObject>
#include <memory>
#include "logger.h"
class QTimer;
namespace WlsTetra
{
class TetraHandlerRx : public QObject
{
Q_OBJECT
public:
explicit TetraHandlerRx(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &rxHandler);
bool handleTelegram(const QByteArray &baJson);
void resetConnection() { m_bWaitForInitialAck = true; }
Q_SIGNALS:
void tetraConnectionChanged(bool bConnected);
void participantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc);
void initialAckReceived();
void txData(const TrainingAreaBase::TetraIcd::Acknowledge &ack);
private Q_SLOTS:
void onAckTimeout();
private:
void handleAcknowledge(qint64 timeStamp, int counter);
template<typename T>
void rxData(const T &data);
protected:
const std::shared_ptr<TrainingAreaBase::RecvFromTab> m_rxHandler;
QTimer *m_ackTimer;
int m_receiveCounter;
bool m_bWarnedOnce;
bool m_bWaitForInitialAck;
NGL::INGLLogger &m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,275 @@
/**
* Write XDR telegrams to a directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#include "tetra_handler_tx.h"
#include <QJsonDocument>
#include <QJsonObject>
namespace WlsTetra
{
TetraHandlerTx::TetraHandlerTx()
: QObject()
, SendToTab()
, m_logger(getLogger("TetraHandlerTx"))
{
resetSendCounter();
}
TrainingAreaBase::SendToTab::HandleState TetraHandlerTx::canHandleTelegram(int equipmentNumber, int telegramId) const
{
if (!m_bConnected)
return HandleState::No;
using namespace TrainingAreaBase::TetraIcd;
if (telegramId == Constraints<ExerciseEquipmentAssignmentComplete>::id() ||
telegramId == Constraints<ExerciseStateData>::id())
return HandleState::YesShare;
Q_UNUSED(equipmentNumber)
return HandleState::YesFallback;
}
void TetraHandlerTx::resetSendCounter()
{
m_sendCounter = 1; // start at 1
}
bool TetraHandlerTx::sendTele(const QByteArray &ba)
{
const QJsonDocument doc(QJsonDocument::fromJson(ba));
QJsonObject obj = doc.object();
const QJsonValue typeId = obj[QStringLiteral("typeId")];
if (typeId.toInt() == TrainingAreaBase::TetraIcd::TelegramId::BESTAETIGUNG)
{
TRACE_LOG(m_logger) << "Outgoing ack";
emit outgoingMessage(ba);
return true;
}
obj[QStringLiteral("counter")] = m_sendCounter++;
const QByteArray baToSend = QJsonDocument(obj).toJson(QJsonDocument::Compact);
DEBUG_LOG(m_logger) << "Outgoing message: " << typeId.toInt();
emit outgoingMessage(baToSend);
return true;
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::Acknowledge &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandBite &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::Init &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::MineTriggered &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::Sanitation &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data)
{
DEBUG_LOG(m_logger) << " TetraHandlerTx::txData: SelectiveReammunition";
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data)
{
return sendToTx(&data);
}
bool TetraHandlerTx::txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data)
{
Q_UNUSED(data);
return false;
}
bool TetraHandlerTx::sendToTx(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data)
{
if (!m_bConnected)
return false;
QJsonObject obj;
obj[QStringLiteral("data")] = data->toJson();
obj[QStringLiteral("type")] = data->type();
obj[QStringLiteral("typeId")] = data->id();
if (data->id() != TrainingAreaBase::TetraIcd::TelegramId::BESTAETIGUNG)
obj[QStringLiteral("counter")] = m_sendCounter++;
const QByteArray ba = QJsonDocument(obj).toJson(QJsonDocument::Compact);
if (data->id() != TrainingAreaBase::TetraIcd::TelegramId::BESTAETIGUNG)
DEBUG_LOG(m_logger) << "Sending tele: " << ba;
emit outgoingMessage(ba);
return true;
}
} // namespace WlsTetra
@@ -0,0 +1,82 @@
/**
* Write XDR telegrams to a directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#pragma once
#include <QObject>
#include <QWebSocket>
#include <TrainingAreaBase/send_to_tab.h>
#include "logger.h"
namespace WlsTetra
{
class TetraHandlerTx final : public QObject, public TrainingAreaBase::SendToTab
{
Q_OBJECT
public:
explicit TetraHandlerTx();
const char *name() const override { return "Tetra"; }
HandleState canHandleTelegram(int equipmentNumber, int telegramId) const override;
void resetSendCounter() override;
bool sendTele(const QByteArray &ba);
void setConnected(bool bConnected) { m_bConnected = bConnected; }
bool isConnected() const { return m_bConnected; }
public:
bool txData(const TrainingAreaBase::TetraIcd::Acknowledge &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandBite &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Init &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data) override;
bool txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data) override;
bool txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineTriggered &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data) override;
bool txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Sanitation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data) override;
bool sendToTx(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data);
Q_SIGNALS:
void outgoingMessage(const QByteArray &msg);
protected:
protected:
int m_sendCounter = 1;
bool m_bConnected = false;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,196 @@
/**
* Send / Receive telegrams to/from PrtCnv
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "plugin.h"
#include "tetra_prtcnv.h"
#include <nglsettings/nglsettings_connections.h>
#include <QCoreApplication>
#include <QFile>
#include <QSqlDatabase>
#include <QSettings>
#include <QTcpServer>
#include <ngldb/dbcommon.h>
namespace WlsTetra
{
TetraPrtCnv::TetraPrtCnv(TrainingAreaBase::Plugin::DataProvider *pdp,
QObject *parent)
: QObject(parent)
, m_pdp(pdp)
, m_prtCnvApp(nullptr)
, m_exerciseId(0)
, m_radioGrpId(0)
, m_logger(getLogger("TetraPrtCnv"))
{}
TetraPrtCnv::~TetraPrtCnv()
{
cleanupProcess();
}
bool TetraPrtCnv::init()
{
m_exerciseId = m_pdp->exerciseId();
NOTICE_LOG(m_logger) << "Our exercise id is " << m_exerciseId;
if (m_exerciseId == 0) // its sufficient to check only in exercise 0
if (!checkConfigTemplates())
return false;
return updatePrtCnv();
}
void TetraPrtCnv::onExerciseChanged()
{
if (m_pdp->exerciseRadioGroup().id() != m_radioGrpId) // radio grp changed
if (!updatePrtCnv())
ERROR_LOG(m_logger) << "Error changing PrtCnv state from radio grp id: "
<< m_radioGrpId
<< " to " << m_pdp->exerciseRadioGroup().id();
}
void TetraPrtCnv::logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool bIsSend)
{
if (m_prtCnvApp)
m_prtCnvApp->logWlsTelegram(tele, bIsSend);
}
bool TetraPrtCnv::updatePrtCnv()
{
int newRadioGrpId = m_pdp->exerciseRadioGroup().id();
if (newRadioGrpId == m_radioGrpId) //nothing changed for PrtCnv
{
NOTICE_LOG(m_logger) << "No need to update PrtCnv configuration - radio group did not change: " << m_radioGrpId;
return true;
}
NOTICE_LOG(m_logger) << "Our radio group id is " << newRadioGrpId;
if (newRadioGrpId > 0)
{
// Create Prtcnv.dat with specific config
QFile::remove(iniFileOut());
if (!QFile::copy(QStringLiteral(":/PrtCnv.dat"), iniFileOut()) ||
!QFile::setPermissions(iniFileOut(), QFile::ReadOwner | QFile::WriteOwner))
{
ERROR_LOG(m_logger) << "Error creating ini file for PrtCnv: " << iniFileOut();
return false;
}
ProjectDataManagement::RadioGroup radioGrp = m_pdp->exerciseRadioGroup();
{
QSettings s(iniFileOut(), QSettings::IniFormat);
s.setValue(QStringLiteral("Common/LogTelegramPath"), QStringLiteral("logdata/ex_%1").arg(m_exerciseId));
s.setValue(QStringLiteral("Common/LogTelegramPrefix"), QStringLiteral("PrtCnv_ex_%1").arg(m_exerciseId));
s.setValue(QStringLiteral("Central/HostName"), QStringLiteral("directConnection")); // direct connection thorugh signals/slots
s.setValue(QStringLiteral("Radio/HostName"), QString::fromStdString(radioGrp.radioHostname()));
s.setValue(QStringLiteral("Radio/Port"), radioGrp.radioPort());
s.setValue(QStringLiteral("Radio/HostName1"), QString::fromStdString(radioGrp.radioBackupHostname()));
s.setValue(QStringLiteral("Radio/Port1"), radioGrp.radioBackupPort());
s.setValue(QStringLiteral("Radio/HostISSI"), radioGrp.issi());
s.setValue(QStringLiteral("Radio/BroadcastISSI"), radioGrp.group_issi1());
s.setValue(QStringLiteral("Radio/ListenGroups"), radioGrp.group_issi2());
s.setValue(QStringLiteral("Radio/UseScrambling"), m_pdp->useTetraScrambling() ? 1 : 0);
s.setValue(QStringLiteral("Injection/Port"), randomListenPort());
s.sync();
}
// Start PrtCnv
if (!startPrtCnv())
return false;
}
else // new radio grp ID is 0 and PrtCnv has ben running
cleanupProcess(); // quit running PrtCnv
// set radio grp at the end of update process
m_radioGrpId = newRadioGrpId;
return true;
}
bool TetraPrtCnv::checkConfigTemplates()
{
if (!QFile::exists(playerIdsFile()))
{
INFO_LOG(m_logger) << "Creating " << playerIdsFile();
if (!QFile::copy(QStringLiteral(":/playerIds.dat"), playerIdsFile()))
{
ERROR_LOG(m_logger) << "Error creating " << playerIdsFile();
return false;
}
else
QFile(playerIdsFile()).setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther | QFile::WriteOwner);
}
return true;
}
bool TetraPrtCnv::startPrtCnv()
{
NOTICE_LOG(m_logger) << "Starting PrtCnv (intern)";
cleanupProcess();
m_prtCnvApp = new PrtCnv::PrtCnvApplication;
const QSqlDatabase db = m_pdp->databaseConnection();
m_prtCnvApp->setDatabaseConnectionParams(db.driverName(),
db.hostName(),
db.databaseName(),
m_pdp->databaseSchemaName(),
db.userName(),
db.password());
m_prtCnvApp->setExerciseId(m_pdp->exerciseId());
m_prtCnvApp->setConfigFile(iniFileOut());
connect(m_prtCnvApp, &PrtCnv::PrtCnvApplication::textMessageFromPrtCnvToCentral,
this, &TetraPrtCnv::textMessageFromPrtCnv);
connect(this, &TetraPrtCnv::textMessageToPrtCnv,
m_prtCnvApp, &PrtCnv::PrtCnvApplication::textMessageFromCentralToPrtCnv);
connect(this, &TetraPrtCnv::broadcastTelegramsRequest,
m_prtCnvApp, &PrtCnv::PrtCnvApplication::outgoingBroadcastTelegramsRequest);
m_prtCnvApp->startApp();
return true;
}
void TetraPrtCnv::cleanupProcess()
{
if (!m_prtCnvApp)
return;
m_prtCnvApp->shutdownApp();
delete m_prtCnvApp;
m_prtCnvApp = nullptr;
emit tetraConnectionChanged(false); // initial
}
QString TetraPrtCnv::iniFileOut() const
{
return iniPath() + QStringLiteral("/PrtCnv_ex_%1.dat").arg(m_exerciseId);
}
QString TetraPrtCnv::iniPath()
{
return QCoreApplication::applicationDirPath() + QLatin1Char('/');
}
QString TetraPrtCnv::playerIdsFile()
{
return iniPath() + QStringLiteral("/playerIds.dat");
}
quint16 TetraPrtCnv::randomListenPort() const
{
QTcpServer *s = new QTcpServer;
s->listen(QHostAddress::Any, 0);
while (!s->isListening())
QCoreApplication::processEvents();
quint16 port = s->serverPort();
delete s;
return port;
}
} // namespace WlsTetra
@@ -0,0 +1,56 @@
/**
* Send / Receive telegrams to/from PrtCnv
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <memory>
#include <TrainingAreaBase/tab_plugin_interface.h>
#include <PrtCnv/PrtCnvApplication.hpp>
#include "logger.h"
namespace WlsTetra
{
class TetraPrtCnv final : public QObject
{
Q_OBJECT
public:
explicit TetraPrtCnv(TrainingAreaBase::Plugin::DataProvider *pdp,
QObject *parent = nullptr);
~TetraPrtCnv();
bool init();
public Q_SLOTS:
void onExerciseChanged();
void logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool bIsSend);
Q_SIGNALS:
void tetraConnectionChanged(bool bConnected);
void textMessageFromPrtCnv(const QByteArray &message);
void textMessageToPrtCnv(const QByteArray &message);
void broadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter);
private:
void cleanupProcess();
static QString iniFileIn();
QString iniFileOut() const;
static QString iniPath();
static QString playerIdsFile();
bool updatePrtCnv();
bool checkConfigTemplates();
bool startPrtCnv();
quint16 randomListenPort() const;
private:
TrainingAreaBase::Plugin::DataProvider *m_pdp;
PrtCnv::PrtCnvApplication *m_prtCnvApp;
int m_exerciseId;
int m_radioGrpId;
NGL::INGLLogger &m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,122 @@
/**
* Send / Receive telegrams to/from Wls
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "wls_dispatcher.h"
#include "wls_handler_rx.h"
#include "wls_handler_tx.h"
#include <QSettings>
#include <QWebSocket>
#include <QTimer>
#include <nglsettings/nglsettings_settings.h>
namespace WlsTetra
{
WlsDispatcher::WlsDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
NGL::Settings *settings)
: m_recvFromTabCb(recvFromTabCb)
, m_recvFromWls(std::make_shared<WlsHandlerRx>(recvFromTabCb, this))
, m_sendToWls(std::make_shared<WlsHandlerTx>(pdp, this))
, m_settings(settings)
, m_webSocket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this))
, m_webSocketReconnectTimer(new QTimer(this))
, m_bWarnedOnce(false)
, m_logger(getLogger("WlsDispatcher"))
{
connect(m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
this, &WlsDispatcher::onWebSocketError);
connect(m_webSocket, &QWebSocket::connected,
this, &WlsDispatcher::onWlsConnected);
connect(m_webSocket, &QWebSocket::disconnected,
this, &WlsDispatcher::onWlsDisconnected);
connect(m_webSocket, &QWebSocket::textMessageReceived,
this, &WlsDispatcher::onTextMessageReceived);
connect(m_webSocketReconnectTimer, &QTimer::timeout,
this, &WlsDispatcher::init);
connect(m_recvFromWls.get(), &WlsHandlerRx::participantConnectionState,
m_sendToWls.get(), &WlsHandlerTx::onParticipantConnectionState);
}
bool WlsDispatcher::init()
{
emit connectionState(QString::fromUtf8(name()), false);
const QUrl url(webSocketUrl());
if (!m_bWarnedOnce)
NOTICE_LOG(m_logger) << "Using WebSocket url: " << url.toString();
m_webSocket->open(url);
return true;
}
std::shared_ptr<TrainingAreaBase::SendToTab> WlsDispatcher::sendToTab()
{
return std::static_pointer_cast<TrainingAreaBase::SendToTab>(m_sendToWls);
}
bool WlsDispatcher::canSendData() const
{
return m_webSocket && m_webSocket->state() == QAbstractSocket::ConnectedState;
}
void WlsDispatcher::onWlsConnected()
{
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
m_sendToWls->onWlsConnected(ws);
m_webSocketReconnectTimer->stop();
m_bWarnedOnce = false;
}
void WlsDispatcher::onWlsDisconnected()
{
INFO_LOG(m_logger) << "Wls socket disconnected";
m_webSocketReconnectTimer->start(5000);
m_sendToWls->onWlsDisconnected();
emit connectionState(QString::fromUtf8(name()), false);
}
void WlsDispatcher::onWlsExternalConnectionStateChanged(bool bConnected)
{
m_sendToWls->onWlsConnectedToExternalSystem(bConnected);
emit connectionState(QString::fromUtf8(name()), bConnected);
}
void WlsDispatcher::onWebSocketError()
{
if (!m_webSocket)
return;
if (!m_bWarnedOnce)
WARNING_LOG(m_logger) << "Error connecting to " << webSocketUrl().toString() << ": " << m_webSocket->errorString();
m_webSocket->close();
m_webSocketReconnectTimer->start(5000);
m_bWarnedOnce = true;
emit connectionState(QString::fromUtf8(name()), false);
}
void WlsDispatcher::onTextMessageReceived(const QString &message)
{
// convert from json to internal representation, send to TAB
m_recvFromWls->handleTelegram(message.toUtf8());
}
void WlsDispatcher::onParticipantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc)
{
INFO_LOG(m_logger) << "onParticipantLicenseChange id=" << lc.id()
<< " equipmentNumber=" << lc.equipmentNumber;
m_recvFromWls->participantLicenseChange(lc);
}
QUrl WlsDispatcher::webSocketUrl() const
{
const quint16 port = m_settings->settings()->value(QStringLiteral("WLS/webSocketListenPort"), 12346).toInt();
const QString addr = m_settings->settings()->value(QStringLiteral("WLS/webSocketHostname"), QStringLiteral("localhost")).toString();
return QUrl(QStringLiteral("ws://%1:%2/").arg(addr).arg(port));
}
} // namespace WlsTetra
@@ -0,0 +1,64 @@
/**
* Send / Receive telegrams to/from Wls
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <QWebSocket>
#include <TrainingAreaBase/tab_plugin_interface.h>
#include <DDS/Core/function_reply_object.h> // tr_lts
#include "logger.h"
class QTimer;
namespace WlsTetra
{
class WlsHandlerRx;
class WlsHandlerTx;
class WlsDispatcher final : public TrainingAreaBase::Plugin::Interface
{
Q_OBJECT
public:
WlsDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
NGL::Settings *settings);
public Q_SLOTS:
bool init() override;
public:
std::shared_ptr<TrainingAreaBase::SendToTab> sendToTab() override;
bool isDebugInterface() const override { return false; }
bool canSendData() const override;
void exerciseChanged() override { return; }
const char *name() const override { return tr_lts("dds", "WLS"); }
public Q_SLOTS:
void onWlsConnected();
void onWlsDisconnected();
void onWlsExternalConnectionStateChanged(bool bConnected);
void onWebSocketError();
void onTextMessageReceived(const QString &message);
void onParticipantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc);
Q_SIGNALS:
void broadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter);
void wlsTelegramReceived(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele);
void wlsTelegramSent(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele);
private:
QUrl webSocketUrl() const;
private:
std::shared_ptr<TrainingAreaBase::RecvFromTab> m_recvFromTabCb;
std::shared_ptr<WlsHandlerRx> m_recvFromWls;
std::shared_ptr<WlsHandlerTx> m_sendToWls;
NGL::Settings *m_settings;
QWebSocket *m_webSocket;
QTimer *m_webSocketReconnectTimer;
bool m_bWarnedOnce;
NGL::INGLLogger &m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,260 @@
/**
* Convert Json from WLS to internal telegrams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "wls_handler_rx.h"
#include "wls_dispatcher.h"
#include <TrainingAreaBase/training_area_telegrams.h>
#include <QJsonDocument>
#include <CoPrtCnv/CoPrtCnvCentralTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
namespace WlsTetra
{
WlsHandlerRx::WlsHandlerRx(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
WlsDispatcher *dispatcher)
: m_rxHandler(recvFromTabCb)
, m_dispatcher(dispatcher)
, m_bWarnedOnce(false)
, m_logger(getLogger("WlsHandlerRx"))
{}
bool WlsHandlerRx::handleTelegram(const QByteArray &baJson)
{
using namespace TrainingAreaBase::TetraIcd;
if (baJson.isEmpty())
return false;
const QJsonObject obj = QJsonDocument::fromJson(baJson).object();
TRACE_LOG(m_logger) << "incoming telegram: " << baJson;
// const QJsonValue sendCounter = obj.value(QStringLiteral("counter"));
// if (!sendCounter.isUndefined())
// {
// if (!sendCounter.isDouble())
// return false;
// recvCounter = sendCounter.toInt(-1);
// DEBUG_LOG(m_logger) << "Incoming telegram with Id " << obj.value(QStringLiteral("type")).toString();
// if (recvCounter < 0)
// return false;
// }
const QJsonValue typeId = obj.value(QStringLiteral("typeId"));
if (!typeId.isDouble())
{
ERROR_LOG(m_logger) << "Can not read type id: " << baJson;
return false;
}
const QJsonObject data = obj.value(QStringLiteral("data")).toObject();
try
{
switch (typeId.toInt())
{
case Constraints<PositionReport>::id(): // 21
rxData(PositionReport::fromJson(data));
break;
case Constraints<ProxyConnectionState>::id(): // 2013
m_dispatcher->onWlsExternalConnectionStateChanged(ProxyConnectionState::fromJson(data).connectedToSystem);
break;
case Constraints<WlsBinarySfmData>::id(): // 3003
sfmData(WlsBinarySfmData::fromJson(data));
break;
case Constraints<WlsParticipantsConnectionState>::id(): // 3004
{
const auto tele = WlsParticipantsConnectionState::fromJson(data);
emit participantConnectionState(tele.equipmentNumber, tele.dataCommunicationPossible);
break;
}
}
}
catch (const std::exception &e)
{
WARNING_LOG(m_logger) << "Could not parse json: " << e.what() << " (" << baJson << ")";
return false;
}
return true;
}
void WlsHandlerRx::participantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc)
{
if (lc.equipmentNumber <= 0)
{
return;
}
switch (lc.licenseState)
{
case TrainingAreaBase::TetraIcd::ParticipantLicenseState::Licensed:
m_licensedEquipmentNumbers.insert(lc.equipmentNumber);
break;
case TrainingAreaBase::TetraIcd::ParticipantLicenseState::Rejected:
case TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unlicense:
m_licensedEquipmentNumbers.remove(lc.equipmentNumber);
break;
case TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unknown:
Q_ASSERT(false);
break;
}
}
template <>
void WlsHandlerRx::rxData(const TrainingAreaBase::TetraIcd::RequestBroadcastTelegrams &data)
{
emit m_dispatcher->broadcastTelegramsRequest(data.header.equipmentNumber,
data.broadcastIndex,
data.resetCounter);
}
template <typename T>
static inline T toSpecialized(TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTele)
{
return *(static_cast<T*>(tabTele));
}
bool WlsHandlerRx::handleTelegram(TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTele)
{
using namespace TrainingAreaBase::TetraIcd;
switch (tabTele->id())
{
// Telegrams converted from WlsBinarySfmData
case Constraints<ManipulationReport>::id(): // 2
rxData(toSpecialized<ManipulationReport>(tabTele));
break;
case Constraints<EquipmentOperationalState>::id(): // 7
rxData(toSpecialized<EquipmentOperationalState>(tabTele));
break;
case Constraints<EquipmentConfigurationReport>::id(): // 11
rxData(toSpecialized<EquipmentConfigurationReport>(tabTele));
break;
case Constraints<CtaDataError>::id(): // 12
rxData(toSpecialized<CtaDataError>(tabTele));
break;
case Constraints<MineTriggered>::id(): // 41
rxData(toSpecialized<MineTriggered>(tabTele));
break;
case Constraints<DefinitionIed>::id(): // 43
rxData(toSpecialized<DefinitionIed>(tabTele));
break;
case Constraints<StateIed>::id(): // 44
rxData(toSpecialized<StateIed>(tabTele));
break;
case Constraints<DusSingleMineState>::id(): // 45
rxData(toSpecialized<DusSingleMineState>(tabTele));
break;
case Constraints<StateChangeDirect>::id(): // 52
rxData(toSpecialized<StateChangeDirect>(tabTele));
break;
case Constraints<StateChangeIndirect>::id(): // 53
rxData(toSpecialized<StateChangeIndirect>(tabTele));
break;
case Constraints<OperatorAction>::id(): // 55
rxData(toSpecialized<OperatorAction>(tabTele));
break;
case Constraints<SelectiveReammunition>::id(): // 56
rxData(toSpecialized<SelectiveReammunition>(tabTele));
break;
case Constraints<StateChange>::id(): // 61
rxData(toSpecialized<StateChange>(tabTele));
break;
case Constraints<OpaquePayloadDataIn>::id(): // 71
rxData(toSpecialized<OpaquePayloadDataIn>(tabTele));
break;
case Constraints<RequestBroadcastTelegrams>::id(): // 82
rxData(toSpecialized<RequestBroadcastTelegrams>(tabTele));
break;
case Constraints<EquipmentEvent>::id(): // 185
rxData(toSpecialized<EquipmentEvent>(tabTele));
break;
case Constraints<EquipmentGearAssignment>::id(): // 200
rxData(toSpecialized<EquipmentGearAssignment>(tabTele));
break;
case Constraints<EquipmentGearChargeState>::id(): // 202
rxData(toSpecialized<EquipmentGearChargeState>(tabTele));
break;
case Constraints<BiteReport>::id(): // 205
rxData(toSpecialized<BiteReport>(tabTele));
break;
case Constraints<EquipmentGearEvent>::id(): // 210
rxData(toSpecialized<EquipmentGearEvent>(tabTele));
break;
case Constraints<ParticipantSwVersions>::id(): // 213
rxData(toSpecialized<ParticipantSwVersions>(tabTele));
break;
case Constraints<ParticipantModeReport>::id(): // 231
rxData(toSpecialized<ParticipantModeReport>(tabTele));
break;
case Constraints<ParticipantConfigurationReport>::id(): // 233
rxData(toSpecialized<ParticipantConfigurationReport>(tabTele));
break;
default:
ERROR_LOG(m_logger) << "WlsHandlerRx::handleTelegram no Handler for " << tabTele->id();
return false;
}
return true;
}
class RadioTelegram : public N_CoPrtCnv::CoPrtCnvRadioTelegram
{
public:
RadioTelegram(const QByteArray &data)
: N_CoPrtCnv::CoPrtCnvRadioTelegram(data)
{}
uint16_t getPayloadSize() const override
{
return m_data.size() - CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH;
}
};
void WlsHandlerRx::sfmData(const TrainingAreaBase::TetraIcd::WlsBinarySfmData &data)
{
if (data.payload.size() < 2)
{
ERROR_LOG(m_logger) << "Invalid binary data from WLS: " << QJsonDocument(data.toJson()).toJson(QJsonDocument::Compact);
return;
}
using namespace N_CoPrtCnv;
const int offset = CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH;
QByteArray ba(data.payload.size() + offset, Qt::Uninitialized);
memcpy(&ba.data()[offset], data.payload.data(), data.payload.size());
const RadioTelegram radio(ba);
TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTele = CoPrtCnvTelegramConverter::convertToTabTele(&radio);
if (!tabTele)
{
WARNING_LOG(m_logger) << "Can not convert binary sfm data to a valid tetra telegram - ignoring ("
<< data.header.equipmentNumber << "): " << QByteArray::fromRawData(reinterpret_cast<const char *>(data.payload.data()),
data.payload.size()).toHex();
return;
}
handleTelegram(tabTele);
delete tabTele;
}
template<typename T>
void WlsHandlerRx::rxData(const T &data)
{
if (!m_rxHandler)
{
if (!m_bWarnedOnce)
{
ERROR_LOG(m_logger) << "No RecvFromTab available";
m_bWarnedOnce = true;
}
return;
}
if (data.header.equipmentNumber != 0 &&
data.id() != TrainingAreaBase::TetraIcd::BITE_MELDUNG2 &&
!m_licensedEquipmentNumbers.contains(data.header.equipmentNumber))
return;
emit m_dispatcher->wlsTelegramReceived(&data);
return m_rxHandler->rxData(data);
}
} // namespace WlsTetra
@@ -0,0 +1,46 @@
/**
* Convert Json from WLS to internal telegrams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <TrainingAreaBase/recv_from_tab.h>
#include <QObject>
#include <QSet>
#include <QString>
#include <memory>
#include "logger.h"
namespace WlsTetra
{
class WlsDispatcher;
class WlsHandlerRx : public QObject
{
Q_OBJECT
public:
explicit WlsHandlerRx(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
WlsDispatcher *dispatcher);
bool handleTelegram(const QByteArray &baJson);
bool handleTelegram(TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTele);
void participantLicenseChange(const TrainingAreaBase::TetraIcd::ParticipantLicenseChange &lc);
Q_SIGNALS:
void participantConnectionState(int equipmentNumber, bool dataCommunicationPossible);
private:
void sfmData(const TrainingAreaBase::TetraIcd::WlsBinarySfmData &data);
template<typename T>
void rxData(const T &data);
private:
std::shared_ptr<TrainingAreaBase::RecvFromTab> m_rxHandler;
QSet<int> m_licensedEquipmentNumbers;
WlsDispatcher *m_dispatcher;
bool m_bWarnedOnce;
LOGGER_T m_logger;
};
} // namespace WlsTetra
@@ -0,0 +1,361 @@
/**
* Convert telegrams to Json and sent to WLS proxy
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "wls_handler_tx.h"
#include "wls_dispatcher.h"
#include <QJsonDocument>
#include <QWebSocket>
#include <CoPrtCnv/CoPrtCnvCentralTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
namespace WlsTetra
{
WlsHandlerTx::WlsHandlerTx(TrainingAreaBase::Plugin::DataProvider *pdp, WlsDispatcher *dispatcher)
: m_pdp(pdp)
, m_webSocket(nullptr)
, m_dispatcher(dispatcher)
, m_bWlsConnectedToExternalSystem(false)
, m_logger(getLogger("WlsHandlerTx"))
{}
void WlsHandlerTx::onWlsConnected(QWebSocket *webSocket)
{
m_webSocket = webSocket;
if (!m_webSocket)
return;
NOTICE_LOG(m_logger) << "Connected to WLS - sending exercise state data and exequipment exercise mapping";
const auto eea = m_pdp->exerciseEquipmentAssignment();
sendToTx(&eea, true);
const auto esd = m_pdp->exerciseStateData();
sendToTx(&esd, true);
}
void WlsHandlerTx::onWlsDisconnected()
{
m_webSocket = nullptr;
}
void WlsHandlerTx::onWlsConnectedToExternalSystem(bool bConnected)
{
m_bWlsConnectedToExternalSystem = bConnected;
}
TrainingAreaBase::SendToTab::HandleState WlsHandlerTx::canHandleTelegram(int equipmentNumber, int telegramId) const
{
if (!m_webSocket || !m_bWlsConnectedToExternalSystem)
return HandleState::No;
using namespace TrainingAreaBase::TetraIcd;
if (telegramId == Constraints<ExerciseEquipmentAssignmentComplete>::id() ||
telegramId == Constraints<ExerciseStateData>::id())
return HandleState::YesShare;
if (equipmentNumber <= 0 || !m_dataCommunicationPossible.value(equipmentNumber, false))
return HandleState::No;
if (telegramId == Constraints<DemandBite>::id() ||
telegramId == Constraints<Init>::id() ||
telegramId == Constraints<DemandVulnerabilityStateChange>::id() ||
telegramId == Constraints<CesHitRequest>::id() ||
telegramId == Constraints<SetVulnerabilityModel>::id() ||
telegramId == Constraints<DemandEquipmentConfigurationReport>::id() ||
telegramId == Constraints<LanguageSelection>::id() ||
telegramId == Constraints<EquipmentMessage>::id() ||
telegramId == Constraints<ParticipantMode>::id() ||
telegramId == Constraints<DemandParticipantMode>::id() ||
telegramId == Constraints<ParticipantConfiguration>::id() ||
telegramId == Constraints<DemandParticipantConfiguration>::id()
)
return HandleState::YesConsume;
// currently no data to wls, TODO
return HandleState::No;
}
void WlsHandlerTx::resetSendCounter()
{
// nothing to do
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::Acknowledge &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandBite &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::Init &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::MineTriggered &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data)
{
return sendToTx(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data)
{
Q_UNUSED(data);
return false; // only for Tetra - really?
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data)
{
Q_UNUSED(data);
return false;
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data)
{
return sendToTxBinary(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data)
{
return sendToTx(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::Sanitation &data)
{
return sendToTx(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data)
{
return sendToTx(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data)
{
return sendToTx(&data);
}
bool WlsHandlerTx::txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data)
{
Q_UNUSED(data);
return false;
}
void WlsHandlerTx::onParticipantConnectionState(int equipmentNumber, bool dataCommunicationPossible)
{
DEBUG_LOG(m_logger) << "onParticipantConnectionState - " << equipmentNumber
<< ", communication possible: " << dataCommunicationPossible;
m_dataCommunicationPossible[equipmentNumber] = dataCommunicationPossible;
}
template <typename T>
bool WlsHandlerTx::sendToTxBinary(const T *data)
{
if (!m_webSocket || !m_bWlsConnectedToExternalSystem || !data)
return false;
using namespace N_CoPrtCnv;
CoPrtCnvRadioTelegram *radio = CoPrtCnvTelegramConverter::convertToRadio(data);
if (!radio)
return false;
emit m_dispatcher->wlsTelegramSent(data);
TrainingAreaBase::TetraIcd::WlsBinarySfmData tele;
tele.header = data->header;
const int offset = CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH;
const char *dataPtr = radio->getData() + offset;
tele.payload.resize(radio->getSize() - offset);
memcpy(tele.payload.data(), dataPtr, tele.payload.size());
delete radio;
return sendToTx(&tele, false, true);
}
bool WlsHandlerTx::sendToTx(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data, bool bForce, bool bIsAlreadyLogged)
{
if (!m_webSocket || (!m_bWlsConnectedToExternalSystem && !bForce))
return false;
QJsonObject obj;
obj[QStringLiteral("data")] = data->toJson();
obj[QStringLiteral("type")] = data->type();
obj[QStringLiteral("typeId")] = data->id();
// if (data->id() != TrainingAreaBase::TetraIcd::TelegramId::BESTAETIGUNG)
// obj[QStringLiteral("counter")] = m_sendCounter++;
const QByteArray ba = QJsonDocument(obj).toJson(QJsonDocument::Compact);
if (data->id() != TrainingAreaBase::TetraIcd::TelegramId::BESTAETIGUNG)
DEBUG_LOG(m_logger) << "Sending tele: " << ba;
m_webSocket->sendTextMessage(QString::fromUtf8(ba));
if (!bIsAlreadyLogged)
emit m_dispatcher->wlsTelegramSent(data);
return true;
}
} // namespace WlsTetra
@@ -0,0 +1,91 @@
/**
* Convert telegrams to Json and sent to WLS proxy
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include "logger.h"
#include <TrainingAreaBase/send_to_tab.h>
#include <TrainingAreaBase/tab_plugin_interface.h>
#include <QHash>
class QWebSocket;
namespace WlsTetra
{
class WlsDispatcher;
class WlsHandlerTx final : public QObject, public TrainingAreaBase::SendToTab
{
Q_OBJECT
public:
explicit WlsHandlerTx(TrainingAreaBase::Plugin::DataProvider *pdp, WlsDispatcher *dispatcher);
void onWlsConnected(QWebSocket *webSocket);
void onWlsDisconnected();
void onWlsConnectedToExternalSystem(bool bConnected);
const char *name() const override { return "Wls"; }
HandleState canHandleTelegram(int equipmentNumber, int telegramId) const override;
void resetSendCounter() override;
bool txData(const TrainingAreaBase::TetraIcd::Acknowledge &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandBite &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Init &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data) override;
bool txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data) override;
bool txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data) override;
bool txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::MineTriggered &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data) override;
bool txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data) override;
bool txData(const TrainingAreaBase::TetraIcd::Sanitation &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data) override;
bool txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data) override;
bool txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data) override;
public Q_SLOTS:
void onParticipantConnectionState(int equipmentNumber, bool dataCommunicationPossible);
private:
template <typename T>
bool sendToTxBinary(const T *data);
bool sendToTx(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data,
bool bForce = false,
bool bIsAlreadyLogged = false);
private:
QHash<int, bool> m_dataCommunicationPossible; // equioNo, reachable
TrainingAreaBase::Plugin::DataProvider *m_pdp;
QWebSocket *m_webSocket;
WlsDispatcher *m_dispatcher;
bool m_bWlsConnectedToExternalSystem;
LOGGER_T m_logger;
};
}