#include "headers/baseconn.h" BaseConn::BaseConn(QObject *parent) : QObject(parent) { socket = new QTcpSocket(); this->setState("disconnected"); connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(gotError(QAbstractSocket::SocketError))); this->nextConnectionId = 1; this->speedTimers.append(pGlobalSpeedTimer); this->refreshTimer = new QTimer(); refreshTimer->setInterval(1); refreshTimer->setSingleShot(true); refreshTimer->connect(this->refreshTimer, &QTimer::timeout, this, &BaseConn::refreshTimers); refreshTimer->start(); } bool BaseConn::connectToHost() { qDebug() << "connecting"; setState("connecting"); this->connection_progress = 0; QEventLoop loop; QTimer timer; timer.setSingleShot(true); // quit the loop when the timer times out loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); //quit the loop when the connection was established loop.connect(this->socket, SIGNAL(connected()), &loop, SLOT(quit())); // start the timer before starting to connect timer.start(3000); //connect this->socket->connectToHost(this->ip, this->port); //wait for the connection to finish (programm gets stuck in here) loop.exec(); //loop finish if(timer.remainingTime() == -1){ //the time has been triggered -> timeout this->socket->abort(); setState("disconnected"); return(false); } // stop the timer as the connection has been established timer.stop(); connect(this->socket, &QTcpSocket::readyRead, this, &BaseConn::readyRead); this->connection_progress = 100; setState("connected"); this->speedTimers[0]->remoteControlled = true; return(true); } void BaseConn::closeConnection() { qDebug() << "closing connection"; switch (socket->state()) { case 0: socket->disconnectFromHost(); break; case 2: socket->abort(); break; default: socket->abort(); } setState("disconnected"); // for(int i = 0; i < this->waitingRequests.length(); i++){ // this->waitingRequests[i].reply = "ERR_NOT_CONNECTED"; // this->waitingRequests[i].loop->quit(); // return; // } } void BaseConn::gotError(QAbstractSocket::SocketError err) { //qDebug() << "got error"; QString strError = "unknown"; switch (err) { case 0: strError = "Connection was refused"; break; case 1: strError = "Remote host closed the connection"; this->closeConnection(); break; case 2: strError = "Host address was not found"; break; case 5: strError = "Connection timed out"; break; default: strError = "Unknown error"; } emit gotError(strError); qDebug() << "got socket error: " << strError; } QVariantMap BaseConn::sendCommand(int header, QJsonValue data = ""){ if(this->state != "connected"){ return {{"status", 910}, {"data", "not connected"}}; } // generate id and witing requests entry int thisId = nextConnectionId; nextConnectionId ++; QEventLoop loop; QJsonObject reply; this->waitingRequests.append({thisId, &loop, reply}); QJsonObject requestObj; requestObj.insert("id", thisId); requestObj.insert("header", header); requestObj.insert("data", data); QString jsonRequest = QJsonDocument(requestObj).toJson(); QByteArray arrBlock; QDataStream out(&arrBlock, QIODevice::WriteOnly); //out.setVersion(QDataStream::Qt_5_10); out << quint16(0) << jsonRequest; out.device()->seek(0); out << quint16(ulong(arrBlock.size()) - sizeof(quint16)); QTimer timer; timer.setSingleShot(true); // quit the loop when the timer times out loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); // quit the loop when the connection was established // loop.connect(this, &BaseConn::gotReply, &loop, &QEventLoop::quit); // start the timer before starting to connect timer.start(3000); //write data socket->write(arrBlock); //wait for an answer to finish (programm gets stuck in here) loop.exec(); //loop finished if(timer.remainingTime() == -1){ //the time has been triggered -> timeout return {{"status", 911}, {"data", ""}}; } for(int i = 0; iwaitingRequests.length(); i++){ if(this->waitingRequests[i].id == thisId){ reply = this->waitingRequests[i].reply; } } // stop the timer as the connection has been established timer.stop(); timer.deleteLater(); //remoteSessions.release(1); return {{"status", reply.value("header").toInt()}, {"data", reply.value("data").toVariant()}}; } void BaseConn::readyRead() { QDataStream in(socket); //in.setVersion(QDataStream::Qt_5_10); qint16 nextBlockSize = 0; for (;;) { if (!nextBlockSize) { if (ulong(socket->bytesAvailable()) < sizeof(quint16)) { break; } in >> nextBlockSize; } if (socket->bytesAvailable() < nextBlockSize) { break; } QString str; in >> str; // if (str == "0") // { // str = "Connection closed"; // closeConnection(); // } nextBlockSize = 0; QString reply = str; int id = 0; QJsonDocument jsonReply = QJsonDocument::fromJson(reply.toUtf8()); QJsonObject replyObj = jsonReply.object(); if(!replyObj.isEmpty()){ id = replyObj.value("id").toInt(); for(int i = 0; i < this->waitingRequests.length(); i++){ if(this->waitingRequests[i].id == id){ this->waitingRequests[i].reply = replyObj; this->waitingRequests[i].loop->quit(); return; } } } latestReadReply = str; emit gotUnexpectedReply(str); } } /*-----Functions to control the local stopwatch-----*/ void BaseConn::refreshTimers(){ if(this->state != "connected"){ this->refreshTimer->start(); return; } QVariantMap tmpReply = this->sendCommand(2000); if(tmpReply["status"] != 200){ return; } int remoteRaceState = tmpReply["data"].toInt(); switch (remoteRaceState) { case 0: { // case IDLE if(speedTimers[0]->state != 0){ speedTimers[0]->setState(SpeedTimer::IDLE); } break; } case 1: { // case STARTING if(speedTimers[0]->state != 1){ speedTimers[0]->setState(SpeedTimer::STARTING); } tmpReply = sendCommand(2004); if(tmpReply["status"] != 200){ //handle Error!! qDebug() << "+--- getting next start action from basestation failed: " << tmpReply["status"]; this->refreshTimer->start(); return; } else { if(this->nextRemoteAction != tmpReply["data"].toString()){ this->nextRemoteAction = tmpReply["data"].toString(); this->nextRemoteActionChanged(); } } tmpReply = sendCommand(2005); if(tmpReply["status"] != 200){ //handle error!! qDebug() << "+--- getting next start action progress from basestation failed"; this->refreshTimer->start(); return; } else { if(this->nextRemoteActionDelayProg != tmpReply["data"].toFloat()){ this->nextRemoteActionDelayProg = tmpReply["data"].toFloat(); this->nextRemoteActionDelayProgChanged(); } } break; } case 2: { // case RUNNING if(speedTimers[0]->state != 2){ speedTimers[0]->setState(SpeedTimer::RUNNING); } // get current time tmpReply = sendCommand(2001, 0); if(tmpReply["status"] != 200){ //handle error!! qDebug() << "+--- getting current time (timer 0) from basestation failed"; this->refreshTimer->start(); return; } else { speedTimers[0]->stoppedTime = tmpReply["data"].toInt(); } break; } case 3: { // case STOPPED if(speedTimers[0]->state != 3){ speedTimers[0]->setState(SpeedTimer::STOPPED); } // get current time tmpReply = sendCommand(2001, 0); if(tmpReply["status"] != 200){ //handle error!! qDebug() << "+--- getting current time (timer 0) from basestation failed"; return; } else { speedTimers[0]->stoppedTime = tmpReply["data"].toInt(); } break; } default: { // some error break; } } this->refreshTimer->start(); } bool BaseConn::startTimers(){ qDebug() << "starting timers"; QVariantMap reply = this->sendCommand(1000); if(reply["status"] != 200){ //handle Error!! return false; } this->speedTimers[0]->setState(SpeedTimer::STARTING); return true; } bool BaseConn::stopTimers(QString type){ qDebug() << "stopping timers"; QVariantMap reply = this->sendCommand(1001); if(reply["status"] != 200){ //handle Error!! return false; } this->speedTimers[0]->stop(type); qDebug() << "stopped timers"; return true; } bool BaseConn::resetTimers(){ qDebug() << "resetting timers"; QVariantMap reply = this->sendCommand(1002); if(reply["status"] != 200){ //handle Error!! return false; } this->speedTimers[0]->reset(); return true; } void BaseConn::setIP(const QString &ipAdress){ this->ip = ipAdress; } QString BaseConn::getIP() const { return(this->ip); } QString BaseConn::getState() const { return(this->state); } void BaseConn::setState(QString newState){ this->state = newState; emit stateChanged(); } int BaseConn::getProgress() const { return(connection_progress); } bool BaseConn::refreshConnections() { QVariantMap reply = this->sendCommand(2006); if(reply["status"] != 200){ //handle Error!! return false; } connections = reply["data"].toString().split("|||"); return true; } QStringList BaseConn::getConnections() { return(connections); } QString BaseConn::getNextRemoteAction() { return this->nextRemoteAction; } float BaseConn::getNextRemoteActionDelayProg(){ return this->nextRemoteActionDelayProg; }