implemented race details
This commit is contained in:
parent
3c626b82da
commit
c9e1f4f8ec
6 changed files with 67 additions and 46 deletions
|
@ -23,6 +23,7 @@
|
||||||
#include "scstwrace.h"
|
#include "scstwrace.h"
|
||||||
#include "scstwclient.h"
|
#include "scstwclient.h"
|
||||||
#include "scstwremotetimer.h"
|
#include "scstwremotetimer.h"
|
||||||
|
#include "scstwsoundplayer.h"
|
||||||
|
|
||||||
class ScStwRemoteRace : public ScStwRace
|
class ScStwRemoteRace : public ScStwRace
|
||||||
{
|
{
|
||||||
|
@ -34,6 +35,7 @@ protected:
|
||||||
double currentStartTotalDelay;
|
double currentStartTotalDelay;
|
||||||
double currentStartDelayStartedAt;
|
double currentStartDelayStartedAt;
|
||||||
bool currentlyWaitingForClimbers;
|
bool currentlyWaitingForClimbers;
|
||||||
|
bool isReadyForNextState;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ScStwClient *scStwClient;
|
ScStwClient *scStwClient;
|
||||||
|
@ -47,11 +49,13 @@ public slots:
|
||||||
ScStw::StatusCode reset();
|
ScStw::StatusCode reset();
|
||||||
bool addTimer(ScStwTimer *timer);
|
bool addTimer(ScStwTimer *timer);
|
||||||
QVariantList getCurrentStartDelay();
|
QVariantList getCurrentStartDelay();
|
||||||
|
bool getIsReadyForNextState();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleClientStateChanged();
|
void handleClientStateChanged();
|
||||||
void handleBaseStationSignal(ScStw::SignalKey key, QVariant data);
|
void handleBaseStationSignal(ScStw::SignalKey key, QVariant data);
|
||||||
bool refreshRemoteTimers(QVariantList remoteTimers);
|
bool refreshRemoteTimers(QVariantList remoteTimers);
|
||||||
|
void refreshDetails(QVariantMap details);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "scstwtimer.h"
|
#include "scstwtimer.h"
|
||||||
#include "scstwsoundplayer.h"
|
#include "scstwsoundplayer.h"
|
||||||
|
|
||||||
|
class ScStwRemoteRace;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The ScStwRace class can be used to measure timings of climbing races with multiple lanes at once.
|
* \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(RaceState state READ getState NOTIFY stateChanged)
|
||||||
Q_PROPERTY(QVariantList timers READ getTimerDetailList NOTIFY timersChanged)
|
Q_PROPERTY(QVariantList timers READ getTimerDetailList NOTIFY timersChanged)
|
||||||
Q_PROPERTY(QVariantList currentStartDelay READ getCurrentStartDelay NOTIFY currentStartDelayChanged)
|
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)
|
Q_PROPERTY(QVariantMap details READ getDetails NOTIFY detailsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScStwRace(QObject *parent = nullptr);
|
explicit ScStwRace(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
friend class ScStwRemoteRace;
|
||||||
|
|
||||||
enum RaceState { IDLE, PREPAIRING, WAITING, STARTING, RUNNING, STOPPED, INCIDENT };
|
enum RaceState { IDLE, PREPAIRING, WAITING, STARTING, RUNNING, STOPPED, INCIDENT };
|
||||||
Q_ENUM(RaceState)
|
Q_ENUM(RaceState)
|
||||||
|
|
||||||
|
@ -154,7 +158,7 @@ private slots:
|
||||||
void handleTimerStop();
|
void handleTimerStop();
|
||||||
|
|
||||||
bool isStarting();
|
bool isStarting();
|
||||||
bool isReadyForNextState();
|
virtual bool getIsReadyForNextState();
|
||||||
void handleTimerReadyStateChange(ScStwTimer::ReadyState readyState);
|
void handleTimerReadyStateChange(ScStwTimer::ReadyState readyState);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -164,11 +168,8 @@ signals:
|
||||||
void stateChanged(RaceState state);
|
void stateChanged(RaceState state);
|
||||||
void currentStartDelayChanged();
|
void currentStartDelayChanged();
|
||||||
void timersChanged();
|
void timersChanged();
|
||||||
<<<<<<< HEAD
|
|
||||||
void isReadyForNextStateChanged();
|
void isReadyForNextStateChanged();
|
||||||
=======
|
|
||||||
void detailsChanged();
|
void detailsChanged();
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -110,7 +110,7 @@ public slots:
|
||||||
* \param volume the volume to play the false start sound at
|
* \param volume the volume to play the false start sound at
|
||||||
* \return true if the playback was successfully stopped, false otherwise
|
* \return true if the playback was successfully stopped, false otherwise
|
||||||
*/
|
*/
|
||||||
bool cancel(double volume = 0);
|
bool cancel();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,11 @@
|
||||||
ScStwRemoteRace::ScStwRemoteRace(ScStwClient *monitorClient, QObject *parent) : ScStwRace(parent)
|
ScStwRemoteRace::ScStwRemoteRace(ScStwClient *monitorClient, QObject *parent) : ScStwRace(parent)
|
||||||
{
|
{
|
||||||
this->currentlyWaitingForClimbers = false;
|
this->currentlyWaitingForClimbers = false;
|
||||||
|
this->isReadyForNextState = true;
|
||||||
|
|
||||||
this->scStwClient = monitorClient;
|
this->scStwClient = monitorClient;
|
||||||
|
|
||||||
this->scStwClient->addSignalSubscription(ScStw::RaceStateChanged);
|
this->scStwClient->addSignalSubscription(ScStw::RaceDetailsChanged);
|
||||||
this->scStwClient->addSignalSubscription(ScStw::TimersChanged);
|
|
||||||
this->scStwClient->addSignalSubscription(ScStw::CurrentStartDelayChanged);
|
|
||||||
|
|
||||||
connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwRemoteRace::handleClientStateChanged);
|
connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwRemoteRace::handleClientStateChanged);
|
||||||
connect(this->scStwClient, &ScStwClient::gotSignal, this, &ScStwRemoteRace::handleBaseStationSignal);
|
connect(this->scStwClient, &ScStwClient::gotSignal, this, &ScStwRemoteRace::handleBaseStationSignal);
|
||||||
|
@ -112,39 +111,48 @@ void ScStwRemoteRace::handleClientStateChanged() {
|
||||||
void ScStwRemoteRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) {
|
void ScStwRemoteRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) {
|
||||||
//qDebug() << "got signal: " << data;
|
//qDebug() << "got signal: " << data;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case ScStw::RaceStateChanged:
|
case ScStw::RaceDetailsChanged:
|
||||||
{
|
{
|
||||||
// the remote race state has changed
|
this->refreshDetails(data.toMap());
|
||||||
this->setState( ScStwRace::RaceState( data.toInt() ) );
|
|
||||||
break;
|
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:
|
default:
|
||||||
return;
|
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) {
|
bool ScStwRemoteRace::refreshRemoteTimers(QVariantList remoteTimers) {
|
||||||
|
|
||||||
if(remoteTimers.length() != this->timers.length()){
|
if(remoteTimers.length() != this->timers.length()){
|
||||||
|
@ -218,3 +226,7 @@ QVariantList ScStwRemoteRace::getCurrentStartDelay() {
|
||||||
nextActionDelayProg
|
nextActionDelayProg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScStwRemoteRace::getIsReadyForNextState() {
|
||||||
|
return this->isReadyForNextState;
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ ScStwRace::ScStwRace(QObject *parent) : QObject(parent)
|
||||||
|
|
||||||
connect(this, &ScStwRace::currentStartDelayChanged, this, &ScStwRace::detailsChanged);
|
connect(this, &ScStwRace::currentStartDelayChanged, this, &ScStwRace::detailsChanged);
|
||||||
connect(this, &ScStwRace::timersChanged, this, &ScStwRace::detailsChanged);
|
connect(this, &ScStwRace::timersChanged, this, &ScStwRace::detailsChanged);
|
||||||
|
connect(this, &ScStwRace::stateChanged, this, &ScStwRace::detailsChanged);
|
||||||
|
|
||||||
// write default settings
|
// write default settings
|
||||||
this->startSoundSettings.insert(ScStwSoundPlayer::Start, {{"Enabled", true}, {"Delay", 1}});
|
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) {
|
ScStw::StatusCode ScStwRace::start(bool asyncronous) {
|
||||||
if(this->state == WAITING) {
|
if(this->state == WAITING) {
|
||||||
if(this->isReadyForNextState()) {
|
if(this->getIsReadyForNextState()) {
|
||||||
this->startWaitLoop->exit(LoopManualExit);
|
this->startWaitLoop->exit(LoopManualExit);
|
||||||
return ScStw::Success;
|
return ScStw::Success;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +62,7 @@ ScStw::StatusCode ScStwRace::start(bool asyncronous) {
|
||||||
return ScStw::CurrentStateNotVaildForOperationError;
|
return ScStw::CurrentStateNotVaildForOperationError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this->isReadyForNextState())
|
if(!this->getIsReadyForNextState())
|
||||||
return ScStw::TimersNotReadyError;
|
return ScStw::TimersNotReadyError;
|
||||||
|
|
||||||
this->setState(PREPAIRING);
|
this->setState(PREPAIRING);
|
||||||
|
@ -181,7 +182,7 @@ ScStw::StatusCode ScStwRace::cancel() {
|
||||||
this->setState(STOPPED);
|
this->setState(STOPPED);
|
||||||
|
|
||||||
this->startWaitLoop->exit(LoopCancelExit);
|
this->startWaitLoop->exit(LoopCancelExit);
|
||||||
this->soundPlayer->cancel(this->soundVolume);
|
this->soundPlayer->cancel();
|
||||||
this->startDelayTimer->stop();
|
this->startDelayTimer->stop();
|
||||||
|
|
||||||
emit this->currentStartDelayChanged();
|
emit this->currentStartDelayChanged();
|
||||||
|
@ -246,7 +247,7 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
bool timerTriggered = true;
|
bool timerTriggered = true;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
if(!this->isReadyForNextState()) {
|
if(!this->getIsReadyForNextState()) {
|
||||||
this->startDelayTimer->stop();
|
this->startDelayTimer->stop();
|
||||||
timerTriggered = false;
|
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();
|
//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!";
|
qDebug() << "[RACE][DEBUG] Wait finished, starting now!";
|
||||||
|
|
||||||
|
@ -296,7 +297,7 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
if(loopExitCode == LoopCancelExit)
|
if(loopExitCode == LoopCancelExit)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} while(loopExitCode != LoopManualExit || !this->isReadyForNextState());
|
} while(loopExitCode != LoopManualExit || !this->getIsReadyForNextState());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qDebug() << "now playing ready sound";
|
qDebug() << "now playing ready sound";
|
||||||
|
@ -449,7 +450,7 @@ void ScStwRace::refreshTimerStates() {
|
||||||
// --- helper functions ---
|
// --- helper functions ---
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
bool ScStwRace::isReadyForNextState() {
|
bool ScStwRace::getIsReadyForNextState() {
|
||||||
if(!this->competitionMode) {
|
if(!this->competitionMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +543,7 @@ QVariantList ScStwRace::getCurrentStartDelay() {
|
||||||
int nextActionDelay = -1;
|
int nextActionDelay = -1;
|
||||||
double nextActionDelayProg = -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
|
// indicate that we are waiting for climbers and the progress shall be zero
|
||||||
nextActionDelayProg = 0;
|
nextActionDelayProg = 0;
|
||||||
}
|
}
|
||||||
|
@ -645,13 +646,14 @@ QVariantList ScStwRace::getTimerDetailList() {
|
||||||
QVariantMap ScStwRace::getDetails() {
|
QVariantMap ScStwRace::getDetails() {
|
||||||
QVariantMap tmpDetails;
|
QVariantMap tmpDetails;
|
||||||
|
|
||||||
tmpDetails.insert("timers", this->getTimerDetailList());
|
tmpDetails.insert("state", this->getState());
|
||||||
tmpDetails.insert("currentStartDelay", this->getCurrentStartDelay());
|
|
||||||
tmpDetails.insert("competitionMode", this->competitionMode);
|
tmpDetails.insert("competitionMode", this->competitionMode);
|
||||||
tmpDetails.insert("readySoundEnabled", this->startSoundSettings[ScStwSoundPlayer::Ready]["Enabled"].toBool());
|
tmpDetails.insert("readySoundEnabled", this->startSoundSettings[ScStwSoundPlayer::Ready]["Enabled"].toBool());
|
||||||
|
tmpDetails.insert("currentStartDelay", this->getCurrentStartDelay());
|
||||||
|
tmpDetails.insert("timers", this->getTimerDetailList());
|
||||||
|
|
||||||
if(this->state == WAITING)
|
if(this->state == WAITING)
|
||||||
tmpDetails.insert("isReady", this->isReadyForNextState());
|
tmpDetails.insert("isReadyForNextState", this->getIsReadyForNextState());
|
||||||
|
|
||||||
return tmpDetails;
|
return tmpDetails;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,13 +79,15 @@ bool ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, d
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScStwSoundPlayer::cancel(double volume) {
|
bool ScStwSoundPlayer::cancel() {
|
||||||
if(!this->soundEffect->isPlaying() )
|
if(!this->soundEffect->isPlaying() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// stop playback
|
// stop playback
|
||||||
this->soundEffect->stop();
|
this->soundEffect->stop();
|
||||||
this->waitLoop->quit();
|
this->waitLoop->quit();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
|
bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
|
||||||
|
|
Reference in a new issue