From f4ee962c9835ea97e08526ba326ad0004111679b Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Sat, 18 Apr 2020 14:25:48 +0200 Subject: [PATCH] - some improvements and fixes - added remote monitor race --- ScStwLibraries/ScStwLibraries.pro | 2 + ScStwLibraries/headers/scstwclient.h | 68 +++--- ScStwLibraries/headers/scstwrace.h | 13 +- .../headers/scstwremotemonitorrace.h | 35 ++++ ScStwLibraries/headers/scstwtimer.h | 52 ++++- ScStwLibraries/sources/scstwclient.cpp | 19 +- .../sources/scstwremotemonitorrace.cpp | 194 ++++++++++++++++++ ScStwLibraries/sources/scstwtimer.cpp | 36 +++- 8 files changed, 372 insertions(+), 47 deletions(-) create mode 100644 ScStwLibraries/headers/scstwremotemonitorrace.h create mode 100644 ScStwLibraries/sources/scstwremotemonitorrace.cpp diff --git a/ScStwLibraries/ScStwLibraries.pro b/ScStwLibraries/ScStwLibraries.pro index 42fe8f2..aa6cfca 100644 --- a/ScStwLibraries/ScStwLibraries.pro +++ b/ScStwLibraries/ScStwLibraries.pro @@ -21,6 +21,7 @@ SOURCES += \ sources/ScStw.cpp \ sources/scstwclient.cpp \ sources/scstwrace.cpp \ + sources/scstwremotemonitorrace.cpp \ sources/scstwsoundplayer.cpp \ sources/scstwtimer.cpp @@ -29,6 +30,7 @@ HEADERS += \ headers/ScStwLibraries_global.h \ headers/scstwrace.h \ headers/scstwclient.h \ + headers/scstwremotemonitorrace.h \ headers/scstwsoundplayer.h \ headers/scstwtimer.h diff --git a/ScStwLibraries/headers/scstwclient.h b/ScStwLibraries/headers/scstwclient.h index f2e2cf3..bd4686b 100644 --- a/ScStwLibraries/headers/scstwclient.h +++ b/ScStwLibraries/headers/scstwclient.h @@ -31,6 +31,8 @@ class ScStwClient : public QObject { Q_OBJECT + Q_PROPERTY(State state READ getState NOTIFY stateChanged) + Q_PROPERTY(QVariantList extensions READ getExtensions NOTIFY extensionsChanged) public: /*! @@ -41,6 +43,7 @@ public: explicit ScStwClient(); enum State {DISCONNECTED, CONNECTING, INITIALISING, CONNECTED}; + Q_ENUM(State); private: // values for the socket connection @@ -49,7 +52,7 @@ private: int errors; const static int ERRORS_UNTIL_DISCONNECT = 4; - QVariantList connections; + QVariantList extensions; //---general status values---// @@ -80,32 +83,6 @@ private: QList waitingRequests; -signals: - /*! - * \brief Is emitted, when the connection state changes - */ - void stateChanged(); - - /*! - * \brief Is emitted, whenever a reply is recieved which does not match any requests - * - * \param reply contains the reply - */ - void gotUnexpectedMessage(QString message); - - /*! - * \brief Is emitted, when an update signal from the basestation is recieved - * - * \param data - */ - void gotSignal(ScStw::SignalKey key, QVariant data); - - /*! - * \brief Is emitted, when there is any network error - * \param error - */ - void gotError(QAbstractSocket::SocketError error); - public slots: /*! @@ -191,10 +168,10 @@ public slots: ScStwClient::State getState(); /*! - * \brief Functio to get the extensions and their state from the base station + * \brief Function to get the extensions and their state from the base station * \return a list with all configured extensions and their state */ - QVariantList getConnections(); + QVariantList getExtensions(); /*! * \brief Function to get the time offset of the base station relative to the clients time @@ -300,7 +277,7 @@ private slots: * \see gotSignal() * \param connections the list to set the chache to */ - void setConnections(QVariantList connections); + void setExtensions(QVariantList extensions); /*! * \brief Function to set the local state. @@ -309,6 +286,37 @@ private slots: * \param newState the state to change to */ void setState(ScStwClient::State newState); + +signals: + /*! + * \brief Is emitted, when the connection state changes + */ + void stateChanged(); + + /*! + * \brief Is emitted, whenever a reply is recieved which does not match any requests + * + * \param reply contains the reply + */ + void gotUnexpectedMessage(QString message); + + /*! + * \brief Is emitted, when an update signal from the basestation is recieved + * + * \param data + */ + void gotSignal(ScStw::SignalKey key, QVariant data); + + /*! + * \brief Is emitted, when there is any network error + * \param error + */ + void gotError(QAbstractSocket::SocketError error); + + /*! + * \brief Is emitted, when the extensions of the base station changed + */ + void extensionsChanged(); }; extern ScStwClient * pGlobalScStwClient; diff --git a/ScStwLibraries/headers/scstwrace.h b/ScStwLibraries/headers/scstwrace.h index 7f20198..2687b0d 100644 --- a/ScStwLibraries/headers/scstwrace.h +++ b/ScStwLibraries/headers/scstwrace.h @@ -30,10 +30,14 @@ public: }; Q_ENUM(NextStartActionDetailAttributes); +protected: + StartAction nextStartAction; + QList timers; + void setState(RaceState newState); + private: RaceState state; - QList timers; QList timerEnableQueque; QTimer *nextActionTimer; @@ -42,7 +46,6 @@ private: // sounds ScStwSoundPlayer * soundPlayer; - StartAction nextStartAction; // some settings double soundVolume; @@ -54,12 +57,10 @@ private: */ QMap startActionSettings; - void setState(RaceState newState); public slots: int start(); int stop(); - void handleTimerStop(); int reset(); void cancelStart(bool falseStart); @@ -74,10 +75,14 @@ public slots: QVariantList getNextStartActionDetails(); QVariantList getTimerDetailList(); +protected slots: + + private slots: void refreshTimerStates(); void handleTimerEnable(ScStwTimer* timer); bool playSoundsAndStartTimers(StartAction thisAction); + void handleTimerStop(); signals: void startTimers(); diff --git a/ScStwLibraries/headers/scstwremotemonitorrace.h b/ScStwLibraries/headers/scstwremotemonitorrace.h new file mode 100644 index 0000000..e031694 --- /dev/null +++ b/ScStwLibraries/headers/scstwremotemonitorrace.h @@ -0,0 +1,35 @@ +#ifndef SCSTWREMOTEMONITORRACE_H +#define SCSTWREMOTEMONITORRACE_H + +#include +#include "scstwrace.h" +#include "scstwclient.h" + +class ScStwRemoteMonitorRace : public ScStwRace +{ + Q_OBJECT +public: + ScStwRemoteMonitorRace(ScStwClient *monitorClient, QObject *parent = nullptr); + +protected: + double nextStartActionTotalDelay; + double nextStartActionDelayStartedAt; + +private: + ScStwClient *scStwClient; + +public slots: + int start(); + void cancelStart(); + int stop(); + int reset(); + bool addTimer(ScStwTimer *timer); + +private slots: + void handleClientStateChanged(); + void handleBaseStationSignal(ScStw::SignalKey key, QVariant data); + bool refreshRemoteTimers(QVariantList remoteTimers); + +}; + +#endif // SCSTWREMOTEMONITORRACE_H diff --git a/ScStwLibraries/headers/scstwtimer.h b/ScStwLibraries/headers/scstwtimer.h index e2c5161..1ee9141 100644 --- a/ScStwLibraries/headers/scstwtimer.h +++ b/ScStwLibraries/headers/scstwtimer.h @@ -46,8 +46,9 @@ public: /*! * \brief ScStwTimer constructor * \param parent the parent object + * \param directControlEnabled Defines if protected properties (startTimer, stopTime, reactionTime and state) can be directly set from outside. */ - explicit ScStwTimer(QObject *parent = nullptr); + explicit ScStwTimer(QObject *parent = nullptr, bool directControlEnabled = false); /*! * \brief The TimerState enum contains all state the timer can be in @@ -96,6 +97,11 @@ protected: */ double reactionTime; + /*! + * \brief Defines if protected properties (startTimer, stopTime, reactionTime and state) can be directly set from outside. + */ + bool directControlEnabled; + public slots: /*! @@ -205,6 +211,48 @@ public slots: */ void setDisabled(bool disabled); + /*! + * \brief Function to change the state of the timer + * + * Only works when directControlEnabled is set to true! + * Doing this will emit the ScStwTimer::stateChanged() signal (only if the new state differs from the current one) + * + * \param newState The new state + * \param force whether to force the state change (just to distinguish between protected and public function) + * \return false when directControlEnabled or force is set to false and the startTime was therefore not modified, true otherwise + */ + bool setState(TimerState newState, bool force); + + /*! + * \brief Function to dircetly change the start time + * + * Only works when directControlEnabled is set to true! + * + * \param startTime the time to change to + * \return false when directControlEnabled is set to false and the startTime was therefore not modified, true otherwise + */ + bool setStartTime(double startTime); + + /*! + * \brief Function to dircetly change the stop time + * + * Only works when directControlEnabled is set to true! + * + * \param stopTime the time to change to + * \return false when directControlEnabled is set to false and the stopTime was therefore not modified, true otherwise + */ + bool setStopTime(double stopTime); + + /*! + * \brief Function to dircetly change the rection time + * + * Only works when directControlEnabled is set to true! + * + * \param reactionTime the time to change to + * \return false when directControlEnabled is set to false and the reactionTime was therefore not modified, true otherwise + */ + bool setReactionTime(double rectionTime); + protected slots: /*! @@ -240,7 +288,6 @@ protected slots: */ bool stop(StopReason reason); - // --- helper functions --- /*! * \brief Function to change the state of the timer * @@ -250,6 +297,7 @@ protected slots: */ void setState(TimerState newState); + signals: /*! * \brief Emitted when the state of the timer changed diff --git a/ScStwLibraries/sources/scstwclient.cpp b/ScStwLibraries/sources/scstwclient.cpp index d53dcda..ae8007e 100644 --- a/ScStwLibraries/sources/scstwclient.cpp +++ b/ScStwLibraries/sources/scstwclient.cpp @@ -6,7 +6,7 @@ ScStwClient::ScStwClient() : QObject(nullptr) { this->state = DISCONNECTED; this->nextConnectionId = 1; - this->connections = QVariantList({}); + this->extensions = QVariantList({}); this->socket = new QTcpSocket(this); @@ -78,7 +78,7 @@ void ScStwClient::deInit() { if(this->state == DISCONNECTED) return; - this->setConnections(QVariantList({})); + this->setExtensions(QVariantList({})); this->setState(DISCONNECTED); } @@ -335,7 +335,7 @@ void ScStwClient::handleSignal(QVariantMap data) { { // the extension connections have changed // -> handle locally - this->setConnections(data["data"].toList()); + this->setExtensions(data["data"].toList()); return; break; } @@ -448,8 +448,8 @@ void ScStwClient::setState(ScStwClient::State newState){ } } -QVariantList ScStwClient::getConnections() { - return connections; +QVariantList ScStwClient::getExtensions() { + return this->extensions; } int ScStwClient::getTimeOffset() { @@ -460,9 +460,10 @@ QString ScStwClient::getFirmwareVersion() { return this->firmwareVersion; } -void ScStwClient::setConnections(QVariantList connections) { - if(this->connections != connections){ - this->connections = connections; - emit this->gotSignal(ScStw::ExtensionsChanged, this->getConnections()); +void ScStwClient::setExtensions(QVariantList extensions) { + if(this->extensions != extensions){ + this->extensions = extensions; + emit this->gotSignal(ScStw::ExtensionsChanged, this->getExtensions()); + emit this->extensionsChanged(); } } diff --git a/ScStwLibraries/sources/scstwremotemonitorrace.cpp b/ScStwLibraries/sources/scstwremotemonitorrace.cpp new file mode 100644 index 0000000..5308291 --- /dev/null +++ b/ScStwLibraries/sources/scstwremotemonitorrace.cpp @@ -0,0 +1,194 @@ +#include "../headers/scstwremotemonitorrace.h" + +ScStwRemoteMonitorRace::ScStwRemoteMonitorRace(ScStwClient *monitorClient, QObject *parent) : ScStwRace(parent) +{ + this->scStwClient = monitorClient; + + connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwRemoteMonitorRace::handleClientStateChanged); + connect(this->scStwClient, &ScStwClient::gotSignal, this, &ScStwRemoteMonitorRace::handleBaseStationSignal); +} + +// -------------------------- +// --- Main Functionality --- +// -------------------------- + +int ScStwRemoteMonitorRace::start() { + + if(this->getState() != ScStwRace::IDLE) { + return 904; + } + + qDebug() << "+ --- starting race"; + + int returnCode = 900; + + QVariantMap reply = this->scStwClient->sendCommand(1000); + + if(reply["status"] != 200){ + //handle Error!! + returnCode = reply["status"].toInt(); + } + else { + + returnCode = 200; + + } + + + return returnCode; +} + +void ScStwRemoteMonitorRace::cancelStart() { + return; +} + +int ScStwRemoteMonitorRace::stop() { + + if(this->getState() != ScStwRace::RUNNING && this->getState() != ScStwRace::STARTING) { + return 904; + } + + // type can be: + // 0: stopp + // 1: cancel + // 2: fail (fase start) + + qDebug() << "+ --- stopping race"; + + int returnCode = 900; + + QVariantMap reply = this->scStwClient->sendCommand(1001); + + if(reply["status"] != 200){ + returnCode = reply["status"].toInt(); + } + else { + returnCode = 200; + } + + + return returnCode; +} + +int ScStwRemoteMonitorRace::reset() { + + if(this->getState() != ScStwRace::STOPPED) { + return 904; + } + + qDebug() << "+ --- resetting race"; + + int returnCode = 900; + + + QVariantMap reply = this->scStwClient->sendCommand(1002); + + if(reply["status"] != 200){ + //handle Error!! + returnCode = reply["status"].toInt(); + } + else { + returnCode = 200; + } + + + + return returnCode; +} + + +// ------------------------- +// --- Base Station sync --- +// ------------------------- + +void ScStwRemoteMonitorRace::handleClientStateChanged() { + // TODO + switch (this->scStwClient->getState()) { + case ScStwClient::CONNECTED: + break; + default: + break; + } +} + +/** + * @brief ScStwAppBackend::handleBaseStationUpdate + * + * Function to handle an update, sent by the base station, which indicates + * that some remote value (like a state) has changed + * + * @param data + */ +void ScStwRemoteMonitorRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) { + qDebug() << "got signal: " << data; + switch (key) { + case ScStw::RaceStateChanged: + { + // the remote race state has changed + this->setState( ScStwRace::RaceState( data.toInt() ) ); + break; + } + case ScStw::TimersChanged: + { + // the remote timers have changed + this->refreshRemoteTimers(data.toList()); + break; + } + case ScStw::NextStartActionChanged: + { + // the next start action has changed + this->nextStartActionTotalDelay = data.toList()[ScStwRace::NextStartActionTotalDelay].toDouble(); + this->nextStartActionDelayStartedAt = QDateTime::currentMSecsSinceEpoch() - (this->nextStartActionTotalDelay * data.toList()[ScStwRace::NextStartActionDelayProgress].toDouble()); + this->nextStartAction = ScStwRace::StartAction( data.toList()[ScStwRace::NextStartAction].toInt() ); + + emit this->nextStartActionChanged(); + break; + } + case ScStw::InvalidSignal: + return; + + default: + return; + } +} + +bool ScStwRemoteMonitorRace::refreshRemoteTimers(QVariantList remoteTimers) { + + if(remoteTimers.length() != this->timers.length()){ + // local timers are out of sync + + // delete all current timers + foreach(ScStwTimer * locTimer, this->timers){ + delete locTimer; + } + + this->timers.clear(); + + foreach(QVariant remoteTimer, remoteTimers){ + // create a local timer for each remote timer + this->timers.append(new ScStwTimer(this, true)); + } + } + + foreach(QVariant remoteTimer, remoteTimers){ + int currId = remoteTimer.toMap()["id"].toInt(); + ScStwTimer::TimerState newState = ScStwTimer::TimerState(remoteTimer.toMap()["state"].toInt()); + double currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); + + this->timers[currId]->setStartTime(currentMSecsSinceEpoch - remoteTimer.toMap()["currentTime"].toDouble()); + + if(newState >= ScStwTimer::WAITING) + this->timers[currId]->setStopTime(currentMSecsSinceEpoch); + + this->timers[currId]->setReactionTime(remoteTimer.toMap()["reactionTime"].toDouble()); + + this->timers[currId]->setState(newState, true); + } + + return true; +} + +bool ScStwRemoteMonitorRace::addTimer(ScStwTimer* timer) { + Q_UNUSED(timer) + return false; +} diff --git a/ScStwLibraries/sources/scstwtimer.cpp b/ScStwLibraries/sources/scstwtimer.cpp index 2362756..e8de52f 100644 --- a/ScStwLibraries/sources/scstwtimer.cpp +++ b/ScStwLibraries/sources/scstwtimer.cpp @@ -1,8 +1,8 @@ #include "../headers/scstwtimer.h" -ScStwTimer::ScStwTimer(QObject *parent) : QObject(parent) +ScStwTimer::ScStwTimer(QObject *parent, bool directControlEnabled) : QObject(parent) { - + this->directControlEnabled = directControlEnabled; this->startTime = 0; this->stopTime = 0; this->reactionTime = 0; @@ -145,6 +145,38 @@ bool ScStwTimer::reset(){ // --- helper functions --- // ------------------------ +bool ScStwTimer::setStartTime(double startTime) { + if(!this->directControlEnabled) + return false; + + this->startTime = startTime; + return true; +} + +bool ScStwTimer::setStopTime(double stopTime) { + if(!this->directControlEnabled) + return false; + + this->stopTime = stopTime; + return true; +} + +bool ScStwTimer::setReactionTime(double reactionTime) { + if(!this->directControlEnabled) + return false; + + this->reactionTime = reactionTime; + return true; +} + +bool ScStwTimer::setState(TimerState newState, bool force) { + if(!this->directControlEnabled || !force) + return false; + + this->setState(newState); + return true; +} + void ScStwTimer::setState(TimerState newState){ if(this->state == DISABLED && newState != IDLE) return;