/** * 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 "settings.h" #include #include namespace EffectShowClient { ConnectionHandlerTcp::ConnectionHandlerTcp(QObject *parent) : QObject(parent) , m_socket(nullptr) , m_timer(new QTimer(this)) , m_currentDataRead(QByteArray()) , 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, &QTcpSocket::disconnected, this, &ConnectionHandlerTcp::open); connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &ConnectionHandlerTcp::handleError); connect(m_socket, &QTcpSocket::connected, this, &ConnectionHandlerTcp::connectedToSerialConverter); open(); //open it and start regardless return true; } bool ConnectionHandlerTcp::send(const QByteArray &message) { if (!m_socket) return false; if (!m_socket->isOpen()) { ERROR_LOG(m_logger) << "Port is not opened!"; return false; } const QByteArray writeThis = LtsUtils::byteStreamFromEscMessage(message); DEBUG_LOG(m_logger) << "Send HEX:" << writeThis.toHex(' '); qint64 byteswritten = m_socket->write(writeThis); DEBUG_LOG(m_logger) << "Binary data:" << message.size(); DEBUG_LOG(m_logger) << "Try sending: " << message.size(); // Check for errors --------------------------------------------- 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 != writeThis.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() << ":" << m_socket->peerPort(); 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(' '); DEBUG_LOG(m_logger) << "Data size" << ba.size(); 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 { //whatever happens: remove current frame from data //m_currentDataRead = m_currentDataRead.mid(idxEnd+1); QByteArray message = m_currentDataRead.mid(idxStart, (idxEnd - idxStart) + 1); m_currentDataRead = m_currentDataRead.mid(idxEnd + 1); DEBUG_LOG(m_logger) << "Data Message found: " << message.toHex(' '); message = LtsUtils::byteStreamToEscMessage(message); if (message.size() > 2) { ERROR_LOG(m_logger) << "Message to long: " << message.size(); continue; } DEBUG_LOG(m_logger) << "Frame from sfm as binary " << message.toHex(); //got message now remove frame unsigned int byte = 0; byte = message.at(0) & 0xFF; DEBUG_LOG(m_logger) << "ConnectionHandler::read var byte is" << byte; if (!isValidCommandByte(byte)) { ERROR_LOG(m_logger) << "ConnectionHandler::read Commandbyte is invalid. Returning"; return; } // If first byte is not between 43 and 91, then we need the second byte, because all other commands have payload. Just not this single piece of if (byte <= 41 || byte >= 91) { if (message.size() > 1 && !isValidPayloadByte(message.at(1))) { ERROR_LOG(m_logger) << "ConnectionHandler::read Payloadbyte is invalid. Returning"; continue; } } if (message.size() != 2) { ERROR_LOG(m_logger) << "ConnectionHandler::read No 2nd byte was appended (QByteArray has bad size). Returning."; continue; } DEBUG_LOG(m_logger) << "Binary data from serial port: " << message.toHex(' '); emit received(message); } 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 WITHOUT trying to reopen it."; close(); m_timer->start(); Q_FALLTHROUGH(); } case QTcpSocket::SocketError::RemoteHostClosedError: { ERROR_LOG(m_logger) << errStr; m_timer->start(); break; } default: { ERROR_LOG(m_logger) << errStr; close(); m_timer->start(); break; } } } bool ConnectionHandlerTcp::isValidCommandByte(const unsigned char command) { DEBUG_LOG(m_logger) << "ConnectionHandler::isValidCommandByte" << command << (command == 192 || command == 240 || command == 244 || command == 255 || command == 144 || command == 202 || command == 224 || command == 213 || command == 15 || command == 42 || command == 41 || (command >= 43 && command <= 91)); return (command == 192 || command == 240 || command == 244 || command == 255 || command == 144 || command == 202 || command == 224 || command == 213 || command == 15 || command == 42 || command == 41 || (command >= 43 && command <= 91)); } bool ConnectionHandlerTcp::isValidPayloadByte(const unsigned char payload) { Q_UNUSED(payload); return true; } }