- some changes to file structure
- started to implement timer, race and sound management
This commit is contained in:
parent
ef600c98ea
commit
1570bd86c9
22 changed files with 838 additions and 185 deletions
Binary file not shown.
|
@ -1,167 +0,0 @@
|
||||||
#ifndef SCSTW_HPP
|
|
||||||
#define SCSTW_HPP
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mainpage ScStw Libraries documentation
|
|
||||||
*
|
|
||||||
* @section intro_sec Introduction
|
|
||||||
*
|
|
||||||
* This library is meant for usage with the Speed climbing stopwatch project.
|
|
||||||
* It contains some helper classes to build a client application for the ScStw basestation with Qt.
|
|
||||||
*
|
|
||||||
* @section section Installation
|
|
||||||
* @code{.sh}
|
|
||||||
* cd yourRepo
|
|
||||||
* git submodule add https://git.itsblue.de/ScStw/shared-libraries/
|
|
||||||
* git submodule update --init --recursive
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* Add to the list of libraries for the Qt-Secret assembly. For an example you can create Main.Pro in which connect Qt-Secret and your project.pro files as subprojects.
|
|
||||||
*
|
|
||||||
* Main.pro:
|
|
||||||
* @code{.pro}
|
|
||||||
* TEMPLATE = subdirs
|
|
||||||
* CONFIG += ordered
|
|
||||||
*
|
|
||||||
* SUBDIRS += \
|
|
||||||
* ScStwLibraries \
|
|
||||||
* MyProject
|
|
||||||
*
|
|
||||||
* ScStwLibraries.file = shared-libraries/ScStwLibraries/ScStwLibraries.pro
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* And in your MyProject.pro include the .pri file:
|
|
||||||
* @code{.pro}
|
|
||||||
* include($$PWD/../shared-libraries/ScStwLibraries/ScStwLibraries.pri)
|
|
||||||
* @endcode
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ScStw class provides some shared functions and enums for use in the ScStw project.
|
|
||||||
*/
|
|
||||||
class ScStw : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The RaceState enum contains all states a race can have
|
|
||||||
*/
|
|
||||||
enum RaceState { IDLE, STARTING, WAITING, RUNNING, STOPPED };
|
|
||||||
Q_ENUM(RaceState)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The SignalKey enum contains all signal keys a client can subscribe to
|
|
||||||
*
|
|
||||||
* @see ScStw::signalKeyFromInt()
|
|
||||||
*/
|
|
||||||
enum SignalKey {
|
|
||||||
InvalidSignal = -1,
|
|
||||||
RaceStateChanged = 9000,
|
|
||||||
TimersChanged = 9001,
|
|
||||||
ExtensionsChanged = 9002,
|
|
||||||
NextStartActionChanged = 9003 /*, ProfilesChanged*/
|
|
||||||
};
|
|
||||||
Q_ENUM(SignalKey)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The NextStartAction enum contains all action that occur before a race is started
|
|
||||||
*/
|
|
||||||
enum NextStartAction { AtYourMarks, Ready, Start, None };
|
|
||||||
Q_ENUM(NextStartAction)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The BaseStationSetting enum contains all settings of the base station that can be changed by a client
|
|
||||||
*
|
|
||||||
* @see ScStw::baseStationSettingFromInt()
|
|
||||||
* @see ScStw::baseStationSettingToString()
|
|
||||||
* @see ScStw::baseStationSettingFromString()
|
|
||||||
* @see ScStw::baseStationSettings
|
|
||||||
*/
|
|
||||||
enum BaseStationSetting {
|
|
||||||
InvalidSetting = -1,
|
|
||||||
ReadySoundEnableSetting,
|
|
||||||
ReadySoundDelaySetting,
|
|
||||||
AtYourMarksSoundEnableSetting,
|
|
||||||
AtYourMarksSoundDelaySetting,
|
|
||||||
SoundVolumeSetting
|
|
||||||
};
|
|
||||||
Q_ENUM(BaseStationSetting)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ErrorCode enum contains all error codes that can occur when sending a command to the basestation
|
|
||||||
*/
|
|
||||||
enum ErrorCode {
|
|
||||||
Success = 200,
|
|
||||||
|
|
||||||
Error = 900,
|
|
||||||
NotConnectedError = 910,
|
|
||||||
TimeoutError = 911,
|
|
||||||
SettingNotAccessibleError = 901
|
|
||||||
};
|
|
||||||
Q_ENUM(ErrorCode)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SOCKET_MESSAGE_START_KEY contains the key, a message is supposed to start with
|
|
||||||
*/
|
|
||||||
static const char* SOCKET_MESSAGE_START_KEY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SOCKET_MESSAGE_END_KEY contains the key, a message is supposed to end with
|
|
||||||
*/
|
|
||||||
static const char* SOCKET_MESSAGE_END_KEY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief baseStationSettings contains a string with reference to all BaseStationSetting values
|
|
||||||
*
|
|
||||||
* @see ScStw::BaseStationSetting
|
|
||||||
* @see ScStw::baseStationSettingToString()
|
|
||||||
* @see ScStw::baseStationSettingFromString()
|
|
||||||
*/
|
|
||||||
static const QMap<QString, ScStw::BaseStationSetting> baseStationSettings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert an int to a BaseStationSetting
|
|
||||||
* @param i the int to convert
|
|
||||||
* @return a BaseStationSetting
|
|
||||||
*
|
|
||||||
* @see ScStw::BaseStationSetting
|
|
||||||
*/
|
|
||||||
static BaseStationSetting baseStationSettingfromInt(int i);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert a QString to a BaseStationSetting
|
|
||||||
* @param s the string to convert
|
|
||||||
* @return a BaseStationSetting
|
|
||||||
*
|
|
||||||
* @see ScStw::BaseStationSetting
|
|
||||||
* @see ScStw::baseStationSettingToString()
|
|
||||||
*/
|
|
||||||
static BaseStationSetting baseStationSettingFromString(QString s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert BaseStationSetting to a QString
|
|
||||||
* @param s the BaseStationSetting to convert
|
|
||||||
* @return a QString
|
|
||||||
*
|
|
||||||
* @see ScStw::BaseStationSetting
|
|
||||||
* @see ScStw::baseStationSettingFromString()
|
|
||||||
*/
|
|
||||||
static QString baseStationSettingToString(BaseStationSetting s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert an int to a SignalKey
|
|
||||||
* @param i the int to convert
|
|
||||||
* @return a SignalKey
|
|
||||||
*
|
|
||||||
* @see ScStw::SignalKey
|
|
||||||
*/
|
|
||||||
static SignalKey signalKeyFromInt(int i);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ScStw() : QObject(nullptr) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SCSTW_HPP
|
|
|
@ -13,3 +13,4 @@ unix:LIBS += -L$$SCSTWLIBRARIES_LIB_OUTPUT_DIR -lScStwLibraries
|
||||||
win32:LIBS += -L$$SCSTWLIBRARIES_LIB_OUTPUT_DIR -lScStwLibraries1
|
win32:LIBS += -L$$SCSTWLIBRARIES_LIB_OUTPUT_DIR -lScStwLibraries1
|
||||||
|
|
||||||
INCLUDEPATH += "$$PWD"
|
INCLUDEPATH += "$$PWD"
|
||||||
|
INCLUDEPATH += "$$PWD"/headers
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
QT -= gui
|
QT -= gui
|
||||||
QT += network
|
QT += network multimedia
|
||||||
|
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
DEFINES += SCSTWLIBRARIES_LIBRARY
|
DEFINES += SCSTWLIBRARIES_LIBRARY
|
||||||
|
@ -18,16 +18,22 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
ScStw.cpp \
|
sources/ScStw.cpp \
|
||||||
scstwclient.cpp
|
sources/scstwclient.cpp \
|
||||||
|
sources/scstwrace.cpp \
|
||||||
|
sources/scstwsoundplayer.cpp \
|
||||||
|
sources/scstwtimer.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
ScStw.hpp \
|
headers/ScStw.hpp \
|
||||||
ScStwLibraries_global.h \
|
headers/ScStwLibraries_global.h \
|
||||||
scstwclient.h
|
headers/scstwrace.h \
|
||||||
|
headers/scstwclient.h \
|
||||||
|
headers/scstwsoundplayer.h \
|
||||||
|
headers/scstwtimer.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
ScStwLibrariesShared.qrc
|
resources/ScStwLibrariesShared.qrc
|
||||||
|
|
||||||
DISTFILES +=
|
DISTFILES +=
|
||||||
|
|
||||||
|
@ -39,7 +45,5 @@ CONFIG(release, debug|release): {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Default rules for deployment.
|
# Default rules for deployment.
|
||||||
unix {
|
target.path = $$GLOBAL_TARGET_PATH/lib
|
||||||
target.path = /usr/lib
|
|
||||||
}
|
|
||||||
!isEmpty(target.path): INSTALLS += target
|
!isEmpty(target.path): INSTALLS += target
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<RCC>
|
|
||||||
<qresource prefix="/">
|
|
||||||
<file>ScStwBasestation.sb64</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
#include <ScStw.hpp>
|
#include "ScStw.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to connect and talk to the ScStw basestation.
|
* This class is used to connect and talk to the ScStw basestation.
|
78
ScStwLibraries/headers/scstwrace.h
Normal file
78
ScStwLibraries/headers/scstwrace.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef SCSTWRACE_H
|
||||||
|
#define SCSTWRACE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include "scstwtimer.h"
|
||||||
|
#include "scstwsoundplayer.h"
|
||||||
|
|
||||||
|
class ScStwRace : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ScStwRace(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
enum RaceState { IDLE, STARTING, WAITING, RUNNING, STOPPED };
|
||||||
|
Q_ENUM(RaceState)
|
||||||
|
|
||||||
|
enum StartAction { None = -1, AtYourMarks, Ready, Start };
|
||||||
|
Q_ENUM(StartAction)
|
||||||
|
|
||||||
|
private:
|
||||||
|
RaceState state;
|
||||||
|
|
||||||
|
QList<ScStwTimer *> timers;
|
||||||
|
QList<ScStwTimer*> timerEnableQueque;
|
||||||
|
|
||||||
|
QTimer *nextActionTimer;
|
||||||
|
QEventLoop *nextActionLoop;
|
||||||
|
|
||||||
|
// sounds
|
||||||
|
ScStwSoundPlayer * soundPlayer;
|
||||||
|
|
||||||
|
StartAction nextStartAction;
|
||||||
|
|
||||||
|
// some settings
|
||||||
|
double soundVolume;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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"
|
||||||
|
*/
|
||||||
|
QMap<StartAction, QVariantMap> startActionSettings;
|
||||||
|
|
||||||
|
void setState(RaceState newState);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
int start();
|
||||||
|
int stop();
|
||||||
|
void handleTimerStop();
|
||||||
|
int reset();
|
||||||
|
void cancelStart(bool falseStart);
|
||||||
|
QVariantMap getNextStartActionDetails();
|
||||||
|
bool writeStartActionSetting(StartAction action, bool enabled, int delay);
|
||||||
|
bool setSoundVolume(double volume);
|
||||||
|
bool addTimer(ScStwTimer *timer);
|
||||||
|
RaceState getState();
|
||||||
|
StartAction getNextStartAction();
|
||||||
|
QVariantList getTimerDetailList();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void refreshTimerStates();
|
||||||
|
void handleTimerEnable(ScStwTimer* timer);
|
||||||
|
bool playSoundsAndStartTimers(StartAction thisAction);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void startTimers();
|
||||||
|
void stopTimers(int type);
|
||||||
|
void resetTimers();
|
||||||
|
void stateChanged(RaceState state);
|
||||||
|
void nextStartActionChanged();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCSTWRACE_H
|
34
ScStwLibraries/headers/scstwstartsoundplayer.h
Normal file
34
ScStwLibraries/headers/scstwstartsoundplayer.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef SCSTWSTARTSOUNDPLAYER_H
|
||||||
|
#define SCSTWSTARTSOUNDPLAYER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QAudioOutput>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
class ScStwStartSoundPlayer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ScStwStartSoundPlayer(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QFile *startSoundFile;
|
||||||
|
QAudioOutput *audioOutput;
|
||||||
|
QEventLoop *waitLoop;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool play(double volume, double *timeOfStop = nullptr);
|
||||||
|
//int interrupt();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleStateChanged(QAudio::State newState);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCSTWSTARTSOUNDPLAYER_H
|
63
ScStwLibraries/headers/scstwtimer.h
Normal file
63
ScStwLibraries/headers/scstwtimer.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef SCSTWTIMER_H
|
||||||
|
#define SCSTWTIMER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "ScStw.hpp"
|
||||||
|
|
||||||
|
class ScStwTimer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ScStwTimer(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
enum TimerState { IDLE, STARTING, WAITING, RUNNING, WON, LOST, FAILED, CANCELLED, DISABLED };
|
||||||
|
enum StopReason { ManualStop, CancelStop, FailStop, TopPadStop };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TimerState state;
|
||||||
|
|
||||||
|
// variables for capturing the time
|
||||||
|
double startTime;
|
||||||
|
double stopTime;
|
||||||
|
double stoppedTime;
|
||||||
|
double reactionTime;
|
||||||
|
|
||||||
|
// values for the startpad
|
||||||
|
double startPadTriggerTime;
|
||||||
|
|
||||||
|
QDateTime *date;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
// --- main functionality ---
|
||||||
|
bool start();
|
||||||
|
bool cancel();
|
||||||
|
bool stop();
|
||||||
|
bool stop(TimerState);
|
||||||
|
bool reset();
|
||||||
|
|
||||||
|
// --- helper functions ---
|
||||||
|
TimerState getState();
|
||||||
|
double getCurrentTime();
|
||||||
|
double getReactionTime();
|
||||||
|
void refreshDisableStatus();
|
||||||
|
void setDisabled(bool disabled);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
|
bool stop(StopReason reason);
|
||||||
|
|
||||||
|
// --- helper functions ---
|
||||||
|
void setState(TimerState newState);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void stateChanged();
|
||||||
|
void startCanceled(bool falseStart);
|
||||||
|
void reactionTimeChanged();
|
||||||
|
void stopRequested();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCSTWTIMER_H
|
10
ScStwLibraries/resources/ScStwLibrariesShared.qrc
Normal file
10
ScStwLibraries/resources/ScStwLibrariesShared.qrc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>ScStwBasestation.sb64</file>
|
||||||
|
<file>sound/AtYourMarksSound.wav</file>
|
||||||
|
<file>sound/IFSC frequenzy and duration conform false start sound.wav</file>
|
||||||
|
<file>sound/ReadySound.wav</file>
|
||||||
|
<file>sound/FalseStartSound.wav</file>
|
||||||
|
<file>sound/StartsignalSound.wav</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
BIN
ScStwLibraries/resources/sound/AtYourMarksSound.wav
Executable file
BIN
ScStwLibraries/resources/sound/AtYourMarksSound.wav
Executable file
Binary file not shown.
BIN
ScStwLibraries/resources/sound/FalseStartSound.wav
Normal file
BIN
ScStwLibraries/resources/sound/FalseStartSound.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
ScStwLibraries/resources/sound/ReadySound.wav
Executable file
BIN
ScStwLibraries/resources/sound/ReadySound.wav
Executable file
Binary file not shown.
BIN
ScStwLibraries/resources/sound/StartsignalSound.wav
Normal file
BIN
ScStwLibraries/resources/sound/StartsignalSound.wav
Normal file
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
#include <ScStw.hpp>
|
#include "../headers/ScStw.hpp"
|
||||||
|
|
||||||
const char *ScStw::SOCKET_MESSAGE_START_KEY = "<message>";
|
const char *ScStw::SOCKET_MESSAGE_START_KEY = "<message>";
|
||||||
const char *ScStw::SOCKET_MESSAGE_END_KEY = "</message>";
|
const char *ScStw::SOCKET_MESSAGE_END_KEY = "</message>";
|
|
@ -1,4 +1,4 @@
|
||||||
#include "scstwclient.h"
|
#include "../headers/scstwclient.h"
|
||||||
|
|
||||||
ScStwClient * pGlobalScStwClient = nullptr;
|
ScStwClient * pGlobalScStwClient = nullptr;
|
||||||
|
|
389
ScStwLibraries/sources/scstwrace.cpp
Normal file
389
ScStwLibraries/sources/scstwrace.cpp
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
#include "../headers/scstwrace.h"
|
||||||
|
|
||||||
|
ScStwRace::ScStwRace(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
this->state = IDLE;
|
||||||
|
|
||||||
|
// configure the loop that waits for the sound effect to finish
|
||||||
|
this->soundPlayer = new ScStwSoundPlayer();
|
||||||
|
|
||||||
|
// configure timer that handles the delay between the start commands
|
||||||
|
this->nextActionTimer = new QTimer(this);
|
||||||
|
nextActionTimer->setSingleShot(true);
|
||||||
|
this->nextActionLoop = new QEventLoop(this);
|
||||||
|
|
||||||
|
connect(this->nextActionTimer, &QTimer::timeout, this->nextActionLoop, &QEventLoop::quit);
|
||||||
|
|
||||||
|
// write default settings
|
||||||
|
this->startActionSettings.insert(Start, {{"Enabled", true}, {"Delay", 1}});
|
||||||
|
this->writeStartActionSetting(AtYourMarks, false, 0);
|
||||||
|
this->writeStartActionSetting(Ready, false, 0);
|
||||||
|
this->setSoundVolume(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// --- Main Functionality ---
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to start the race
|
||||||
|
*
|
||||||
|
* @brief ScStwRace::startRace
|
||||||
|
* @return {int} 200: OK; 904: MAIN state not matching
|
||||||
|
*/
|
||||||
|
int ScStwRace::start() {
|
||||||
|
if(this->state != IDLE) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "+ [INFO] starting race";
|
||||||
|
|
||||||
|
this->setState(STARTING);
|
||||||
|
|
||||||
|
this->playSoundsAndStartTimers(None);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to stop the currently running race
|
||||||
|
*
|
||||||
|
* @brief ScStwRace::stopRace
|
||||||
|
* @param {int} type 0: stop; 1: cancel; 2: false start
|
||||||
|
* @return {int} 200: OK; 904: MAIN state not matching
|
||||||
|
*/
|
||||||
|
int ScStwRace::stop() {
|
||||||
|
if(this->state != RUNNING && this->state != STARTING) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "+ [INFO] stopping race";
|
||||||
|
|
||||||
|
int returnCode = 900;
|
||||||
|
|
||||||
|
bool stopOk = true;
|
||||||
|
|
||||||
|
foreach(ScStwTimer *speedTimer, this->timers){
|
||||||
|
if(!speedTimer->stop() && speedTimer->getState() != ScStwTimer::DISABLED){
|
||||||
|
stopOk = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnCode = stopOk ? 200:904;
|
||||||
|
|
||||||
|
if(returnCode == 200) {
|
||||||
|
this->setState(STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ScStwRace::handleTimerStop Function to declare the winner and looser timers after a timer has been stopped
|
||||||
|
*/
|
||||||
|
void ScStwRace::handleTimerStop() {
|
||||||
|
if(this->state == RUNNING) {
|
||||||
|
// find out which timer has won
|
||||||
|
double lowestStoppedTime = -1;
|
||||||
|
QList<int> timersWhichHaveWonIds;
|
||||||
|
|
||||||
|
// iterate through all timers and find the lowest time taht was stopped
|
||||||
|
for(int i = 0; i < this->timers.length(); i++) {
|
||||||
|
ScStwTimer * timer = this->timers[i];
|
||||||
|
if(timer->getCurrentTime() > 0 && (timer->getCurrentTime() <= lowestStoppedTime || lowestStoppedTime < 0)) {
|
||||||
|
// this is the timer with the lowest stopped time
|
||||||
|
lowestStoppedTime = timer->getCurrentTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the timer(s) with the lowest stopped time to the winner list
|
||||||
|
for(int i = 0; i < this->timers.length(); i++) {
|
||||||
|
ScStwTimer * timer = this->timers[i];
|
||||||
|
if(timer->getCurrentTime() > 0 && (timer->getCurrentTime() <= lowestStoppedTime || lowestStoppedTime < 0)) {
|
||||||
|
// this is the timer with the lowest stopped time
|
||||||
|
timersWhichHaveWonIds.append(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the states of all timers
|
||||||
|
for(int i = 0; i < this->timers.length(); i++) {
|
||||||
|
ScStwTimer * timer = this->timers[i];
|
||||||
|
|
||||||
|
if(!timersWhichHaveWonIds.contains(i) && timer->getCurrentTime() > 0) {
|
||||||
|
timer->stop(ScStwTimer::LOST);
|
||||||
|
}
|
||||||
|
else if (timersWhichHaveWonIds.contains(i)) {
|
||||||
|
qDebug() << "timer " << i << " has won";
|
||||||
|
timer->stop(ScStwTimer::WON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ScStwRace::resetRace
|
||||||
|
* @return {int} 200: OK; 904: MAIN state not matching
|
||||||
|
*/
|
||||||
|
int ScStwRace::reset() {
|
||||||
|
if(this->state != STOPPED) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "+ [INFO] resetting race";
|
||||||
|
|
||||||
|
int returnCode = 200;
|
||||||
|
|
||||||
|
foreach(ScStwTimer *speedTimer, this->timers){
|
||||||
|
if(!speedTimer->reset() && speedTimer->getState() != ScStwTimer::DISABLED) {
|
||||||
|
returnCode = 904;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(returnCode == 200){
|
||||||
|
this->setState(IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwRace::cancelStart(bool falseStart){
|
||||||
|
// TODO: FIXME
|
||||||
|
qDebug() << "+ [INFO] cancelling race: " << falseStart;
|
||||||
|
|
||||||
|
if(falseStart){
|
||||||
|
// cancel all running timers
|
||||||
|
foreach(ScStwTimer *timer, this->timers) {
|
||||||
|
timer->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setState(STOPPED);
|
||||||
|
|
||||||
|
this->soundPlayer->cancel(this->soundVolume);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->soundPlayer->cancel(this->soundVolume);
|
||||||
|
this->nextActionTimer->stop();
|
||||||
|
this->nextActionLoop->quit();
|
||||||
|
this->nextStartAction = None;
|
||||||
|
|
||||||
|
foreach(ScStwTimer *timer, this->timers){
|
||||||
|
timer->cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwRace::playSoundsAndStartTimers(StartAction thisAction) {
|
||||||
|
if(this->state != STARTING)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
double timeOfSoundPlaybackStart;
|
||||||
|
if(this->startActionSettings.contains(thisAction) && this->startActionSettings[thisAction]["Enabled"].toBool()) {
|
||||||
|
if(!this->soundPlayer->play(thisAction, this->soundVolume, &timeOfSoundPlaybackStart))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->nextStartAction = StartAction(thisAction + 1);
|
||||||
|
qDebug() << "next action is: " << nextStartAction;
|
||||||
|
|
||||||
|
int nextActionDelay = -1;
|
||||||
|
if(this->startActionSettings.contains(this->nextStartAction) && this->startActionSettings[this->nextStartAction]["Enabled"].toBool()) {
|
||||||
|
nextActionDelay = this->startActionSettings[this->nextStartAction]["Delay"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->nextStartAction <= Start) {
|
||||||
|
// perform next action
|
||||||
|
this->nextActionTimer->start(nextActionDelay > 0 ? nextActionDelay:1);
|
||||||
|
if(nextActionDelay > 0)
|
||||||
|
emit this->nextStartActionChanged();
|
||||||
|
this->nextActionLoop->exec();
|
||||||
|
return this->playSoundsAndStartTimers(this->nextStartAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform start
|
||||||
|
|
||||||
|
// start all timers
|
||||||
|
bool startOk = true;
|
||||||
|
foreach(ScStwTimer *timer, this->timers){
|
||||||
|
if(!timer->start(timeOfSoundPlaybackStart + 3100) && timer->getState() != ScStwTimer::DISABLED){
|
||||||
|
startOk = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!startOk) {
|
||||||
|
qDebug() << "[ERROR][START] error staring all timers";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->soundPlayer->waitForSoundFinish()) {
|
||||||
|
qDebug() << "[ERROR][START] start sound wait error";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if a false start occured
|
||||||
|
if(this->state != STARTING)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
nextStartAction = None;
|
||||||
|
emit this->nextStartActionChanged();
|
||||||
|
|
||||||
|
this->setState(RUNNING);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ScStwRace::setState
|
||||||
|
* @param {QString} newState
|
||||||
|
*/
|
||||||
|
void ScStwRace::setState(RaceState newState) {
|
||||||
|
if(newState != this->state) {
|
||||||
|
qDebug() << "+ [INFO][MAIN] state changed: " << newState;
|
||||||
|
this->state = newState;
|
||||||
|
emit this->stateChanged(newState);
|
||||||
|
|
||||||
|
if(this->state == IDLE) {
|
||||||
|
// if we changed to IDLE -> enable timers
|
||||||
|
foreach(ScStwTimer* timer, this->timerEnableQueque) {
|
||||||
|
this->handleTimerEnable(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->timerEnableQueque.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ScStwRace::refreshTimerStates
|
||||||
|
*/
|
||||||
|
void ScStwRace::refreshTimerStates() {
|
||||||
|
|
||||||
|
qDebug() << "[INFO][MAIN] refreshing timer states";
|
||||||
|
|
||||||
|
// check if the race is over
|
||||||
|
int stoppedState = 1;
|
||||||
|
|
||||||
|
foreach(ScStwTimer * timer, this->timers){
|
||||||
|
if(timer->getState() < ScStwTimer::WON){
|
||||||
|
// if the timer is not in stoped state
|
||||||
|
stoppedState = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(this->state != RUNNING) {
|
||||||
|
// TODO athleteProfiles->addResult(timer->getCurrTime(), timer->getReactionTime(), this->speedTimers.indexOf(timer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stoppedState == 1){
|
||||||
|
this->setState(STOPPED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------
|
||||||
|
// --- helper functions ---
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
void ScStwRace::handleTimerEnable(ScStwTimer* timer) {
|
||||||
|
if(this->state == IDLE) {
|
||||||
|
if(timer->getState() == ScStwTimer::DISABLED) {
|
||||||
|
timer->setDisabled(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timer->setDisabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->timerEnableQueque.append(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap ScStwRace::getNextStartActionDetails() {
|
||||||
|
int nextActionDelay = 0;
|
||||||
|
double nextActionDelayProg = 0;
|
||||||
|
|
||||||
|
if(this->nextStartAction == AtYourMarks || this->nextStartAction == Ready) {
|
||||||
|
// get the total delay and the delay progress of the next action timer
|
||||||
|
double remaining = this->nextActionTimer->remainingTime();
|
||||||
|
nextActionDelay = this->startActionSettings[this->nextStartAction]["Delay"].toInt();
|
||||||
|
if(remaining < 0) {
|
||||||
|
remaining = nextActionDelay;
|
||||||
|
}
|
||||||
|
nextActionDelayProg = 1 - (remaining / nextActionDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {{"nextAction", this->nextStartAction}, {"nextActionDelay", nextActionDelay}, {"nextActionDelayProg", nextActionDelayProg}};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwRace::writeStartActionSetting(StartAction action, bool enabled, int delay) {
|
||||||
|
if(action != AtYourMarks && action != Ready)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QVariantMap setting = {{"Enabled", enabled}, {"Delay", delay}};
|
||||||
|
|
||||||
|
if(!this->startActionSettings.contains(action))
|
||||||
|
this->startActionSettings.insert(action, setting);
|
||||||
|
else
|
||||||
|
this->startActionSettings[action] = setting;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwRace::setSoundVolume(double volume) {
|
||||||
|
if(volume >= 0 && volume <= 1) {
|
||||||
|
this->soundVolume = volume;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwRace::addTimer(ScStwTimer *timer) {
|
||||||
|
if(this->state != IDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach(ScStwTimer *existingTimer, this->timers) {
|
||||||
|
if(existingTimer == timer)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->timers.append(timer);
|
||||||
|
|
||||||
|
connect(timer, &ScStwTimer::startCanceled, this, &ScStwRace::cancelStart);
|
||||||
|
connect(timer, &ScStwTimer::stateChanged, this, &ScStwRace::refreshTimerStates);
|
||||||
|
connect(timer, &ScStwTimer::stopRequested, this, &ScStwRace::handleTimerStop);
|
||||||
|
connect(timer, &ScStwTimer::requestEnableChange, this, &ScStwRace::handleTimerEnable);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ScStwRace::RaceState ScStwRace::getState() {
|
||||||
|
return this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScStwRace::StartAction ScStwRace::getNextStartAction()
|
||||||
|
{
|
||||||
|
return this->nextStartAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList ScStwRace::getTimerDetailList() {
|
||||||
|
QVariantList tmpTimers;
|
||||||
|
|
||||||
|
foreach(ScStwTimer * timer, this->timers){
|
||||||
|
QVariantMap tmpTimer;
|
||||||
|
tmpTimer.insert("id", this->timers.indexOf(timer));
|
||||||
|
tmpTimer.insert("state", timer->getState());
|
||||||
|
tmpTimer.insert("currentTime", timer->getCurrentTime());
|
||||||
|
tmpTimer.insert("reactionTime", timer->getReactionTime());
|
||||||
|
tmpTimers.append(tmpTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpTimers;
|
||||||
|
}
|
94
ScStwLibraries/sources/scstwstartsoundplayer.cpp
Normal file
94
ScStwLibraries/sources/scstwstartsoundplayer.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#include "../headers/scstwstartsoundplayer.h"
|
||||||
|
|
||||||
|
ScStwStartSoundPlayer::ScStwStartSoundPlayer(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
this->waitLoop = new QEventLoop();
|
||||||
|
|
||||||
|
this->startSoundFile = new QFile(":/sound/StartsignalSound.wav", this);
|
||||||
|
|
||||||
|
if(!this->startSoundFile->open(QFile::ReadOnly)) {
|
||||||
|
qWarning() << "Cannot open audio File!!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init sound format
|
||||||
|
QAudioFormat format;
|
||||||
|
format.setSampleRate(44100);
|
||||||
|
format.setChannelCount(2);
|
||||||
|
format.setSampleSize(16);
|
||||||
|
format.setCodec("audio/pcm");
|
||||||
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
format.setSampleType(QAudioFormat::SignedInt);
|
||||||
|
|
||||||
|
// check if format is valid
|
||||||
|
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
|
||||||
|
if (!info.isFormatSupported(format)) {
|
||||||
|
qWarning() << "Raw audio format not supported by backend, cannot play audio.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->audioOutput = new QAudioOutput(format);
|
||||||
|
this->audioOutput->setCategory("ScStw start sound");
|
||||||
|
|
||||||
|
connect(this->audioOutput, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwStartSoundPlayer::play(double volume, double *timeOfStop) {
|
||||||
|
|
||||||
|
double st = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
|
// update volume
|
||||||
|
this->audioOutput->setVolume(volume);
|
||||||
|
|
||||||
|
// start
|
||||||
|
this->audioOutput->start(this->startSoundFile);
|
||||||
|
|
||||||
|
double ed = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
qDebug() << "time passed: " << ed-st << " playback elapsed: " << this->audioOutput->elapsedUSecs();
|
||||||
|
|
||||||
|
// wait until the audio output reports the sound is over
|
||||||
|
waitLoop->exec();
|
||||||
|
|
||||||
|
qDebug() << "waitLoop exited!! elapsed: " << this->audioOutput->elapsedUSecs() << " processed: " << this->audioOutput->processedUSecs();
|
||||||
|
// wait until the sound is actually over
|
||||||
|
// the timeOffset is the buffer time before the audio started!
|
||||||
|
int timeOffset = ((this->audioOutput->processedUSecs() - this->audioOutput->elapsedUSecs()) / 1000);
|
||||||
|
if(timeOffset > 0) {
|
||||||
|
QTimer timer;
|
||||||
|
timer.singleShot(timeOffset, this->waitLoop, &QEventLoop::quit);
|
||||||
|
waitLoop->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the point in time where the sound playback actually ended
|
||||||
|
if(timeOfStop != nullptr) {
|
||||||
|
int latency = (this->audioOutput->processedUSecs() - this->audioOutput->elapsedUSecs()) / 1000;
|
||||||
|
*timeOfStop = QDateTime::currentMSecsSinceEpoch() - latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for errors and return
|
||||||
|
if(this->audioOutput->state() == QAudio::IdleState)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwStartSoundPlayer::handleStateChanged(QAudio::State newState)
|
||||||
|
{
|
||||||
|
switch (newState) {
|
||||||
|
case QAudio::IdleState:
|
||||||
|
// Finished playing (no more data)
|
||||||
|
qDebug() << "sound reported over!! elapsed: " << this->audioOutput->elapsedUSecs() << " processed: " << this->audioOutput->processedUSecs();
|
||||||
|
waitLoop->exit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAudio::StoppedState:
|
||||||
|
// Stopped for other reasons
|
||||||
|
if (this->audioOutput->error() != QAudio::NoError) {
|
||||||
|
// Error handling
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// ... other cases as appropriate
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
152
ScStwLibraries/sources/scstwtimer.cpp
Normal file
152
ScStwLibraries/sources/scstwtimer.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#include "../headers/scstwtimer.h"
|
||||||
|
|
||||||
|
ScStwTimer::ScStwTimer(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
this->startTime = 0;
|
||||||
|
this->stopTime = 0;
|
||||||
|
this->stoppedTime = 0;
|
||||||
|
this->reactionTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::start() {
|
||||||
|
switch (this->state) {
|
||||||
|
case STARTING: {
|
||||||
|
// in case of STARTING, start the race!
|
||||||
|
|
||||||
|
this->startTime = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
this->stopTime = 0;
|
||||||
|
this->stoppedTime = 0;
|
||||||
|
|
||||||
|
this->setState(RUNNING);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// otherwise the timer is not supposed to be started!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::cancel() {
|
||||||
|
if(!(this->state == STARTING || this->state == RUNNING))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->setState(CANCELLED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::stop() {
|
||||||
|
this->stop(ManualStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::stop(TimerState result) {
|
||||||
|
switch (result) {
|
||||||
|
case WON:
|
||||||
|
this->setState(WON);
|
||||||
|
return true;
|
||||||
|
case LOST:
|
||||||
|
this->setState(LOST);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::stop(StopReason reason) {
|
||||||
|
if(this->state != STARTING && this->state != RUNNING && this->state != WAITING){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reason) {
|
||||||
|
case ManualStop: {
|
||||||
|
if(this->state == STARTING){
|
||||||
|
emit startCanceled(false);
|
||||||
|
this->setState(CANCELLED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
this->stopTime = this->date->currentMSecsSinceEpoch();
|
||||||
|
this->stoppedTime = this->stopTime - this->startTime;
|
||||||
|
|
||||||
|
// trigger an external state refresh to set the state to either WON or LOST depending on the other timers values (see MainActivity::refreshTimerStates())
|
||||||
|
emit this->stopRequested();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FailStop: {
|
||||||
|
this->stoppedTime = 0;
|
||||||
|
//qDebug() << "+ [INFO][TIMER] Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||||
|
|
||||||
|
if(this->state == RUNNING){
|
||||||
|
qDebug() << "+ [INFO][TIMER] False Start detected, step 2: " << "start Time: " << startTime << " startpadTriggerTime: " << startPadTriggerTime << " reactionTime: " << reactionTime;
|
||||||
|
this->setState(FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit startCanceled(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "+ [INFO][TIMER] Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwTimer::reset(){
|
||||||
|
if( this->state < WON || this->state == DISABLED ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->startTime = 0;
|
||||||
|
this->stopTime = 0;
|
||||||
|
this->stoppedTime = 0;
|
||||||
|
this->reactionTime = 0;
|
||||||
|
|
||||||
|
this->startPadTriggerTime = 0;
|
||||||
|
|
||||||
|
this->setState(IDLE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------
|
||||||
|
// --- helper functions ---
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
void ScStwTimer::setState(TimerState newState){
|
||||||
|
if(this->state == DISABLED && newState != IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(this->state != newState) {
|
||||||
|
this->state = newState;
|
||||||
|
qDebug() << "+ [INFO][TIMER] timer state changed: " << newState;
|
||||||
|
emit this->stateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScStwTimer::TimerState ScStwTimer::getState() {
|
||||||
|
return this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ScStwTimer::getCurrentTime() {
|
||||||
|
if(this->state == RUNNING){
|
||||||
|
return this->date->currentMSecsSinceEpoch() - this->startTime;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this->stoppedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double ScStwTimer::getReactionTime() {
|
||||||
|
return this->reactionTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwTimer::setDisabled(bool disabled) {
|
||||||
|
if(disabled)
|
||||||
|
this->setState(DISABLED);
|
||||||
|
else
|
||||||
|
this->setState(IDLE);
|
||||||
|
}
|
Reference in a new issue