- some improvements and fixes

- added remote monitor race
This commit is contained in:
Dorian Zedler 2020-04-18 14:25:48 +02:00
parent 73d62d01d8
commit f4ee962c98
Signed by: dorian
GPG key ID: 989DE36109AFA354
8 changed files with 372 additions and 47 deletions

View file

@ -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

View file

@ -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<waitingRequest> 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;

View file

@ -30,10 +30,14 @@ public:
};
Q_ENUM(NextStartActionDetailAttributes);
protected:
StartAction nextStartAction;
QList<ScStwTimer *> timers;
void setState(RaceState newState);
private:
RaceState state;
QList<ScStwTimer *> timers;
QList<ScStwTimer*> timerEnableQueque;
QTimer *nextActionTimer;
@ -42,7 +46,6 @@ private:
// sounds
ScStwSoundPlayer * soundPlayer;
StartAction nextStartAction;
// some settings
double soundVolume;
@ -54,12 +57,10 @@ private:
*/
QMap<StartAction, QVariantMap> 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();

View file

@ -0,0 +1,35 @@
#ifndef SCSTWREMOTEMONITORRACE_H
#define SCSTWREMOTEMONITORRACE_H
#include <QObject>
#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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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;