Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Write all incoming / outgoing telegrams to a socket for PrtCnv (xdr encoded)
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(SRCS
|
||||
convert_from_json.cpp
|
||||
convert_from_json.h
|
||||
convert_to_json.cpp
|
||||
convert_to_json.h
|
||||
socket_dispatcher_json.cpp
|
||||
socket_dispatcher_json.h
|
||||
plugin.cpp
|
||||
plugin.h
|
||||
playerIds.dat
|
||||
PrtCnv.dat
|
||||
)
|
||||
|
||||
QT5_ADD_RESOURCES(SRCS tetra.qrc)
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV tabPluginTetraJson MODULE ${SRCS})
|
||||
NGL_INSTALL_TARGET(tabPluginTetraJson)
|
||||
NGL_TARGET_LINK_LIBRARIES(tabPluginTetraJson
|
||||
CoPrtCnv
|
||||
NGLLogger
|
||||
nglsettings
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
Qt5::Sql
|
||||
Qt5::WebSockets
|
||||
tabPluginInterface
|
||||
tabTelegrams
|
||||
PrtCnvLib
|
||||
)
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
[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
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Read XDR telegrams from a directory and convert it to EtsTetraIcd structures
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-14
|
||||
*/
|
||||
|
||||
#include "convert_from_json.h"
|
||||
#include <TrainingAreaBase/training_area_telegrams.h>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
|
||||
ConvertFromJson::ConvertFromJson(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &rxHandler,
|
||||
const char *loggerName)
|
||||
: m_rxHandler(rxHandler)
|
||||
, m_bWarnedOnce(false)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{}
|
||||
|
||||
bool ConvertFromJson::handleTelegram(const QByteArray &baJson, int &recvCounter)
|
||||
{
|
||||
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;
|
||||
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<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<RestoreRadioReadiness>::id(): // 13
|
||||
rxData(RestoreRadioReadiness::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<SanitationRepair>::id(): //24
|
||||
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<EmergencyCall>::id(): // 1120
|
||||
rxData(EmergencyCall::fromJson(data));
|
||||
break;
|
||||
case Constraints<ApacheLaserDesignation>::id():
|
||||
rxData(ApacheLaserDesignation::fromJson(data));
|
||||
break;
|
||||
case Constraints<ProxyConnectionState>::id(): // 2013
|
||||
handleTetraConnectionChanged(ProxyConnectionState::fromJson(data).connectedToSystem);
|
||||
break;
|
||||
case Constraints<ParticipantLicenseChange>::id(): // 2014
|
||||
//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;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ConvertFromJson::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 TetraRadio
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 <NGLLogger/INGLLogger.h>
|
||||
#include <TrainingAreaBase/recv_from_tab.h>
|
||||
#include <memory>
|
||||
|
||||
class XDR_Wrapper_it;
|
||||
namespace TetraRadio
|
||||
{
|
||||
class ConvertFromJson
|
||||
{
|
||||
public:
|
||||
explicit ConvertFromJson(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &rxHandler, const char *loggerName);
|
||||
virtual ~ConvertFromJson() = default;
|
||||
|
||||
protected:
|
||||
bool handleTelegram(const QByteArray &baJson, int &recvCounter);
|
||||
virtual void handleAcknowledge(qint64 timeStamp, int counter) = 0;
|
||||
virtual void handleTetraConnectionChanged(bool bConnected) = 0;
|
||||
private:
|
||||
template<typename T>
|
||||
void rxData(const T &data);
|
||||
|
||||
private:
|
||||
// helper for convertBite
|
||||
static TrainingAreaBase::TetraIcd::BiteError convertBiteError(const QJsonObject &obj);
|
||||
std::shared_ptr<TrainingAreaBase::RecvFromTab> m_rxHandler;
|
||||
protected:
|
||||
bool m_bWarnedOnce;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace TetraRadio
|
||||
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Write XDR telegrams to a directory
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-14
|
||||
*/
|
||||
|
||||
#include "convert_to_json.h"
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
ConvertToJson::ConvertToJson(const char *loggerName)
|
||||
: QObject()
|
||||
, SendToTab()
|
||||
, m_bConnected(false)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{
|
||||
resetSendCounter();
|
||||
}
|
||||
|
||||
ConvertToJson::~ConvertToJson()
|
||||
{}
|
||||
|
||||
TrainingAreaBase::SendToTab::HandleState ConvertToJson::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 ConvertToJson::resetSendCounter()
|
||||
{
|
||||
m_sendCounter = 1; // start at 1
|
||||
}
|
||||
|
||||
bool ConvertToJson::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)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "Outgoing ack";
|
||||
emit outgoingMessage(ba);
|
||||
return true;
|
||||
}
|
||||
|
||||
obj[QStringLiteral("counter")] = m_sendCounter++;
|
||||
const QByteArray baToSend = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
NOTICE_LOG(m_logger) << "Outgoing message: " << typeId.toInt();
|
||||
emit outgoingMessage(baToSend);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::Acknowledge &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DemandBite &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::Init &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::MineTriggered &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool TetraRadio::ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::Sanitation &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ConvertToJson::txData SelectiveReammunition";
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data)
|
||||
{
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::OcCommand &data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ConvertToJson::txData OcCommand";
|
||||
return sendToTx(&data);
|
||||
}
|
||||
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConvertToJson::txData(const TrainingAreaBase::TetraIcd::UAVChangeState &data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConvertToJson::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 TetraRadio
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Write XDR telegrams to a directory
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-14
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QWebSocket>
|
||||
#include <TrainingAreaBase/send_to_tab.h>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
class ConvertToJson final : public QObject, public TrainingAreaBase::SendToTab
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConvertToJson(const char *loggerName);
|
||||
~ConvertToJson();
|
||||
|
||||
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; }
|
||||
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::OcCommand &data) override;
|
||||
bool txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data) override;
|
||||
bool txData(const TrainingAreaBase::TetraIcd::UAVChangeState &) override ;
|
||||
bool txData(const TrainingAreaBase::TetraIcd::ExFireReadiness &) override { return false; };
|
||||
bool txData(const TrainingAreaBase::TetraIcd::ExFiredReport &) override { return false; };
|
||||
bool txData(const TrainingAreaBase::TetraIcd::ExConfirmationReport &) override { return false; };
|
||||
|
||||
bool sendToTx(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data);
|
||||
Q_SIGNALS:
|
||||
void outgoingMessage(const QByteArray &msg);
|
||||
protected:
|
||||
protected:
|
||||
int m_sendCounter;
|
||||
bool m_bConnected;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
1-65535
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* Send / Receive telegrams to/from PrtCnv
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-09-26
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "NGLLogger/INGLLogger.h"
|
||||
#include "socket_dispatcher_json.h"
|
||||
#include <nglsettings/nglsettings_connections.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QSqlDatabase>
|
||||
#include <QJsonDocument>
|
||||
#include <QSettings>
|
||||
#include <ngldb/dbcommon.h>
|
||||
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
|
||||
#include <QSettings>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <qglobal.h>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
|
||||
//
|
||||
// TetraXdrPlugin
|
||||
//
|
||||
std::shared_ptr<TrainingAreaBase::Plugin::Interface> TetraJsonPlugin::createInterface(TrainingAreaBase::Plugin::DataProvider *pdp,
|
||||
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
|
||||
const std::shared_ptr<TrainingAreaBase::TxMixin> &,
|
||||
const std::shared_ptr<TrainingAreaBase::DdsHandler> &,
|
||||
NGL::Settings *settings)
|
||||
{
|
||||
return std::make_shared<TetraJsonInterfaceImpl>(pdp, recvFromTabCb, settings);
|
||||
}
|
||||
|
||||
TetraJsonInterfaceImpl::TetraJsonInterfaceImpl(TrainingAreaBase::Plugin::DataProvider *pdp,
|
||||
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
|
||||
NGL::Settings *settings)
|
||||
: m_socketDispatcher(new SocketDispatcher(pdp, recvFromTabCb))
|
||||
, m_pdp(pdp)
|
||||
, m_prtCnvApp(nullptr)
|
||||
, m_exerciseId(0)
|
||||
, m_radioGrpId(0)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TAB.Plugin.TetraJsonInterfaceImpl"))
|
||||
{
|
||||
N_CoPrtCnv::CoPrtCnvTelegramConverter::setUse2BytesForSingleFireDiameter(
|
||||
settings->settings()->value(QLatin1String("AES/use2BytesForSingleFireDiameter"), true).toBool());
|
||||
N_CoPrtCnv::CoPrtCnvTelegramConverter::setUsePvSan(
|
||||
settings->settings()->value(QLatin1String("TrainingAreaBase/UsePvSan"), false).toBool());
|
||||
ERROR_LOG(m_logger) << "hello i got this!";
|
||||
}
|
||||
|
||||
TetraJsonInterfaceImpl::~TetraJsonInterfaceImpl()
|
||||
{
|
||||
cleanupProcess();
|
||||
}
|
||||
|
||||
bool TetraJsonInterfaceImpl::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 TetraJsonInterfaceImpl::exerciseChanged()
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "TetraJsonInterfaceImpl::exerciseChanged";
|
||||
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();
|
||||
}
|
||||
|
||||
bool TetraJsonInterfaceImpl::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(iniFileIn(), iniFileOut()))
|
||||
{
|
||||
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"), m_socketDispatcher->randomListenPort());
|
||||
NOTICE_LOG(m_logger) << "TetraJson Injection/Port = " << s.value(QStringLiteral("Injection/Port")).toInt();
|
||||
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 TetraJsonInterfaceImpl::checkConfigTemplates()
|
||||
{
|
||||
if (!QFile::exists(iniFileIn()))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Creating " << iniFileIn();
|
||||
if (!QFile::copy(QStringLiteral(":/PrtCnv.dat"), iniFileIn()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating " << iniFileIn();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
QFile(iniFileIn()).setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther | QFile::WriteOwner);
|
||||
}
|
||||
|
||||
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 TetraJsonInterfaceImpl::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());
|
||||
m_prtCnvApp->startApp();
|
||||
m_socketDispatcher->init(m_prtCnvApp);
|
||||
|
||||
onTetraConnectionChanged(false); // initial
|
||||
connect(m_socketDispatcher.get(), &SocketDispatcher::tetraConnectionChanged,
|
||||
this, &TetraJsonInterfaceImpl::onTetraConnectionChanged);
|
||||
|
||||
connect(m_socketDispatcher.get(), &SocketDispatcher::warehouseMessage,
|
||||
this, &TetraJsonInterfaceImpl::directMessage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::SendToTab> TetraJsonInterfaceImpl::sendToTab()
|
||||
{
|
||||
return m_socketDispatcher->sendToTab();
|
||||
}
|
||||
|
||||
bool TetraJsonInterfaceImpl::canSendData() const
|
||||
{
|
||||
return m_socketDispatcher->canSendData() && m_prtCnvApp != nullptr;
|
||||
}
|
||||
|
||||
void TetraJsonInterfaceImpl::onTetraConnectionChanged(bool bConnected)
|
||||
{
|
||||
emit connectionState(QString::fromUtf8(name()), bConnected);
|
||||
}
|
||||
|
||||
void TetraJsonInterfaceImpl::cleanupProcess()
|
||||
{
|
||||
m_socketDispatcher->init(nullptr);
|
||||
if (!m_prtCnvApp)
|
||||
return;
|
||||
m_prtCnvApp->shutdownApp();
|
||||
delete m_prtCnvApp;
|
||||
m_prtCnvApp = nullptr;
|
||||
onTetraConnectionChanged(false);
|
||||
}
|
||||
|
||||
QString TetraJsonInterfaceImpl::iniFileIn()
|
||||
{
|
||||
return iniPath() + QStringLiteral("/PrtCnv.dat");
|
||||
}
|
||||
|
||||
QString TetraJsonInterfaceImpl::iniFileOut() const
|
||||
{
|
||||
return iniPath() + QStringLiteral("/PrtCnv_ex_%1.dat").arg(m_exerciseId);
|
||||
}
|
||||
|
||||
QString TetraJsonInterfaceImpl::iniPath()
|
||||
{
|
||||
return QCoreApplication::applicationDirPath() + QLatin1Char('/');
|
||||
}
|
||||
|
||||
QString TetraJsonInterfaceImpl::playerIdsFile()
|
||||
{
|
||||
return iniPath() + QStringLiteral("/playerIds.dat");
|
||||
}
|
||||
|
||||
} // namespace TetraRadio
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Send / Receive telegrams to/from PrtCnv
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-09-26
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <TrainingAreaBase/tab_plugin_interface.h>
|
||||
#include <memory>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <PrtCnv/PrtCnvApplication.hpp>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
class TetraJsonPlugin : public QObject, public TrainingAreaBase::Plugin::Plugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "special:3:tab.jsonsocket")
|
||||
Q_INTERFACES(TrainingAreaBase::Plugin::Plugin)
|
||||
public:
|
||||
TetraJsonPlugin() = default;
|
||||
~TetraJsonPlugin() = 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,
|
||||
const std::shared_ptr<TrainingAreaBase::DdsHandler> &,
|
||||
NGL::Settings *settings) override;
|
||||
};
|
||||
|
||||
class SocketDispatcher;
|
||||
class TetraJsonInterfaceImpl final : public TrainingAreaBase::Plugin::Interface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TetraJsonInterfaceImpl(TrainingAreaBase::Plugin::DataProvider *pdp,
|
||||
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
|
||||
NGL::Settings *settings);
|
||||
~TetraJsonInterfaceImpl();
|
||||
|
||||
bool init() override;
|
||||
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 "TETRA"; }
|
||||
private Q_SLOTS:
|
||||
void onTetraConnectionChanged(bool bConnected);
|
||||
private:
|
||||
void cleanupProcess();
|
||||
static QString iniFileIn();
|
||||
QString iniFileOut() const;
|
||||
static QString iniPath();
|
||||
static QString playerIdsFile();
|
||||
bool updatePrtCnv();
|
||||
bool checkConfigTemplates();
|
||||
bool startPrtCnv();
|
||||
|
||||
private:
|
||||
std::unique_ptr<SocketDispatcher> m_socketDispatcher;
|
||||
TrainingAreaBase::Plugin::DataProvider *m_pdp;
|
||||
PrtCnv::PrtCnvApplication *m_prtCnvApp;
|
||||
int m_exerciseId;
|
||||
int m_radioGrpId;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TetraRadio
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Send / Receive telegrams to/from PrtCnv
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-09-26
|
||||
*/
|
||||
|
||||
#include "socket_dispatcher_json.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QTcpServer>
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
|
||||
//
|
||||
// SocketDispatcher
|
||||
//
|
||||
SocketDispatcher::SocketDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
|
||||
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb)
|
||||
: QObject()
|
||||
, ConvertFromJson(recvFromTabCb, "TAB.Plugin.SocketDispatcher")
|
||||
, m_txHandler(std::make_shared<ConvertToJson>("TxSocketHandler"))
|
||||
, m_dataProvider(pdp)
|
||||
, m_prtCnvApp(nullptr)
|
||||
, m_ackTimer(new QTimer(this))
|
||||
, m_bInitialAck(false)
|
||||
, m_receiveCounter(0)
|
||||
{
|
||||
m_ackTimer->setInterval(1000);
|
||||
m_ackTimer->setSingleShot(false);
|
||||
connect(m_ackTimer, &QTimer::timeout,
|
||||
this, &SocketDispatcher::onAckTimeout);
|
||||
}
|
||||
|
||||
SocketDispatcher::~SocketDispatcher()
|
||||
{
|
||||
delete m_ackTimer;
|
||||
}
|
||||
|
||||
bool SocketDispatcher::init(PrtCnv::PrtCnvApplication *prtCnvApp)
|
||||
{
|
||||
if (m_prtCnvApp == prtCnvApp)
|
||||
return true;
|
||||
if (m_prtCnvApp)
|
||||
m_prtCnvApp->disconnect(this);
|
||||
m_prtCnvApp = prtCnvApp;
|
||||
if (m_prtCnvApp)
|
||||
{
|
||||
connect(m_txHandler.get(), &ConvertToJson::outgoingMessage,
|
||||
m_prtCnvApp, &PrtCnv::PrtCnvApplication::textMessageFromCentralToPrtCnv);
|
||||
connect(m_prtCnvApp, &PrtCnv::PrtCnvApplication::textMessageFromPrtCnvToCentral,
|
||||
this, &SocketDispatcher::onTextMessageReceived);
|
||||
connect(m_prtCnvApp, &PrtCnv::PrtCnvApplication::warehouseMessageFromPtrCnv,
|
||||
this, &SocketDispatcher::warehouseMessage);
|
||||
|
||||
m_ackTimer->start();
|
||||
m_bInitialAck = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bInitialAck = false;
|
||||
m_ackTimer->stop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
quint16 SocketDispatcher::randomListenPort() const
|
||||
{
|
||||
QTcpServer *s = new QTcpServer;
|
||||
s->listen(QHostAddress::Any, 0);
|
||||
while (!s->isListening())
|
||||
QCoreApplication::processEvents();
|
||||
quint16 port = s->serverPort();
|
||||
delete s;
|
||||
return port;
|
||||
}
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::SendToTab> SocketDispatcher::sendToTab()
|
||||
{
|
||||
return std::static_pointer_cast<TrainingAreaBase::SendToTab>(m_txHandler);
|
||||
}
|
||||
|
||||
void SocketDispatcher::onTextMessageReceived(const QByteArray &message)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TetraJson onTextMessageReceived: '" << message << "'";
|
||||
int newRecvCounter = 0;
|
||||
if (!handleTelegram(message, newRecvCounter))
|
||||
return;
|
||||
m_receiveCounter = newRecvCounter;
|
||||
}
|
||||
|
||||
void SocketDispatcher::handleTetraConnectionChanged(bool bConnected)
|
||||
{
|
||||
emit tetraConnectionChanged(bConnected);
|
||||
}
|
||||
|
||||
void SocketDispatcher::handleAcknowledge(qint64 timeStamp, int counter)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "Ack from Socket for time " << timeStamp
|
||||
<< " with counter " << counter
|
||||
<< ", initial: " << m_bInitialAck;
|
||||
if (m_bInitialAck)
|
||||
{
|
||||
m_txHandler->setConnected(true);
|
||||
m_bInitialAck = false;
|
||||
onSendInitialData();
|
||||
}
|
||||
// TODO: remove all now outdated telegrams !?
|
||||
}
|
||||
|
||||
void SocketDispatcher::onAckTimeout()
|
||||
{
|
||||
TrainingAreaBase::TetraIcd::Acknowledge ack;
|
||||
ack.timeStamp = time(nullptr) * 1000;
|
||||
ack.ackCounter = m_receiveCounter;
|
||||
m_txHandler->txData(ack);
|
||||
}
|
||||
|
||||
void SocketDispatcher::onSendInitialData()
|
||||
{
|
||||
if (m_dataProvider)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "sending initial data exerciseId=" << m_dataProvider->exerciseId();
|
||||
// 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 TetraRadio
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 "convert_from_json.h"
|
||||
#include "convert_to_json.h"
|
||||
|
||||
namespace TetraRadio
|
||||
{
|
||||
class SocketDispatcher final : public QObject, protected ConvertFromJson
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SocketDispatcher(TrainingAreaBase::Plugin::DataProvider *pdp,
|
||||
const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb);
|
||||
~SocketDispatcher();
|
||||
|
||||
bool init(PrtCnv::PrtCnvApplication *prtCnvApp);
|
||||
std::shared_ptr<TrainingAreaBase::SendToTab> sendToTab();
|
||||
quint16 randomListenPort() const;
|
||||
bool canSendData() const { return m_prtCnvApp != nullptr; }
|
||||
Q_SIGNALS:
|
||||
void tetraConnectionChanged(bool bConnected);
|
||||
void warehouseMessage(const QByteArray &jsonData);
|
||||
private Q_SLOTS:
|
||||
void onTextMessageReceived(const QByteArray &message);
|
||||
void onAckTimeout();
|
||||
void onSendInitialData();
|
||||
private:
|
||||
void disconnectSocket(QWebSocket *s);
|
||||
void handleTetraConnectionChanged(bool bConnected) override;
|
||||
void handleAcknowledge(qint64 timeStamp, int counter) override;
|
||||
private:
|
||||
std::shared_ptr<ConvertToJson> m_txHandler;
|
||||
TrainingAreaBase::Plugin::DataProvider *m_dataProvider;
|
||||
PrtCnv::PrtCnvApplication *m_prtCnvApp;
|
||||
QTimer *m_ackTimer;
|
||||
bool m_bInitialAck;
|
||||
int m_receiveCounter;
|
||||
};
|
||||
|
||||
} // namespace TetraRadio
|
||||
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>playerIds.dat</file>
|
||||
<file>PrtCnv.dat</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Reference in new issue
Block a user