diff --git a/ScStwLibraries/headers/client/scstwclient.h b/ScStwLibraries/headers/client/scstwclient.h index e316097..ed589ab 100644 --- a/ScStwLibraries/headers/client/scstwclient.h +++ b/ScStwLibraries/headers/client/scstwclient.h @@ -101,15 +101,14 @@ private: QString readBuffer; - int nextConnectionId; + unsigned int currentRequestId; - struct waitingRequest { - int id; + struct WaitingRequest { QEventLoop * loop; QJsonObject reply; }; - QList waitingRequests; + QMap waitingRequests; public slots: @@ -152,7 +151,7 @@ public slots: * \param key the key to read from * \return the value of the key or "false" if the key is not found or an error occured */ - QVariant readRemoteSetting(ScStwSettings::BaseStationSetting key); + QVariant readRemoteSetting(ScStwSettings::BaseStationSetting key, ScStw::StatusCode* status = nullptr); /*! Getter fuctions */ diff --git a/ScStwLibraries/headers/scstwsetting.h b/ScStwLibraries/headers/scstwsetting.h index bd57cd7..6a7b36c 100644 --- a/ScStwLibraries/headers/scstwsetting.h +++ b/ScStwLibraries/headers/scstwsetting.h @@ -28,6 +28,7 @@ class ScStwSetting : public QObject { Q_OBJECT Q_PROPERTY(QVariant value READ getValue WRITE setValue NOTIFY valueChanged) + Q_PROPERTY(QVariant readonlyValue READ getValue NOTIFY valueChanged) protected: explicit ScStwSetting(int key, int keyLevel, ScStwSettings*scStwSettings, QObject *parent); diff --git a/ScStwLibraries/sources/client/scstwclient.cpp b/ScStwLibraries/sources/client/scstwclient.cpp index cf12a27..c705b46 100644 --- a/ScStwLibraries/sources/client/scstwclient.cpp +++ b/ScStwLibraries/sources/client/scstwclient.cpp @@ -23,7 +23,7 @@ ScStwClient * pGlobalScStwClient = nullptr; ScStwClient::ScStwClient(QObject * parent, QList signalSubscriptions) : QObject(parent) { this->state = DISCONNECTED; - this->nextConnectionId = 1; + this->currentRequestId = 1; this->extensions = QVariantMap({}); this->signalSubscriptions = signalSubscriptions; @@ -50,6 +50,9 @@ ScStwClient::ScStwClient(QObject * parent, QList signalSubscri void ScStwClient::connectToHost() { + if(this->state != DISCONNECTED) + return; + setState(CONNECTING); //connect @@ -84,7 +87,6 @@ bool ScStwClient::init() { QVariantMap initResponse = this->sendCommand(1, sessionParams, 3000, false); if(initResponse["status"] != 200) { - this->closeConnection(); return false; } @@ -121,7 +123,17 @@ void ScStwClient::deInit() { if(this->state == DISCONNECTED) return; + this->currentRequestId = 1; + this->firmwareVersion = ""; + this->apiVersion = ""; this->setExtensions(QVariantMap({})); + + for(WaitingRequest waitingRequest : this->waitingRequests.values()) + if(waitingRequest.loop != nullptr) + waitingRequest.loop->exit(ScStw::NotConnectedError); + + this->waitingRequests.clear(); + this->setState(DISCONNECTED); } @@ -160,16 +172,22 @@ QVariantMap ScStwClient::sendCommand(int header, QJsonValue data, int timeout, b return {{"status", ScStw::NotConnectedError}, {"data", "not connected"}}; } - // generate id and witing requests entry - int thisId = nextConnectionId; + // pick a new request id that is not already active + do { + if(this->currentRequestId >= 99) + this->currentRequestId = 0; + else + this->currentRequestId ++; + } while(this->waitingRequests.contains(this->currentRequestId)); + + int thisId = currentRequestId; //qDebug() << "sending command: " << header << " with data: " << data << " and id: " << thisId; - nextConnectionId ++; QEventLoop *loop = new QEventLoop(this); QTimer *timer = new QTimer(this); QJsonObject reply; - this->waitingRequests.append({thisId, loop, reply}); + this->waitingRequests.insert(thisId, {loop, reply}); QJsonObject requestObj; requestObj.insert("id", thisId); @@ -180,7 +198,7 @@ QVariantMap ScStwClient::sendCommand(int header, QJsonValue data, int timeout, b timer->setSingleShot(true); // quit the loop when the timer times out - loop->connect(timer, SIGNAL(timeout()), loop, SLOT(quit())); + connect(timer, &QTimer::timeout, [=]{loop->exit(ScStw::TimeoutError);}); // start the timer before starting to connect timer->start(timeout); @@ -191,37 +209,38 @@ QVariantMap ScStwClient::sendCommand(int header, QJsonValue data, int timeout, b socket->write(jsonRequest.toUtf8()); //wait for an answer to finish (programm gets stuck in here) - loop->exec(); + ScStw::StatusCode statusCode = ScStw::StatusCode(loop->exec()); - - - bool replyFound = false; + // delete the timer + timer->deleteLater(); // find reply and delete the request from waiting list - for(int i = 0; iwaitingRequests.length(); i++){ - if(this->waitingRequests[i].id == thisId){ - // request was found - replyFound = true; - // delete event loop - if(this->waitingRequests[i].loop != nullptr) { - delete this->waitingRequests[i].loop; - } - // store reply - reply = this->waitingRequests[i].reply; - // remove reply from waiting list - this->waitingRequests.removeAt(i); + if(this->waitingRequests.contains(thisId)) { + // request was found + // delete event loop + if(this->waitingRequests[thisId].loop != nullptr) { + this->waitingRequests[thisId].loop->deleteLater(); } - } - if(!replyFound) { + // store reply + reply = this->waitingRequests[thisId].reply; + + // remove reply from waiting list + this->waitingRequests.remove(thisId); + } + else { // some internal error occured - return {{"status", ScStw::Error}, {"data", ""}}; + return {{"status", ScStw::InternalError}, {"data", ""}}; } - if(timer->remainingTime() == -1){ + if(statusCode == ScStw::TimeoutError){ //the time has been triggered -> timeout return {{"status", ScStw::TimeoutError}, {"data", ""}}; } + else if(statusCode == ScStw::NotConnectedError) { + // connection was closed during request + return {{"status", ScStw::NotConnectedError}, {"data", ""}}; + } delete timer; return {{"status", reply.value("header").toInt()}, {"data", reply.value("data").toVariant()}}; @@ -273,7 +292,6 @@ void ScStwClient::handleReadyRead() { //qDebug() << "ready to ready " << socket->bytesAvailable() << " bytes" ; QString reply = socket->readAll(); - //qWarning() << "socket read: " << reply; processSocketMessage(reply); @@ -335,7 +353,7 @@ void ScStwClient::handleSocketMessage(QString reply) { reply.replace(ScStw::SOCKET_MESSAGE_START_KEY, ""); reply.replace(ScStw::SOCKET_MESSAGE_END_KEY, ""); - //qDebug() << "got message: " << reply; + qDebug() << "got message: " << qPrintable(reply); int id = 0; @@ -352,14 +370,12 @@ void ScStwClient::handleSocketMessage(QString reply) { } // this message is the reply to a command! - for(int i = 0; i < this->waitingRequests.length(); i++){ - if(this->waitingRequests[i].id == id){ - this->waitingRequests[i].reply = replyObj; - if(this->waitingRequests[i].loop != nullptr){ - this->waitingRequests[i].loop->quit(); - } - return; + if(this->waitingRequests.contains(id)){ + this->waitingRequests[id].reply = replyObj; + if(this->waitingRequests[id].loop != nullptr){ + this->waitingRequests[id].loop->exit(ScStw::Success); } + return; } } @@ -404,8 +420,13 @@ ScStw::StatusCode ScStwClient::writeRemoteSetting(ScStwSettings::BaseStationSett return ScStw::StatusCode(this->sendCommand(3000, requestData)["status"].toInt()); } -QVariant ScStwClient::readRemoteSetting(ScStwSettings::BaseStationSetting key) { - QVariantMap reply = this->sendCommand(3001, int(key)); +QVariant ScStwClient::readRemoteSetting(ScStwSettings::BaseStationSetting key, ScStw::StatusCode* status) { + QVariantMap reply = this->sendCommand(3001, int(key), 10000); + qDebug() << "Setting read status is: " << reply["status"]; + + if(status != nullptr) + *status = ScStw::StatusCode(reply["status"].toInt()); + if(reply["status"] != 200){ return "false"; } diff --git a/ScStwLibraries/sources/client/scstwremoterace.cpp b/ScStwLibraries/sources/client/scstwremoterace.cpp index 65bad83..53b3f54 100644 --- a/ScStwLibraries/sources/client/scstwremoterace.cpp +++ b/ScStwLibraries/sources/client/scstwremoterace.cpp @@ -102,8 +102,8 @@ ScStw::StatusCode ScStwRemoteRace::setTimerDisabled(int timerId, bool disabled) qDebug() << "+ --- setting timer " << timerId << " to disabled: " << disabled; QVariantMap requestData = { - {"timerId", timerId}, - {"disabled", disabled} + {"timerId", timerId}, + {"disabled", disabled} }; QVariantMap reply = this->scStwClient->sendCommand(ScStw::SetTimerDisabledCommand, QJsonValue::fromVariant(requestData)); @@ -125,11 +125,12 @@ void ScStwRemoteRace::handleClientStateChange() { // delete all obsolete remote timers for(ScStwRemoteTimer* oldRemoteTimer : this->remoteTimers) oldRemoteTimer->deleteLater(); + this->remoteTimers.clear(); break; case ScStwClient::DISCONNECTED: this->remoteTimers.clear(); - this->setTimers(this->localTimers, true); + this->setTimers(this->localTimers, false); emit this->timersChanged(); emit this->detailsChanged(); emit this->currentStartDelayChanged(); @@ -141,6 +142,30 @@ void ScStwRemoteRace::handleClientStateChange() { } } +void ScStwRemoteRace::setTimers(QList timers, bool deleteOldTimers) { + + // disconnect all signals of all current timers + //qDebug() << "SETTING TIMERS"; + + foreach(ScStwTimer *existingTimer, this->timers) { + disconnect(existingTimer, &ScStwTimer::stateChanged, this, &ScStwRace::handleTimerStateChange); + disconnect(existingTimer, &ScStwTimer::stateChanged, this, &ScStwRace::timersChanged); + disconnect(existingTimer, &ScStwTimer::wantsToBeDisabledChanged, this, &ScStwRace::handleTimerWantsToBeDisabledChange); + disconnect(existingTimer, &ScStwTimer::reactionTimeChanged, this, &ScStwRace::timersChanged); + disconnect(existingTimer, &ScStwTimer::readyStateChanged, this, &ScStwRace::handleTimerReadyStateChange); + disconnect(existingTimer, &ScStwTimer::readyStateChanged, this, &ScStwRace::isReadyForNextStateChanged); + + if(deleteOldTimers) + existingTimer->deleteLater(); + } + + this->timers.clear(); + + for(ScStwTimer* timer : timers) { + this->addTimer(timer); + } +} + ScStwRemoteRace::RaceMode ScStwRemoteRace::getMode() { if(this->scStwClient == nullptr || this->scStwClient->getState() != ScStwClient::CONNECTED) return LOCAL; @@ -233,43 +258,43 @@ void ScStwRemoteRace::rebuildRemoteTimers(QVariantList remoteTimers) { } } -bool ScStwRemoteRace::refreshRemoteTimers(QVariantList remoteTimers) { +bool ScStwRemoteRace::refreshRemoteTimers(QVariantList newRemoteTimers) { qDebug() << "REFRESHING TIMERS"; - if(remoteTimers.length() != this->remoteTimers.length()){ - // local timers are out of sync - this->rebuildRemoteTimers(remoteTimers); - qDebug() << "rebuilding remote timers"; - } + if(newRemoteTimers.length() != this->remoteTimers.length()){ + // local timers are out of sync + this->rebuildRemoteTimers(newRemoteTimers); + qDebug() << "rebuilding remote timers"; + } - foreach(QVariant remoteTimer, remoteTimers){ - int currId = remoteTimer.toMap()["id"].toInt(); + for(QVariant remoteTimer : newRemoteTimers){ + int currId = remoteTimer.toMap()["id"].toInt(); - if(this->remoteTimers.length() <= currId) - this->rebuildRemoteTimers(remoteTimers); + if(this->remoteTimers.length() <= currId) + this->rebuildRemoteTimers(newRemoteTimers); - ScStwTimer::TimerState newState = ScStwTimer::TimerState(remoteTimer.toMap()["state"].toInt()); + ScStwTimer::TimerState newState = ScStwTimer::TimerState(remoteTimer.toMap()["state"].toInt()); - qDebug() << "refreshing timers: id: " << currId << " state: " << newState << " readyState: " << remoteTimer.toMap()["readyState"].toInt() << " currentTime: " << remoteTimer.toMap()["currentTime"].toDouble(); + qDebug() << "refreshing timers: id: " << currId << " state: " << newState << " readyState: " << remoteTimer.toMap()["readyState"].toInt() << " currentTime: " << remoteTimer.toMap()["currentTime"].toDouble(); - double currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); + double currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); - this->remoteTimers[currId]->setStartTime(currentMSecsSinceEpoch - remoteTimer.toMap()["currentTime"].toDouble()); + this->remoteTimers[currId]->setStartTime(currentMSecsSinceEpoch - remoteTimer.toMap()["currentTime"].toDouble()); - if(newState >= ScStwTimer::WAITING) - this->remoteTimers[currId]->setStopTime(currentMSecsSinceEpoch); + if(newState >= ScStwTimer::WAITING) + this->remoteTimers[currId]->setStopTime(currentMSecsSinceEpoch); - this->remoteTimers[currId]->setReactionTime(remoteTimer.toMap()["reactionTime"].toDouble()); - this->remoteTimers[currId]->setLetter(remoteTimer.toMap()["letter"].toString()); - this->remoteTimers[currId]->setReadyState(ScStwTimer::ReadyState(remoteTimer.toMap()["readyState"].toInt())); + this->remoteTimers[currId]->setReactionTime(remoteTimer.toMap()["reactionTime"].toDouble()); + this->remoteTimers[currId]->setLetter(remoteTimer.toMap()["letter"].toString()); + this->remoteTimers[currId]->setReadyState(ScStwTimer::ReadyState(remoteTimer.toMap()["readyState"].toInt())); - this->remoteTimers[currId]->setState(newState); - } + this->remoteTimers[currId]->setState(newState); + } - emit this->timersChanged(); + emit this->timersChanged(); - return true; + return true; } bool ScStwRemoteRace::addTimer(ScStwTimer* timer) { @@ -281,30 +306,6 @@ bool ScStwRemoteRace::addTimer(ScStwTimer* timer) { return false; } -void ScStwRemoteRace::setTimers(QList timers, bool deleteOldTimers) { - - // disconnect all signals of all current timers - qDebug() << "SETTING TIMERS"; - - foreach(ScStwTimer *existingTimer, this->timers) { - disconnect(existingTimer, &ScStwTimer::stateChanged, this, &ScStwRace::handleTimerStateChange); - disconnect(existingTimer, &ScStwTimer::stateChanged, this, &ScStwRace::timersChanged); - disconnect(existingTimer, &ScStwTimer::wantsToBeDisabledChanged, this, &ScStwRace::handleTimerWantsToBeDisabledChange); - disconnect(existingTimer, &ScStwTimer::reactionTimeChanged, this, &ScStwRace::timersChanged); - disconnect(existingTimer, &ScStwTimer::readyStateChanged, this, &ScStwRace::handleTimerReadyStateChange); - disconnect(existingTimer, &ScStwTimer::readyStateChanged, this, &ScStwRace::isReadyForNextStateChanged); - - if(deleteOldTimers) - existingTimer->deleteLater(); - } - - this->timers.clear(); - - for(ScStwTimer* timer : timers) { - this->addTimer(timer); - } -} - QVariantMap ScStwRemoteRace::getCurrentStartDelay() { if(this->local()) return ScStwRace::getCurrentStartDelay(); diff --git a/ScStwLibraries/sources/client/scstwremotesettings.cpp b/ScStwLibraries/sources/client/scstwremotesettings.cpp index db5afb9..ca30b92 100644 --- a/ScStwLibraries/sources/client/scstwremotesettings.cpp +++ b/ScStwLibraries/sources/client/scstwremotesettings.cpp @@ -41,7 +41,13 @@ QVariant ScStwRemoteSettings::readSetting(QString key, int keyInt, int keyLevel) qDebug() << "Setting read: keyLevel: " << keyLevel << " key: " << key; - return this->scStwClient->readRemoteSetting(ScStwSettings::BaseStationSetting(keyInt)); + ScStw::StatusCode status; + QVariant value = this->scStwClient->readRemoteSetting(ScStwSettings::BaseStationSetting(keyInt), &status); + + if(status == ScStw::Success) + return value; + else + return QVariant(); } bool ScStwRemoteSettings::writeSetting(QString key, QVariant value, int keyInt, int keyLevel) { @@ -66,8 +72,8 @@ bool ScStwRemoteSettings::setDefaultSetting(QString key, QVariant defaultVariant void ScStwRemoteSettings::handleClientStateChange() { if(this->scStwClient->getState() == ScStwClient::DISCONNECTED) emit this->settingChanged(-1, ScStwSettings::KeyLevel, QVariant()); - else if(this->scStwClient->getState() == ScStwClient::CONNECTED) - emit this->settingChanged(-1, ScStwSettings::KeyLevel, QVariant()); + // Dont't need to do that when changing to connected, + // as the basestation emits a wildcrd setting changed on connect anyway } void ScStwRemoteSettings::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) { diff --git a/ScStwLibraries/sources/scstwrace.cpp b/ScStwLibraries/sources/scstwrace.cpp index 567a794..b576d81 100644 --- a/ScStwLibraries/sources/scstwrace.cpp +++ b/ScStwLibraries/sources/scstwrace.cpp @@ -172,7 +172,7 @@ ScStw::StatusCode ScStwRace::setTimerDisabled(int timerId, bool disabled) { } ScStw::StatusCode ScStwRace::setTimerDisabled(ScStwTimer* timer, bool disabled) { - qDebug() << "[INFO][RACE] Setting timer "<< timer->getLetter() << " to disabled: " << disabled << " this state: " << this->state; + //qDebug() << "[INFO][RACE] Setting timer "<< timer->getLetter() << " to disabled: " << disabled << " this state: " << this->state; if(this->state != IDLE && this->state != WAITING) return ScStw::CurrentStateNotVaildForOperationError; @@ -189,7 +189,7 @@ ScStw::StatusCode ScStwRace::setTimerDisabled(ScStwTimer* timer, bool disabled) if(disabled && enabledTimerCount <= 1) return ScStw::LastTimerCannotBeDisabledError; - qDebug() << "[INFO][RACE] Setting timer "<< timer->getLetter() << " to disabled: " << disabled; + //qDebug() << "[INFO][RACE] Setting timer "<< timer->getLetter() << " to disabled: " << disabled; timer->setDisabled(disabled); @@ -623,13 +623,12 @@ bool ScStwRace::getIsReadyForNextState() { * @param {ScStwExtensionControlledTimer*} timer timer to be enabled */ void ScStwRace::handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled) { - qDebug() << "Handling timer wants to be disabled"; + //qDebug() << "Handling timer wants to be disabled"; if(this->competitionMode) return; if(this->state == IDLE) { - - qDebug() << "Handling timer wants to be disabled: " << wantsToBeDisabled; + //qDebug() << "Handling timer wants to be disabled: " << wantsToBeDisabled; this->setTimerDisabled(timer, wantsToBeDisabled); } } diff --git a/ScStwLibraries/sources/scstwsetting.cpp b/ScStwLibraries/sources/scstwsetting.cpp index 7880326..83e3ed3 100644 --- a/ScStwLibraries/sources/scstwsetting.cpp +++ b/ScStwLibraries/sources/scstwsetting.cpp @@ -30,6 +30,7 @@ ScStwSetting::ScStwSetting(int key, int keyLevel, ScStwSettings*scStwSettings, Q } QVariant ScStwSetting::getValue() { + qDebug() << "Getting setting: " << this->key << " has to reload: " << this->hasToReload; if(this->hasToReload) { this->valueCache = this->scStwSettings->readSetting(this->key, this->keyLevel); this->hasToReload = false; diff --git a/ScStwLibraries/sources/scstwtimer.cpp b/ScStwLibraries/sources/scstwtimer.cpp index c3b2c03..f426313 100644 --- a/ScStwLibraries/sources/scstwtimer.cpp +++ b/ScStwLibraries/sources/scstwtimer.cpp @@ -29,7 +29,7 @@ ScStwTimer::ScStwTimer(QString letter, QObject *parent) : QObject(parent) else this->letter = letter; - qDebug() << "Timer created with letter: " << letter; + //qDebug() << "Timer created with letter: " << letter; this->startTime = 0; this->stopTime = 0;