Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+316
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TTCI-Server Library
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, NLS, 2019-01-17
|
||||
*/
|
||||
|
||||
#include "ttci_device.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QByteArray>
|
||||
#include <QChar>
|
||||
|
||||
namespace TrainingAreaBaseOC
|
||||
{
|
||||
Device::Device(QObject *parent, bool tcpMode)
|
||||
: QObject(parent)
|
||||
, m_spQuerry(new LtsSerialPortQuerry::LtsSerialPortQuerry(this))
|
||||
, m_socket(new QTcpSocket(this))
|
||||
, m_restartTimer(new QTimer(this))
|
||||
, m_receiveTimeoutTimer(new QTimer(this))
|
||||
, m_tcpMode(tcpMode)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTCI.Device"))
|
||||
{
|
||||
connect(m_spQuerry, &LtsSerialPortQuerry::LtsSerialPortQuerry::connectionEstablished, this, &Device::open);
|
||||
m_spQuerry->restartQuerry();
|
||||
|
||||
m_receiveTimeoutTimer->setInterval(15000);
|
||||
connect(m_receiveTimeoutTimer, &QTimer::timeout, m_spQuerry, &LtsSerialPortQuerry::LtsSerialPortQuerry::continueQuerry);
|
||||
connect(m_receiveTimeoutTimer, &QTimer::timeout, this, &Device::disconnectedFromEq);
|
||||
|
||||
m_receiveTimeoutTimer->start();
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void Device::reOpen()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ConnectionHandlerSerial::reOpen";
|
||||
close();
|
||||
QTimer::singleShot(2000, this, &Device::open);
|
||||
}
|
||||
|
||||
bool Device::open()
|
||||
{
|
||||
if (m_tcpMode)
|
||||
{
|
||||
m_restartTimer->stop();
|
||||
|
||||
close();
|
||||
m_socket = new QTcpSocket(this);
|
||||
m_socket->connectToHost(Settings::hostName(), Settings::portTtci());
|
||||
if (!m_socket->waitForConnected())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not (re)open tcp destination " << m_socket->peerName() << ":" << m_socket->peerPort() << ", error: " << m_socket->errorString();
|
||||
return false;
|
||||
}
|
||||
connect(m_socket, &QTcpSocket::readyRead, this, &Device::onDataAvailable);
|
||||
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &Device::handleError);
|
||||
connect(m_socket, &QTcpSocket::disconnected, this, &Device::open);
|
||||
DEBUG_LOG(m_logger) << "(Re)openend tcp destination " << m_socket->peerName() << ":" << Settings::portTtci();
|
||||
}
|
||||
else
|
||||
{
|
||||
//use portscanner
|
||||
m_serialPort = m_spQuerry->currentSerialPort();
|
||||
DEBUG_LOG(m_logger) << "(Re)openend serial destination " << m_serialPort->portName() << ":";
|
||||
|
||||
connect(m_serialPort, &QSerialPort::readyRead, this, &Device::onDataAvailable);
|
||||
|
||||
}
|
||||
m_receiveTimeoutTimer->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::close()
|
||||
{
|
||||
if (m_socket)
|
||||
{
|
||||
if (m_socket->isOpen())
|
||||
m_socket->close();
|
||||
DEBUG_LOG(m_logger) << "Closing TCP Port";
|
||||
delete m_socket;
|
||||
m_socket = nullptr;
|
||||
m_receiveTimeoutTimer->stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::isOpen() const
|
||||
{
|
||||
if (m_tcpMode)
|
||||
return m_socket->isOpen();
|
||||
else
|
||||
return m_serialPort->isOpen();
|
||||
}
|
||||
|
||||
void Device::onDataAvailable()
|
||||
{
|
||||
if (m_tcpMode)
|
||||
m_buffer += m_socket->readAll();
|
||||
else
|
||||
m_buffer += m_serialPort->readAll();
|
||||
|
||||
parseBuffer();
|
||||
}
|
||||
|
||||
void Device::parseBuffer()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Buffer - size: " << m_buffer.size()
|
||||
<< ", data: " << m_buffer.toHex() ;
|
||||
// TTCI-Frame: 02 <len> <data> <crc> 03
|
||||
// data: <destination> <payload>
|
||||
// nicht gefunden oder letztes Byte -> ignore
|
||||
int idxStart = -1;
|
||||
while ((idxStart = m_buffer.indexOf(0x02)) >= 0)
|
||||
{
|
||||
TRACE_LOG(m_logger) << "idxStart: " << idxStart ;
|
||||
// Laengenbyte im Buffer?
|
||||
int idxLen = idxStart + 1;
|
||||
if (idxLen >= m_buffer.size())
|
||||
return;
|
||||
|
||||
unsigned char len = static_cast<unsigned char>(m_buffer.at(idxLen));
|
||||
TRACE_LOG(m_logger) << "idxLen: " << idxLen
|
||||
<< ", len: " << len
|
||||
<< " = 0x" << QByteArray::number(len, 16);
|
||||
int idxCrc = idxLen + len + 1;
|
||||
int idxEnd = idxCrc + 1;
|
||||
if (idxEnd >= m_buffer.size())
|
||||
return;
|
||||
TRACE_LOG(m_logger) << "idxCrc: " << idxCrc
|
||||
<< ", idxEnd: " << idxEnd ;
|
||||
if (idxEnd >= m_buffer.size())
|
||||
return;
|
||||
|
||||
// korrekten Ende-Marker gefunden?
|
||||
if (m_buffer.at(idxEnd) != 0x03)
|
||||
{
|
||||
// nein -> neu aufsetzen
|
||||
WARNING_LOG(m_logger) << "Could not find valid end marker - searching new start marker"
|
||||
;
|
||||
m_buffer = m_buffer.mid(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char crc = static_cast<unsigned char>(m_buffer.at(idxCrc));
|
||||
unsigned char crcCalc = calcChecksum(m_buffer.mid(idxStart, idxCrc - idxStart));
|
||||
TRACE_LOG(m_logger) << "crc: " << crc
|
||||
<< ", calculated: " << crcCalc
|
||||
;
|
||||
if (crc != crcCalc)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Invalid checksum - is: " << crcCalc
|
||||
<< " - should be: " << crc ;
|
||||
}
|
||||
|
||||
unsigned char destination = static_cast<unsigned char>(m_buffer.at(idxLen + 1));
|
||||
QByteArray payload = m_buffer.mid(idxLen + 2, len - 1);
|
||||
|
||||
if (len == 255 || !m_payload.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "telegram with more than 254 bytes ..." ;
|
||||
// Erstes Telegram -> destination merken
|
||||
if (len == 255 && m_payload.isEmpty())
|
||||
DEBUG_LOG(m_logger) << "Remember the payload destination: " << destination ;
|
||||
m_payload += payload;
|
||||
if (len != 255)
|
||||
{
|
||||
// Letztes Telegramm -> ausgeben
|
||||
DEBUG_LOG(m_logger) << "destination: " << destination
|
||||
<< ", data: " << m_payload.toHex() ;
|
||||
emit dataAvailable(m_payload);
|
||||
m_payload.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// normales Telegramm -> ausgeben
|
||||
DEBUG_LOG(m_logger) << "destination: " << destination
|
||||
<< ", data: " << payload.toHex() ;
|
||||
emit dataAvailable(payload);
|
||||
}
|
||||
|
||||
m_buffer = m_buffer.mid(idxEnd + 1);
|
||||
m_receiveTimeoutTimer->start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::writeData(const QChar destination, const QByteArray &payload)
|
||||
{
|
||||
|
||||
if ((m_tcpMode && !m_socket->isOpen()) || (!m_tcpMode && !m_serialPort->isOpen()))
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Writing " << payload.size()
|
||||
<< " Bytes to channel " << destination ;
|
||||
// in TTCI-Frames verpacken, nicht schnell aber fuer die paar Bytes sollte es ok sein
|
||||
QByteArray data = payload;
|
||||
do
|
||||
{
|
||||
QByteArray payloadToWrite = data.left(254);
|
||||
|
||||
QByteArray buf;
|
||||
buf.reserve(payloadToWrite.size() + 5);
|
||||
|
||||
buf.append(0x02);
|
||||
buf.append(static_cast<unsigned char>(payloadToWrite.size() + 1));
|
||||
buf.append(destination.toLatin1());
|
||||
buf.append(payloadToWrite);
|
||||
buf.append(calcChecksum(buf));
|
||||
buf.append(0x03);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Writing: " << buf.toHex() ;
|
||||
if (m_tcpMode)
|
||||
m_socket->write(buf);
|
||||
else
|
||||
m_serialPort->write(buf);
|
||||
|
||||
data = data.mid(254);
|
||||
|
||||
}
|
||||
while (!data.isEmpty());
|
||||
|
||||
if(m_tcpMode)
|
||||
m_socket->flush();
|
||||
else
|
||||
m_serialPort->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char Device::calcChecksum(const QByteArray &checksumData)
|
||||
{
|
||||
unsigned char sum = 0;
|
||||
for (const char c : checksumData)
|
||||
sum ^= static_cast<unsigned char>(c);
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
void Device::handleError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Spontaneous error " << error << " doesn't have to be an error ...";
|
||||
|
||||
const QString errStr(QStringLiteral("QTcpSocket::SocketError ") + QString::number(error) +
|
||||
QStringLiteral(" from tcp port ") + QString::number(m_socket->peerPort()) +
|
||||
QStringLiteral(" error: ") + m_socket->errorString());
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case QTcpSocket::SocketError::ConnectionRefusedError:
|
||||
case QTcpSocket::SocketError::SocketAccessError:
|
||||
case QTcpSocket::SocketError::SocketResourceError:
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Closing port trying to reopen it.";
|
||||
close();
|
||||
m_restartTimer->start();
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case QTcpSocket::SocketError::RemoteHostClosedError:
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Host closed trying to reopen.";
|
||||
m_restartTimer->start();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(m_logger) << errStr;
|
||||
close();
|
||||
m_restartTimer->start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Device::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(" error: ") + m_serialPort->errorString());
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case QSerialPort::SerialPortError::OpenError:
|
||||
case QSerialPort::SerialPortError::NotOpenError:
|
||||
case QSerialPort::SerialPortError::DeviceNotFoundError:
|
||||
case QSerialPort::SerialPortError::PermissionError:
|
||||
case QSerialPort::SerialPortError::WriteError:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Closing port trying to reopen it.";
|
||||
m_restartTimer->start();
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
m_restartTimer->start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} //namespace TrainingAreaBaseOC
|
||||
Reference in new issue
Block a user