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

+37
View File
@@ -0,0 +1,37 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# CMakeLists.txt fuer SerialToTcpConverter
#
SET (serialToTcpConverter_SRCS
controller.cpp
controller.h
converter.cpp
converter.h
logger.cpp
logger.h
settings.cpp
settings.h
main.cpp
)
NGL_ADD_TOOL_ICON(serialToTcpConverter_SRCS)
NGL_ADD_EXECUTABLE(SerialToTcpConverter WS NO_TRANSLATION ${serialToTcpConverter_SRCS})
NGL_TARGET_LINK_LIBRARIES(SerialToTcpConverter
LtsCommandLineParser
Qt5::Core
Qt5::Network
Qt5::SerialPort
NGLLogger
nglapplication
nglsettings
ngltools
RmeDarkStylePlugin
)
NGL_INSTALL_TARGET(SerialToTcpConverter)
NGL_INSTALL(WS FILES log4cxx_serialToTcpConverter.props DESTINATION bin)
NGL_INSTALL(WS FILES soc.ini DESTINATION bin)
+93
View File
@@ -0,0 +1,93 @@
/**
* Controller for managing converter threads
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, NLT, 30-11-2018
*/
#include "controller.h"
#include "settings.h"
#include <QSystemTrayIcon>
#include <QMenu>
namespace SerialToTcpConverter
{
Controller::Controller(QObject *parent)
: QObject(parent)
, m_converterData()
, m_icon(new QSystemTrayIcon(this))
, m_logger(getLogger("Controller"))
{
m_icon->setIcon(QIcon(QLatin1String(":/style/messages.svg")));
m_icon->show();
}
Controller::~Controller()
{
for (const ConverterData &data : qAsConst(m_converterData))
{
if (!data.thread)
continue;
data.thread->disconnect(this);
data.thread->quit();
}
for (const ConverterData &data : qAsConst(m_converterData))
{
if (!data.thread)
continue;
data.thread->wait();
}
}
bool Controller::init()
{
QMenu *menu = new QMenu;
const auto configs = Settings::configs();
for (const Settings::Config &config : configs)
{
INFO_LOG(m_logger) << "Creating converter-thread for " << config.serialPortName;
ConverterData data;
data.serialPortName = config.serialPortName;
ConverterThread *converterThread = new ConverterThread(config.serialPortName, config.serialBaudrate, config.tcpPort);
data.thread = converterThread;
QAction *action = new QAction(QIcon(QLatin1String(":/style/pu_yellow.svg")), tr("%1 <-> %2").arg(config.serialPortName, QString::number(config.tcpPort)), menu);
data.menuAction = action;
menu->addAction(action);
m_converterData.insert(data.serialPortName, data);
connect(converterThread, &ConverterThread::finished, this, &Controller::onThreadExit);
connect(converterThread, &ConverterThread::connected, this, &Controller::onThreadConnected);
converterThread->start();
}
m_icon->setContextMenu(menu);
return true;
}
void Controller::onThreadExit()
{
ConverterThread *t = qobject_cast<ConverterThread*>(sender());
if (!t)
return;
const QString name = t->portName();
auto &data = m_converterData[name];
INFO_LOG (m_logger) << "Exiting converter-thread for serial port: "<< data.serialPortName;
data.menuAction->setIcon(QIcon(QLatin1String(":/style/pu_red.svg")));
data.thread->deleteLater();
data.thread = nullptr;
}
void Controller::onThreadConnected(const QString &portName)
{
if (!m_converterData.contains(portName))
return;
m_converterData[portName].menuAction->setIcon(QIcon(QLatin1String(":/style/pu_green.svg")));
}
} //namespace SerialToTcpConverter
+50
View File
@@ -0,0 +1,50 @@
/**
* Controller for managing converter threads
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, NLT, 30-11-2018
*/
#pragma once
#include <QObject>
#include <QString>
#include "converter.h"
#include "logger.h"
class QSystemTrayIcon;
class QAction;
namespace SerialToTcpConverter
{
struct ConverterData
{
QString serialPortName;
ConverterThread *thread = nullptr;
QAction *menuAction = nullptr;
};
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject* parent = nullptr);
~Controller();
bool init();
private slots:
void onThreadExit();
void onThreadConnected(const QString &portName);
private:
QMap<QString, ConverterData> m_converterData; // portName, converter data
QSystemTrayIcon *m_icon;
LOGGER_T m_logger;
};
} //namespace SerialToTcpConverter
+217
View File
@@ -0,0 +1,217 @@
/**
* Converter serial to tcp
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, NLT, 30-11-2018
*/
#include "converter.h"
#include <QTimer>
namespace SerialToTcpConverter
{
ConverterThread::ConverterThread(const QString &serialPortName, int baudrate, int tcpPort)
: m_serialPortName(serialPortName)
, m_baudrate(baudrate)
, m_tcpPort(tcpPort)
, m_logger(getLogger(QStringLiteral("ConverterThread.") + serialPortName))
{}
void ConverterThread::run()
{
Converter converter;
DEBUG_LOG(m_logger) << "Converter-Thread started for serial port: " << m_serialPortName << " / TCP-port: " << m_tcpPort;
if (!converter.init(m_serialPortName, m_baudrate, m_tcpPort))
{
ERROR_LOG(m_logger) << "Could not initialize Converter " << m_serialPortName;
quit();
return;
}
emit connected(m_serialPortName);
INFO_LOG(m_logger) << "Converter-Thread started for serial port: " << m_serialPortName << " / TCP-port: " << m_tcpPort;
exec();
}
Converter::Converter(QObject *parent)
: QObject(parent)
, m_serialPort(new QSerialPort(this))
, m_baudrate(-1)
, m_tcpServer(new QTcpServer(this))
, m_sockets(QVector<QTcpSocket*>())
, m_logger(getLogger("Converter"))
{}
Converter::~Converter()
{
for (auto socket : qAsConst(m_sockets))
{
socket->close();
socket->deleteLater();
}
m_serialPort->close();
m_tcpServer->close();
delete m_serialPort;
delete m_tcpServer;
}
bool Converter::init(const QString &serialPortName, int baudrate, int tcpPort)
{
m_serialPortName = serialPortName;
m_baudrate = baudrate;
connect(m_tcpServer, &QTcpServer::newConnection, this, &Converter::newConnection);
bool result = m_tcpServer->listen(QHostAddress::Any, tcpPort);
quint16 actualPort = m_tcpServer->serverPort();
INFO_LOG(m_logger) << "Start listen to port " << actualPort << " result: " << result;
if (!result)
return false;
connect(m_serialPort, &QSerialPort::errorOccurred, this, &Converter::handleSerialError);
connect(m_serialPort, &QSerialPort::readyRead, this, &Converter::readSerial);
// TODO: Serial Port Watcher über einen Timer zum öffnen des seriellen Ports
openSerialPort();
// (This is not necesarily working as the sp disconnect may not be sensed)
// Don't care if SP does not come up...
return true;
}
bool Converter::openSerialPort()
{
m_serialPort->setPortName(m_serialPortName);
if (!m_serialPort->setBaudRate(m_baudrate) ||
!m_serialPort->setDataBits(QSerialPort::Data8) ||
!m_serialPort->setParity(QSerialPort::NoParity) ||
!m_serialPort->setStopBits(QSerialPort::OneStop) ||
!m_serialPort->setFlowControl(QSerialPort::NoFlowControl))
{
ERROR_LOG(m_logger) << "Error configuring port before open.";
return false;
}
if (m_serialPort->isOpen())
return true;
if (!m_serialPort->open(QSerialPort::ReadWrite))
{
ERROR_LOG(m_logger) << "Could not (re)open serial port " << m_serialPort->portName() << " error: " << m_serialPort->errorString();
return false;
}
INFO_LOG(m_logger) << "(Re)openend serial port " << m_serialPort->portName() << " baudrate: " << m_serialPort->baudRate();
return true;
}
void Converter::readSerial()
{
const QByteArray ba = m_serialPort->readAll();
INFO_LOG(m_logger) << "Read Serial: " << ba;
for (QTcpSocket *socket : qAsConst(m_sockets))
{
socket->write(ba);
socket->flush();
}
}
void Converter::serialClosed()
{
// TODO: Serial Port Watcher über einen Timer zum öffnen des seriellen Ports
}
void Converter::handleSerialError(QSerialPort::SerialPortError error)
{
DEBUG_LOG(m_logger) << "Spontaneous error " << error << " doesn't have to be an error ...";
const QString errStr(QStringLiteral("QSerialPort::SerialPortError ") + QString::number(error) +
QStringLiteral(" from serial port ") + m_serialPort->portName() +
QStringLiteral(" error: ") + m_serialPort->errorString());
switch (error)
{
case QSerialPort::SerialPortError::NoError:
{
INFO_LOG(m_logger) << errStr;
break;
}
case QSerialPort::SerialPortError::DeviceNotFoundError:
case QSerialPort::SerialPortError::OpenError:
case QSerialPort::SerialPortError::PermissionError:
case QSerialPort::SerialPortError::UnknownError:
case QSerialPort::SerialPortError::UnsupportedOperationError:
{
Q_FALLTHROUGH();
}
default:
{
ERROR_LOG(m_logger) << errStr;
if (m_serialPort->isOpen())
m_serialPort->close();
QTimer::singleShot(2000, this, &Converter::openSerialPort);
break;
}
}
}
void Converter::newConnection()
{
while (m_tcpServer->hasPendingConnections())
{
// store socket and connect to signals
QTcpSocket *socket = m_tcpServer->nextPendingConnection();
connect(socket, &QTcpSocket::readyRead, this, &Converter::readTcp);
connect(socket, &QTcpSocket::disconnected, this, &Converter::tcpDisconnected);
m_sockets.append(socket);
INFO_LOG(m_logger) << "New TCP-connection on port " << m_tcpServer->serverPort();
}
}
void Converter::readTcp()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (!socket)
return;
const QByteArray ba = socket->readAll(); // clear socket buffer, no matter if there is an endpoint or not
if (!m_serialPort->isOpen())
{
ERROR_LOG(m_logger) << "Read TCP data, but serial Port is not open to receive that data.";
return;
}
m_serialPort->write(ba);
m_serialPort->flush();
}
void Converter::tcpDisconnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
m_sockets.removeOne(socket);
socket->deleteLater();
}
void Converter::handleTcpError(QAbstractSocket::SocketError error)
{
DEBUG_LOG(m_logger) << "Spontaneous error " << error << " doesn't have to be an error ...";
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (!socket)
return;
ERROR_LOG(m_logger) << "QTcpSocket::SocketError " << error
<< " from tcp port " << QString::number(socket->peerPort())
<< " error: " << socket->errorString();
if (socket->isOpen())
socket->close();
m_sockets.removeOne(socket);
socket->deleteLater();
}
} //namespace SerialToTcpConverter
+80
View File
@@ -0,0 +1,80 @@
/**
* Converter serial to tcp
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, NLT, 30-11-2018
*/
#pragma once
#include <QObject>
#include <QSerialPort>
#include <QString>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
#include "logger.h"
namespace SerialToTcpConverter
{
class Converter;
class ConverterThread : public QThread
{
Q_OBJECT
public:
explicit ConverterThread(const QString &serialPortName,
int baudrate,
int tcpPort);
QString portName() const { return m_serialPortName; }
protected:
void run() override;
signals:
void connected(const QString &port);
private:
QString m_serialPortName;
int m_baudrate;
int m_tcpPort;
LOGGER_T &m_logger; // Logger-Object
};
class Converter : public QObject
{
Q_OBJECT
public:
explicit Converter(QObject* parent = nullptr);
~Converter();
bool init(const QString &serialPortName, int baudrate, int tcpPort);
private slots:
// serial
bool openSerialPort();
void readSerial();
void serialClosed();
void handleSerialError(QSerialPort::SerialPortError error);
// tcp
void newConnection();
void readTcp();
void tcpDisconnected();
void handleTcpError(QAbstractSocket::SocketError error);
private:
QSerialPort *m_serialPort;
QString m_serialPortName;
int m_baudrate;
QTcpServer *m_tcpServer;
QVector<QTcpSocket*> m_sockets;
LOGGER_T m_logger;
};
} //namespace SerialToTcpConverter
@@ -0,0 +1,80 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# Service: SerialToTcpConverter
###########################################################
log4j.logger.Controller=DEBUG
log4j.logger.ConverterThread=DEBUG
log4j.logger.Converter=DEBUG
#log4j.logger.XXX.MainHandler=DEBUG
#
# Lts::RollingFileAppender
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 SerialToTcpConverter
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "SerialToTcpConverter.";
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 SerialToTcpConverter
+22
View File
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for XxxXxxXxx
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace SerialToTcpConverter
{
typedef NGL::INGLLogger &LOGGER_T;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace SerialToTcpConverter
+48
View File
@@ -0,0 +1,48 @@
/**
* @RDE_HEADER@
* SerialToTcpConverter -> connecting serial to TCP Ports
* $Id$
* $HeadURL$
* $Author$
*/
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include <NGLLogger/INGLLogger.h>
#include <nglapplication/nglapplication.h>
#include "controller.h"
#include "settings.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("SerialToTcpConverter", "log4cxx_serialToTcpConverter.props");
NGL::INGLLogger &logger = app.baseLogger();
QCoreApplication::setApplicationName(QLatin1String("Serial to TCP converter"));
QCoreApplication::setOrganizationName(QLatin1String("RME"));
QString iniFile = options.iniFileSet() ? options.iniFile() : QStringLiteral("serialconverter.ini");
SerialToTcpConverter::Settings::setIniFile(iniFile);
// TODO: Versionsausgabe bei -v Option?
int retval = 0;
STARTUP_LOG(logger);
{
SerialToTcpConverter::Controller controller;
controller.init();
retval = app.exec();
SHUTDOWN_LOG(logger);
}
return retval;
}
+67
View File
@@ -0,0 +1,67 @@
/**
* Settings for SerialToTcpConverter
* $Id$
* $HeadURL$
* $Author$
*/
#include "settings.h"
#include <QtCore/QSettings>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_filesystem.h>
namespace SerialToTcpConverter
{
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);
}
//-----------------------------------------------------------------------------
QVector<Settings::Config> Settings::configs()
{
QSettings *settings = s()->settings();
QVector<Config> vec;
settings->beginGroup(QStringLiteral("Configs"));
{
int size_configs = settings->beginReadArray(QStringLiteral("Config"));
for (int i = 0; i < size_configs; ++i)
{
settings->setArrayIndex(i);
Config config;
config.serialPortName = settings->value(QStringLiteral("SerialPortName")).toString();
config.serialBaudrate = settings->value(QStringLiteral("SerialBaudrate"), 115200).toInt();
config.tcpPort = settings->value(QStringLiteral("TcpPort"), 0).toInt();
vec << config;
}
settings->endArray();
}
settings->endGroup();
return vec;
}
} // namespace SerialToTcpConverter
+35
View File
@@ -0,0 +1,35 @@
/**
* Settings for SerialToTcpConverter
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
namespace NGL
{
class Settings;
}
namespace SerialToTcpConverter
{
namespace Settings
{
struct Config
{
QString serialPortName;
int serialBaudrate;
int tcpPort;
};
NGL::Settings *settings();
void setIniFile(const QString &ini);
QVector<Config> configs();
}
} // namespace SerialToTcpConverter
+4
View File
@@ -0,0 +1,4 @@
[Configs]
Config/1/SerialPortName=COM6
Config/1/TcpPort=8006
Config/size=1