/** * Connection Handler for the serial connection to the sfm * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Dassow, NLST, 2018-01-29 */ #include "connection_handler_tcp.h" #include #include "settings.h" namespace TrainingAreaBaseOC { ConnectionHandlerTcp::ConnectionHandlerTcp() : m_timer(new QTimer(this)) , m_logger(getLogger("ConnectionHandlerTcp")) { m_timer->setInterval(5000); connect(m_timer, &QTimer::timeout, this, &ConnectionHandlerTcp::open); } ConnectionHandlerTcp::~ConnectionHandlerTcp() { m_socket->close(); delete m_socket; } bool ConnectionHandlerTcp::init() { m_socket = new QTcpSocket(); connect(m_socket, &QTcpSocket::readyRead, this, &ConnectionHandlerTcp::read); connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &ConnectionHandlerTcp::handleError); connect(m_socket, &QTcpSocket::disconnected, this, &ConnectionHandlerTcp::open); connect(m_socket, &QTcpSocket::disconnected, this, &ConnectionHandlerTcp::disconnectedFromEq); open(); return true; } bool ConnectionHandlerTcp::send(const LtsUtils::SfmMessage &message) { if (!m_socket) return false; if (!m_socket->isOpen()) { ERROR_LOG(m_logger) << "Port is not opened!"; return false; } QByteArray data = LtsUtils::byteStreamFromSfmMessage(message); DEBUG_LOG(m_logger) << "Sending frame: " << data.toHex(' '); const qint64 byteswritten = m_socket->write(data); if (byteswritten == -1) { ERROR_LOG(m_logger) << "Failed to write data to port " << m_socket->peerPort() << " error: " << m_socket->errorString(); m_timer->start(); return false; } else if (byteswritten != data.size()) { ERROR_LOG(m_logger) << "Failed to write all data to port " << m_socket->peerPort() << " error: " << m_socket->errorString(); return false; } return true; } bool ConnectionHandlerTcp::open() { m_timer->stop(); m_socket->connectToHost(Settings::hostName(), Settings::port()); 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; } INFO_LOG(m_logger) << "(Re)openend tcp destination " << m_socket->peerName() << ":" << Settings::port(); return true; } void ConnectionHandlerTcp::close() { m_socket->close(); } bool ConnectionHandlerTcp::isOpen() const { return m_socket->isOpen(); } void ConnectionHandlerTcp::read() { const QByteArray ba = m_socket->readAll(); m_currentDataRead.append(ba); DEBUG_LOG(m_logger) << "Binary data from sfm: " << ba.toHex(' '); int idxStart = -1; int idxEnd = -1; while ((idxStart = m_currentDataRead.indexOf(0x02)) >= 0 && (idxEnd = m_currentDataRead.indexOf(0x03)) >= 0) // while complete message frame in buffer { QByteArray message = m_currentDataRead.mid(idxStart, (idxEnd - idxStart) + 1); LtsUtils::SfmMessage sfmMsg; DEBUG_LOG(m_logger) << "Frame from sfm as binary " << message.toHex(); try { sfmMsg = LtsUtils::byteStreamToSfmMessage(message); } catch (const LtsUtils::ConversionError &ex) { ERROR_LOG(m_logger) << "Error converting QByteArray into LtsUtils::SfmMessage: " << ex.what(); ERROR_LOG(m_logger) << "Faulty Data from sfm as binary " << message.toHex(); } INFO_LOG(m_logger) << "Decoded message from sfm Id: " << sfmMsg.id() << " RTR: " << sfmMsg.rtr() << " Data: " << sfmMsg.payload().toHex(); m_currentDataRead = m_currentDataRead.mid(idxEnd + 1); emit received(sfmMsg); } if (m_socket->bytesAvailable() > 0) DEBUG_LOG(m_logger) << "Still " << m_socket->bytesAvailable() << " available to be read"; } void ConnectionHandlerTcp::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_timer->start(); Q_FALLTHROUGH(); } case QTcpSocket::SocketError::RemoteHostClosedError: { ERROR_LOG(m_logger) << "Host closed trying to reopen."; m_timer->start(); break; } default: { ERROR_LOG(m_logger) << errStr; close(); m_timer->start(); break; } } } } // namespace TrainingAreaBaseOC