/**************************************************************************** ** ScStw Libraries ** Copyright (C) 2020 Itsblue development ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ****************************************************************************/ #include "../headers/scstwremotemonitorrace.h" ScStwRemoteMonitorRace::ScStwRemoteMonitorRace(ScStwClient *monitorClient, QObject *parent) : ScStwRace(parent) { this->scStwClient = monitorClient; connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwRemoteMonitorRace::handleClientStateChanged); connect(this->scStwClient, &ScStwClient::gotSignal, this, &ScStwRemoteMonitorRace::handleBaseStationSignal); } // -------------------------- // --- Main Functionality --- // -------------------------- int ScStwRemoteMonitorRace::start() { if(this->getState() != ScStwRace::IDLE) { return 904; } qDebug() << "+ --- starting race"; int returnCode = 900; QVariantMap reply = this->scStwClient->sendCommand(1000); if(reply["status"] != 200){ //handle Error!! returnCode = reply["status"].toInt(); } else { returnCode = 200; } return returnCode; } int ScStwRemoteMonitorRace::cancel() { return this->stop(); } int ScStwRemoteMonitorRace::stop() { if(this->getState() != ScStwRace::RUNNING && this->getState() != ScStwRace::STARTING) { return 904; } // type can be: // 0: stopp // 1: cancel // 2: fail (fase start) qDebug() << "+ --- stopping race"; int returnCode = 900; QVariantMap reply = this->scStwClient->sendCommand(1001); if(reply["status"] != 200){ returnCode = reply["status"].toInt(); } else { returnCode = 200; } return returnCode; } int ScStwRemoteMonitorRace::reset() { if(this->getState() != ScStwRace::STOPPED) { return 904; } qDebug() << "+ --- resetting race"; int returnCode = 900; QVariantMap reply = this->scStwClient->sendCommand(1002); if(reply["status"] != 200){ //handle Error!! returnCode = reply["status"].toInt(); } else { returnCode = 200; } return returnCode; } // ------------------------- // --- Base Station sync --- // ------------------------- void ScStwRemoteMonitorRace::handleClientStateChanged() { // TODO switch (this->scStwClient->getState()) { case ScStwClient::CONNECTED: break; default: this->timers.clear(); this->setState(IDLE); break; } } /** * @brief ScStwAppBackend::handleBaseStationUpdate * * Function to handle an update, sent by the base station, which indicates * that some remote value (like a state) has changed * * @param data */ void ScStwRemoteMonitorRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) { //qDebug() << "got signal: " << data; switch (key) { case ScStw::RaceStateChanged: { // the remote race state has changed this->setState( ScStwRace::RaceState( data.toInt() ) ); break; } case ScStw::TimersChanged: { // the remote timers have changed this->refreshRemoteTimers(data.toList()); break; } case ScStw::NextStartActionChanged: { // the next start action has changed this->nextStartActionTotalDelay = data.toList()[ScStwRace::NextStartActionTotalDelay].toDouble(); this->nextStartActionDelayStartedAt = QDateTime::currentMSecsSinceEpoch() - (this->nextStartActionTotalDelay * data.toList()[ScStwRace::NextStartActionDelayProgress].toDouble()); this->nextStartAction = ScStwRace::StartAction( data.toList()[ScStwRace::NextStartAction].toInt() ); emit this->nextStartActionChanged(); break; } case ScStw::InvalidSignal: return; default: return; } } bool ScStwRemoteMonitorRace::refreshRemoteTimers(QVariantList remoteTimers) { if(remoteTimers.length() != this->timers.length()){ // local timers are out of sync // delete all current timers foreach(ScStwTimer * locTimer, this->timers){ delete locTimer; } this->timers.clear(); foreach(QVariant remoteTimer, remoteTimers){ // create a local timer for each remote timer ScStwTimer * timer = new ScStwTimer(this, true); this->timers.append(timer); connect(timer, &ScStwTimer::stateChanged, this, &ScStwRace::timersChanged); connect(timer, &ScStwTimer::reactionTimeChanged, this, &ScStwRace::timersChanged); } } foreach(QVariant remoteTimer, remoteTimers){ int currId = remoteTimer.toMap()["id"].toInt(); ScStwTimer::TimerState newState = ScStwTimer::TimerState(remoteTimer.toMap()["state"].toInt()); double currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); this->timers[currId]->setStartTime(currentMSecsSinceEpoch - remoteTimer.toMap()["currentTime"].toDouble()); if(newState >= ScStwTimer::WAITING) this->timers[currId]->setStopTime(currentMSecsSinceEpoch); this->timers[currId]->setReactionTime(remoteTimer.toMap()["reactionTime"].toDouble()); this->timers[currId]->setState(newState, true); this->timers[currId]->setLetter(remoteTimer.toMap()["letter"].toString()); } return true; } bool ScStwRemoteMonitorRace::addTimer(ScStwTimer* timer) { Q_UNUSED(timer) return false; } QVariantList ScStwRemoteMonitorRace::getNextStartActionDetails() { int nextActionDelay = 0; double nextActionDelayProg = -1; if(this->nextStartAction == AtYourMarks || this->nextStartAction == Ready) { // get the total delay and the delay progress of the next action timer double elapsed = QDateTime::currentMSecsSinceEpoch() - this->nextStartActionDelayStartedAt; nextActionDelay = this->nextStartActionTotalDelay; if(elapsed < 0 || elapsed > nextActionDelay) { elapsed = nextActionDelay; } nextActionDelayProg = elapsed / nextActionDelay; } return { this->nextStartAction, nextActionDelay, nextActionDelayProg }; }