/** * Converter serial to tcp * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Dassow, NLT, 30-11-2018 */ #include "converter.h" #include 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()) , 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(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(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(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