diff --git a/ScStwLibraries/headers/client/scstwremoterace.h b/ScStwLibraries/headers/client/scstwremoterace.h index 42c68dc..9c89e56 100644 --- a/ScStwLibraries/headers/client/scstwremoterace.h +++ b/ScStwLibraries/headers/client/scstwremoterace.h @@ -23,6 +23,7 @@ #include "scstwrace.h" #include "scstwclient.h" #include "scstwremotetimer.h" +#include "scstwsoundplayer.h" class ScStwRemoteRace : public ScStwRace { @@ -34,6 +35,7 @@ protected: double currentStartTotalDelay; double currentStartDelayStartedAt; bool currentlyWaitingForClimbers; + bool isReadyForNextState; private: ScStwClient *scStwClient; @@ -47,11 +49,13 @@ public slots: ScStw::StatusCode reset(); bool addTimer(ScStwTimer *timer); QVariantList getCurrentStartDelay(); + bool getIsReadyForNextState(); private slots: void handleClientStateChanged(); void handleBaseStationSignal(ScStw::SignalKey key, QVariant data); bool refreshRemoteTimers(QVariantList remoteTimers); + void refreshDetails(QVariantMap details); }; diff --git a/ScStwLibraries/headers/scstwrace.h b/ScStwLibraries/headers/scstwrace.h index 78b5c44..6d9b682 100644 --- a/ScStwLibraries/headers/scstwrace.h +++ b/ScStwLibraries/headers/scstwrace.h @@ -26,6 +26,8 @@ #include "scstwtimer.h" #include "scstwsoundplayer.h" +class ScStwRemoteRace; + /*! * \brief The ScStwRace class can be used to measure timings of climbing races with multiple lanes at once. * @@ -52,12 +54,14 @@ class ScStwRace : public QObject Q_PROPERTY(RaceState state READ getState NOTIFY stateChanged) Q_PROPERTY(QVariantList timers READ getTimerDetailList NOTIFY timersChanged) Q_PROPERTY(QVariantList currentStartDelay READ getCurrentStartDelay NOTIFY currentStartDelayChanged) - Q_PROPERTY(bool isReadyForNextState READ isReadyForNextState NOTIFY isReadyForNextStateChanged) + Q_PROPERTY(bool isReadyForNextState READ getIsReadyForNextState NOTIFY isReadyForNextStateChanged) Q_PROPERTY(QVariantMap details READ getDetails NOTIFY detailsChanged) public: explicit ScStwRace(QObject *parent = nullptr); + friend class ScStwRemoteRace; + enum RaceState { IDLE, PREPAIRING, WAITING, STARTING, RUNNING, STOPPED, INCIDENT }; Q_ENUM(RaceState) @@ -154,7 +158,7 @@ private slots: void handleTimerStop(); bool isStarting(); - bool isReadyForNextState(); + virtual bool getIsReadyForNextState(); void handleTimerReadyStateChange(ScStwTimer::ReadyState readyState); signals: @@ -164,11 +168,8 @@ signals: void stateChanged(RaceState state); void currentStartDelayChanged(); void timersChanged(); -<<<<<<< HEAD void isReadyForNextStateChanged(); -======= void detailsChanged(); ->>>>>>> origin/master }; diff --git a/ScStwLibraries/headers/scstwsoundplayer.h b/ScStwLibraries/headers/scstwsoundplayer.h index ac05926..82a8436 100644 --- a/ScStwLibraries/headers/scstwsoundplayer.h +++ b/ScStwLibraries/headers/scstwsoundplayer.h @@ -110,7 +110,7 @@ public slots: * \param volume the volume to play the false start sound at * \return true if the playback was successfully stopped, false otherwise */ - bool cancel(double volume = 0); + bool cancel(); private slots: diff --git a/ScStwLibraries/sources/client/scstwremoterace.cpp b/ScStwLibraries/sources/client/scstwremoterace.cpp index 13f94ba..a8f53e2 100644 --- a/ScStwLibraries/sources/client/scstwremoterace.cpp +++ b/ScStwLibraries/sources/client/scstwremoterace.cpp @@ -21,12 +21,11 @@ ScStwRemoteRace::ScStwRemoteRace(ScStwClient *monitorClient, QObject *parent) : ScStwRace(parent) { this->currentlyWaitingForClimbers = false; + this->isReadyForNextState = true; this->scStwClient = monitorClient; - this->scStwClient->addSignalSubscription(ScStw::RaceStateChanged); - this->scStwClient->addSignalSubscription(ScStw::TimersChanged); - this->scStwClient->addSignalSubscription(ScStw::CurrentStartDelayChanged); + this->scStwClient->addSignalSubscription(ScStw::RaceDetailsChanged); connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwRemoteRace::handleClientStateChanged); connect(this->scStwClient, &ScStwClient::gotSignal, this, &ScStwRemoteRace::handleBaseStationSignal); @@ -112,39 +111,48 @@ void ScStwRemoteRace::handleClientStateChanged() { void ScStwRemoteRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) { //qDebug() << "got signal: " << data; switch (key) { - case ScStw::RaceStateChanged: + case ScStw::RaceDetailsChanged: { - // the remote race state has changed - this->setState( ScStwRace::RaceState( data.toInt() ) ); + this->refreshDetails(data.toMap()); break; } - case ScStw::TimersChanged: - { - // the remote timers have changed - this->refreshRemoteTimers(data.toList()); - break; - } - case ScStw::CurrentStartDelayChanged: - { - // the next start action has changed - this->currentStartTotalDelay = data.toList()[ScStwRace::CurrentStartStateTotalDelay].toInt(); - this->currentStartDelayStartedAt = QDateTime::currentMSecsSinceEpoch() - (this->currentStartTotalDelay * data.toList()[ScStwRace::CurrentStartStateDelayProgress].toDouble()); - this->currentlyWaitingForClimbers = data.toList()[ScStwRace::CurrentStartStateDelayProgress].toDouble() == 0 && this->currentStartTotalDelay == -1; - - emit this->currentStartDelayChanged(); - - qDebug() << "Current start delay changed: total:" << this->currentStartTotalDelay << " progress: " << data.toList()[ScStwRace::CurrentStartStateDelayProgress].toDouble(); - - break; - } - case ScStw::InvalidSignal: - return; - default: return; } } +void ScStwRemoteRace::refreshDetails(QVariantMap details) { + // the details of the race have changed: + + // state + this->setState(ScStwRace::RaceState(details["state"].toInt())); + + // competition mode + this->competitionMode = details["competitionMode"].toBool(); + + // ready sound enabled + this->writeStartSoundSetting(ScStwSoundPlayer::Ready, details["readySoundEnabled"].toBool(), 0); + + // current start delay + this->currentStartTotalDelay = details["currentStartDelay"].toList()[ScStwRace::CurrentStartStateTotalDelay].toInt(); + this->currentStartDelayStartedAt = QDateTime::currentMSecsSinceEpoch() - (this->currentStartTotalDelay * details["currentStartDelay"].toList()[ScStwRace::CurrentStartStateDelayProgress].toDouble()); + this->currentlyWaitingForClimbers = details["currentStartDelay"].toList()[ScStwRace::CurrentStartStateDelayProgress].toDouble() == 0 && this->currentStartTotalDelay == -1; + + emit this->currentStartDelayChanged(); + + // timers + this->refreshRemoteTimers(details["timers"].toList()); + + // isReady + if(this->state == WAITING) { + this->isReadyForNextState = details["isReadyForNextState"].toBool(); + emit this->isReadyForNextStateChanged(); + } + + emit this->detailsChanged(); + +} + bool ScStwRemoteRace::refreshRemoteTimers(QVariantList remoteTimers) { if(remoteTimers.length() != this->timers.length()){ @@ -218,3 +226,7 @@ QVariantList ScStwRemoteRace::getCurrentStartDelay() { nextActionDelayProg }; } + +bool ScStwRemoteRace::getIsReadyForNextState() { + return this->isReadyForNextState; +} diff --git a/ScStwLibraries/sources/scstwrace.cpp b/ScStwLibraries/sources/scstwrace.cpp index f5dd736..6f6ae98 100644 --- a/ScStwLibraries/sources/scstwrace.cpp +++ b/ScStwLibraries/sources/scstwrace.cpp @@ -34,6 +34,7 @@ ScStwRace::ScStwRace(QObject *parent) : QObject(parent) connect(this, &ScStwRace::currentStartDelayChanged, this, &ScStwRace::detailsChanged); connect(this, &ScStwRace::timersChanged, this, &ScStwRace::detailsChanged); + connect(this, &ScStwRace::stateChanged, this, &ScStwRace::detailsChanged); // write default settings this->startSoundSettings.insert(ScStwSoundPlayer::Start, {{"Enabled", true}, {"Delay", 1}}); @@ -49,7 +50,7 @@ ScStwRace::ScStwRace(QObject *parent) : QObject(parent) ScStw::StatusCode ScStwRace::start(bool asyncronous) { if(this->state == WAITING) { - if(this->isReadyForNextState()) { + if(this->getIsReadyForNextState()) { this->startWaitLoop->exit(LoopManualExit); return ScStw::Success; } @@ -61,7 +62,7 @@ ScStw::StatusCode ScStwRace::start(bool asyncronous) { return ScStw::CurrentStateNotVaildForOperationError; } - if(!this->isReadyForNextState()) + if(!this->getIsReadyForNextState()) return ScStw::TimersNotReadyError; this->setState(PREPAIRING); @@ -181,7 +182,7 @@ ScStw::StatusCode ScStwRace::cancel() { this->setState(STOPPED); this->startWaitLoop->exit(LoopCancelExit); - this->soundPlayer->cancel(this->soundVolume); + this->soundPlayer->cancel(); this->startDelayTimer->stop(); emit this->currentStartDelayChanged(); @@ -246,7 +247,7 @@ bool ScStwRace::playSoundsAndStartTimers() { bool timerTriggered = true; do { - if(!this->isReadyForNextState()) { + if(!this->getIsReadyForNextState()) { this->startDelayTimer->stop(); timerTriggered = false; } @@ -276,7 +277,7 @@ bool ScStwRace::playSoundsAndStartTimers() { //qDebug() << "At end of loop: remaining time: " << this->startDelayTimer->remainingTime() << " timer triggered: " << timerTriggered << " ready for next state: " << this->isReadyForNextState(); - } while(this->startDelayTimer->remainingTime() > 0 || !timerTriggered || !this->isReadyForNextState()); + } while(this->startDelayTimer->remainingTime() > 0 || !timerTriggered || !this->getIsReadyForNextState()); qDebug() << "[RACE][DEBUG] Wait finished, starting now!"; @@ -296,7 +297,7 @@ bool ScStwRace::playSoundsAndStartTimers() { if(loopExitCode == LoopCancelExit) return false; - } while(loopExitCode != LoopManualExit || !this->isReadyForNextState()); + } while(loopExitCode != LoopManualExit || !this->getIsReadyForNextState()); } else { qDebug() << "now playing ready sound"; @@ -449,7 +450,7 @@ void ScStwRace::refreshTimerStates() { // --- helper functions --- // ------------------------ -bool ScStwRace::isReadyForNextState() { +bool ScStwRace::getIsReadyForNextState() { if(!this->competitionMode) { return true; } @@ -542,7 +543,7 @@ QVariantList ScStwRace::getCurrentStartDelay() { int nextActionDelay = -1; double nextActionDelayProg = -1; - if(this->state == WAITING && !this->isReadyForNextState()) { + if(this->state == WAITING && !this->getIsReadyForNextState()) { // indicate that we are waiting for climbers and the progress shall be zero nextActionDelayProg = 0; } @@ -645,13 +646,14 @@ QVariantList ScStwRace::getTimerDetailList() { QVariantMap ScStwRace::getDetails() { QVariantMap tmpDetails; - tmpDetails.insert("timers", this->getTimerDetailList()); - tmpDetails.insert("currentStartDelay", this->getCurrentStartDelay()); + tmpDetails.insert("state", this->getState()); tmpDetails.insert("competitionMode", this->competitionMode); tmpDetails.insert("readySoundEnabled", this->startSoundSettings[ScStwSoundPlayer::Ready]["Enabled"].toBool()); + tmpDetails.insert("currentStartDelay", this->getCurrentStartDelay()); + tmpDetails.insert("timers", this->getTimerDetailList()); if(this->state == WAITING) - tmpDetails.insert("isReady", this->isReadyForNextState()); + tmpDetails.insert("isReadyForNextState", this->getIsReadyForNextState()); return tmpDetails; } diff --git a/ScStwLibraries/sources/scstwsoundplayer.cpp b/ScStwLibraries/sources/scstwsoundplayer.cpp index 07de6f0..943513b 100644 --- a/ScStwLibraries/sources/scstwsoundplayer.cpp +++ b/ScStwLibraries/sources/scstwsoundplayer.cpp @@ -79,13 +79,15 @@ bool ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, d return true; } -bool ScStwSoundPlayer::cancel(double volume) { +bool ScStwSoundPlayer::cancel() { if(!this->soundEffect->isPlaying() ) return false; // stop playback this->soundEffect->stop(); this->waitLoop->quit(); + + return true; } bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {