did some adjustments to allow waiting for climbers before start; renamed some stuff
This commit is contained in:
parent
78b0b883d5
commit
41818ff308
5 changed files with 204 additions and 146 deletions
|
@ -61,7 +61,7 @@ public:
|
||||||
RaceStateChanged = 9000,
|
RaceStateChanged = 9000,
|
||||||
TimersChanged = 9001,
|
TimersChanged = 9001,
|
||||||
ExtensionsChanged = 9002,
|
ExtensionsChanged = 9002,
|
||||||
NextStartActionChanged = 9003, /*, ProfilesChanged*/
|
CurrentStartDelayChanged = 9003, /*, ProfilesChanged*/
|
||||||
SettingChanged = 9004
|
SettingChanged = 9004
|
||||||
};
|
};
|
||||||
Q_ENUM(SignalKey)
|
Q_ENUM(SignalKey)
|
||||||
|
@ -84,7 +84,7 @@ public:
|
||||||
GetNextStartActionCommand = 2005,
|
GetNextStartActionCommand = 2005,
|
||||||
GetExtensionsCommand = 2006,
|
GetExtensionsCommand = 2006,
|
||||||
GetTimersCommand = 2007,
|
GetTimersCommand = 2007,
|
||||||
GetNextStartActionDetailsCommand = 2009,
|
GetCurrentStartDelayCommand = 2009,
|
||||||
|
|
||||||
WriteSettingCommand = 3000,
|
WriteSettingCommand = 3000,
|
||||||
ReadSettingCommand = 3001,
|
ReadSettingCommand = 3001,
|
||||||
|
@ -160,8 +160,8 @@ public:
|
||||||
*/
|
*/
|
||||||
enum ExtensionBatteryState {
|
enum ExtensionBatteryState {
|
||||||
BatteryUnknown = -1,
|
BatteryUnknown = -1,
|
||||||
BatteryFine = 1,
|
BatteryCritical = 0,
|
||||||
BatteryCritical = 0
|
BatteryFine = 1
|
||||||
};
|
};
|
||||||
Q_ENUM(ExtensionBatteryState);
|
Q_ENUM(ExtensionBatteryState);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public slots:
|
||||||
int stop();
|
int stop();
|
||||||
int reset();
|
int reset();
|
||||||
bool addTimer(ScStwTimer *timer);
|
bool addTimer(ScStwTimer *timer);
|
||||||
QVariantList getNextStartActionDetails();
|
QVariantList getCurrentStartDelay();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleClientStateChanged();
|
void handleClientStateChanged();
|
||||||
|
|
|
@ -51,7 +51,7 @@ class ScStwRace : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
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 nextStartActionDetails READ getNextStartActionDetails NOTIFY nextStartActionDetailsChanged)
|
Q_PROPERTY(QVariantList currentStartDelay READ getCurrentStartDelay NOTIFY currentStartDelayChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScStwRace(QObject *parent = nullptr);
|
explicit ScStwRace(QObject *parent = nullptr);
|
||||||
|
@ -59,42 +59,43 @@ public:
|
||||||
enum RaceState { IDLE, PREPAIRING, WAITING, STARTING, RUNNING, STOPPED, INCIDENT };
|
enum RaceState { IDLE, PREPAIRING, WAITING, STARTING, RUNNING, STOPPED, INCIDENT };
|
||||||
Q_ENUM(RaceState)
|
Q_ENUM(RaceState)
|
||||||
|
|
||||||
enum StartAction { None = -1, AtYourMarks = 0, Ready = 1, Start = 2 };
|
enum CurrentStartDetailAttributes {
|
||||||
Q_ENUM(StartAction)
|
CurrentStartStateTotalDelay = 0,
|
||||||
|
CurrentStartStateDelayProgress = 1
|
||||||
enum NextStartActionDetailAttributes {
|
|
||||||
NextStartAction = 0,
|
|
||||||
NextStartActionTotalDelay = 1,
|
|
||||||
NextStartActionDelayProgress = 2
|
|
||||||
};
|
};
|
||||||
Q_ENUM(NextStartActionDetailAttributes);
|
Q_ENUM(CurrentStartDetailAttributes);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StartAction nextStartAction;
|
|
||||||
QList<ScStwTimer *> timers;
|
QList<ScStwTimer *> timers;
|
||||||
void setState(RaceState newState);
|
void setState(RaceState newState);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RaceState state;
|
RaceState state;
|
||||||
|
|
||||||
QTimer *nextActionTimer;
|
QTimer *startDelayTimer;
|
||||||
QEventLoop *nextActionLoop;
|
QEventLoop *startWaitLoop;
|
||||||
QEventLoop *climberReadyWaitLoop;
|
|
||||||
|
|
||||||
// sounds
|
// sounds
|
||||||
ScStwSoundPlayer * soundPlayer;
|
ScStwSoundPlayer * soundPlayer;
|
||||||
|
|
||||||
// some settings
|
// some settings
|
||||||
double soundVolume;
|
double soundVolume;
|
||||||
bool allowAutomaticTimerDisable;
|
bool competitionMode;
|
||||||
bool allowAutomaticTimerDisableChanged;
|
bool competitionModeChanged;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief stores the start action settings
|
* \brief stores the start action settings
|
||||||
*
|
*
|
||||||
* \details Stores the settings for the action ScStwRace::AtYourMarks and ScStwRace::Ready. The settings keys are: "Enabled" and "Delay"
|
* \details Stores the settings for the action ScStwRace::AtYourMarks and ScStwRace::Ready. The settings keys are: "Enabled" and "Delay"
|
||||||
*/
|
*/
|
||||||
QMap<StartAction, QVariantMap> startActionSettings;
|
QMap<ScStwSoundPlayer::StartSound, QVariantMap> startSoundSettings;
|
||||||
|
|
||||||
|
|
||||||
|
enum LoopExitTypes {
|
||||||
|
LoopAutomaticExit = 0,
|
||||||
|
LoopManualExit = 2,
|
||||||
|
LoopCancelExit = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -122,15 +123,14 @@ public slots:
|
||||||
virtual int cancel();
|
virtual int cancel();
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
bool writeStartActionSetting(StartAction action, bool enabled, int delay);
|
bool writeStartSoundSetting(ScStwSoundPlayer::StartSound sound, bool enabled, int delay);
|
||||||
bool setSoundVolume(double volume);
|
bool setSoundVolume(double volume);
|
||||||
virtual bool addTimer(ScStwTimer *timer);
|
virtual bool addTimer(ScStwTimer *timer);
|
||||||
void setAllowAutomaticTimerDisable(bool allow);
|
void setCompetitionMode(bool competitionMode);
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
RaceState getState();
|
RaceState getState();
|
||||||
StartAction getNextStartAction();
|
virtual QVariantList getCurrentStartDelay();
|
||||||
virtual QVariantList getNextStartActionDetails();
|
|
||||||
QList<ScStwTimer*> getTimers();
|
QList<ScStwTimer*> getTimers();
|
||||||
QVariantList getTimerDetailList();
|
QVariantList getTimerDetailList();
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ private slots:
|
||||||
void handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled);
|
void handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled);
|
||||||
int handleFalseStart();
|
int handleFalseStart();
|
||||||
bool playSoundsAndStartTimers();
|
bool playSoundsAndStartTimers();
|
||||||
bool doDelayAndSoundOfStartAction(StartAction action, double *timeOfSoundPlaybackStart = nullptr);
|
bool doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart = nullptr);
|
||||||
void enableAllTimers();
|
void enableAllTimers();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,14 +151,14 @@ private slots:
|
||||||
void handleTimerStop();
|
void handleTimerStop();
|
||||||
|
|
||||||
bool isStarting();
|
bool isStarting();
|
||||||
|
bool isReadyForNextState();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void startTimers();
|
void startTimers();
|
||||||
void stopTimers(int type);
|
void stopTimers(int type);
|
||||||
void resetTimers();
|
void resetTimers();
|
||||||
void stateChanged(RaceState state);
|
void stateChanged(RaceState state);
|
||||||
void nextStartActionChanged();
|
void currentStartDelayChanged();
|
||||||
void nextStartActionDetailsChanged();
|
|
||||||
void timersChanged();
|
void timersChanged();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,12 @@ public:
|
||||||
*/
|
*/
|
||||||
explicit ScStwSoundPlayer(QObject *parent = nullptr);
|
explicit ScStwSoundPlayer(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
enum StartSound {
|
||||||
|
Start,
|
||||||
|
Ready,
|
||||||
|
AtYourMarks
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
* \brief A map containing all sound files
|
* \brief A map containing all sound files
|
||||||
|
|
|
@ -26,22 +26,18 @@ ScStwRace::ScStwRace(QObject *parent) : QObject(parent)
|
||||||
this->soundPlayer = new ScStwSoundPlayer();
|
this->soundPlayer = new ScStwSoundPlayer();
|
||||||
|
|
||||||
// configure timer that handles the delay between the start commands
|
// configure timer that handles the delay between the start commands
|
||||||
this->nextActionTimer = new QTimer(this);
|
this->startDelayTimer = new QTimer(this);
|
||||||
nextActionTimer->setSingleShot(true);
|
startDelayTimer->setSingleShot(true);
|
||||||
this->nextActionLoop = new QEventLoop(this);
|
this->startWaitLoop = new QEventLoop(this);
|
||||||
this->nextStartAction = None;
|
|
||||||
this->climberReadyWaitLoop = new QEventLoop(this);
|
|
||||||
|
|
||||||
connect(this->nextActionTimer, &QTimer::timeout, this->nextActionLoop, &QEventLoop::quit);
|
connect(this->startDelayTimer, &QTimer::timeout, this->startWaitLoop, &QEventLoop::quit);
|
||||||
connect(this->nextActionTimer, &QTimer::timeout, this->climberReadyWaitLoop, &QEventLoop::quit);
|
|
||||||
connect(this, &ScStwRace::nextStartActionChanged, this, &ScStwRace::nextStartActionDetailsChanged);
|
|
||||||
|
|
||||||
// write default settings
|
// write default settings
|
||||||
this->startActionSettings.insert(Start, {{"Enabled", true}, {"Delay", 1}});
|
this->startSoundSettings.insert(ScStwSoundPlayer::Start, {{"Enabled", true}, {"Delay", 1}});
|
||||||
this->writeStartActionSetting(AtYourMarks, false, 0);
|
this->writeStartSoundSetting(ScStwSoundPlayer::AtYourMarks, false, 0);
|
||||||
this->writeStartActionSetting(Ready, false, 0);
|
this->writeStartSoundSetting(ScStwSoundPlayer::Ready, false, 0);
|
||||||
this->setSoundVolume(1.0);
|
this->setSoundVolume(1.0);
|
||||||
this->allowAutomaticTimerDisable = false;
|
this->competitionMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
@ -49,40 +45,22 @@ ScStwRace::ScStwRace(QObject *parent) : QObject(parent)
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
||||||
int ScStwRace::start(bool asyncronous) {
|
int ScStwRace::start(bool asyncronous) {
|
||||||
if(this->state != IDLE) {
|
if(this->state == WAITING) {
|
||||||
|
if(this->isReadyForNextState()) {
|
||||||
|
this->startWaitLoop->exit(LoopManualExit);
|
||||||
|
return ScStw::Success;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ScStw::TimersNotReadyError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(this->state != IDLE) {
|
||||||
return ScStw::CurrentStateNotVaildForOperationError;
|
return ScStw::CurrentStateNotVaildForOperationError;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "[INFO][RACE] checking timers";
|
qDebug() << "[INFO][RACE] checking timers";
|
||||||
foreach (ScStwTimer *timer, this->timers) {
|
if(!this->isReadyForNextState())
|
||||||
if(timer->getState() == ScStwTimer::DISABLED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(timer->getReadyState() == ScStwTimer::ExtensionIsNotConnected || timer->getReadyState() == ScStwTimer::ExtensionBatteryNotFine) {
|
|
||||||
|
|
||||||
if(this->allowAutomaticTimerDisable) {
|
|
||||||
timer->setDisabled(true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Timer ready state is: " << timer->getReadyState();
|
|
||||||
|
|
||||||
timer->technicalIncident();
|
|
||||||
|
|
||||||
foreach (ScStwTimer *subTimer, this->timers) {
|
|
||||||
if(timer != subTimer && (timer->getReadyState() == ScStwTimer::ExtensionIsNotConnected || timer->getReadyState() == ScStwTimer::ExtensionBatteryNotFine))
|
|
||||||
subTimer->technicalIncident();
|
|
||||||
else if(timer != subTimer)
|
|
||||||
subTimer->setState(ScStwTimer::CANCELLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->setState(INCIDENT);
|
|
||||||
|
|
||||||
qDebug() << "[ERROR][RACE] Could not start due to not-ready timers";
|
|
||||||
|
|
||||||
return ScStw::TimersNotReadyError;
|
return ScStw::TimersNotReadyError;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "[INFO][RACE] starting race";
|
qDebug() << "[INFO][RACE] starting race";
|
||||||
this->setState(PREPAIRING);
|
this->setState(PREPAIRING);
|
||||||
|
@ -199,11 +177,9 @@ int ScStwRace::cancel() {
|
||||||
|
|
||||||
this->setState(STOPPED);
|
this->setState(STOPPED);
|
||||||
|
|
||||||
|
this->startWaitLoop->exit(LoopCancelExit);
|
||||||
this->soundPlayer->cancel(this->soundVolume);
|
this->soundPlayer->cancel(this->soundVolume);
|
||||||
this->nextActionTimer->stop();
|
this->startDelayTimer->stop();
|
||||||
this->nextActionLoop->quit();
|
|
||||||
this->climberReadyWaitLoop->quit();
|
|
||||||
this->nextStartAction = None;
|
|
||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
@ -230,9 +206,8 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// The check if all timers are ready has already happened at this point
|
// The check if all timers are ready has already happened at this point
|
||||||
if(!this->doDelayAndSoundOfStartAction(AtYourMarks)) {
|
if(!this->doDelayAndSoundOfCurrentStartState())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// check if the start was cancelled
|
// check if the start was cancelled
|
||||||
if(!this->isStarting())
|
if(!this->isStarting())
|
||||||
|
@ -241,65 +216,84 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
this->setState(WAITING);
|
this->setState(WAITING);
|
||||||
|
|
||||||
// do climber readiness tests
|
// do climber readiness tests
|
||||||
this->nextStartAction = Ready;
|
|
||||||
emit this->nextStartActionChanged();
|
// wait until both climbers are ready
|
||||||
|
|
||||||
// if the automatic ready tone is enabled, wait for the climbers to become ready
|
// if the automatic ready tone is enabled, wait for the climbers to become ready
|
||||||
if(this->startActionSettings.contains(Ready) && this->startActionSettings[Ready]["Enabled"].toBool()) {
|
if(this->startSoundSettings.contains(ScStwSoundPlayer::Ready) && this->startSoundSettings[ScStwSoundPlayer::Ready]["Enabled"].toBool()) {
|
||||||
|
|
||||||
qDebug() << "[RACE][INFO] Now waiting for climbers";
|
qDebug() << "[RACE][INFO] Now waiting for climbers";
|
||||||
|
|
||||||
// get delay
|
// get delay
|
||||||
int minimumReadyDelay = 1000;
|
int minimumReadyDelay = 1000;
|
||||||
if(this->startActionSettings[Ready]["Delay"].toInt() > 1000 || !this->allowAutomaticTimerDisable)
|
if(this->startSoundSettings[ScStwSoundPlayer::Ready]["Delay"].toInt() > 1000)
|
||||||
minimumReadyDelay = this->startActionSettings[Ready]["Delay"].toInt();
|
minimumReadyDelay = this->startSoundSettings[ScStwSoundPlayer::Ready]["Delay"].toInt();
|
||||||
|
|
||||||
|
this->startDelayTimer->setInterval(minimumReadyDelay);
|
||||||
|
|
||||||
// wait for climbers to become ready initially
|
// wait for climbers to become ready initially
|
||||||
bool allClimbersReady = false;
|
bool timerTriggered = true;
|
||||||
while (!allClimbersReady) {
|
do {
|
||||||
allClimbersReady = true;
|
|
||||||
foreach (ScStwTimer *timer, this->timers) {
|
if(!this->isReadyForNextState()) {
|
||||||
if(timer->getReadyState() != ScStwTimer::IsReady)
|
this->startDelayTimer->stop();
|
||||||
allClimbersReady = false;
|
timerTriggered = false;
|
||||||
|
}
|
||||||
|
else if(this->startDelayTimer->isActive()) {
|
||||||
|
timerTriggered = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->startDelayTimer->stop();
|
||||||
|
this->startDelayTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!allClimbersReady)
|
emit this->currentStartDelayChanged();
|
||||||
this->climberReadyWaitLoop->exec();
|
|
||||||
|
|
||||||
// check if the start was cancelled
|
int loopExitCode = this->startWaitLoop->exec();
|
||||||
if(!this->isStarting())
|
|
||||||
|
switch (loopExitCode) {
|
||||||
|
case LoopAutomaticExit:
|
||||||
|
break;
|
||||||
|
case LoopManualExit:
|
||||||
|
// prevent manual stop
|
||||||
|
timerTriggered = false;
|
||||||
|
break;
|
||||||
|
case LoopCancelExit:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} while(this->startDelayTimer->remainingTime() > 0 || !timerTriggered || !this->isReadyForNextState());
|
||||||
|
|
||||||
qDebug() << "[RACE][DEBUG] Initial wait finished";
|
qDebug() << "[RACE][DEBUG] Initial wait finished";
|
||||||
|
|
||||||
// wait for all climbers to be ready for the ReadyActionDelay, but at least one second continuosly
|
// wait for all climbers to be ready for the ReadyActionDelay, but at least one second continuosly
|
||||||
// the climber ready wait loop will also quit, if the climber steps of the pad
|
// the climber ready wait loop will also quit, if the climber steps of the pad
|
||||||
// -> wait for both climbers to stand on the pad for at least one second
|
// -> wait for both climbers to stand on the pad for at least one second
|
||||||
do {
|
|
||||||
this->nextActionTimer->stop();
|
|
||||||
this->nextActionTimer->start(minimumReadyDelay);
|
|
||||||
this->climberReadyWaitLoop->exec();
|
|
||||||
|
|
||||||
// check if the start was cancelled
|
|
||||||
if(!this->isStarting())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} while(this->nextActionTimer->remainingTime() > 0);
|
|
||||||
|
|
||||||
qDebug() << "[RACE][DEBUG] Wait finished, starting now!";
|
qDebug() << "[RACE][DEBUG] Wait finished, starting now!";
|
||||||
|
|
||||||
// play ready tone
|
// play ready tone
|
||||||
if(!this->soundPlayer->play(Ready, this->soundVolume))
|
if(!this->soundPlayer->play(ScStwSoundPlayer::Ready, this->soundVolume))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// wait for climbers and manual start
|
||||||
|
int loopExitCode;
|
||||||
|
do {
|
||||||
|
loopExitCode = this->startWaitLoop->exec();
|
||||||
|
|
||||||
|
if(loopExitCode == LoopCancelExit)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} while(loopExitCode != LoopManualExit || !this->isReadyForNextState());
|
||||||
|
}
|
||||||
|
|
||||||
// enter starting state
|
// enter starting state
|
||||||
this->setState(STARTING);
|
this->setState(STARTING);
|
||||||
|
|
||||||
// play start tone
|
// play start tone
|
||||||
double timeOfSoundPlaybackStart;
|
double timeOfSoundPlaybackStart;
|
||||||
this->doDelayAndSoundOfStartAction(Start, &timeOfSoundPlaybackStart);
|
this->doDelayAndSoundOfCurrentStartState(&timeOfSoundPlaybackStart);
|
||||||
|
|
||||||
// perform start
|
// perform start
|
||||||
|
|
||||||
|
@ -324,9 +318,6 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
if(!this->isStarting())
|
if(!this->isStarting())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
nextStartAction = None;
|
|
||||||
emit this->nextStartActionChanged();
|
|
||||||
|
|
||||||
this->setState(RUNNING);
|
this->setState(RUNNING);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -334,32 +325,48 @@ bool ScStwRace::playSoundsAndStartTimers() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScStwRace::doDelayAndSoundOfStartAction(ScStwRace::StartAction action, double *timeOfSoundPlaybackStart) {
|
bool ScStwRace::doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart) {
|
||||||
if(!this->isStarting())
|
ScStwSoundPlayer::StartSound sound;
|
||||||
|
|
||||||
|
switch (this->state) {
|
||||||
|
case PREPAIRING:
|
||||||
|
sound = ScStwSoundPlayer::AtYourMarks;
|
||||||
|
break;
|
||||||
|
case WAITING:
|
||||||
|
sound = ScStwSoundPlayer::Ready;
|
||||||
|
break;
|
||||||
|
case STARTING:
|
||||||
|
sound = ScStwSoundPlayer::Start;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(this->startActionSettings.contains(action) && this->startActionSettings[action]["Enabled"].toBool()) {
|
if(this->startSoundSettings.contains(sound) && this->startSoundSettings[sound]["Enabled"].toBool()) {
|
||||||
|
|
||||||
this->nextStartAction = action;
|
|
||||||
emit this->nextStartActionChanged();
|
|
||||||
|
|
||||||
if(action != Start && this->startActionSettings[action]["Delay"].toInt() > 0) {
|
if(sound != ScStwSoundPlayer::Start && this->startSoundSettings[sound]["Delay"].toInt() > 0) {
|
||||||
// perform the delay before the start
|
// perform the delay before the start
|
||||||
|
|
||||||
// get delay
|
// get delay
|
||||||
int thisActionDelay = this->startActionSettings[action]["Delay"].toInt();
|
int thisSoundDelay = this->startSoundSettings[sound]["Delay"].toInt();
|
||||||
|
|
||||||
// perform next action
|
// perform next action
|
||||||
if(thisActionDelay > 0) {
|
if(thisSoundDelay > 0) {
|
||||||
this->nextActionTimer->start(thisActionDelay);
|
this->startDelayTimer->setInterval(thisSoundDelay);
|
||||||
this->nextActionLoop->exec();
|
this->startDelayTimer->start();
|
||||||
|
|
||||||
|
emit this->currentStartDelayChanged();
|
||||||
|
|
||||||
|
if(this->startWaitLoop->exec() == LoopCancelExit)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this->isStarting())
|
if(!this->isStarting())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!this->soundPlayer->play(action, this->soundVolume, timeOfSoundPlaybackStart))
|
if(!this->soundPlayer->play(sound, this->soundVolume, timeOfSoundPlaybackStart))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,12 +381,12 @@ void ScStwRace::setState(RaceState newState) {
|
||||||
|
|
||||||
if(this->state == IDLE) {
|
if(this->state == IDLE) {
|
||||||
// if we changed to IDLE -> handle timer enable / disable
|
// if we changed to IDLE -> handle timer enable / disable
|
||||||
if(this->allowAutomaticTimerDisableChanged && !this->allowAutomaticTimerDisable) {
|
if(this->competitionModeChanged && this->competitionMode) {
|
||||||
this->enableAllTimers();
|
this->enableAllTimers();
|
||||||
this->allowAutomaticTimerDisableChanged = false;
|
this->competitionModeChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this->allowAutomaticTimerDisable) {
|
if(!this->competitionMode) {
|
||||||
foreach(ScStwTimer* timer, this->timers) {
|
foreach(ScStwTimer* timer, this->timers) {
|
||||||
if(timer->getWantsToBeDisabled() && timer->getState() != ScStwTimer::DISABLED)
|
if(timer->getWantsToBeDisabled() && timer->getState() != ScStwTimer::DISABLED)
|
||||||
this->handleTimerWantsToBeDisabledChange(timer, timer->getWantsToBeDisabled());
|
this->handleTimerWantsToBeDisabledChange(timer, timer->getWantsToBeDisabled());
|
||||||
|
@ -418,12 +425,64 @@ void ScStwRace::refreshTimerStates() {
|
||||||
// --- helper functions ---
|
// --- helper functions ---
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
|
bool ScStwRace::isReadyForNextState() {
|
||||||
|
switch (this->state) {
|
||||||
|
case IDLE: {
|
||||||
|
foreach (ScStwTimer *timer, this->timers) {
|
||||||
|
if(timer->getState() == ScStwTimer::DISABLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(timer->getReadyState() == ScStwTimer::ExtensionIsNotConnected || timer->getReadyState() == ScStwTimer::ExtensionBatteryNotFine) {
|
||||||
|
|
||||||
|
if(!this->competitionMode) {
|
||||||
|
timer->setDisabled(true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Timer ready state is: " << timer->getReadyState();
|
||||||
|
|
||||||
|
timer->technicalIncident();
|
||||||
|
|
||||||
|
foreach (ScStwTimer *subTimer, this->timers) {
|
||||||
|
if(timer != subTimer && (timer->getReadyState() == ScStwTimer::ExtensionIsNotConnected || timer->getReadyState() == ScStwTimer::ExtensionBatteryNotFine))
|
||||||
|
subTimer->technicalIncident();
|
||||||
|
else if(timer != subTimer)
|
||||||
|
subTimer->setState(ScStwTimer::CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setState(INCIDENT);
|
||||||
|
|
||||||
|
qDebug() << "[ERROR][RACE] Could not start due to not-ready timers";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case WAITING: {
|
||||||
|
foreach (ScStwTimer *timer, this->timers) {
|
||||||
|
if(timer->getReadyState() != ScStwTimer::IsReady)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ScStwRace::handleTimerEnable function to enable timers at the right moment to prevent them from bricking the state machine
|
* @brief ScStwRace::handleTimerEnable function to enable timers at the right moment to prevent them from bricking the state machine
|
||||||
* @param {ScStwExtensionControlledTimer*} timer timer to be enabled
|
* @param {ScStwExtensionControlledTimer*} timer timer to be enabled
|
||||||
*/
|
*/
|
||||||
void ScStwRace::handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled) {
|
void ScStwRace::handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled) {
|
||||||
if(!this->allowAutomaticTimerDisable)
|
if(this->competitionMode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(this->state == IDLE) {
|
if(this->state == IDLE) {
|
||||||
|
@ -431,18 +490,17 @@ void ScStwRace::handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wants
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScStwRace::setCompetitionMode(bool competitionMode) {
|
||||||
void ScStwRace::setAllowAutomaticTimerDisable(bool allow) {
|
if(this->competitionMode == competitionMode)
|
||||||
if(this->allowAutomaticTimerDisable == allow)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << "Setting allow automatic timer disable to " << allow;
|
qDebug() << "Setting competition mode to " << competitionMode;
|
||||||
|
|
||||||
this->allowAutomaticTimerDisable = allow;
|
this->competitionMode = competitionMode;
|
||||||
|
|
||||||
if(this->state != IDLE)
|
if(this->state != IDLE)
|
||||||
this->allowAutomaticTimerDisableChanged = true;
|
this->competitionModeChanged = true;
|
||||||
else if(!this->allowAutomaticTimerDisable)
|
else if(this->competitionMode)
|
||||||
this->enableAllTimers();
|
this->enableAllTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,14 +515,14 @@ void ScStwRace::enableAllTimers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList ScStwRace::getNextStartActionDetails() {
|
QVariantList ScStwRace::getCurrentStartDelay() {
|
||||||
int nextActionDelay = 0;
|
int nextActionDelay = 0;
|
||||||
double nextActionDelayProg = -1;
|
double nextActionDelayProg = -1;
|
||||||
|
|
||||||
if(this->nextStartAction == AtYourMarks || this->nextStartAction == Ready) {
|
if(this->state == PREPAIRING || this->state == WAITING) {
|
||||||
// get the total delay and the delay progress of the next action timer
|
// get the total delay and the delay progress of the next action timer
|
||||||
double remaining = this->nextActionTimer->remainingTime();
|
double remaining = this->startDelayTimer->remainingTime();
|
||||||
nextActionDelay = this->startActionSettings[this->nextStartAction]["Delay"].toInt();
|
nextActionDelay = this->startDelayTimer->interval();;
|
||||||
if(remaining < 0) {
|
if(remaining < 0) {
|
||||||
remaining = nextActionDelay;
|
remaining = nextActionDelay;
|
||||||
}
|
}
|
||||||
|
@ -472,22 +530,21 @@ QVariantList ScStwRace::getNextStartActionDetails() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
this->nextStartAction,
|
|
||||||
nextActionDelay,
|
nextActionDelay,
|
||||||
nextActionDelayProg
|
nextActionDelayProg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScStwRace::writeStartActionSetting(StartAction action, bool enabled, int delay) {
|
bool ScStwRace::writeStartSoundSetting(ScStwSoundPlayer::StartSound sound, bool enabled, int delay) {
|
||||||
if(action != AtYourMarks && action != Ready)
|
if(sound != ScStwSoundPlayer::AtYourMarks && sound != ScStwSoundPlayer::Ready)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QVariantMap setting = {{"Enabled", enabled}, {"Delay", delay}};
|
QVariantMap setting = {{"Enabled", enabled}, {"Delay", delay}};
|
||||||
|
|
||||||
if(!this->startActionSettings.contains(action))
|
if(!this->startSoundSettings.contains(sound))
|
||||||
this->startActionSettings.insert(action, setting);
|
this->startSoundSettings.insert(sound, setting);
|
||||||
else
|
else
|
||||||
this->startActionSettings[action] = setting;
|
this->startSoundSettings[sound] = setting;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -517,9 +574,9 @@ bool ScStwRace::addTimer(ScStwTimer *timer) {
|
||||||
connect(timer, &ScStwTimer::wantsToBeDisabledChanged, this, &ScStwRace::handleTimerWantsToBeDisabledChange);
|
connect(timer, &ScStwTimer::wantsToBeDisabledChanged, this, &ScStwRace::handleTimerWantsToBeDisabledChange);
|
||||||
connect(timer, &ScStwTimer::stateChanged, this, &ScStwRace::timersChanged);
|
connect(timer, &ScStwTimer::stateChanged, this, &ScStwRace::timersChanged);
|
||||||
connect(timer, &ScStwTimer::reactionTimeChanged, this, &ScStwRace::timersChanged);
|
connect(timer, &ScStwTimer::reactionTimeChanged, this, &ScStwRace::timersChanged);
|
||||||
connect(timer, &ScStwTimer::readyStateChanged, this->climberReadyWaitLoop, &QEventLoop::quit);
|
connect(timer, &ScStwTimer::readyStateChanged, this->startWaitLoop, &QEventLoop::quit);
|
||||||
|
|
||||||
if(!this->allowAutomaticTimerDisable && timer->getState() == ScStwTimer::DISABLED)
|
if(this->competitionMode && timer->getState() == ScStwTimer::DISABLED)
|
||||||
timer->setDisabled(false);
|
timer->setDisabled(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -530,11 +587,6 @@ ScStwRace::RaceState ScStwRace::getState() {
|
||||||
return this->state;
|
return this->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScStwRace::StartAction ScStwRace::getNextStartAction()
|
|
||||||
{
|
|
||||||
return this->nextStartAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ScStwTimer*> ScStwRace::getTimers() {
|
QList<ScStwTimer*> ScStwRace::getTimers() {
|
||||||
return this->timers;
|
return this->timers;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue