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

+43
View File
@@ -0,0 +1,43 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Hanna Rathje, SLTE, 2022-03-29
#
SET(SRCS
main.cpp
mainwindow.h
mainwindow.cpp
position_helper.h
position_helper.cpp
settings.h
settings.cpp
simulated_player.h
simulated_player.cpp
worker.h
worker.cpp
)
NGL_WRAP_UI(SRCS mainwindow.ui )
NGL_ADD_EXECUTABLE(TOOLSSV wlsRandomPositions ${SRCS})
NGL_TARGET_LINK_LIBRARIES(wlsRandomPositions
Qt5::Widgets
Qt5::Core
Qt5::Network
LtsCommandLineParser
LtsWidgets
ltsCoordWidget
LtsCoordTrans
LtsUtilsCore
SfmConverter
nglapplication
nglsettings
ngltools
NGLLogger
)
NGL_INSTALL_TARGET(wlsRandomPositions)
NGL_INSTALL(TOOLSSV FILES log4cxx_wrp.props wrp_data.ini DESTINATION bin)
+80
View File
@@ -0,0 +1,80 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# DbAdministration
###########################################################
log4j.logger.MainWindow=DEBUG
log4j.logger.Worker=DEBUG
log4j.logger.PositionHelper=DEBUG
log4j.logger.SimulatedPlayer=DEBUG
# File
###########################################################
log4j.appender.file=Lts::RollingFileAppender
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=9
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
# Appnd_Console
###########################################################
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
# Appnd_Syslog
###########################################################
log4j.appender.syslog=org.apache.log4j.SyslogAppender
log4j.appender.syslog.Threshold=ERROR
log4j.appender.syslog.SysLogHost=localhost
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
###########################################################
###########################################################
###########################################################
# 1) Available Levels in LOG4CXX Version 0.10.0:
# TRACE,
# DEBUG,
# INFO,
# WARN,
# ERROR
# FATAL
#
# d = date/time
# p = priority (Level)
# c = category/channel
# m = message
# F = file
# L = line
# n = platform dependent line separator character or characters.
# ....
#
# Examples for console:
# a)
# %d %p %c #%m# (%.50F:%L)%n
# date/time
# priority
# category/channel
# #message#
# (Maximal 50Character des Filename von rechts:Line)
# line separator
#
# b)
# %d (%.15F:%L) %-5p %c |#| %m%n
# date/time
# (Maximal 15Character des Filename von rechts:Line)
# priority, Right pad with spaces if the priority name is less than 5 characters long.
# category/channel
# message
# line separator
#
# Examples for files:
+31
View File
@@ -0,0 +1,31 @@
#include "mainwindow.h"
#include "settings.h"
#include <nglapplication/nglapplication.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
int main(int argc, char *argv[])
{
NGLApplication app(argc, argv);
LtsCommandLineParser::LtsCommandLineParser options(LtsCommandLineParser::LtsCommandLineParser::ProvideCommandLineParameterOptions::CustomConfigFile);
if (!options.init())
return -1;
app.createLogger("WRP", "log4cxx_wrp.props");
NGL::INGLLogger &logger = app.logger("main");
QCoreApplication::setApplicationName(QLatin1String("WLS Random Position Generator"));
QCoreApplication::setOrganizationName(QLatin1String("RME"));
QString iniFile = options.iniFileSet() ? options.iniFile() : QStringLiteral("wrp_training_areas.ini");
WlsRandomPositions::Settings::setIniFile(iniFile);
WlsRandomPositions::MainWindow w;
w.show();
STARTUP_LOG(logger);
int iRet = app.exec();
SHUTDOWN_LOG(logger);
return iRet;
}
+153
View File
@@ -0,0 +1,153 @@
/*
* @RDE_HEADER@
* MainWindow
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "position_helper.h"
#include "settings.h"
#include "worker.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsCoordTrans/lts_coord_widget.h>
namespace WlsRandomPositions
{
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, m_ui(new Ui::MainWindow)
, m_worker(new Worker(this))
, m_posHelper(nullptr)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("MainWindow"))
{
m_ui->setupUi(this);
const QMap<int, Settings::TrainingArea> trainingAreas = Settings::trainingAreas();
ERROR_LOG(m_logger) << "trainingArea size: " << trainingAreas.size();
for (const auto &item : trainingAreas)
{
DEBUG_LOG(m_logger) << "ta name: " << item.name << ", id: " << item.id;
m_ui->cbTrainingArea->addItem(item.name, QVariant::fromValue(item));
}
connect(m_worker, &Worker::connectionStateChanged, this, &MainWindow::onConnectionStateChanged);
connect(m_worker, &Worker::telegramsIncremented, this, &MainWindow::onTelegramsIncremented);
m_ui->sbAmountPlayers->setValue(Settings::amountPlayers());
m_ui->sbEquipNo->setValue(Settings::firstEquipNo());
m_ui->sbMsecs->setValue(Settings::msecs());
m_ui->sbJitter->setValue(Settings::jitter());
m_ui->leMacAddress->setInputMask(QStringLiteral("HH:HH:HH:HH:HH:HH"));
m_ui->leMacAddress->setText(Settings::firstMacAddress());
m_ui->leServerName->setText(Settings::serverName());
m_ui->sbServerPort->setValue(Settings::serverPort());
m_ui->sbHeightMin->setValue(Settings::heightMin());
m_ui->sbHeightMax->setValue(Settings::heightMax());
m_ui->sbMaxdistance->setValue(Settings::maxDistance());
m_statusLabelConnected = new QLabel(this);
m_statusLabelConnected->setText(tr("Disconnected"));
m_statusLabelSentTelegrams = new QLabel(this);
m_statusLabelSentTelegrams->setText(tr("0 telegrams"));
m_ui->statusbar->addWidget(m_statusLabelConnected, 50);
m_ui->statusbar->addWidget(m_statusLabelSentTelegrams, 100);
connect(m_ui->actionExit, &QAction::triggered, this, &MainWindow::close);
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("Start"));
m_ui->buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &MainWindow::onStartClicked);
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setText(tr("Stop"));
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, &MainWindow::onStopClicked);
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close)->hide();
m_ui->sbMaxdistance->setEnabled(false);
connect(m_ui->cbMaxDistance, &QCheckBox::toggled, m_ui->sbMaxdistance, &LtsWidgets::LtsDoubleSpinBox::setEnabled);
connect(m_ui->cbTrainingArea, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onTrainingAreaChanged);
onTrainingAreaChanged(m_ui->cbTrainingArea->currentIndex());
}
MainWindow::~MainWindow()
{
delete m_ui;
delete m_posHelper;
}
void MainWindow::onTrainingAreaChanged(int index)
{
Settings::TrainingArea ta = m_ui->cbTrainingArea->itemData(index).value<Settings::TrainingArea>();
LtsCoordTrans::UtmCoordinate bottomLeft = LtsCoordTrans::UtmCoordinate::fromMgrs(ta.bottomLeft);
LtsCoordTrans::getMgrsSquares(QRectF(bottomLeft.geographic(0, 0), bottomLeft.geographic(ta.width, ta.height)), true, true);
delete m_ui->peTopLeft;
m_ui->peTopLeft = new LtsCoordWidget::LtsCoordWidget(m_ui->centralwidget);
m_ui->peTopLeft->setObjectName(QString::fromUtf8("peTopLeft"));
m_ui->gridLayout->addWidget(m_ui->peTopLeft, 8, 1, 1, 3);
m_ui->peTopLeft->setCoordinate(bottomLeft.geographic(0, ta.height), true);
delete m_ui->peBottomRight;
m_ui->peBottomRight = new LtsCoordWidget::LtsCoordWidget(m_ui->centralwidget);
m_ui->peBottomRight->setObjectName(QString::fromUtf8("peButtomRight"));
m_ui->gridLayout->addWidget(m_ui->peBottomRight, 9, 1, 1, 3);
m_ui->peBottomRight->setCoordinate(bottomLeft.geographic(ta.width, 0), true);
}
void MainWindow::onStartClicked()
{
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Load)->setDisabled(true);
if (!m_posHelper)
m_posHelper = new PositionHelper(m_ui->peTopLeft->coordinate(), m_ui->peBottomRight->coordinate(), m_ui->sbHeightMin->value(), m_ui->sbHeightMax->value());
else
m_posHelper->set(m_ui->peTopLeft->coordinate(), m_ui->peBottomRight->coordinate(), m_ui->sbHeightMin->value(), m_ui->sbHeightMax->value());
m_worker->connectToServer(m_ui->leServerName->text(), m_ui->sbServerPort->value());
}
void MainWindow::onConnectionStateChanged(bool connected, const QString &status)
{
m_statusLabelConnected->setText(status);
if (!connected)
{
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Load)->setDisabled(false);
return;
}
QString macAddressStr = m_ui->leMacAddress->text();
macAddressStr.remove(QLatin1Char(':'));
bool ok;
qint64 macAddress = macAddressStr.toLongLong(&ok, 16);
DEBUG_LOG(m_logger) << "MacAdress: " << macAddressStr << ", numeric: " << macAddress << ", Okay? " << ok;
double maxDistance = 0;
if (m_ui->cbMaxDistance->isChecked())
maxDistance = m_ui->sbMaxdistance->value();
m_worker->start(m_ui->sbAmountPlayers->value(), m_ui->sbEquipNo->value(), macAddress, m_ui->sbMsecs->value(), m_ui->sbJitter->value(), maxDistance);
}
void MainWindow::onStopClicked()
{
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Load)->setDisabled(false);
m_worker->stop();
}
void MainWindow::onTelegramsIncremented(int sentTelegrams)
{
m_statusLabelSentTelegrams->setText(tr("%1 telegrams sent.").arg(sentTelegrams));
}
} // Namespace WlsRandomPositions}
+56
View File
@@ -0,0 +1,56 @@
/*
* @RDE_HEADER@
* MainWindow
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#pragma once
#include <QMainWindow>
class QLabel;
namespace NGL
{
class INGLLogger;
}
namespace Ui
{
class MainWindow;
}
namespace WlsRandomPositions
{
class PositionHelper;
class Worker;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void onStartClicked();
void onStopClicked();
void onConnectionStateChanged(bool connected, const QString &status);
void onTelegramsIncremented(int sentTelegrams);
void onTrainingAreaChanged(int index);
private:
Ui::MainWindow *m_ui;
QLabel *m_statusLabelConnected;
QLabel *m_statusLabelSentTelegrams;
Worker *m_worker;
PositionHelper *m_posHelper;
NGL::INGLLogger &m_logger;
};
} // Namespace WlsRandomPositions
+311
View File
@@ -0,0 +1,311 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>588</width>
<height>570</height>
</rect>
</property>
<property name="windowTitle">
<string>WLS Random Positions</string>
</property>
<property name="windowIcon">
<iconset resource="../../../TetraIF/LogView/LogViewResources.qrc">
<normaloff>:/image/P2C.png</normaloff>:/image/P2C.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="10" column="2">
<widget class="QLabel" name="lbxHeightMax">
<property name="text">
<string>Altitude Max:</string>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QLabel" name="lbxServerPort">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="lbxBottomRight">
<property name="text">
<string>Bottom Right Coordinate:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbxAmountPlayers">
<property name="text">
<string>Amount Players:</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="lbxTcpServer">
<property name="text">
<string>TCP Server:</string>
</property>
</widget>
</item>
<item row="10" column="3">
<widget class="LtsWidgets::LtsSpinBox" name="sbHeightMax">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>500</number>
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<widget class="LtsWidgets::LtsSpinBox" name="sbEquipNo">
<property name="minimum">
<number>500</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="lbxHeightMin">
<property name="text">
<string>Altitude Min:</string>
</property>
</widget>
</item>
<item row="9" column="1" colspan="3">
<widget class="LtsCoordWidget::LtsCoordWidget" name="peBottomRight"/>
</item>
<item row="6" column="0" colspan="4">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="13" column="3">
<widget class="LtsWidgets::LtsSpinBox" name="sbServerPort">
<property name="minimum">
<number>1025</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="lbxJitter">
<property name="text">
<string>Jitter:</string>
</property>
</widget>
</item>
<item row="7" column="1" colspan="3">
<widget class="QComboBox" name="cbTrainingArea"/>
</item>
<item row="15" column="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lbxFirstMacAddress">
<property name="text">
<string>First Mac Address:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="leServerName"/>
</item>
<item row="3" column="1" colspan="3">
<widget class="QLineEdit" name="leMacAddress"/>
</item>
<item row="8" column="1" colspan="3">
<widget class="LtsCoordWidget::LtsCoordWidget" name="peTopLeft"/>
</item>
<item row="12" column="0" colspan="4">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="LtsWidgets::LtsSpinBox" name="sbJitter">
<property name="maximum">
<number>2000</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbxFirstEquipNo">
<property name="text">
<string>First EquipNo:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="LtsWidgets::LtsSpinBox" name="sbHeightMin">
<property name="minimum">
<number>-10</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lbxTrainingArea">
<property name="text">
<string>Training Area:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="LtsWidgets::LtsSpinBox" name="sbAmountPlayers">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="14" column="0" colspan="4">
<widget class="LtsWidgets::LtsDialogButtonBox" name="buttonBox"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="lbxTopLeft">
<property name="text">
<string>Top Left Coordinate:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lbxMsecs">
<property name="text">
<string>MSecs:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="LtsWidgets::LtsSpinBox" name="sbMsecs">
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item row="4" column="0" colspan="4">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="LtsWidgets::LtsDoubleSpinBox" name="sbMaxdistance">
<property name="maximum">
<double>50.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="cbMaxDistance">
<property name="text">
<string>Max. Distance to old position:</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>588</width>
<height>32</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionExit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
<property name="shortcut">
<string>Ctrl+D</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>LtsCoordWidget::LtsCoordWidget</class>
<extends>QWidget</extends>
<header>LtsCoordTrans/lts_coord_widget.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsDialogButtonBox</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_dialog_button_box.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsSpinBox</class>
<extends>QSpinBox</extends>
<header>LtsWidgets/lts_spinbox.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>LtsWidgets/lts_spinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>sbAmountPlayers</tabstop>
<tabstop>sbEquipNo</tabstop>
<tabstop>leMacAddress</tabstop>
<tabstop>sbMsecs</tabstop>
<tabstop>sbJitter</tabstop>
<tabstop>cbTrainingArea</tabstop>
<tabstop>peTopLeft</tabstop>
<tabstop>peBottomRight</tabstop>
<tabstop>sbHeightMin</tabstop>
<tabstop>sbHeightMax</tabstop>
<tabstop>leServerName</tabstop>
<tabstop>sbServerPort</tabstop>
</tabstops>
<resources>
<include location="../../../TetraIF/LogView/LogViewResources.qrc"/>
</resources>
<connections/>
</ui>
+74
View File
@@ -0,0 +1,74 @@
/*
* @RDE_HEADER@
* Generates a postion for a player
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#include "position_helper.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QLineF>
static QRectF s_area;
static double s_heightMin;
static double s_heightMax;
namespace WlsRandomPositions
{
PositionHelper::PositionHelper(const QPointF &topLeft, const QPointF &bottomRight, double heightMin, double heightMax)
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PositionHelper"))
{
s_area = QRectF(topLeft, bottomRight).normalized();
s_heightMin = heightMin;
s_heightMax = heightMax;
INFO_LOG(m_logger) << "Area initialized: " << LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.topLeft()).mgrs() << "//"
<< LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.bottomRight()).mgrs();
}
void PositionHelper::set(const QPointF &topLeft, const QPointF &bottomRight, double heightMin, double heightMax)
{
s_area = QRectF(topLeft, bottomRight).normalized();
s_heightMin = heightMin;
s_heightMax = heightMax;
INFO_LOG(m_logger) << "New Area initialized: " << LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.topLeft()).mgrs() << "//"
<< LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.bottomRight()).mgrs();
}
QPair<QPointF,double> PositionHelper::randPos()
{
LtsCoordTrans::UtmCoordinate bl = LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.bottomLeft());
LtsCoordTrans::UtmCoordinate tr = LtsCoordTrans::UtmCoordinate::fromGeographic(s_area.topRight());
QPointF distance = bl.relativeTo(tr);
// Multiplying with -1 works for all Degree Squares (northern/southern hemisphere, west/east of Greenwich)
distance.setX((rand() % 100) / 100.0 * distance.x() * -1.0);
distance.setY((rand() % 100) / 100.0 * distance.y() * -1.0);
double z = (rand() % 100) / 100.0 * (s_heightMax - s_heightMin) + s_heightMin;
return {bl.geographic(distance),z};
}
QPair<QPointF,double> PositionHelper::randPos(const QPointF &oldPos, double maxDistance)
{
double z = (rand() % 100) / 100.0 * (s_heightMax - s_heightMin) + s_heightMin;
LtsCoordTrans::UtmCoordinate utm = LtsCoordTrans::UtmCoordinate::fromGeographic(oldPos);
QLineF line;
line.setP1({0,0});
line.setP2({1,0});
do
{
line.setAngle((rand() % 36000) / 100.0);
line.setLength(((rand() % 100) / 100.0) * maxDistance);
} while (!s_area.contains(utm.geographic(line.p2())));
return {utm.geographic(line.p2()),z};
}
} // Namespace WlsRandomPositions
+35
View File
@@ -0,0 +1,35 @@
/*
* @RDE_HEADER@
* Generates a postion for a player
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include <QRectF>
#include <QPair>
/*
* Class only works with Relative Positions!!!!
*/
namespace WlsRandomPositions
{
class PositionHelper
{
public:
PositionHelper(const QPointF &topLeft, const QPointF &bottomRight, double heightMin, double heightMax);
static QPair<QPointF, double> randPos(); // lon/lat, height
static QPair<QPointF, double> randPos(const QPointF &oldPos, double maxDistance); // lon/lat, height
void set(const QPointF &topLeft, const QPointF &bottomRight, double heightMin, double heightMax);
private:
NGL::INGLLogger &m_logger;
};
} // Namespace WlsRandomPositions
+119
View File
@@ -0,0 +1,119 @@
/**
* Settings for WlsRandomPositions
* $Id$
* $HeadURL$
* $Author$
* * Created by Hanna E. Rathje, SLTE, 2022-04-01
*/
#include "settings.h"
#include <QtCore/QSettings>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_filesystem.h>
namespace WlsRandomPositions
{
class NGLSettingsClass : public NGL::Settings
{
public:
NGLSettingsClass()
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
{}
static void setIniFile(const QString &fn)
{
s_iniFile = fn;
}
static QString s_iniFile;
};
QString NGLSettingsClass::s_iniFile;
Q_GLOBAL_STATIC(NGLSettingsClass, s)
//-----------------------------------------------------------------------------
NGL::Settings *Settings::settings()
{
return s();
}
//-----------------------------------------------------------------------------
void Settings::setIniFile(const QString &ini)
{
NGLSettingsClass::setIniFile(ini);
}
//-----------------------------------------------------------------------------
QMap<int,Settings::TrainingArea> Settings::trainingAreas()
{
QSettings *settings = s()->settings();
QMap<int, TrainingArea> map;
settings->beginGroup(QStringLiteral("TrainingAreas"));
{
int size_ta = settings->beginReadArray(QStringLiteral("TrainingArea"));
for (int i = 0; i < size_ta; ++i)
{
settings->setArrayIndex(i);
TrainingArea ta;
ta.id = settings->value(QStringLiteral("id")).toInt();
ta.name = settings->value(QStringLiteral("name")).toString();
ta.bottomLeft = settings->value(QStringLiteral("bottomLeftMgrs")).toString();
ta.width = settings->value(QStringLiteral("width"), 1000).toInt();
ta.height = settings->value(QStringLiteral("height"), 1000).toInt();
map.insert(ta.id, ta);
}
settings->endArray();
}
settings->endGroup();
return map;
}
int Settings::amountPlayers()
{
return s()->settings()->value(QStringLiteral("Global/amountPlayers"), 100).toInt();
}
int Settings::firstEquipNo()
{
return s()->settings()->value(QStringLiteral("Global/firstEquipNo"), 1000).toInt();
}
QString Settings::firstMacAddress()
{
return s()->settings()->value(QStringLiteral("Global/firstMacAddress"), QStringLiteral("01:12:23:34:45:5")).toString();
}
int Settings::msecs()
{
return s()->settings()->value(QStringLiteral("Global/msecs"), 100).toInt();
}
int Settings::jitter()
{
return s()->settings()->value(QStringLiteral("Global/jitter"), 00).toInt();
}
int Settings::heightMin()
{
return s()->settings()->value(QStringLiteral("Global/altitudeMin"), 0).toInt();
}
int Settings::heightMax()
{
return s()->settings()->value(QStringLiteral("Global/altitudeMax"), 10).toInt();
}
double Settings::maxDistance()
{
return s()->settings()->value(QStringLiteral("Global/naxDistance"), 10).toDouble();
}
QString Settings::serverName()
{
return s()->settings()->value(QStringLiteral("Global/serverName"), QStringLiteral("EXCTDS01")).toString();
}
int Settings::serverPort()
{
return s()->settings()->value(QStringLiteral("Global/serverPort"), 12002).toInt();
}
} // namespace WlsRandomPositions
+54
View File
@@ -0,0 +1,54 @@
/**
* Settings for WlsRandomPositions
* $Id$
* $HeadURL$
* $Author$
* * Created by Hanna E. Rathje, SLTE, 2022-04-01
*/
#pragma once
#include <QString>
#include <QObject>
namespace NGL
{
class Settings;
}
namespace WlsRandomPositions
{
namespace Settings
{
NGL::Settings *settings();
void setIniFile(const QString &ini);
struct TrainingArea
{
int id;
QString name;
QString bottomLeft;
int width;
int height;
};
QMap<int, TrainingArea> trainingAreas();
int amountPlayers();
int firstEquipNo();
QString firstMacAddress();
int msecs();
int jitter();
int heightMin();
int heightMax();
double maxDistance();
QString serverName();
int serverPort();
}
} // namespace WlsRandomPositions
// needed for QVariant
Q_DECLARE_METATYPE(WlsRandomPositions::Settings::TrainingArea)
+82
View File
@@ -0,0 +1,82 @@
/*
* @RDE_HEADER@
* Simulate players
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#include "simulated_player.h"
#include "position_helper.h"
#include <WirelessLocationSystem/wls_sfm_message_converter.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsUtils/LtsUtilsCore/sfm_bytemessage_converter.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QTimer>
#include "math.h"
namespace WlsRandomPositions
{
SimulatedPlayer::SimulatedPlayer(int equipNo, qint64 mac, int msecs, int jitter, double maxDistance, QObject *parent)
: QObject(parent)
, m_equipNo(equipNo)
, m_macAddress(toMacString(mac))
, m_msecs(msecs)
, m_jitter(jitter)
, m_maxDistance(maxDistance)
, m_pos({{},0.0})
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(QString::fromLatin1("SimulatedPlayer.%1").arg(QString::number(m_equipNo)).toStdString()))
{
}
void SimulatedPlayer::start()
{
QString eqNoString = QString::number(m_equipNo);
QString initialTelegram = QString::fromLatin1("%1;%2;%3").arg(4).arg(m_macAddress).arg(eqNoString);
INFO_LOG(m_logger) << "initTelegram: " << initialTelegram;
WirelessLocationSystem::SfmMsgEquipmentId msg;
msg.setEquipmentNumber(m_equipNo);
QByteArray ba = WirelessLocationSystem::SfmMessageConverter::generateTxMessage(msg);
emit sendInitTelegram(m_macAddress, ba);
QTimer::singleShot(m_msecs + (((rand() % 200) - 100) / 100) * m_jitter, this, &SimulatedPlayer::onTimerTimeout);
}
void SimulatedPlayer::onTimerTimeout()
{
QPair<QPointF,double> pos;
if (qFuzzyIsNull(m_maxDistance) || m_pos.first.isNull())
pos = PositionHelper::randPos();
else
pos = PositionHelper::randPos(m_pos.first, m_maxDistance);
DEBUG_LOG(m_logger) << "posTelegram: x: " << pos.first.x() << ", y: " << pos.first.y() << ", z: " << pos.second;
DEBUG_LOG(m_logger) << "MGRS: " << LtsCoordTrans::UtmCoordinate::fromGeographic(pos.first).mgrs(5, true);
emit sendPositionTelegram(m_macAddress, pos.first, pos.second);
m_pos = pos;
QTimer::singleShot(m_msecs + (((rand() % 200) - 100) / 100) * m_jitter, this, &SimulatedPlayer::onTimerTimeout);
}
QString SimulatedPlayer::toMacString(qint64 mac)
{
QString macString = QString::number(mac, 16);
macString = macString.prepend(QString(12 - macString.length(), QLatin1Char('0')));
macString.insert(10, QLatin1Char(':'));
macString.insert( 8, QLatin1Char(':'));
macString.insert( 6, QLatin1Char(':'));
macString.insert( 4, QLatin1Char(':'));
macString.insert( 2, QLatin1Char(':'));
return macString;
}
} // Namespace WlsRandomPositions
+45
View File
@@ -0,0 +1,45 @@
/*
* @RDE_HEADER@
* Simulate players
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include <QObject>
#include <QPointF>
namespace WlsRandomPositions
{
class SimulatedPlayer : public QObject
{
Q_OBJECT
public:
SimulatedPlayer(int equipNo, qint64 mac, int msecs, int jitter = 0, double maxDistance = 0.0, QObject *parent = nullptr);
void start();
signals:
void sendInitTelegram(const QString &macAddress, const QByteArray &msg);
void sendPositionTelegram(const QString &macAddress, QPointF pos, double height);
private slots:
void onTimerTimeout();
private:
static QString toMacString(qint64 mac);
int m_equipNo;
QString m_macAddress;
int m_msecs;
int m_jitter;
double m_maxDistance;
QPair<QPointF,double> m_pos;
NGL::INGLLogger &m_logger;
};
} // Namespace WlsRandomPositions
+181
View File
@@ -0,0 +1,181 @@
/*
* @RDE_HEADER@
* Sending of telegrams to websocket
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#include "worker.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QDateTime>
#include <QPointF>
namespace WlsRandomPositions
{
static inline QByteArray escapeData(const QByteArray &bufferData)
{
QByteArray ret;
ret.reserve(bufferData.size() * 6 / 5);
for (const unsigned char c : bufferData)
{
if (c >= 0x20 && c < 0x7f)
ret += c;
else
ret += "\\x" + QByteArray::number(static_cast<unsigned char>(c), 16);
}
return ret;
}
Worker::Worker(QObject *parent)
: QObject(parent)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Worker"))
{
m_tcpClient = new QTcpSocket(this);
connect(m_tcpClient, &QTcpSocket::connected, this, &Worker::onTcpConnected);
connect(m_tcpClient, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &Worker::error);
connect(m_tcpClient, &QTcpSocket::disconnected, this, &Worker::onTcpDisconnected);
}
Worker::~Worker()
{
delete m_tcpClient;
}
void Worker::connectToServer(const QString &serverName, int serverPort)
{
m_server = serverName;
m_serverPort = serverPort;
m_tcpClient->connectToHost(m_server, m_serverPort);
}
void Worker::onTcpConnected()
{
INFO_LOG(m_logger) << "Connected to " << m_server << ", Port: " << m_serverPort;
QString status = tr("Connected to %1, Port: %2").arg(m_server).arg(m_serverPort);
emit connectionStateChanged(true, status);
}
void Worker::onTcpDisconnected()
{
INFO_LOG(m_logger) << "Disconnected";
QString status = tr("Disconnected");
emit connectionStateChanged(false, status);
}
void Worker::error()
{
ERROR_LOG(m_logger) << "SocketError " << m_tcpClient->errorString();
emit connectionStateChanged(false, m_tcpClient->errorString());
}
void Worker::start(int numberParticipants, int firstEquipNo, qint64 firstMacAddress, int mSecs, int jitter, double maxDistance)
{
m_sentTelegrams = 0;
int equipNo = firstEquipNo;
qint64 mac = firstMacAddress;
for (int i=0; i<numberParticipants; ++i)
{
DEBUG_LOG(m_logger) << "SimulatedPlayer: equipNo: " << equipNo << ", macAddress: " << mac;
SimulatedPlayer *sp = new SimulatedPlayer(equipNo++, mac++, mSecs, jitter, maxDistance, this);
connect(sp, &SimulatedPlayer::sendInitTelegram, this, &Worker::onInit);
connect(sp, &SimulatedPlayer::sendPositionTelegram, this, &Worker::onPosition);
m_players << sp;
sp->start();
}
INFO_LOG(m_logger) << numberParticipants << " Players started";
}
void Worker::onInit(const QString &macAddress, const QByteArray &content)
{
QDateTime dt = QDateTime::currentDateTime();
QByteArray data;
data.clear();
data.append(0x7F); // Startkennung
data.append(QByteArray::number(3)); //
data.append(';'); // Trennzeichen
data.append(dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz")).toLatin1()); // Aktuelle Zeit
data.append(';'); // Trennzeichen
data.append(macAddress.toUtf8()); // Tag-ID
data.append(';'); // Trennzeichen
data.append(content); // ba < 80 Zeichen!
data.append(0x8F); // Endekennung
qint64 ret = m_tcpClient->write(data);
if (ret < 0)
{
ERROR_LOG(m_logger) << "Could not send init data for macAddress " << macAddress;
}
else
{
DEBUG_LOG(m_logger) << "Sending telegram to wls: " << escapeData(data);
m_tcpClient->flush();
emit telegramsIncremented(++m_sentTelegrams);
}
}
void Worker::onPosition(const QString &macAddress, QPointF pos, double height)
{
QString mgrs = LtsCoordTrans::mgrsFromGeographic(pos.x(), pos.y(), 7, false);
QString value = mgrs.right(14);
QString x = value.left(7);
QString y = value.right(7);
QString z = QString::number(height);
QDateTime dt = QDateTime::currentDateTime();
QByteArray data;
data.clear();
data.append(0x7F); // Startkennung
data.append(QByteArray::number(1)); //
data.append(';'); // Trennzeichen
data.append(dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz")).toLatin1()); // Aktuelle Zeit
data.append(';'); // Trennzeichen
data.append(macAddress.toUtf8()); // Tag-ID
data.append(';'); // Trennzeichen
data.append(x.toUtf8());
data.append(';'); // Trennzeichen
data.append(y.toUtf8());
data.append(';'); // Trennzeichen
data.append(z.toUtf8());
data.append(";1;0;0;-1;-1");
data.append(0x8F); // Endekennung
qint64 ret = m_tcpClient->write(data);
if (ret < 0)
{
ERROR_LOG(m_logger) << "Could not send pos data for macAddress " << macAddress;
}
else
{
DEBUG_LOG(m_logger) << "Sending telegram to wls: " << escapeData(data);
m_tcpClient->flush();
emit telegramsIncremented(++m_sentTelegrams);
}
}
void Worker::stop()
{
INFO_LOG(m_logger) << "stop worker";
for (SimulatedPlayer* sp : m_players)
sp->deleteLater();
m_players.clear();
m_tcpClient->close();
}
} // Namespace WlsRandomPositions
+52
View File
@@ -0,0 +1,52 @@
/*
* @RDE_HEADER@
* Sending of telegrams to websocket
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLTE, 2022-03-29
*/
#pragma once
#include "simulated_player.h"
#include <NGLLogger/INGLLogger.h>
#include <QTcpSocket>
namespace WlsRandomPositions
{
class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = nullptr);
~Worker();
void connectToServer(const QString &serverName, int serverPort);
void start(int numberParticipants, int firstEquipNo, qint64 firstMacAddress, int mSecs, int jitter, double maxDistance);
void stop();
void error();
signals:
void telegramsIncremented(int sentTelegrams);
void connectionStateChanged(bool connected, QString status);
private slots:
void onInit(const QString &macAddress, const QByteArray &content);
void onPosition(const QString &macAddress, QPointF pos, double height);
void onTcpConnected();
void onTcpDisconnected();
private:
QVector<SimulatedPlayer*> m_players;
QTcpSocket *m_tcpClient;
QString m_server;
int m_serverPort;
int m_sentTelegrams;
NGL::INGLLogger &m_logger;
};
} // Namespace WlsRandomPositions
+40
View File
@@ -0,0 +1,40 @@
[Global]
amountPlayers=10
firstEquipNo=500
firstMacAddress=01:12:23:34:45:56
msecs=100
jitter=10
altitudeMin=0
altitudeMax=10
maxDistance=10.0
serverName=EXCTDS01
serverPort=12002
[TrainingAreas]
TrainingArea/1/id=1
TrainingArea/1/name=Alhamra
TrainingArea/1/bottomLeftMgrs=39QXG1000000000
TrainingArea/1/width=80000
TrainingArea/1/height=70000
TrainingArea/2/id=6
TrainingArea/2/name=Bremen
TrainingArea/2/bottomLeftMgrs=32UMD0000000000
TrainingArea/2/width=12800
TrainingArea/2/height=12800
TrainingArea/3/id=3
TrainingArea/3/name=Bremen 2
TrainingArea/3/bottomLeftMgrs=32UMD8000080000
TrainingArea/3/width=100
TrainingArea/3/height=100
TrainingArea/4/id=4
TrainingArea/4/name=Rio
TrainingArea/4/bottomLeftMgrs=23KPP5000060000
TrainingArea/4/width=100
TrainingArea/4/height=100
TrainingArea/size=4