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

+68
View File
@@ -0,0 +1,68 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(xml_FILE dgps_service.xml)
SET(if_SRCS
tcpsocket.cpp
tcpsocket.h
tetra_if.cpp
tetra_if.h
)
NGL_ADD_LIBRARY(AAR SV Tetra_Interface ${if_SRCS})
NGL_TARGET_LINK_LIBRARIES(Tetra_Interface
Qt5::Core
Qt5::Network
CoPrtCnv
NGLLogger
)
SET(dgps_SRCS
main.cpp
dds_handler.cpp
dds_handler.h
dgps_config.cpp
dgps_config.h
logger.cpp
logger.h
mainthread.cpp
mainthread.h
tetra_if_impl.cpp
tetra_if_impl.h
trimble_if.cpp
trimble_if.h
log4cxx_dgps.props
${xml_FILE}
)
# make sure xml file is properly installed
CODEGEN_HANDLE_SVC_XML(dgps_SRCS ${xml_FILE})
NGL_ADD_SVC_ICON(dgps_SRCS)
NGL_ADD_EXECUTABLE(AAR SV svcDifferentialGPS ${dgps_SRCS})
NGL_TARGET_LINK_LIBRARIES(svcDifferentialGPS
ddsconnector
svcCoreClient
Tetra_Interface
Qt5::Core
Qt5::Network
CoPrtCnv
LtsCommandLineParser
NGLLogger
nglcoreapplication
)
NGL_INSTALL_TARGET(svcDifferentialGPS)
NGL_INSTALL(AAR SV FILES log4cxx_dgps.props DESTINATION bin)
NGL_INSTALL(AAR SV FILES dgps.ini DESTINATION bin RENAME dgps.ini.distrib)
#
# Tetra_dgps_simulator
#
NGL_ADD_EXECUTABLE(AAR SV Tetra_dgps_simulator Simulator/main_sim.cpp Simulator/main_sim.h)
NGL_TARGET_LINK_LIBRARIES(Tetra_dgps_simulator
Qt5::Core
Qt5::Network
)
+124
View File
@@ -0,0 +1,124 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include <QCoreApplication>
#include <QStringList>
#include <QTcpSocket>
#include <QTimer>
#include <QDebug>
#include "main_sim.h"
//
// PayloadSender
//
PayloadSender::PayloadSender(int numByte, int ctrFail, QTcpSocket *s, QObject *parent)
: QObject(parent)
, m_socket(s)
, m_timer(new QTimer(this))
, m_char('1')
, m_numByte(numByte)
, m_ctrFail(ctrFail)
{
m_timer->setInterval(10 * 1000); // 10s
m_timer->setSingleShot(false);
m_timer->start();
connect(m_timer, &QTimer::timeout,
this, &PayloadSender::onTimeout);
}
PayloadSender::~PayloadSender()
{
if (m_socket->state() != QAbstractSocket::UnconnectedState)
{
m_socket->disconnectFromHost();
m_socket->waitForDisconnected(2000);
}
delete m_socket;
delete m_timer;
}
void PayloadSender::onTimeout()
{
static int ctrFail = 0;
ctrFail++;
bool failure = ((ctrFail >= m_ctrFail) && (ctrFail <= (m_ctrFail + 2)));
if (!failure)
{
qDebug() << "Sending data to socket " << m_socket << " content: 256 * 0x" << QString::number(m_char, 16);
QByteArray ba(m_numByte, m_char++);
m_socket->write(ba);
}
else
qDebug() << " +++ Failure: Sending data ";
}
//
// TcpTestServer
//
TcpTestServer::TcpTestServer(int numByte, int ctrFail, QObject *parent)
: QTcpServer(parent)
, m_numByte(numByte)
, m_ctrFail(ctrFail)
{
connect(this, &TcpTestServer::newConnection,
this, &TcpTestServer::onNewIncomingConnection);
}
TcpTestServer::~TcpTestServer()
{
qDeleteAll(m_openConnections);
}
void TcpTestServer::onNewIncomingConnection()
{
QTcpSocket *newSocket = nextPendingConnection();
if (!newSocket)
return;
PayloadSender *ps = new PayloadSender(m_numByte, m_ctrFail, newSocket, this);
connect(newSocket, &QTcpSocket::disconnected,
ps, &PayloadSender::deleteLater);
qDebug() << "Created new payload sender" << ps << "for socket " << newSocket;
m_openConnections += ps;
connect(ps, &PayloadSender::destroyed,
this, &TcpTestServer::onPayloadSenderDestroyed);
}
void TcpTestServer::onPayloadSenderDestroyed(QObject *obj)
{
qDebug() << "Payload sender " << obj << "destroyed";
m_openConnections -= obj;
}
//
// main
//
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
unsigned short port = 1234;
int numByte = 40;
int ctrFail = -10;
if (app.arguments().size() > 1) port = app.arguments().at(1).toInt();
if (app.arguments().size() > 2) numByte = app.arguments().at(2).toInt();
if (app.arguments().size() > 3) ctrFail = app.arguments().at(3).toInt();
TcpTestServer *srv = new TcpTestServer(numByte, ctrFail);
if (!srv->listen(QHostAddress::Any, port))
return 1;
int ret = app.exec();
delete srv;
return ret;
}
+43
View File
@@ -0,0 +1,43 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QTcpServer>
class QTimer;
class PayloadSender : public QObject
{
Q_OBJECT
public:
PayloadSender(int numByte, int ctrFail, QTcpSocket *s, QObject *parent = nullptr);
~PayloadSender();
private Q_SLOTS:
void onTimeout();
private:
QTcpSocket *m_socket;
QTimer *m_timer;
char m_char;
int m_numByte;
int m_ctrFail;
};
class TcpTestServer : public QTcpServer
{
Q_OBJECT
public:
TcpTestServer(int numByte, int ctrFail, QObject *parent = nullptr);
~TcpTestServer();
private Q_SLOTS:
void onNewIncomingConnection();
void onPayloadSenderDestroyed(QObject *obj);
private:
QSet<QObject *> m_openConnections;
int m_numByte;
int m_ctrFail;
};
+45
View File
@@ -0,0 +1,45 @@
/**
* DdsHandler for VideoOverlayManagement
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-07-06
*/
#include "dds_handler.h"
#include <DDS/Core/pacemaker.h>
namespace DifferentialGPS
{
DdsHandler::DdsHandler(int domainId)
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(domainId, IDL::PartitionType::Global))
, m_logger(getLogger("DdsHandler"))
{
DEBUG_LOG(m_logger) << "DdsHandler(" << domainId << ") for partition: " << m_ddsConnector->getDefaultPartition();
} // end of ctor()
//-----------------------------------------------------------------------------
bool DdsHandler::init(const QStringList &qosFileList)
{
INFO_LOG(m_logger) << "--- Start DifferentialGPS DDSHandler.";
if (!m_ddsConnector->init(qosFileList))
{
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
return false;
}
// default initialize Publisher only
m_ddsConnector->initPublisher();
// Pacemaker
m_pacemaker = std::make_shared<Core::Pacemaker>(m_ddsConnector);
return true;
} // end of init()
//-----------------------------------------------------------------------------
} // Namespace DifferentialGPS
+44
View File
@@ -0,0 +1,44 @@
/**
* DdsHandler for VideoOverlayManagement
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-07-06
*/
#pragma once
#include <DDS/DDSConnector/dds_connector.h>
#include "logger.h"
namespace Core
{
class Pacemaker;
}
namespace DifferentialGPS
{
class DdsHandler final
{
public:
explicit DdsHandler(int domainId);
~DdsHandler() = default;
bool init(const QStringList &qosFileList = QStringList());
std::shared_ptr<Core::Pacemaker> pacemaker() const
{
return m_pacemaker;
}
std::shared_ptr<DDSConnector::DdsConnector> dds() const
{
return m_ddsConnector;
}
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<Core::Pacemaker> m_pacemaker;
NGL::INGLLogger &m_logger;
};
} // namespace DifferentialGPS
+26
View File
@@ -0,0 +1,26 @@
[Trimble]
RxCycle_ms=10000
[Trimble0]
IP= fuer TESTS!!! Benutzung von: localHost 192.168.133.81
Port=1234
[Trimble1]
IP= fuer TESTS!!! Benutzung von: localHost 192.168.133.81
Port=1235
[Tetra]
FeedbackTimeout_ms = 100
[Tetra0]
IP=192.168.133.81
Port=52010
ISSI=9989
ISSIBroadcast=5014
[Tetra1]
IP=192.168.133.81
Port=52011
ISSI=9989
ISSIBroadcast=5014
+52
View File
@@ -0,0 +1,52 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include <QSettings>
#include <QFileInfo>
#include <QCoreApplication>
#include "dgps_config.h"
using namespace DifferentialGPS;
DgpsConfig::DgpsConfig()
{
}
DgpsConfig &DgpsConfig::instance()
{
static DgpsConfig instance;
return instance;
}
void DgpsConfig::readIniData(QString iniFileName)
{
QFileInfo fi(iniFileName);
if (!fi.isAbsolute())
iniFileName = QCoreApplication::applicationDirPath() + QLatin1Char('/') + iniFileName;
// Reading of configuration data from "dgps.ini" file
QSettings iniData(iniFileName, QSettings::IniFormat);
m_trimbleConfig.rxCycle_ms = iniData.value(QLatin1String("Trimble/RxCycle_ms"), 0).toInt();
m_trimbleConfig.ip[0] = iniData.value(QLatin1String("Trimble0/IP"), QString()).toString();
m_trimbleConfig.port[0] = iniData.value(QLatin1String("Trimble0/Port"), 11).toInt();
m_trimbleConfig.ip[1] = iniData.value(QLatin1String("Trimble1/IP")).toString();
m_trimbleConfig.port[1] = iniData.value(QLatin1String("Trimble1/Port"), 11).toInt();
m_tetraConfig.feedbackTimeout_ms = iniData.value(QLatin1String("Tetra/FeedbackTimeout_ms"), 0).toInt();
m_tetraConfig.ip[0] = iniData.value(QLatin1String("Tetra0/IP"), QString()).toString();
m_tetraConfig.port[0] = iniData.value(QLatin1String("Tetra0/Port"), 0).toInt();
m_tetraConfig.issi[0] = iniData.value(QLatin1String("Tetra0/ISSI"), 11).toInt();
m_tetraConfig.broadcastIssi[0] = iniData.value(QLatin1String("Tetra0/ISSIBroadcast"), 5000).toInt();
m_tetraConfig.ip[1] = iniData.value(QLatin1String("Tetra1/IP"), QString()).toString();
m_tetraConfig.port[1] = iniData.value(QLatin1String("Tetra1/Port"), 0).toInt();
m_tetraConfig.issi[1] = iniData.value(QLatin1String("Tetra1/ISSI"), 11).toInt();
m_tetraConfig.broadcastIssi[1] = iniData.value(QLatin1String("Tetra1/ISSIBroadcast"), 5000).toInt();
}
+52
View File
@@ -0,0 +1,52 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
namespace DifferentialGPS
{
class DgpsConfig
{
private:
DgpsConfig();
public:
DgpsConfig(DgpsConfig &) = delete;
static DgpsConfig &instance();
void readIniData(QString iniFileName = QLatin1String("dgps.ini"));
struct TrimbleConfig_t
{
int rxCycle_ms = 0;
QString ip[2];
quint16 port[2] = {};
};
const TrimbleConfig_t &getTrimbleConfig() const { return m_trimbleConfig; }
struct TetraConfig_t
{
int feedbackTimeout_ms = 0;
QString ip[2];
quint16 port[2] = {};
int issi[2] = {};
int broadcastIssi[2] = {};
};
const TetraConfig_t &getTetraConfig() const { return m_tetraConfig; }
private:
TrimbleConfig_t m_trimbleConfig;
TetraConfig_t m_tetraConfig;
};
} // namespace DifferentialGPS
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<service namespace="DifferentialGPS" procNames="DifferentialGPS" abbreviation="DGPS" exerciseDependency="Global" groups="Core">
<rcs>
<Id Id="$Id$"/>
<HeadURL HeadURL="$HeadURL$"/>
<Author Author="$Author$"/>
</rcs>
<tables/>
<dbServiceStructs/>
<topicTypes/>
<functionTopics/>
<enumerations/>
</service>
+76
View File
@@ -0,0 +1,76 @@
log4j.reset=true
log4j.rootLogger=WARN, file
#log4j.logger.DGPS=DEBUG
#log4j.logger.DGPS.Main=DEBUG
#log4j.logger.DGPS.TetraIF=DEBUG
#log4j.logger.DGPS.TrimbleIF=ERROR
###########################################################
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:
+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace DifferentialGPS
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "DGPS.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace DifferentialGPS
+22
View File
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for Buildings
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace DifferentialGPS
{
using LOGGER_T = NGL::INGLLogger &;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace DifferentialGPS
+43
View File
@@ -0,0 +1,43 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include <nglapplication/nglcoreapplication.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include <QNetworkProxy>
#include "logger.h"
#include "mainthread.h"
#include "dgps_config.h"
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
QNetworkProxy::setApplicationProxy(QNetworkProxy());
int iRet = -1;
LtsCommandLineParser::LtsCommandLineParser options;
if (!options.init())
return iRet;
app.createLogger("DGPS", options.exerciseId());
// Reading of configuration data from "dgps.ini" file
QString iniFileName(options.iniFile());
if (iniFileName.isEmpty())
DifferentialGPS::DgpsConfig::instance().readIniData();
else
DifferentialGPS::DgpsConfig::instance().readIniData(iniFileName);
{
std::unique_ptr<DifferentialGPS::MainThread> mainThread(new DifferentialGPS::MainThread);
if (mainThread->init(options.domainId()))
{
STARTUP_LOG(app.baseLogger());
iRet = app.exec();
SHUTDOWN_LOG(app.baseLogger());
}
}
return iRet;
}
+127
View File
@@ -0,0 +1,127 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "mainthread.h"
#include "tetra_if_impl.h"
#include "trimble_if.h"
#include <QMutexLocker>
#include <QTimer>
#include <DDS/Core/pacemaker.h>
namespace DifferentialGPS
{
MainThread::MainThread(QObject *parent)
: QObject(parent)
, m_ddsHandler(nullptr)
, m_dgpsTimer(new QTimer(this))
, m_tetraIfNum(0)
, m_trimbleIfNum(0)
, m_logger(getLogger("MainThread"))
, m_broadcastTime(QTime::currentTime())
, m_broadcastCycle_ms(10000)
{
m_tetraIF[0] = new TetraImpl;
m_tetraIF[1] = new TetraImpl;
m_trimbleIF[0] = new TrimbleIF;
m_trimbleIF[1] = new TrimbleIF;
connect(this, &MainThread::newDataAvailable,
m_tetraIF[m_tetraIfNum], &TetraImpl::onNewDataAvailable,
Qt::QueuedConnection);
}
MainThread::~MainThread()
{
m_ddsHandler = nullptr;
m_tetraIF[0]->quit();
m_tetraIF[1]->quit();
m_trimbleIF[0]->quit();
m_trimbleIF[1]->quit();
m_tetraIF[0]->wait();
m_tetraIF[1]->wait();
m_trimbleIF[0]->wait();
m_trimbleIF[1]->wait();
delete m_tetraIF[0];
delete m_tetraIF[1];
delete m_trimbleIF[0];
delete m_trimbleIF[1];
}
bool MainThread::init(int domainId)
{
m_ddsHandler.reset(new DdsHandler(domainId));
if (!m_ddsHandler->init())
{
ERROR_LOG(m_logger) << "Initialisation DdsHandler failed.";
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError);
return false;
}
m_trimbleIF[0]->startThread(0, this);
m_trimbleIF[1]->startThread(1, this);
m_tetraIF[m_tetraIfNum]->startThread(m_tetraIfNum, this);
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::Running);
return true;
}
void MainThread::addNewData(const QByteArray &ba, int trimbleIfNum)
{
const int cycle_ms = m_broadcastCycle_ms + (m_broadcastCycle_ms / 5); // Zykluszeit + 20%
QTime currentTime = QTime::currentTime();
bool overtake = (trimbleIfNum == m_trimbleIfNum);
if (!overtake)
{
if (m_broadcastTime.msecsTo(currentTime) > cycle_ms)
{
overtake = true;
m_trimbleIfNum = trimbleIfNum; // Lese ab jetzt bevorzugt von diesem IF
}
}
if (overtake)
{
QMutexLocker l(&m_mutex);
m_dgpsData = ba;
if (m_tetraIF[m_tetraIfNum]->isRunning())
emit newDataAvailable();
else
{
disconnect(this, &MainThread::newDataAvailable,
m_tetraIF[m_tetraIfNum], &TetraImpl::onNewDataAvailable);
m_tetraIfNum = (m_tetraIfNum + 1) % 2;
connect(this, &MainThread::newDataAvailable,
m_tetraIF[m_tetraIfNum], &TetraImpl::onNewDataAvailable,
Qt::QueuedConnection);
m_tetraIF[m_tetraIfNum]->startThread(m_tetraIfNum, this);
}
m_broadcastTime = currentTime; // Die Broadcast-Zeit merken
}
}
bool MainThread::getNewData(QByteArray &ba)
{
QMutexLocker l(&m_mutex);
if (!m_dgpsData.size())
return false;
ba = m_dgpsData;
return true;
}
} // namespace DifferentialGPS
+51
View File
@@ -0,0 +1,51 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QObject>
#include <QtCore/QMutex>
#include <QtCore/QTime>
#include <QtNetwork/QHostAddress>
#include "logger.h"
#include "dds_handler.h"
class QTimer;
namespace DifferentialGPS
{
class TetraImpl;
class TrimbleIF;
class MainThread final : public QObject
{
Q_OBJECT
public:
explicit MainThread(QObject *parent = nullptr);
~MainThread();
bool init(int domainId);
void addNewData(const QByteArray &ba, int trimbleIfNum);
bool getNewData(QByteArray &ba);
Q_SIGNALS:
void newDataAvailable();
protected:
std::shared_ptr<DdsHandler> m_ddsHandler;
QByteArray m_dgpsData;
QTimer *m_dgpsTimer;
QMutex m_mutex;
TetraImpl *m_tetraIF[2];
int m_tetraIfNum; // Nummer des Tetra IF-es, an das Daten gesendet werden.
TrimbleIF *m_trimbleIF[2];
int m_trimbleIfNum; // Nummer des Trimble IF-es, von dem Daten erwartet werden.
NGL::INGLLogger &m_logger;
QTime m_broadcastTime;
int m_broadcastCycle_ms;
};
} // namespace DifferentialGPS
+118
View File
@@ -0,0 +1,118 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "tcpsocket.h"
#include <QTcpSocket>
#include <QHostAddress>
#include <QTimer>
namespace DifferentialGPS
{
TcpSocket::TcpSocket(const char *logName)
: QThread()
, m_socket(nullptr)
, m_logger(getLogger(logName))
, m_waitTime(1)
, m_reconnectTimer(nullptr)
{
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
moveToThread(this);
}
TcpSocket::~TcpSocket()
{
cleanupObject(); // just to be sure
}
void TcpSocket::startThreadInternal(const QString &hostName, quint16 port)
{
m_hostName = hostName;
m_hostPort = port;
start();
}
void TcpSocket::run()
{
DEBUG_LOG(m_logger) << "Starting thread";
m_reconnectTimer = new QTimer(this);
doConnect();
exec();
cleanupObject();
}
void TcpSocket::doConnect()
{
if (m_socket)
m_socket->deleteLater();;
m_socket = new QTcpSocket(this);
connect(m_socket, &QTcpSocket::connected,
this, &TcpSocket::onConnected);
connect(m_socket, &QTcpSocket::disconnected,
this, &TcpSocket::onDisconnected);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
this, &TcpSocket::onError);
connect(m_socket, &QTcpSocket::readyRead,
this, &TcpSocket::onReadyRead);
INFO_LOG(m_logger) << "Connecting to tcp server at "
<< m_hostName << ":" << m_hostPort;
m_socket->connectToHost(m_hostName, m_hostPort);
}
void TcpSocket::onConnected()
{
INFO_LOG(m_logger) << "Connected to "
<< m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
m_waitTime = 1;
}
void TcpSocket::onDisconnected()
{
INFO_LOG(m_logger) << "Disconnected from " << m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
}
void TcpSocket::onError(QAbstractSocket::SocketError err)
{
ERROR_LOG(m_logger) << "Socket error: " << err
<< " " << m_socket->errorString()
<< ":" << m_socket->peerPort()
<< " - trying to reconnect in " << m_waitTime << " seconds";
m_socket->disconnectFromHost();
if (m_socket->state() != QAbstractSocket::UnconnectedState)
m_socket->waitForDisconnected();
m_waitTime += 2;
if (!m_reconnectTimer->isActive())
m_reconnectTimer->start(m_waitTime * 1000);
if (m_waitTime > 120)
m_waitTime = 120;
}
void TcpSocket::cleanupObject()
{
if (m_reconnectTimer)
{
m_reconnectTimer->disconnect(this);
delete m_reconnectTimer;
m_reconnectTimer = nullptr;
}
if (m_socket)
{
m_socket->disconnect(this);
m_socket->close();
if (m_socket->state() != QAbstractSocket::UnconnectedState)
m_socket->waitForDisconnected();
delete m_socket;
m_socket = nullptr;
}
}
} // namespace DifferentialGPS
+47
View File
@@ -0,0 +1,47 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtNetwork/QAbstractSocket>
#include <QtCore/QThread>
#include "logger.h"
class QTcpSocket;
class QTimer;
namespace DifferentialGPS
{
class TcpSocket : public QThread
{
Q_OBJECT
public:
TcpSocket(const char *logName);
~TcpSocket();
protected:
void startThreadInternal(const QString &hostName, quint16 port);
void run() override;
void doConnect();
void cleanupObject();
protected Q_SLOTS:
virtual void onConnected();
virtual void onDisconnected();
virtual void onError(QAbstractSocket::SocketError);
virtual void onReadyRead() = 0;
protected:
QString m_hostName;
quint16 m_hostPort;
QTcpSocket *m_socket;
NGL::INGLLogger &m_logger;
private:
qint32 m_waitTime;
QTimer *m_reconnectTimer;
};
} // namespace DifferentialGPS
+248
View File
@@ -0,0 +1,248 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "tetra_if.h"
#include "dgps_config.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QTcpSocket>
#include <QHostAddress>
#include <QNetworkInterface>
#include <QTimer>
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <CoPrtCnv/CoPrtCnvTelegramConverter.hpp>
#include <CoPrtCnv/CoPrtCnvHexDumpHelper.hpp>
namespace DifferentialGPS
{
void TetraIF::startThreadInternal(int threadIndex)
{
const DgpsConfig::TetraConfig_t &cfg = DgpsConfig::instance().getTetraConfig();
m_srcIssi = cfg.issi[threadIndex];
m_broadcastIssi = cfg.broadcastIssi[threadIndex];
m_feedbackTimeout_ms = cfg.feedbackTimeout_ms;
TcpSocket::startThreadInternal(cfg.ip[threadIndex], cfg.port[threadIndex]);
}
void TetraIF::run()
{
m_feedbackTimeout = new QTimer(this);
m_feedbackTimeout->setSingleShot(true);
connect(m_feedbackTimeout, &QTimer::timeout,
this, &TetraIF::onFeedbackTimeout);
TcpSocket::run();
m_feedbackTimeout->disconnect(this);
delete m_feedbackTimeout;
m_feedbackTimeout = nullptr;
}
void TetraIF::onNewDataAvailable()
{
if (m_socket->state() != QAbstractSocket::ConnectedState)
{
DEBUG_LOG(m_logger) << "Can not send new data to Tetra - not yet connected ("
<< m_socket->state() << ")";
return;
}
if (!m_bTetraOk)
{
DEBUG_LOG(m_logger) << "Can not send new data to Tetra - not yet logged in";
return;
}
if (onNewDataAvailableInternal())
{
// feedback expected; start feedback timeout timer
m_feedbackTimeout->start(m_feedbackTimeout_ms);
}
}
void TetraIF::onFeedbackTimeout()
{
ERROR_LOG(m_logger) << "Tetra feedback timeout"
<< m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
m_socket->disconnectFromHost();
if (m_socket->state() != QAbstractSocket::UnconnectedState)
m_socket->waitForDisconnected();
exit(3);
}
bool TetraIF::checkTetraConnecting()
{
return m_bTetraOk;
}
void TetraIF::doInitialLogin()
{
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_srcIssi);
m_socket->write(tele.data());
m_socket->flush();
}
void TetraIF::onConnected()
{
TcpSocket::onConnected();
m_counter = 1;
doInitialLogin();
}
void TetraIF::onDisconnected()
{
INFO_LOG(m_logger) << "Disconnected from " << m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
exit(3); // stop the thread
}
void TetraIF::onReadyRead()
{
do
{
DEBUG_LOG(m_logger) << "Reading " << m_socket->bytesAvailable()
<< " from " << m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
// read the 4-byte frame-header for find out the length of whole telegram
N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header;
if (m_socket->bytesAvailable() < (int)sizeof(header))
return;
m_socket->peek((char *)&header, sizeof(header));
if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber)
{
ERROR_LOG(m_logger) << "Incorrect magic number (0x"
<< (int)header.m_MagicNumber
<< " - aborting";
exit(2);
}
if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length))
{
ERROR_LOG(m_logger) << "Radio-Telegram length to big: "
<< header.m_Length
<< ", but I proceed with this telegram.";
}
quint16 dataSize = header.m_Length + sizeof(header);
if (m_socket->bytesAvailable() < dataSize)
{
INFO_LOG(m_logger) << "not enough bytes available";
return;
}
uint8_t *data = new uint8_t[dataSize];
m_socket->read((char *)data, dataSize);
handleReceivedTelegram(data, dataSize);
}
while (m_socket->bytesAvailable());
}
void TetraIF::onError(QAbstractSocket::SocketError err)
{
ERROR_LOG(m_logger) << "Socket error: " << err
<< " " << m_socket->errorString()
<< ":" << m_socket->peerPort();
m_socket->disconnectFromHost();
if (m_socket->state() != QAbstractSocket::UnconnectedState)
m_socket->waitForDisconnected();
exit(3);
}
void TetraIF::handleReceivedTelegram(uint8_t *a_data, quint16 a_dataSize)
{
if (a_dataSize < 4)
{
ERROR_LOG(m_logger) << "To few bytes for handle receieved telegramm ("
<< a_dataSize << ")";
return;
}
switch (a_data[4])
{
// response to register indication
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq:
INFO_LOG(m_logger) << "Got data from Tetra ...";
if (m_feedbackTimeout->isActive())
m_feedbackTimeout->stop();
break;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp:
if (a_dataSize < 5)
{
ERROR_LOG(m_logger) << "To few bytes for handle register response telegramm ("
<< a_dataSize << ")";
return;
}
handleRegisterRsp(a_data[5]); // registration status
break;
default:
INFO_LOG(m_logger) << "Radio-Telegram with PDU-Type="
<< (int)a_data[4]
<< " ignored";
break;
}
}
void TetraIF::handleRegisterRsp(const uint8_t a_registrationStatus)
{
std::stringstream logText;
switch (a_registrationStatus)
{
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered:
INFO_LOG(m_logger) << "Valid register response from Tetra";
m_bTetraOk = true;
onAddGroupMonitoring();
onNewDataAvailable();
return;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI:
logText << "TETRA: Register-Response: Status=Duplicate ISSI";
break;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI:
logText << "TETRA: Register-Response: Status=Invalid ISSI";
break;
case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress:
logText << "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address (";
{
const QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
QList<QHostAddress>::const_iterator iter = ipList.begin();
while (iter != ipList.end())
{
logText << (*iter).toString().toStdString() << ", ";
++iter;
}
logText << ")...";
}
break;
default:
logText << "Unknown registration status: " << (int)a_registrationStatus;
break;
}
ERROR_LOG(m_logger) << logText.str();
exit(2);
}
void TetraIF::onAddGroupMonitoring()
{
std::set<uint32_t> groupsToMonitor;
groupsToMonitor.insert(m_broadcastIssi);
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_srcIssi, groupsToMonitor);
tele.setZaehler(m_counter++);
m_socket->write(tele.data());
m_socket->flush();
NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Debug, tele.data());
}
} // namespace DifferentialGPS
+53
View File
@@ -0,0 +1,53 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtNetwork/QHostAddress>
#include "tcpsocket.h"
class QTcpSocket;
class QTimer;
namespace DifferentialGPS
{
class TetraIF : public TcpSocket
{
Q_OBJECT
public:
using TcpSocket::TcpSocket;
void run() override;
public Q_SLOTS:
void onNewDataAvailable();
void onFeedbackTimeout();
bool checkTetraConnecting();
protected:
virtual void startThreadInternal(int threadIndex);
virtual bool onNewDataAvailableInternal() = 0;
private:
void doConnect();
void doInitialLogin();
void handleReceivedTelegram(uint8_t *a_data, quint16 a_dataSize);
void handleRegisterRsp(const uint8_t a_registrationStatus);
void onAddGroupMonitoring();
private Q_SLOTS:
void onConnected() override;
void onDisconnected() override;
void onReadyRead() override;
void onError(QAbstractSocket::SocketError) override;
protected:
int m_srcIssi = 0;
int m_broadcastIssi = 0;
bool m_bTetraOk = true;
quint8 m_counter = 1;
QTimer *m_feedbackTimeout = nullptr; // timer for feedback timeout
int m_feedbackTimeout_ms = 0; // feedback timeout in ms
};
} // DifferentialGPS
+65
View File
@@ -0,0 +1,65 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "tetra_if_impl.h"
#include "mainthread.h"
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <QtNetwork/QTcpSocket>
#include <time.h>
namespace DifferentialGPS
{
TetraImpl::TetraImpl()
: TetraIF("TetraIF")
, m_main(nullptr)
{}
TetraImpl::~TetraImpl()
{}
void TetraImpl::startThread(int threadIndex, MainThread *main)
{
m_main = main;
startThreadInternal(threadIndex);
}
bool TetraImpl::onNewDataAvailableInternal()
{
QByteArray payload;
if (!m_main->getNewData(payload))
{
DEBUG_LOG(m_logger) << "No data to send";
return false;
}
// GEF_BESTAETIGUNG -> Dummy, gets overridden by setPayloadDataComplete()
N_CoPrtCnv::CoPrtCnvRadioTelegram tele(GEF_BESTAETIGUNG, payload.size(), m_broadcastIssi);
tele.setPayloadDataComplete(payload);
tele.setSrcISSI(m_srcIssi);
tele.setDestISSI(m_broadcastIssi);
tele.setZaehler(m_counter++);
m_socket->write(tele.data());
m_socket->flush();
/*
uint8_t* p = tele.getData();
QString outText("Data: \n ");
for (int i=0; i<tele.getSize(); ++i)
{
outText.append(QString::number(p[i], 16).rightJustified(2,QChar('0')));
outText.append(" ");
if(i%8 == 7 )
outText.append("\n");
}
DEBUG_LOG(m_logger) << outText;
*/
DEBUG_LOG(m_logger) << "Sent " << tele.getSize() << " to Tetra";
return true;
}
} // namespace DifferentialGPS
+28
View File
@@ -0,0 +1,28 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "tetra_if.h"
namespace DifferentialGPS
{
class MainThread;
class TetraImpl final : public TetraIF
{
Q_OBJECT
public:
TetraImpl();
~TetraImpl();
void startThread(int threadIndex, MainThread *main);
protected:
bool onNewDataAvailableInternal() override;
protected:
MainThread *m_main;
};
} //namespace DifferentialGPS
+92
View File
@@ -0,0 +1,92 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "trimble_if.h"
#include "mainthread.h"
#include "dgps_config.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QTimer>
namespace DifferentialGPS
{
TrimbleIF::TrimbleIF()
: TcpSocket("TrimbleIF")
, m_main(nullptr)
, m_rxCycle_ms(10000)
, m_socketTimeout(nullptr)
, m_socketReconnect(nullptr)
, m_threadIndex(0)
{
}
TrimbleIF::~TrimbleIF()
{
}
void TrimbleIF::startThread(int threadIndex, MainThread *main)
{
const DgpsConfig::TrimbleConfig_t &cfg = DgpsConfig::instance().getTrimbleConfig();
m_threadIndex = threadIndex;
m_main = main;
startThreadInternal(cfg.ip[threadIndex], cfg.port[threadIndex]);
}
void TrimbleIF::run()
{
m_socketTimeout = new QTimer;
connect(m_socketTimeout, &QTimer::timeout, this, &TrimbleIF::onTimeout);
m_socketReconnect = new QTimer;
m_socketReconnect->setInterval(60 * 1000);
connect(m_socketReconnect, &QTimer::timeout, this, &TrimbleIF::doConnect);
TcpSocket::run();
delete m_socketTimeout;
delete m_socketReconnect;
}
void TrimbleIF::onError(QAbstractSocket::SocketError err)
{
m_socketTimeout->stop(); // Timer anhalten
TcpSocket::onError(err); // Generelle Fehlerbehandlung
}
void TrimbleIF::onReadyRead()
{
DEBUG_LOG(m_logger) << "Reading " << m_socket->bytesAvailable()
<< " bytes from " << m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort();
m_buf = m_socket->readAll();
m_main->addNewData(m_buf, m_threadIndex);
const DgpsConfig::TrimbleConfig_t &cfg = DgpsConfig::instance().getTrimbleConfig();
m_socketTimeout->start(3 * cfg.rxCycle_ms); // starte/ restarte timeout-Ueberwachung (3-fache Zykluszeit)
}
void TrimbleIF::onTimeout()
{
ERROR_LOG(m_logger) << "Socket timeout "
<< m_socket->peerAddress().toString()
<< ":" << m_socket->peerPort()
<< " - trying to reconnect in " << m_socketReconnect->interval() / 1000 << " seconds";
m_socketTimeout->stop(); // Timer anhalten
m_socket->disconnectFromHost();
if (m_socket->state() != QAbstractSocket::UnconnectedState)
m_socket->waitForDisconnected();
m_socketReconnect->start();
}
} // namespace DifferentialGPS
+44
View File
@@ -0,0 +1,44 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "mainthread.h"
#include "tcpsocket.h"
class QTcpSocket;
class QTimer;
class MainThread;
namespace DifferentialGPS
{
class TrimbleIF final : public TcpSocket
{
Q_OBJECT
public:
TrimbleIF();
~TrimbleIF();
void startThread(int threadIndex, MainThread *main);
void run() override;
protected:
void dumpDataText(const QByteArray &ba);
void dumpDataBinary(const QByteArray &ba);
protected Q_SLOTS:
void onError(QAbstractSocket::SocketError) override;
void onReadyRead() override;
void onTimeout();
protected:
MainThread *m_main;
QByteArray m_buf;
int m_rxCycle_ms; // Zyklus in ms in dem Daten empfangen werden sollten
QTimer *m_socketTimeout; // Timer zur Ueberwachung des receive-Daten-Zyklus
QTimer *m_socketReconnect; // Timer zum Reconnect-Versuch nachdem m_socketTimeout zugeschlagen hat
int m_threadIndex; // Index des Thread [0..1]
};
} // namespace DifferentialGPS