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,33 @@
#
# Write all incoming / outgoing telegrams to a directory (xdr encoded)
# $Id$
# $HeadURL$
# $Author$
#
ADD_SUBDIRECTORY(XDR_QtHandler)
SET(SRCS
directory_cleaner.cpp
directory_cleaner.h
directory_dispatcher.cpp
directory_dispatcher.h
plugin.cpp
plugin.h
../TetraJson/convert_from_json.cpp
../TetraJson/convert_from_json.h
convert_to_json_file.cpp
convert_to_json_file.h
)
NGL_ADD_LIBRARY(SV tabPluginDebugJsonDir MODULE ${SRCS})
NGL_INSTALL_TARGET(tabPluginDebugJsonDir)
NGL_TARGET_LINK_LIBRARIES(tabPluginDebugJsonDir
tabPluginInterface
tabTelegrams
NGLLogger
nglsettings
Qt5::Core
Qt5::WebSockets
tabPluginInterface
xdr_qthandler_dir
)
@@ -0,0 +1,31 @@
SET(xdr_dh_SRCS
XDR_DirHandler.cpp
XDR_DirHandler_ifc.cpp
)
SET(xdr_dh_HDRS
XDR_DirHandler.h
XDR_DirHandler_ifc.h
)
IF(WIN32)
LIST(APPEND xdr_dh_SRCS
XDR_DirHandler_win.cpp
)
LIST(APPEND xdr_dh_HDRS
XDR_DirHandler_win.h
)
ELSE(WIN32)
LIST(APPEND xdr_dh_SRCS
XDR_DirHandler_linux.cpp
)
LIST(APPEND xdr_dh_HDRS
XDR_DirHandler_linux.h
)
ENDIF(WIN32)
NGL_ADD_LIBRARY(AAR SV xdr_qthandler_dir SHARED ${xdr_dh_SRCS} ${xdr_dh_HDRS})
NGL_TARGET_LINK_LIBRARIES(xdr_qthandler_dir
PRIVATE
NGLLogger
PUBLIC
Qt5::Core
)
NGL_INSTALL_TARGET(xdr_qthandler_dir)
@@ -0,0 +1,58 @@
/**
* Scan directory for new XDR files
* $Id$
* $HeadURL$
* $Author$
*/
#include "XDR_DirHandler.h"
#include <QtCore/QTimer>
#include <QtCore/QThread>
#ifdef WIN32
#include "XDR_DirHandler_win.h"
#else
#include "XDR_DirHandler_linux.h"
#endif
XDR_DirHandler::XDR_DirHandler(const QString &dirToWatch, bool startWatching, QObject *parent)
: QObject(parent)
, m_workerThread(new QThread)
, m_workerObject(nullptr)
, m_startWatching(startWatching)
, m_dirToWatch(dirToWatch)
{
#ifdef WIN32
m_workerObject = new XDR_DirHandlerWin(dirToWatch);
#else
m_workerObject = new XDR_DirHandlerLinux(dirToWatch);
#endif
m_workerThread->start();
m_workerObject->moveToThread(m_workerThread);
connect(m_workerObject, &XDR_DirHandlerIfc::newTelegramArrived,
this, &XDR_DirHandler::newTelegramArrived);
connect(m_workerThread, &QThread::finished,
m_workerObject, &XDR_DirHandlerIfc::deleteLater);
if (startWatching)
QTimer::singleShot(0, m_workerObject, &XDR_DirHandlerIfc::startWatching);
}
XDR_DirHandler::~XDR_DirHandler()
{
m_workerThread->requestInterruption();
m_workerThread->quit();
if (!m_workerThread->wait(10000))
m_workerThread->terminate();
delete m_workerThread;
}
void XDR_DirHandler::startWatching()
{
if (!m_startWatching)
{
QTimer::singleShot(0, m_workerObject, &XDR_DirHandlerIfc::startWatching);
m_startWatching = true;
}
}
@@ -0,0 +1,62 @@
/**
* Scan directory for new XDR files
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QObject>
#include <QtCore/QString>
#ifndef XDR_QTHANDLER_DIR_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define XDR_QTHANDLER_DIR_EXPORT
# else
# ifdef MAKE_XDR_QTHANDLER_DIR_LIB
# define XDR_QTHANDLER_DIR_EXPORT Q_DECL_EXPORT
# else
# define XDR_QTHANDLER_DIR_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
class XDR_DirHandlerIfc;
class XDR_QTHANDLER_DIR_EXPORT XDR_DirHandler : public QObject
{
Q_OBJECT
public:
XDR_DirHandler(const QString &dirToWatch, bool startWatching = true, QObject *parent = nullptr);
~XDR_DirHandler();
void startWatching();
QString dirToWatch() const { return m_dirToWatch; }
protected Q_SLOTS:
virtual void newTelegramArrived(const QString &fullPath) = 0;
private:
QThread *m_workerThread;
XDR_DirHandlerIfc *m_workerObject;
bool m_startWatching;
QString m_dirToWatch;
};
class XDR_QTHANDLER_DIR_EXPORT XDR_DirHandler_emit : public XDR_DirHandler
{
Q_OBJECT
public:
XDR_DirHandler_emit(const QString &dirToWatch, QObject *parent = nullptr)
: XDR_DirHandler(dirToWatch, true, parent)
{}
~XDR_DirHandler_emit()
{}
protected:
virtual void newTelegramArrived(const QString &fullPath)
{
emit newTelegram(fullPath);
}
Q_SIGNALS:
void newTelegram(const QString &fullPath);
};
@@ -0,0 +1,19 @@
/**
* Scan directory for new XDR files - internal interfacefor OS abstraction
* $Id$
* $HeadURL$
* $Author$
*/
#include "XDR_DirHandler_ifc.h"
XDR_DirHandlerIfc::XDR_DirHandlerIfc(const QString &dirToWatch, QObject *parent)
: QObject(parent)
, mDirToWatchBA(dirToWatch.toLocal8Bit())
, mDirToWatch(dirToWatch)
{
if (!mDirToWatch.endsWith(QLatin1Char('/')))
mDirToWatch += QLatin1Char('/');
if (!mDirToWatchBA.endsWith('/'))
mDirToWatchBA += '/';
}
@@ -0,0 +1,27 @@
/**
* Scan directory for new XDR files - internal interfacefor OS abstraction
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QObject>
#include <QByteArray>
#include <QString>
class XDR_DirHandlerIfc : public QObject
{
Q_OBJECT
public:
XDR_DirHandlerIfc(const QString &dirToWatch, QObject *parent = nullptr);
public Q_SLOTS:
virtual void startWatching() = 0;
Q_SIGNALS:
void newTelegramArrived(const QString &fullPath);
protected:
QByteArray mDirToWatchBA;
QString mDirToWatch;
};
@@ -0,0 +1,199 @@
/**
* Scan directory for new XDR files - windows specific implementation
* $Id$
* $HeadURL$
* $Author$
*/
#include "XDR_DirHandler_linux.h"
#include <QMap>
#include <QThread>
#include <QTimer>
#include <QVarLengthArray>
#include <poll.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void XDR_DirHandlerLinux::startWatching()
{
onScanDirectory();
startEPoll();
}
void XDR_DirHandlerLinux::onScanDirectory()
{
QByteArray nameBA;
nameBA.reserve(128);
QVarLengthArray<char, 512> tmpFilename;
const int tmpFilenameOffset = mDirToWatchBA.size();
tmpFilename.clear();
tmpFilename.append(mDirToWatchBA.data(), mDirToWatchBA.size());
// Verzeichnis oeffnen
DIR *dirp = opendir(mDirToWatchBA.constData());
if(!dirp)
return;
// Schleife ueber alle Files
dirent* entry;
while ((entry = readdir(dirp)) != nullptr) {
const char *name = entry->d_name;
// skip directories
size_t len = strlen(name);
// skip "."
if( len == 1 && name[0] == '.' )
continue;
// skip ".."
if( len == 2 && name[0] == '.' && name[1] == '.' )
continue;
if(len > 4) {
size_t pos = len - 4;
if( name[pos] == '.' &&
tolower(name[pos+1]) == 't' &&
tolower(name[pos+2]) == 'm' &&
tolower(name[pos+3]) == 'p')
continue;
}
// ist es ein Verzeichnis?
struct stat st;
tmpFilename.resize(tmpFilenameOffset);
tmpFilename.append(name, len);
tmpFilename.append('\0');
int res = stat(tmpFilename.constData(), &st);
if (res || S_ISDIR(st.st_mode) ) {
// Unterverzeichnis
continue;
}
// einfuegen
nameBA.clear();
nameBA.append(name, len);
m_newFilesMap.insert(nameBA, 1);
}
closedir(dirp);
// map is sorted by key, we don't care about value
QMap<QByteArray, int>::ConstIterator it = m_newFilesMap.constBegin();
QMap<QByteArray, int>::ConstIterator end = m_newFilesMap.constEnd();
for( ; it != end; ++it)
{
emit newTelegramArrived(mDirToWatch + QString::fromLocal8Bit(it.key()));
}
QTimer::singleShot(5000, this, &XDR_DirHandlerLinux::clearNewFilesMap);
}
void XDR_DirHandlerLinux::clearNewFilesMap()
{
m_newFilesMap.clear();
}
#if 0
// fuer debug-Zwecke
static void /* Display information from inotify_event structure */
displayInotifyEvent(const inotify_event *i)
{
printf(" wd =%2d; ", i->wd);
if (i->cookie > 0)
printf("cookie =%4d; ", i->cookie);
printf("mask = ");
if (i->mask & IN_ACCESS) printf("IN_ACCESS ");
if (i->mask & IN_ATTRIB) printf("IN_ATTRIB ");
if (i->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE ");
if (i->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE ");
if (i->mask & IN_CREATE) printf("IN_CREATE ");
if (i->mask & IN_DELETE) printf("IN_DELETE ");
if (i->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF ");
if (i->mask & IN_IGNORED) printf("IN_IGNORED ");
if (i->mask & IN_ISDIR) printf("IN_ISDIR ");
if (i->mask & IN_MODIFY) printf("IN_MODIFY ");
if (i->mask & IN_MOVE_SELF) printf("IN_MOVE_SELF ");
if (i->mask & IN_MOVED_FROM) printf("IN_MOVED_FROM ");
if (i->mask & IN_MOVED_TO) printf("IN_MOVED_TO ");
if (i->mask & IN_OPEN) printf("IN_OPEN ");
if (i->mask & IN_Q_OVERFLOW) printf("IN_Q_OVERFLOW ");
if (i->mask & IN_UNMOUNT) printf("IN_UNMOUNT ");
printf("\n");
if (i->len > 0)
printf(" name = %s\n", i->name);
}
#endif
void XDR_DirHandlerLinux::startEPoll()
{
int inotifyFd = inotify_init();
if (inotifyFd != -1) {
// Entweder wenn foo.tmp nach foo verschoben wird oder
// wenn eine Datei geschlossen wird (inklusive Schreibvorgang vorher)
// d.h. wir würden das umbenennen von foo.tmp nach foo gar nicht mehr benoetigen
int wd = inotify_add_watch(inotifyFd, mDirToWatchBA.constData(), IN_MOVED_TO|IN_CLOSE_WRITE);
if (wd != -1) {
Q_FOREVER {
if (QThread::currentThread()->isInterruptionRequested())
break;
struct pollfd fds[1];
memset(fds, 0, sizeof(fds));
fds[0].fd = inotifyFd;
fds[0].events = POLLIN | POLLPRI;
constexpr int timeout_msecs = 5;
int ret = poll(fds, 1, timeout_msecs);
if (ret > 0) {
static const int BUF_LEN = (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
char buf[BUF_LEN] __attribute__ ((aligned(8)));
int numRead = read(inotifyFd, buf, BUF_LEN);
if(numRead <= 0)
break;
for (const char *p = buf; p < buf + numRead; ) {
const inotify_event *event = reinterpret_cast<const inotify_event *>(p);
//displayInotifyEvent(event);
handleInotifyEvents(event);
p += sizeof(struct inotify_event) + event->len;
}
}
}
close(wd);
}
close(inotifyFd);
}
}
void XDR_DirHandlerLinux::handleInotifyEvents(const inotify_event *entry)
{
// wir gehen davon aus, dass wir nur IN_CLOSE_WRITE und IN_MOVED_TO
// bekommen so wie wir es auch aboniert haben.
// skip directories
if((entry->mask & IN_ISDIR) == IN_ISDIR)
return;
const char *name = entry->name;
const size_t len = strlen(name); // entry->len contains the length including \0 and padding bytes!
if (len > 4) {
size_t pos = len - 4;
if( name[pos] == '.' &&
tolower(name[pos+1]) == 't' &&
tolower(name[pos+2]) == 'm' &&
tolower(name[pos+3]) == 'p') {
return;
}
}
if (!m_newFilesMap.isEmpty()) {
if (m_newFilesMap.contains(QByteArray::fromRawData(name, len)))
return;
}
emit newTelegramArrived(mDirToWatch + QString::fromLocal8Bit(name));
}
@@ -0,0 +1,29 @@
/**
* Scan directory for new XDR files - windows specific implementation
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "XDR_DirHandler_ifc.h"
#include <QMap>
struct inotify_event;
class XDR_DirHandlerLinux final : public XDR_DirHandlerIfc
{
Q_OBJECT
public:
using XDR_DirHandlerIfc::XDR_DirHandlerIfc;
private Q_SLOTS:
void onScanDirectory();
void startWatching();
void startEPoll();
void clearNewFilesMap();
private:
void handleInotifyEvents(const inotify_event *entry);
private:
QMap<QByteArray, int> m_newFilesMap; // fuer initiales lesen
};
@@ -0,0 +1,78 @@
/**
* Scan directory for new XDR files - windows specific implementation
* $Id$
* $HeadURL$
* $Author$
*/
#include "XDR_DirHandler_win.h"
#include <QtCore/QTimer>
#include <QtCore/QMap>
#include <QtCore/QVarLengthArray>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
#include <tchar.h>
void XDR_DirHandlerWin::startWatching()
{
onScanDirectory();
}
void XDR_DirHandlerWin::onScanDirectory()
{
QString lastFilename = mLastFilename;
QMap<QString, int> newFilesMap;
// Verzeichnis oeffnen
WIN32_FIND_DATA findData;
HANDLE dirp = FindFirstFile(reinterpret_cast<LPCWSTR>(mDirToWatch.utf16()), &findData);
while(dirp != INVALID_HANDLE_VALUE)
return;
// Schleife ueber alle Files
do {
// skip directories
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
if (FindNextFile(dirp, &findData) == 0)
break;
continue;
}
const TCHAR *name = findData.cFileName;
const size_t len = wcslen(name);
if(len > 4) {
size_t pos = len - 4;
if( name[pos] == '.' &&
_totlower(name[pos+1]) == 't' &&
_totlower(name[pos+2]) == 'm' &&
_totlower(name[pos+3]) == 'p')
continue;
}
// hatten wir schon ?
const QString nameStr = QString::fromUtf16(reinterpret_cast<const ushort*>(name), len);
if ( mLastFilename.size() && nameStr <= mLastFilename )
continue;
if (nameStr > lastFilename)
lastFilename = nameStr;
// einfuegen
newFilesMap.insert(nameStr, 1);
} while (FindNextFile(dirp, &findData) != 0);
FindClose(dirp);
mLastFilename = lastFilename;
// map is sorted by key, we don't care about value
QMap<QString, int>::ConstIterator it = newFilesMap.constBegin();
QMap<QString, int>::ConstIterator end = newFilesMap.constEnd();
for( ; it != end; ++it)
emit newTelegramArrived(mDirToWatch + it.key());
// Alle 200 msec lesen
QTimer::singleShot(200, this, &XDR_DirHandlerWin::onScanDirectory);
}
@@ -0,0 +1,23 @@
/**
* Scan directory for new XDR files - windows specific implementation
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "XDR_DirHandler_ifc.h"
class XDR_DirHandlerWin : public XDR_DirHandlerIfc
{
Q_OBJECT
public:
using XDR_DirHandlerIfc::XDR_DirHandlerIfc;
private Q_SLOTS:
void onScanDirectory();
void startWatching();
private:
QString mLastFilename;
};
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef XDR_QTHANDLER_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define XDR_QTHANDLER_EXPORT
# else
# if defined(MAKE_XDR_QTHANDLER_LIB)
# define XDR_QTHANDLER_EXPORT Q_DECL_EXPORT
# else
# define XDR_QTHANDLER_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,277 @@
/**
* Write XDR telegrams to a directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-04-14
*/
#include "convert_to_json_file.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QDateTime>
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace TetraRadio
{
ConvertToJsonFile::ConvertToJsonFile(const QString &txDir)
: SendToTab()
, m_bRetvalOnError(false)
, m_txDir(txDir + QLatin1Char('/'))
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TAB.Plugin.ConvertToJsonFile"))
{
resetSendCounter();
}
TrainingAreaBase::SendToTab::HandleState ConvertToJsonFile::canHandleTelegram(int equipmentNumber, int telegramId) const
{
Q_UNUSED(equipmentNumber)
Q_UNUSED(telegramId)
return HandleState::Debug;
}
void ConvertToJsonFile::resetSendCounter()
{}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::Acknowledge &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DemandBite &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::Init &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::SetVulnerabilityModel &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DemandEquipmentConfigurationReport &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::LanguageSelection &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::EquipmentMessage &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::EquipmentMessageOC &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateAreaExplosion &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateMineArea &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::MineAreaSingleMineState &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateNContamination &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateCContamination &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DeactivateEffectSimulation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ModifyAreaEffectSimulationName &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::PauseEffectSimulation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ResumeEffectSimulation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::MineTriggered &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DusMineReactivation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateFunctionalArea &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CreateDusSingleMine &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExerciseEnvironmentData &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExerciseStateData &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ParticipantSwVersionsRequest &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::OpaquePayloadDataOut &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::TechnicalArea &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CesHitInformation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::CesHitRequest &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ParticipantMode &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DemandParticipantMode &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ParticipantConfiguration &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::DemandParticipantConfiguration &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::Sanitation &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::SelectiveReammunition &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::SetDevicePowerRequest &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::OcCommand &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::UAVPerformMission &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::UAVChangeState &data)
{
return sendToTx(&data);
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExFireReadiness &data)
{
Q_UNUSED(data)
return false;
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExFiredReport &data)
{
Q_UNUSED(data)
return false;
}
bool ConvertToJsonFile::txData(const TrainingAreaBase::TetraIcd::ExConfirmationReport &data)
{
Q_UNUSED(data)
return false;
}
template <typename T>
bool ConvertToJsonFile::sendToTx(const T *data)
{
const QString fileName = m_txDir + QString::number(QDateTime::currentMSecsSinceEpoch());
QFile f(fileName);
if (!f.open(QIODevice::WriteOnly))
return m_bRetvalOnError;
QJsonObject obj;
obj[QStringLiteral("data")] = data->toJson();
obj[QStringLiteral("type")] = TrainingAreaBase::TetraIcd::Constraints<T>::type();
obj[QStringLiteral("typeId")] = data->id();
const QByteArray ba = QJsonDocument(obj).toJson(QJsonDocument::Compact);
f.write(ba);
f.close();
return true;
}
} // namespace TetraRadio
@@ -0,0 +1,79 @@
/**
* 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 <TrainingAreaBase/send_to_tab.h>
namespace TetraRadio
{
class ConvertToJsonFile : public TrainingAreaBase::SendToTab
{
public:
explicit ConvertToJsonFile(const QString &txDir);
const char *name() const override { return "ConvertToJsonFile"; }
HandleState canHandleTelegram(int equipmentNumber, int telegramId) const override;
void resetSendCounter() override;
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 &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExFireReadiness &data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExFiredReport&data) override;
bool txData(const TrainingAreaBase::TetraIcd::ExConfirmationReport &data) override;
protected:
template <typename T>
bool sendToTx(const T *data);
protected:
bool m_bRetvalOnError;
QString m_txDir;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,163 @@
/**
* Helper class to remove outdated telegram files in a directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "directory_cleaner.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <TrainingAreaBase/training_area_telegrams.h>
#include <QDateTime>
#include <QDir>
#include <QDirIterator>
#include <QTimer>
#include <QThread>
#include <QJsonDocument>
#include <QJsonObject>
#include <ctime>
namespace TetraRadio
{
//
// DirectoryCleaner
//
DirectoryCleaner::DirectoryCleaner(const QString &directory, unsigned int maxAgeSec, QObject *parent)
: QObject(parent)
, m_cleanerThread(new QThread(this))
, m_worker(new DirectoryCleanerWorker(directory, maxAgeSec))
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TAB.Plugin.DirectoryCleaner"))
{
QDir().mkpath(directory);
doInitialCleanup(directory);
m_worker->moveToThread(m_cleanerThread);
m_cleanerThread->start();
QTimer::singleShot(0, m_worker, &DirectoryCleanerWorker::onTimeout);
}
DirectoryCleaner::~DirectoryCleaner()
{
m_cleanerThread->quit();
m_cleanerThread->wait();
delete m_worker;
}
void DirectoryCleaner::doInitialCleanup(const QString &directory)
{
QDir d(directory);
if (!d.exists())
{
WARNING_LOG(m_logger) << "Directory " << directory
<< " does not exist - can not cleanup directory";
return;
}
QDirIterator it(d.absolutePath(), QDir::Files | QDir::NoDotAndDotDot);
while (it.hasNext())
{
it.next();
QFile f(it.filePath());
if (!f.open(QIODevice::ReadOnly))
continue;
const QByteArray ba = f.readAll();
const QJsonObject obj = QJsonDocument::fromJson(ba).object();
const int teleId = obj[QStringLiteral("typeId")].toInt();
if (teleShouldBeRemoved(teleId))
QFile::remove(it.filePath());
}
}
bool DirectoryCleaner::teleShouldBeRemoved(int teleId)
{
switch (teleId)
{
case TrainingAreaBase::TetraIcd::WIRKFELD_EINZELGESCHOSS:
case TrainingAreaBase::TetraIcd::WIRKFELD_FLAECHENDECKENDES_FEUER:
case TrainingAreaBase::TetraIcd::WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
case TrainingAreaBase::TetraIcd::WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
case TrainingAreaBase::TetraIcd::WIRKFELD_MINENSPERRE:
case TrainingAreaBase::TetraIcd::WIRKFELD_STATUS_MINENSPERRE:
case TrainingAreaBase::TetraIcd::WIRKFELD_AENDERUNG_BEZEICHNER:
case TrainingAreaBase::TetraIcd::REAKTIVIERUNG_DUS_MINE:
case TrainingAreaBase::TetraIcd::WIRKFELD_A_KAMPFMITTEL:
case TrainingAreaBase::TetraIcd::WIRKFELD_C_KAMPFMITTEL:
case TrainingAreaBase::TetraIcd::DEAKTIVIERUNG_WIRKFELD:
case TrainingAreaBase::TetraIcd::DEAKTIVIERUNG_EINZELMINE:
case TrainingAreaBase::TetraIcd::FUNKTIONSRAUM:
case TrainingAreaBase::TetraIcd::DEAKTIVIEREN_FUNKTIONSRAUM:
case TrainingAreaBase::TetraIcd::BETRIEBSZUSTANDSMELDUNG:
return true;
default:
break;
}
return false;
}
//
// DirectoryCleanerWorker
//
DirectoryCleanerWorker::DirectoryCleanerWorker(const QString &directory, unsigned int maxAgeSec)
: m_directory(directory)
, m_maxAgeSec(maxAgeSec)
, m_bWarnedOnce(false)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TRA.Plugin.DirectoryCleaner"))
{}
void DirectoryCleanerWorker::onTimeout()
{
doCleanup();
// search every 5sec
QTimer::singleShot(5000, Qt::VeryCoarseTimer, this, &DirectoryCleanerWorker::onTimeout);
}
void DirectoryCleanerWorker::doCleanup()
{
QDir d(m_directory);
if (!d.exists())
{
if (!m_bWarnedOnce)
WARNING_LOG(m_logger) << "Directory " << m_directory
<< " does not exist - can not cleanup directory";
m_bWarnedOnce = true;
return;
}
m_bWarnedOnce = false;
const qint64 tRemoveTimeMSec = (time(nullptr) - m_maxAgeSec) * 1000;
QDirIterator it(d.absolutePath(), QDir::Files | QDir::NoDotAndDotDot);
while (it.hasNext())
{
const QString filepath(it.next());
const QString filename(it.fileName());
bool bOk = false;
qint64 timestampUSec = filename.toLongLong(&bOk);
TRACE_LOG(m_logger) << "File: " << filename
<< " timestamp: " << timestampUSec
<< " remove time: " << tRemoveTimeMSec * 1000;
if (!bOk)
{
WARNING_LOG(m_logger) << "Found file with name '" << filepath
<< " which is not a valid xdr filename"
<< " - removing this file when mtime older than "
<< m_maxAgeSec << "seconds";
qint64 modTime = it.fileInfo().lastModified().toMSecsSinceEpoch();
if (modTime < tRemoveTimeMSec)
QFile::remove(filepath);
}
else
{
const qint64 timestampMSec = timestampUSec / 1000; // usec -> msec
if (timestampMSec < tRemoveTimeMSec)
{
if (!QFile::remove(filepath))
WARNING_LOG(m_logger) << "Could not remove " << filepath;
else
TRACE_LOG(m_logger) << "Removed " << filepath;
}
}
}
}
} // namespace TetraRadio
@@ -0,0 +1,50 @@
/**
* Helper class to remove outdated telegram files in a directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#pragma once
#include <QObject>
#include <NGLLogger/INGLLogger.h>
class QThread;
class XDR_Wrapper_it;
namespace TetraRadio
{
class DirectoryCleanerWorker;
class DirectoryCleaner : public QObject
{
Q_OBJECT
public:
DirectoryCleaner(const QString &directory, unsigned int maxAgeSec, QObject *parent = nullptr);
~DirectoryCleaner();
private:
// remove xdr telegrams which are regenerated on startup (e.g. AES telegrams)
// and therefore must not be reread on startup
void doInitialCleanup(const QString &directory);
bool teleShouldBeRemoved(int teleId);
QThread *m_cleanerThread;
DirectoryCleanerWorker *m_worker;
NGL::INGLLogger &m_logger;
};
class DirectoryCleanerWorker: public QObject
{
Q_OBJECT
public:
DirectoryCleanerWorker(const QString &directory, unsigned int maxAgeSec);
~DirectoryCleanerWorker() = default;
public Q_SLOTS:
void onTimeout();
private:
void doCleanup();
private:
QString m_directory;
qint64 m_maxAgeSec;
bool m_bWarnedOnce;
NGL::INGLLogger &m_logger;
};
} // namespace TetraRadio
@@ -0,0 +1,82 @@
/**
* Send / Receive telegrams to/from TX/RX directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "directory_dispatcher.h"
#include "convert_to_json_file.h"
#include "directory_cleaner.h"
#include <XDR_QtHandler/XDR_DirHandler.h>
#include <QDir>
namespace TetraRadio
{
//
// DirectoryDispatcher
//
DirectoryDispatcher::DirectoryDispatcher(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
const QString &txDir,
const QString &rxDir)
: TrainingAreaBase::Plugin::Interface()
, ConvertFromJson(recvFromTabCb, "TAB.Plugin.DirectoryDispatcher")
, m_xdrDirHandler(new XDR_DirHandler_emit(rxDir, this))
, m_txCleaner(new DirectoryCleaner(txDir, 10 * 60, this))
, m_txDir(txDir)
, m_rxDir(rxDir)
{
QFileInfo fi(m_txDir);
if (!fi.exists() || !fi.isDir())
{
QDir d;
if (!d.mkpath(m_txDir))
ERROR_LOG(m_logger) << "Can not create directory " << m_txDir;
}
fi = QFileInfo(m_rxDir);
if (!fi.exists() || !fi.isDir())
{
QDir d;
if (!d.mkpath(m_rxDir))
ERROR_LOG(m_logger) << "Can not create directory " << m_rxDir;
}
NOTICE_LOG(m_logger) << "Using RX dir: " << m_rxDir;
NOTICE_LOG(m_logger) << "Using TX dir: " << m_txDir;
connect(m_xdrDirHandler, &XDR_DirHandler_emit::newTelegram,
this, &DirectoryDispatcher::newTelegramArrived);
}
DirectoryDispatcher::~DirectoryDispatcher()
{
delete m_xdrDirHandler;
}
bool DirectoryDispatcher::init()
{
m_tx = std::make_shared<ConvertToJsonFile>(m_txDir);
m_xdrDirHandler->startWatching();
return true;
}
std::shared_ptr<TrainingAreaBase::SendToTab> DirectoryDispatcher::sendToTab()
{
return m_tx;
}
void DirectoryDispatcher::newTelegramArrived(const QString &fullPath)
{
DEBUG_LOG(m_logger) << "Got new telegram: "
<< fullPath;
QFile f(fullPath);
if (!f.open(QIODevice::ReadOnly))
return;
const QByteArray tele = f.readAll();
f.close();
int recvCounterUnused;
handleTelegram(tele, recvCounterUnused);
}
} // namespace TetraRadio
@@ -0,0 +1,53 @@
/**
* 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>
#include <DDS/Core/function_reply_object.h>
#include "../TetraJson/convert_from_json.h"
#include "convert_to_json_file.h"
class XDR_DirHandler_emit;
namespace TetraRadio
{
class DirectoryCleaner;
class DirectoryDispatcher final : public TrainingAreaBase::Plugin::Interface,
protected ConvertFromJson
{
Q_OBJECT
public:
explicit DirectoryDispatcher(const std::shared_ptr<TrainingAreaBase::RecvFromTab> &recvFromTabCb,
const QString &txDir,
const QString &rxDir);
~DirectoryDispatcher();
bool init() override;
std::shared_ptr<TrainingAreaBase::SendToTab> sendToTab() override;
bool isDebugInterface() const override { return true; }
bool canSendData() const override { return true; }
void exerciseChanged() override { return; }
const char *name() const override { return tr_lts("dds", "Debug Directory XDR Dispatcher"); }
void handleAcknowledge(qint64, int) override {}
void handleTetraConnectionChanged(bool) override {}
private Q_SLOTS:
void newTelegramArrived(const QString &fullPath);
private:
std::shared_ptr<ConvertToJsonFile> m_tx;
std::shared_ptr<TrainingAreaBase::RecvFromTab> m_rx;
XDR_DirHandler_emit *m_xdrDirHandler;
DirectoryCleaner *m_txCleaner;
QString m_txDir;
QString m_rxDir;
};
} // namespace TetraRadio
@@ -0,0 +1,30 @@
/**
* Send / Receive telegrams to/from TX/RX directory
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-09-26
*/
#include "plugin.h"
#include "directory_dispatcher.h"
#include <nglsettings/nglsettings_settings.h>
namespace TetraRadio
{
//
// DebugJsonDirPlugin
//
std::shared_ptr<TrainingAreaBase::Plugin::Interface> DebugJsonDirPlugin::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)
{
const QString dir = QStringLiteral("/ex_%1_json/").arg(pdp->exerciseId());
return std::make_shared<DirectoryDispatcher>(recvFromTabCb,
settings->zsks_txPath() + dir,
settings->zsks_rxPath() + dir);
}
} // namespace TetraRadio
+31
View File
@@ -0,0 +1,31 @@
/**
* 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 TetraRadio
{
class DebugJsonDirPlugin : public QObject, public TrainingAreaBase::Plugin::Plugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "special:3:tab.jsondir")
Q_INTERFACES(TrainingAreaBase::Plugin::Plugin)
public:
DebugJsonDirPlugin() = default;
~DebugJsonDirPlugin() = 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> &ddsHandler,
NGL::Settings *settings) override;
};
} // namespace TetraRadio