309 lines
8.1 KiB
C++
Executable File
309 lines
8.1 KiB
C++
Executable File
|
|
|
|
|
|
#include "ttci_device.h"
|
|
#include "settings.h"
|
|
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
#include <QtCore/QByteArray>
|
|
#include <QtCore/QChar>
|
|
|
|
namespace TrainingAreaBaseOC
|
|
{
|
|
Device::Device(QObject *parent, bool tcpMode) : QObject(parent)
|
|
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTCI.Device"))
|
|
, m_spQuerry(new LtsSerialPortQuerry::LtsSerialPortQuerry(this))
|
|
, m_socket(new QTcpSocket(this))
|
|
, m_restartTimer(new QTimer(this))
|
|
, m_receiveTimeoutTimer(new QTimer(this))
|
|
, m_tcpMode(tcpMode) {
|
|
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, &QAbstractSocket::errorOccurred, 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
|
|
{
|
|
|
|
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() ;
|
|
|
|
|
|
|
|
int idxStart = -1;
|
|
while ((idxStart = m_buffer.indexOf(0x02)) >= 0)
|
|
{
|
|
TRACE_LOG(m_logger) << "idxStart: " << idxStart ;
|
|
|
|
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;
|
|
|
|
|
|
if (m_buffer.at(idxEnd) != 0x03)
|
|
{
|
|
|
|
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 ..." ;
|
|
|
|
if (len == 255 && m_payload.isEmpty())
|
|
DEBUG_LOG(m_logger) << "Remember the payload destination: " << destination ;
|
|
m_payload += payload;
|
|
if (len != 255)
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << "destination: " << destination
|
|
<< ", data: " << m_payload.toHex() ;
|
|
emit dataAvailable(m_payload);
|
|
m_payload.clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
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 ;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|