fixed remote base station stuff
This commit is contained in:
parent
315ef27cc5
commit
9d7e26aff0
13 changed files with 83 additions and 1655 deletions
|
@ -1,79 +0,0 @@
|
|||
#ifndef BUZZERCONN_H
|
||||
#define BUZZERCONN_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QObject>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QtNetwork>
|
||||
#include <QAuthenticator>
|
||||
#include <QDesktopServices>
|
||||
#include <QDateTime>
|
||||
#include <QtDebug>
|
||||
|
||||
typedef struct strReturnData{
|
||||
int status_code;
|
||||
QString text;
|
||||
}ReturnData_t;
|
||||
|
||||
class BuzzerConn : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BuzzerConn(QObject *parent = nullptr, QString ip = "http://192.168.4.1", int port = 80);
|
||||
double offset;
|
||||
QList<double> latest_offsets;
|
||||
double latest_button_pressed;
|
||||
double starttime;
|
||||
bool connected;
|
||||
int connection_progress;
|
||||
QString ip;
|
||||
int port;
|
||||
int errors;
|
||||
int errors_until_disconnect = 4;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *networkManager;
|
||||
QNetworkAccessManager *reloadNetworkManager;
|
||||
QDateTime *date;
|
||||
QTcpSocket *socket;
|
||||
QStringList pending_commands;
|
||||
//QSemaphore dataPipe(1);
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
ReturnData_t senddata(QNetworkAccessManager * NetMan, QUrl serviceUrl, int timeout);
|
||||
//function to communicate with the buzzer
|
||||
Q_INVOKABLE signed long sendCommand(QString command, int timeout);
|
||||
//function to send commands to the sensor
|
||||
//Can be:
|
||||
//command - return
|
||||
//GET_TIMESTAMP - timestamp of the sensor
|
||||
//GET_LASTPRESSED - timestamp of the sensor when it was triggered the last time
|
||||
//
|
||||
//error codes:
|
||||
//(-1) : timeout
|
||||
//(-2) : invalid data was recieved
|
||||
Q_INVOKABLE QList<double> gettimes(int timeout);
|
||||
//function to get the times from the buzzer as a list with the normal network manager
|
||||
Q_INVOKABLE bool connect();
|
||||
//function to connect to buzzer
|
||||
Q_INVOKABLE bool calcoffset(QList<double> times);
|
||||
//function that calculates the average time offset between the buzzer and the device
|
||||
Q_INVOKABLE bool buzzer_triggered();
|
||||
//function that checks ih the buzzer has been pushed since the last call of this function
|
||||
Q_INVOKABLE bool start();
|
||||
//syncs the buzzer and the base to make a start possible
|
||||
Q_INVOKABLE double get(QString key);
|
||||
//can return some things (offset, lastpressed, currtime, connection_progress, connected)
|
||||
Q_INVOKABLE QString test();
|
||||
Q_INVOKABLE bool refresh();
|
||||
//refreshed the connection to the buzzer
|
||||
Q_INVOKABLE void appendCommand(QString command);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // BUZZERCONN_H
|
|
@ -1,116 +0,0 @@
|
|||
#ifndef CLIMBINGRACE_H
|
||||
#define CLIMBINGRACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSound>
|
||||
#include <QSoundEffect>
|
||||
#include <QMediaPlayer>
|
||||
|
||||
#include <scstwclient.h>
|
||||
#include <ScStw.hpp>
|
||||
|
||||
#include "headers/appsettings.h"
|
||||
#include "headers/speedtimer.h"
|
||||
|
||||
class ClimbingRace : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(int mode READ getMode NOTIFY modeChanged)
|
||||
Q_PROPERTY(QVariant timers READ getTimerTextList NOTIFY timerTextChanged)
|
||||
Q_PROPERTY(QString baseStationState READ getBaseStationState NOTIFY baseStationStateChanged)
|
||||
Q_PROPERTY(QVariant baseStationConnections READ getBaseStationConnections NOTIFY baseStationConnectionsChanged)
|
||||
Q_PROPERTY(double nextStartActionDelayProgress READ getNextStartActionDelayProgress NOTIFY nextStartActionDelayProgressChanged)
|
||||
Q_PROPERTY(int nextStartAction READ getNextStartAction NOTIFY nextStartActionChanged)
|
||||
Q_PROPERTY(QVariantMap baseStationProperties READ getBaseStationProperties NOTIFY baseStationPropertiesChanged)
|
||||
|
||||
public:
|
||||
explicit ClimbingRace(QObject *parent = nullptr);
|
||||
|
||||
enum RaceMode { LOCAL, REMOTE };
|
||||
RaceMode mode;
|
||||
|
||||
private:
|
||||
AppSettings * appSettings;
|
||||
ScStwClient * scStwClient;
|
||||
|
||||
QMediaPlayer * player;
|
||||
|
||||
QTimer * timerTextRefreshTimer;
|
||||
QTimer * nextStartActionTimer;
|
||||
|
||||
QDateTime *date;
|
||||
|
||||
QList<SpeedTimer *> speedTimers;
|
||||
|
||||
double nextStartActionDelayProgress;
|
||||
// only used in remote mode:
|
||||
double nextStartActionDelayStartedAt;
|
||||
double nextStartActionTotalDelay;
|
||||
|
||||
// helper vars
|
||||
QVariantList qmlTimers;
|
||||
|
||||
private slots:
|
||||
// helper functions
|
||||
void playSoundsAndStartRace();
|
||||
bool playSound(QString path);
|
||||
void setState(ScStw::RaceState newState);
|
||||
void refreshMode();
|
||||
void refreshTimerText();
|
||||
|
||||
bool refreshRemoteTimers(QVariantList timers);
|
||||
|
||||
signals:
|
||||
void nextStartActionChanged();
|
||||
void nextStartActionDelayProgressChanged();
|
||||
|
||||
void stateChanged(int state);
|
||||
void modeChanged();
|
||||
void timerTextChanged();
|
||||
void baseStationStateChanged();
|
||||
void baseStationConnectionsChanged();
|
||||
void baseStationPropertiesChanged();
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE int startRace();
|
||||
Q_INVOKABLE int stopRace(int type);
|
||||
Q_INVOKABLE int resetRace();
|
||||
|
||||
// base station sync
|
||||
void handleBaseStationSignal(ScStw::SignalKey key, QVariant data);
|
||||
Q_INVOKABLE bool pairConnectedUsbExtensions();
|
||||
|
||||
// functions for qml
|
||||
Q_INVOKABLE int getState();
|
||||
Q_INVOKABLE int getMode();
|
||||
Q_INVOKABLE QVariant getTimerTextList();
|
||||
Q_INVOKABLE double getNextStartActionDelayProgress();
|
||||
Q_INVOKABLE int getNextStartAction();
|
||||
|
||||
Q_INVOKABLE void writeSetting(QString key, QVariant value);
|
||||
Q_INVOKABLE void writeSetting(ScStw::BaseStationSetting key, QVariant value);
|
||||
Q_INVOKABLE QString readSetting(QString key);
|
||||
Q_INVOKABLE QString readSetting(ScStw::BaseStationSetting key);
|
||||
|
||||
Q_INVOKABLE void connectBaseStation();
|
||||
Q_INVOKABLE void disconnectBaseStation();
|
||||
Q_INVOKABLE QString getBaseStationState();
|
||||
Q_INVOKABLE QVariant getBaseStationConnections();
|
||||
Q_INVOKABLE QVariantMap getBaseStationProperties();
|
||||
|
||||
Q_INVOKABLE bool updateBasestationFirmware();
|
||||
Q_INVOKABLE bool updateBasestationTime();
|
||||
|
||||
// athlete management
|
||||
Q_INVOKABLE QVariant getAthletes();
|
||||
Q_INVOKABLE bool createAthlete( QString userName, QString fullName );
|
||||
Q_INVOKABLE bool deleteAthlete( QString userName );
|
||||
Q_INVOKABLE bool selectAthlete( QString userName, int timerId );
|
||||
Q_INVOKABLE QVariant getResults( QString userName );
|
||||
|
||||
Q_INVOKABLE bool reloadBaseStationIpAdress();
|
||||
};
|
||||
|
||||
#endif // CLIMBINGRACE_H
|
|
@ -6,19 +6,18 @@
|
|||
#include <scstwclient.h>
|
||||
#include <scstwrace.h>
|
||||
#include <ScStw.hpp>
|
||||
#include <scstwremotemonitorrace.h>
|
||||
|
||||
#include "headers/appsettings.h"
|
||||
|
||||
|
||||
class ScStwAppBackend : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
//Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(int mode READ getMode NOTIFY modeChanged)
|
||||
//Q_PROPERTY(QString baseStationState READ getBaseStationState NOTIFY baseStationStateChanged)
|
||||
Q_PROPERTY(ScStwRace* race READ getRace NOTIFY raceChanged)
|
||||
Q_PROPERTY(QVariant baseStationConnections READ getBaseStationConnections NOTIFY baseStationConnectionsChanged)
|
||||
Q_PROPERTY(QVariantMap baseStationProperties READ getBaseStationProperties NOTIFY baseStationPropertiesChanged)
|
||||
Q_PROPERTY(ScStwClient *scStwClient READ getScStwClient NOTIFY scStwClientChanged)
|
||||
|
||||
public:
|
||||
explicit ScStwAppBackend(QObject *parent = nullptr);
|
||||
|
@ -35,15 +34,12 @@ private:
|
|||
// TODO: DOINEED? QTimer * nextStartActionTimer;
|
||||
|
||||
ScStwRace * localRace;
|
||||
ScStwRemoteMonitorRace * remoteRace;
|
||||
|
||||
public slots:
|
||||
// base station sync
|
||||
//void handleBaseStationSignal(ScStw::SignalKey key, QVariant data);
|
||||
Q_INVOKABLE bool pairConnectedUsbExtensions();
|
||||
|
||||
// functions for qml
|
||||
Q_INVOKABLE ScStwRace *getRace();
|
||||
//Q_INVOKABLE int getState();
|
||||
Q_INVOKABLE ScStwClient *getScStwClient();
|
||||
Q_INVOKABLE int getMode();
|
||||
|
||||
Q_INVOKABLE void writeSetting(QString key, QVariant value);
|
||||
|
@ -51,15 +47,6 @@ public slots:
|
|||
Q_INVOKABLE QString readSetting(QString key);
|
||||
Q_INVOKABLE QString readSetting(ScStw::BaseStationSetting key);
|
||||
|
||||
Q_INVOKABLE void connectBaseStation();
|
||||
Q_INVOKABLE void disconnectBaseStation();
|
||||
Q_INVOKABLE QString getBaseStationState();
|
||||
Q_INVOKABLE QVariant getBaseStationConnections();
|
||||
Q_INVOKABLE QVariantMap getBaseStationProperties();
|
||||
|
||||
Q_INVOKABLE bool updateBasestationFirmware();
|
||||
Q_INVOKABLE bool updateBasestationTime();
|
||||
|
||||
// athlete management
|
||||
Q_INVOKABLE QVariant getAthletes();
|
||||
Q_INVOKABLE bool createAthlete( QString userName, QString fullName );
|
||||
|
@ -67,23 +54,20 @@ public slots:
|
|||
Q_INVOKABLE bool selectAthlete( QString userName, int timerId );
|
||||
Q_INVOKABLE QVariant getResults( QString userName );
|
||||
|
||||
Q_INVOKABLE bool reloadBaseStationIpAdress();
|
||||
|
||||
|
||||
private slots:
|
||||
void refreshTimerText();
|
||||
void refreshMode();
|
||||
void reloadRaceSettings();
|
||||
void reloadBaseStationIpAdress();
|
||||
|
||||
signals:
|
||||
void modeChanged();
|
||||
void raceChanged();
|
||||
void scStwClientChanged();
|
||||
|
||||
void baseStationStateChanged();
|
||||
void baseStationConnectionsChanged();
|
||||
void baseStationPropertiesChanged();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // SCSTWAPPBACKEND_H
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef SPEEDTIMER_H
|
||||
#define SPEEDTIMER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
class SpeedTimer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpeedTimer(QObject *parent = nullptr);
|
||||
|
||||
enum timerState { IDLE, STARTING, WAITING, RUNNING, WON, LOST, FAILED, CANCELLED, DISABLED };
|
||||
timerState state;
|
||||
|
||||
// variables for capturing the time
|
||||
double startTime;
|
||||
double stopTime;
|
||||
double stoppedTime;
|
||||
double reactionTime;
|
||||
|
||||
signals:
|
||||
void stateChanged(timerState newState);
|
||||
void startCanceled(bool falseStart);
|
||||
|
||||
public slots:
|
||||
bool start(bool force = false);
|
||||
bool stop(int type, bool force = false);
|
||||
bool reset(bool force = false);
|
||||
|
||||
void setState(timerState newState);
|
||||
QString getState();
|
||||
double getCurrTime();
|
||||
QString getText();
|
||||
|
||||
//helper functions
|
||||
|
||||
void delay(int mSecs);
|
||||
|
||||
timerState stateFromString(QString state);
|
||||
private:
|
||||
QDateTime *date;
|
||||
};
|
||||
|
||||
#endif // SPEEDTIMER_H
|
|
@ -16,7 +16,7 @@ ListView {
|
|||
spacing: parentObj.rowSpacing
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
model: speedBackend.baseStationConnections.length
|
||||
model: speedBackend.scStwClient.extensions.length
|
||||
delegate: ConnectionDelegate {
|
||||
|
||||
opacity: 1
|
||||
|
@ -24,7 +24,7 @@ ListView {
|
|||
width: parent.width
|
||||
height: parentObj.delegateHeight
|
||||
|
||||
text: speedBackend.baseStationConnections[index]["name"]
|
||||
status: {'status': speedBackend.baseStationConnections[index]["state"], 'progress': speedBackend.baseStationConnections[index]["progress"]}
|
||||
text: speedBackend.scStwClient.extensions[index]["name"]
|
||||
status: {'status': speedBackend.scStwClient.extensions[index]["state"], 'progress': speedBackend.scStwClient.extensions[index]["progress"]}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ import QtQuick.Layouts 1.3
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
import com.itsblue.speedclimbingstopwatch 2.0
|
||||
|
||||
import "../components"
|
||||
|
||||
Column {
|
||||
|
@ -13,7 +16,7 @@ Column {
|
|||
|
||||
property string title: qsTr("base station")
|
||||
|
||||
property bool baseConnected: speedBackend.baseStationState === "connected"
|
||||
property bool baseConnected: speedBackend.scStwClient.state === ScStwClient.CONNECTED
|
||||
property var parentObj
|
||||
|
||||
opacity: 0
|
||||
|
@ -31,18 +34,32 @@ Column {
|
|||
|
||||
onTriggered: {
|
||||
busyDl.open()
|
||||
var ret = speedBackend.updateBasestationFirmware()
|
||||
var ret = speedBackend.scStwClient.updateFirmware()
|
||||
busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionDelegate {
|
||||
id: connectToBaseDel
|
||||
|
||||
function clientStateToString(state) {
|
||||
switch(state) {
|
||||
case ScStwClient.DISCONNECTED:
|
||||
return "disconnected"
|
||||
case ScStwClient.CONNECTING:
|
||||
return "connecting"
|
||||
case ScStwClient.INITIALISING:
|
||||
return "connecting"
|
||||
case ScStwClient.CONNECTED:
|
||||
return "connected"
|
||||
}
|
||||
}
|
||||
|
||||
text: status.status === "connected" ? qsTr("disconnect"): status.status === "disconnected" ? qsTr("connect"):qsTr("connecting...")
|
||||
|
||||
status: { "status": speedBackend.baseStationState, "progress": 100 }
|
||||
connect: speedBackend.connectBaseStation
|
||||
disconnect: speedBackend.disconnectBaseStation
|
||||
status: { "status": clientStateToString(speedBackend.scStwClient.state), "progress": 100 }
|
||||
connect: speedBackend.scStwClient.connectToHost
|
||||
disconnect: speedBackend.scStwClient.closeConnection
|
||||
type: "baseStation"
|
||||
|
||||
width: parent.width
|
||||
|
@ -136,7 +153,6 @@ Column {
|
|||
|
||||
onInputTextChanged: {
|
||||
speedBackend.writeSetting("baseStationIpAdress", inputText)
|
||||
speedBackend.reloadBaseStationIpAdress()
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
|
@ -246,8 +262,8 @@ Column {
|
|||
|
||||
onClicked: {
|
||||
busyDl.open()
|
||||
var ret = speedBackend.pairConnectedUsbExtensions()
|
||||
busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
|
||||
var ret = speedBackend.scStwClient.pairConnectedUsbExtensions()
|
||||
busyDl.displayMessageAndClose(ret === ScStw.Success ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,8 +271,8 @@ Column {
|
|||
id: baseStationUpdateDel
|
||||
|
||||
// 0: hidden 1: update firmware 2: sync time
|
||||
property int mode: speedBackend.baseStationProperties["firmware"]["upToDate"] ?
|
||||
(Math.abs(parseInt(speedBackend.baseStationProperties["timeOffset"])) > 10000 ? 2:0)
|
||||
property int mode: speedBackend.scStwClient.isFirmwareUpToDate() ?
|
||||
(Math.abs(parseInt(speedBackend.scStwClient.getTimeOffset())) > 10000 ? 2:0)
|
||||
:1
|
||||
|
||||
width: parent.width
|
||||
|
@ -272,7 +288,7 @@ Column {
|
|||
}
|
||||
else if(mode === 2){
|
||||
busyDl.open()
|
||||
var ret = speedBackend.updateBasestationTime()
|
||||
var ret = speedBackend.scStwClient.updateTime()
|
||||
busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
|
||||
}
|
||||
|
||||
|
@ -312,12 +328,12 @@ Column {
|
|||
minimumPixelSize: 1
|
||||
|
||||
color: appTheme.style.lineColor
|
||||
text: "version: " + speedBackend.baseStationProperties["firmware"]["version"]
|
||||
text: "version: " + speedBackend.scStwClient.getFirmwareVersion()
|
||||
}
|
||||
|
||||
Label {
|
||||
|
||||
property var date: new Date(new Date().getTime() + parseInt(speedBackend.baseStationProperties["timeOffset"]))
|
||||
property var date: new Date(new Date().getTime() + parseInt(speedBackend.scStwClient.getTimeOffset()))
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
|
|
|
@ -10,6 +10,7 @@ SmoothItemDelegate {
|
|||
property var disconnect
|
||||
|
||||
property string type
|
||||
|
||||
text: qsTr(type)
|
||||
|
||||
enabled: (status.status === "disconnected" && control.connect !== undefined) || ( status.status === "connected" && control.disconnect !== undefined )
|
||||
|
|
|
@ -67,8 +67,8 @@ Window {
|
|||
target: speedBackend.race
|
||||
onStateChanged: {
|
||||
var stateString
|
||||
console.log("race state changed to: " + state)
|
||||
switch (state){
|
||||
console.log("race state changed to: " + speedBackend.race.state)
|
||||
switch (speedBackend.race.state){
|
||||
case ScStwRace.IDLE:
|
||||
stateString = "IDLE"
|
||||
break;
|
||||
|
@ -200,8 +200,8 @@ Window {
|
|||
height: parent.height
|
||||
|
||||
elide: "ElideRight"
|
||||
color: ["WON"].includes(speedBackend.timers[index]["state"]) ? appTheme.style.successColor :
|
||||
["LOST", "FAILED"].includes(speedBackend.timers[index]["state"]) ? appTheme.style.errorColor:
|
||||
color: [ScStwTimer.WON].includes(speedBackend.race.timers[index]["state"]) ? appTheme.style.successColor :
|
||||
[ScStwTimer.LOST, ScStwTimer.FAILED].includes(speedBackend.race.timers[index]["state"]) ? appTheme.style.errorColor:
|
||||
appTheme.style.textColor
|
||||
|
||||
enabled: speedBackend.race.timers[index]["state"] !== ScStwTimer.DISABLED
|
||||
|
@ -282,7 +282,21 @@ Window {
|
|||
|
||||
ConnectionIcon {
|
||||
id: baseConnConnIcon
|
||||
status: speedBackend.baseStationState
|
||||
|
||||
function clientStateToString(state) {
|
||||
switch(state) {
|
||||
case ScStwClient.DISCONNECTED:
|
||||
return "disconnected"
|
||||
case ScStwClient.CONNECTING:
|
||||
return "connecting"
|
||||
case ScStwClient.INITIALISING:
|
||||
return "connecting"
|
||||
case ScStwClient.CONNECTED:
|
||||
return "connected"
|
||||
}
|
||||
}
|
||||
|
||||
status: clientStateToString(speedBackend.scStwClient.state)
|
||||
|
||||
source: appTheme.style.baseStationIcon
|
||||
anchors {
|
||||
|
@ -311,14 +325,14 @@ Window {
|
|||
Repeater {
|
||||
id: connectedExtensionsRep
|
||||
anchors.fill: parent
|
||||
model: speedBackend.baseStationConnections.length
|
||||
model: speedBackend.scStwClient.extensions.lenght
|
||||
delegate: ConnectionIcon {
|
||||
id: buzzerConnIcon
|
||||
status: speedBackend.baseStationConnections[index]["state"]
|
||||
status: speedBackend.extensions[index]["state"]
|
||||
|
||||
source: {
|
||||
var source
|
||||
switch(speedBackend.baseStationConnections[index]["type"]){
|
||||
switch(speedBackend.extensions[index]["type"]){
|
||||
case "STARTPAD":
|
||||
source = appTheme.style.startpadIcon
|
||||
break
|
||||
|
@ -373,7 +387,7 @@ Window {
|
|||
text: "start"
|
||||
property int size: app.landscape() ? parent.width * 0.5:parent.height * 0.5
|
||||
property color backgroundColor: appTheme.style.buttonColor
|
||||
property bool progressControlActivated: speedBackend.baseStationState === "connected" && app.state === "RUNNING"
|
||||
property bool progressControlActivated: speedBackend.scStwClient.state === ScStwClient.CONNECTED && app.state === "RUNNING"
|
||||
delay: progressControlActivated ? 2000:0
|
||||
|
||||
anchors {
|
||||
|
@ -681,7 +695,7 @@ Window {
|
|||
|
||||
enabled: height > 0
|
||||
|
||||
state: speedBackend.baseStationState === "connected" ? "visible":"hidden"
|
||||
state: speedBackend.scStwClient.state === ScStwClient.CONNECTED ? "visible":"hidden"
|
||||
width: height
|
||||
|
||||
onClicked: {
|
||||
|
|
|
@ -1,367 +0,0 @@
|
|||
/*
|
||||
Speed Climbing Stopwatch - Simple Stopwatch for Climbers
|
||||
Copyright (C) 2018 Itsblue Development - Dorian Zeder
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "headers/buzzerconn.h"
|
||||
|
||||
BuzzerConn::BuzzerConn(QObject *parent, QString ip, int port) : QObject(parent)
|
||||
{
|
||||
this->networkManager = new QNetworkAccessManager();
|
||||
this->reloadNetworkManager = new QNetworkAccessManager();
|
||||
|
||||
this->socket = new QTcpSocket();
|
||||
|
||||
this->date = new QDateTime;
|
||||
this->latest_button_pressed = 0;
|
||||
this->connected = false;
|
||||
|
||||
this->ip = ip;
|
||||
this->port = port;
|
||||
// "http://192.168.4.1"
|
||||
}
|
||||
|
||||
bool BuzzerConn::connect()
|
||||
{
|
||||
qDebug() << "connecting...";
|
||||
|
||||
//wait until the request has finished
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
loop.connect(this->socket, SIGNAL(connected()), &loop, SLOT(quit()));
|
||||
|
||||
timer.start(3000);
|
||||
this->socket->connectToHost(this->ip, this->port);
|
||||
loop.exec();
|
||||
timer.stop();
|
||||
|
||||
if(timer.remainingTime() == 0){
|
||||
//the time has been triggered -> timeout
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
QList<double> times = gettimes(2000);
|
||||
qDebug() << times[0];
|
||||
if(times[0] == 200.0){
|
||||
this->latest_button_pressed = times[2];
|
||||
for(int i=0;i<=100;i++){
|
||||
this->connection_progress = i;
|
||||
if(!calcoffset(this->gettimes(1000))){
|
||||
this->connection_progress = 100;
|
||||
this->connected = false;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
this->connected = true;
|
||||
return(true);
|
||||
}
|
||||
else{
|
||||
this->connected = false;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool BuzzerConn::calcoffset(QList<double> times)
|
||||
{
|
||||
if(times.length() != 3){
|
||||
return(false);
|
||||
}
|
||||
if(times[0] == 200.0){
|
||||
this->latest_button_pressed = times[2];
|
||||
double offset = date->currentMSecsSinceEpoch() - times[1];
|
||||
if(this->latest_offsets.length()>=100){
|
||||
this->latest_offsets.removeFirst();
|
||||
}
|
||||
this->latest_offsets.append(offset);
|
||||
|
||||
double mem = 0;
|
||||
for(int i=0;i<latest_offsets.length();i++){
|
||||
mem += latest_offsets[i];
|
||||
}
|
||||
this->offset = mem / double(latest_offsets.length());
|
||||
qDebug("%20f", this->offset);
|
||||
return(true);
|
||||
}
|
||||
else {
|
||||
//this->connected = false;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
QList<double> BuzzerConn::gettimes(int timeout)
|
||||
{
|
||||
// QList<double> times;
|
||||
// ReturnData_t ret = senddata(this->networkManager, QUrl(this->ip), timeout);
|
||||
// times.append(double(ret.status_code));
|
||||
|
||||
// if(ret.status_code == 200){
|
||||
// ret.text.replace("\n","");
|
||||
// ret.text.replace("\r","");
|
||||
// QStringList times_cache = ret.text.split("<br>");
|
||||
// times.append(times_cache[0].toDouble());
|
||||
// times.append(times_cache[1].toDouble());
|
||||
|
||||
// return(times);
|
||||
// }
|
||||
// else{
|
||||
// return(times);
|
||||
// }
|
||||
|
||||
QList<double> times;
|
||||
signed long ret;
|
||||
ret = this->sendCommand("GET_TIMESTAMP", timeout);
|
||||
if(ret >= 0){
|
||||
times.append(double(200));
|
||||
times.append(double(ret));
|
||||
ret = this->sendCommand("GET_LASTPRESSED", timeout);
|
||||
if(ret >= 0){
|
||||
times.append(double(ret));
|
||||
return(times);
|
||||
}
|
||||
else {
|
||||
times[0] = ret;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
times.append(ret);
|
||||
}
|
||||
return(times);
|
||||
|
||||
}
|
||||
|
||||
bool BuzzerConn::buzzer_triggered()
|
||||
{
|
||||
|
||||
if(!this->connected){
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(pending_commands.length() > 0){
|
||||
QString command = this->pending_commands.first();
|
||||
|
||||
signed long retval = this->sendCommand(command, 800);
|
||||
if(retval > 0){
|
||||
this->pending_commands.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
QList<double> times = this->gettimes(1000);
|
||||
if(times[0] == 200.0){
|
||||
if(times[2] > this->latest_button_pressed){
|
||||
this->latest_button_pressed = times[2];
|
||||
|
||||
return(true);
|
||||
}
|
||||
else {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
else{
|
||||
//this->connected = false;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool BuzzerConn::start()
|
||||
{
|
||||
if(!this->connected){
|
||||
return(false);
|
||||
}
|
||||
QList<double> times = this->gettimes(1000);
|
||||
if(times[0] == 200.0 && this->connected){
|
||||
this->latest_button_pressed = times[2];
|
||||
return(true);
|
||||
}
|
||||
else{
|
||||
this->connected = false;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
double BuzzerConn::get(QString key)
|
||||
{
|
||||
if(key == "offset"){
|
||||
return(this->offset);
|
||||
}
|
||||
else if (key == "lastpressed") {
|
||||
return(this->latest_button_pressed);
|
||||
}
|
||||
else if( key == "currtime") {
|
||||
return(this->date->currentMSecsSinceEpoch());
|
||||
}
|
||||
else if( key == "connection_progress") {
|
||||
return(this->connection_progress);
|
||||
}
|
||||
else if( key == "connected") {
|
||||
if(this->connected){
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
QString BuzzerConn::test()
|
||||
{
|
||||
ReturnData_t ret = this->senddata(this->networkManager, QUrl("http://www.google.de"), 500);
|
||||
return(ret.text);
|
||||
}
|
||||
|
||||
bool BuzzerConn::refresh()
|
||||
{
|
||||
if(!this->connected){
|
||||
return(false);
|
||||
}
|
||||
// QList<double> times;
|
||||
// ReturnData_t ret = senddata(this->reloadNetworkManager, QUrl(this->ip), 1000);
|
||||
// times.append(double(ret.status_code));
|
||||
|
||||
// if(ret.status_code == 200){
|
||||
// ret.text.replace("\n","");
|
||||
// ret.text.replace("\r","");
|
||||
// QStringList times_cache = ret.text.split("<br>");
|
||||
// times.append(times_cache[0].toDouble());
|
||||
// times.append(times_cache[1].toDouble());
|
||||
// calcoffset(times);
|
||||
// return(true);
|
||||
// }
|
||||
// else{
|
||||
// //this->connected = false;
|
||||
// return(false);
|
||||
// }
|
||||
|
||||
if(pending_commands.length() > 0){
|
||||
QString command = this->pending_commands.first();
|
||||
|
||||
signed long retval = this->sendCommand(command, 800);
|
||||
if(retval > 0){
|
||||
this->pending_commands.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
//refresh the times
|
||||
QList<double> ret = this->gettimes(800);
|
||||
if(ret[0] >= 0){
|
||||
this->errors = 0;
|
||||
return(this->calcoffset(ret));
|
||||
}
|
||||
else {
|
||||
this->errors ++;
|
||||
if(this->errors > errors_until_disconnect){
|
||||
this->socket->disconnectFromHost();
|
||||
this->connected = false;
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ReturnData_t BuzzerConn::senddata(QNetworkAccessManager * NetMan, QUrl serviceUrl, int timeout)
|
||||
{
|
||||
|
||||
ReturnData_t ret; //this is a custom type to store the returned data
|
||||
// Call the webservice
|
||||
|
||||
QNetworkRequest request(serviceUrl);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
//send a POST request with the given url and data to the server
|
||||
QUrlQuery pdata;
|
||||
QNetworkReply* reply;
|
||||
|
||||
//wait until the request has finished
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
loop.connect(NetMan, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));
|
||||
|
||||
timer.start(timeout);
|
||||
reply = NetMan->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
|
||||
loop.exec();
|
||||
timer.stop();
|
||||
|
||||
//get the status code
|
||||
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
|
||||
ret.status_code = status_code.toInt();
|
||||
if(ret.status_code == 0){ //if the statuscode is zero, the connecion to the server was not possible
|
||||
ret.status_code = 444;
|
||||
}
|
||||
//get the full text response
|
||||
ret.text = QString::fromUtf8(reply->readAll());
|
||||
|
||||
//return the data
|
||||
return(ret);
|
||||
}
|
||||
|
||||
signed long BuzzerConn::sendCommand(QString command, int timeout){
|
||||
|
||||
//if there is any data in the storage, clear it
|
||||
if(this->socket->bytesAvailable() > 0){
|
||||
this->socket->readAll();
|
||||
}
|
||||
|
||||
//send request to the socket server
|
||||
QByteArray arrBlock;
|
||||
QDataStream out(&arrBlock, QIODevice::WriteOnly);
|
||||
//out.setVersion(QDataStream::Qt_5_10);
|
||||
out << quint16(0) << command;
|
||||
|
||||
out.device()->seek(0);
|
||||
out << quint16(arrBlock.size() - sizeof(quint16));
|
||||
|
||||
this->socket->write(arrBlock);
|
||||
|
||||
//now wait for the server of the sensor to answer
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
loop.connect(socket, SIGNAL(readyRead()), &loop, SLOT(quit()));
|
||||
timer.start(timeout);
|
||||
loop.exec();
|
||||
|
||||
//loop finished
|
||||
timer.stop();
|
||||
if(timer.remainingTime() == 0){
|
||||
//the time has been triggered -> timeout
|
||||
return(-1);
|
||||
}
|
||||
|
||||
//if the data is not 4 bites long if is invalid -> clear and terminate
|
||||
if(this->socket->bytesAvailable() != 4){
|
||||
this->socket->readAll();
|
||||
return(-2);
|
||||
}
|
||||
long data = 0;
|
||||
this->socket->read((char*)&data,4);
|
||||
|
||||
qDebug() << data;
|
||||
qDebug() << this->socket->bytesAvailable();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void BuzzerConn::appendCommand(QString command){
|
||||
this->pending_commands.append(command);
|
||||
}
|
|
@ -1,656 +0,0 @@
|
|||
#include "headers/climbingrace.h"
|
||||
|
||||
/*
|
||||
* manages:
|
||||
* - global state
|
||||
* - timers
|
||||
* - sounds
|
||||
* - next start action
|
||||
* - next start action delay progress
|
||||
* - settings (remote and local)
|
||||
*/
|
||||
|
||||
ClimbingRace::ClimbingRace(QObject *parent) : QObject(parent)
|
||||
{
|
||||
this->state = ScStw::ScStw::IDLE;
|
||||
this->mode = LOCAL;
|
||||
|
||||
this->appSettings = new AppSettings(this);
|
||||
this->scStwClient = new ScStwClient();
|
||||
|
||||
this->scStwClient->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
||||
connect(this->scStwClient, &ScStwClient::stateChanged, this, &ClimbingRace::baseStationStateChanged);
|
||||
connect(this->scStwClient, &ScStwClient::stateChanged, this, &ClimbingRace::refreshMode);
|
||||
connect(this->scStwClient, &ScStwClient::gotSignal, this, &ClimbingRace::handleBaseStationSignal);
|
||||
connect(this, &ClimbingRace::baseStationStateChanged, this, &ClimbingRace::baseStationPropertiesChanged);
|
||||
|
||||
this->speedTimers.append( new SpeedTimer(this) );
|
||||
|
||||
this->player = new QMediaPlayer;
|
||||
this->date = new QDateTime;
|
||||
|
||||
this->nextStartActionTimer = new QTimer(this);
|
||||
nextStartActionTimer->setSingleShot(true);
|
||||
|
||||
this->timerTextRefreshTimer = new QTimer(this);
|
||||
this->timerTextRefreshTimer->setInterval(1);
|
||||
this->timerTextRefreshTimer->setSingleShot(true);
|
||||
this->timerTextRefreshTimer->connect(this->timerTextRefreshTimer, &QTimer::timeout, this, &ClimbingRace::refreshTimerText);
|
||||
this->refreshTimerText();
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// --- Main Functionality ---
|
||||
// --------------------------
|
||||
|
||||
int ClimbingRace::startRace() {
|
||||
|
||||
if(this->state != ScStw::IDLE) {
|
||||
return 904;
|
||||
}
|
||||
|
||||
qDebug() << "+ --- starting race";
|
||||
|
||||
int returnCode = 900;
|
||||
|
||||
switch (this->mode) {
|
||||
case LOCAL:
|
||||
{
|
||||
|
||||
this->setState(ScStw::STARTING);
|
||||
|
||||
this->nextStartAction = ScStw::None;
|
||||
this->playSoundsAndStartRace();
|
||||
|
||||
returnCode = 200;
|
||||
|
||||
break;
|
||||
}
|
||||
case REMOTE:
|
||||
{
|
||||
QVariantMap reply = this->scStwClient->sendCommand(1000);
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
returnCode = reply["status"].toInt();
|
||||
}
|
||||
else {
|
||||
|
||||
returnCode = 200;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int ClimbingRace::stopRace(int type) {
|
||||
|
||||
if(this->state != ScStw::RUNNING && this->state != ScStw::STARTING) {
|
||||
return 904;
|
||||
}
|
||||
|
||||
// type can be:
|
||||
// 0: stopp
|
||||
// 1: cancel
|
||||
// 2: fail (fase start)
|
||||
|
||||
qDebug() << "+ --- stopping race";
|
||||
|
||||
int returnCode = 900;
|
||||
|
||||
switch (this->mode) {
|
||||
case LOCAL:
|
||||
{
|
||||
|
||||
if(type == 1){
|
||||
this->nextStartActionTimer->stop();
|
||||
this->player->stop();
|
||||
this->nextStartAction = ScStw::None;
|
||||
}
|
||||
|
||||
returnCode = this->speedTimers[0]->stop(type) ? 200:904;
|
||||
|
||||
if(returnCode == 200) {
|
||||
this->setState(ScStw::STOPPED);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case REMOTE:
|
||||
{
|
||||
QVariantMap reply = this->scStwClient->sendCommand(1001);
|
||||
|
||||
if(reply["status"] != 200){
|
||||
returnCode = reply["status"].toInt();
|
||||
}
|
||||
else {
|
||||
returnCode = 200;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int ClimbingRace::resetRace() {
|
||||
|
||||
if(this->state != ScStw::STOPPED) {
|
||||
return 904;
|
||||
}
|
||||
|
||||
qDebug() << "+ --- resetting race";
|
||||
|
||||
int returnCode = 900;
|
||||
|
||||
|
||||
switch (this->mode) {
|
||||
case LOCAL:
|
||||
{
|
||||
returnCode = this->speedTimers[0]->reset() ? 200:904;
|
||||
|
||||
if(returnCode == 200){
|
||||
this->setState(ScStw::IDLE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case REMOTE:
|
||||
{
|
||||
|
||||
QVariantMap reply = this->scStwClient->sendCommand(1002);
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
returnCode = reply["status"].toInt();
|
||||
}
|
||||
else {
|
||||
returnCode = 200;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// --- Base Station sync ---
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief ClimbingRace::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 ClimbingRace::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) {
|
||||
qDebug() << "got signal: " << data;
|
||||
switch (key) {
|
||||
case ScStw::RaceStateChanged:
|
||||
{
|
||||
// the remote race state has changed
|
||||
this->setState( ScStw::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.toMap()["nextActionDelay"].toDouble();
|
||||
this->nextStartActionDelayStartedAt = this->date->currentMSecsSinceEpoch() - (this->nextStartActionTotalDelay * data.toMap()["nextActionDelayProg"].toDouble());
|
||||
this->nextStartAction = ScStw::NextStartAction( data.toMap()["nextAction"].toInt() );
|
||||
|
||||
emit this->nextStartActionChanged();
|
||||
break;
|
||||
}
|
||||
case ScStw::ExtensionsChanged:
|
||||
{
|
||||
emit this->baseStationConnectionsChanged();
|
||||
break;
|
||||
}
|
||||
case ScStw::InvalidSignal:
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ClimbingRace::refreshRemoteTimers(QVariantList timers) {
|
||||
|
||||
if(timers.length() != speedTimers.length()){
|
||||
// local timers are out of sync
|
||||
|
||||
// delete all current timers
|
||||
foreach(SpeedTimer * locTimer, this->speedTimers){
|
||||
delete locTimer;
|
||||
}
|
||||
|
||||
speedTimers.clear();
|
||||
|
||||
foreach(QVariant remTimer, timers){
|
||||
// create a local timer for each remote timer
|
||||
this->speedTimers.append(new SpeedTimer(this));
|
||||
}
|
||||
}
|
||||
|
||||
foreach(QVariant remTimer, timers){
|
||||
int currId = remTimer.toMap()["id"].toInt();
|
||||
speedTimers[currId]->startTime = this->date->currentMSecsSinceEpoch() - remTimer.toMap()["currentTime"].toDouble();
|
||||
speedTimers[currId]->stoppedTime = remTimer.toMap()["currentTime"].toDouble();
|
||||
speedTimers[currId]->reactionTime = remTimer.toMap()["reactionTime"].toDouble();
|
||||
|
||||
speedTimers[currId]->setState(SpeedTimer::timerState(remTimer.toMap()["state"].toInt()));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// --- helper functions ---
|
||||
// ------------------------
|
||||
|
||||
void ClimbingRace::playSoundsAndStartRace() {
|
||||
qDebug() << "next Action: " << nextStartAction;
|
||||
|
||||
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||
|
||||
switch (this->nextStartAction) {
|
||||
case ScStw::AtYourMarks:
|
||||
{
|
||||
if(!playSound("qrc:/sounds/at_marks_1.wav")){
|
||||
return;
|
||||
}
|
||||
if(appSettings->loadSetting("ready_en") == "true"){
|
||||
nextStartAction = ScStw::Ready;
|
||||
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
||||
}
|
||||
else{
|
||||
nextStartAction = ScStw::Start;
|
||||
nextStartActionTimer->setInterval(1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ScStw::Ready:
|
||||
{
|
||||
if(!playSound("qrc:/sounds/ready_1.wav")){
|
||||
return;
|
||||
}
|
||||
nextStartAction = ScStw::Start;
|
||||
nextStartActionTimer->setInterval(1);
|
||||
|
||||
break;
|
||||
}
|
||||
case ScStw::Start:
|
||||
{
|
||||
if(!playSound("qrc:/sounds/IFSC_STARTSIGNAL_SINE.wav")){
|
||||
return;
|
||||
}
|
||||
nextStartAction = ScStw::None;
|
||||
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||
|
||||
this->setState(ScStw::RUNNING);
|
||||
speedTimers[0]->start();
|
||||
|
||||
emit this->nextStartActionChanged();
|
||||
|
||||
return;
|
||||
}
|
||||
case ScStw::None:
|
||||
{
|
||||
this->speedTimers[0]->setState(SpeedTimer::STARTING);
|
||||
if(appSettings->loadSetting("at_marks_en") == "true"){
|
||||
nextStartAction = ScStw::AtYourMarks;
|
||||
nextStartActionTimer->setInterval(appSettings->loadSetting("at_marks_delay").toInt() <= 0 ? 1:appSettings->loadSetting("at_marks_delay").toInt());
|
||||
}
|
||||
else if(appSettings->loadSetting("ready_en") == "true"){
|
||||
nextStartAction = ScStw::Ready;
|
||||
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
||||
}
|
||||
else{
|
||||
nextStartAction = ScStw::Start;
|
||||
nextStartActionTimer->setInterval(1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit this->nextStartActionChanged();
|
||||
|
||||
nextStartActionTimer->connect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||
nextStartActionTimer->start();
|
||||
}
|
||||
|
||||
bool ClimbingRace::playSound(QString path) {
|
||||
|
||||
player->setMedia(QUrl(path));
|
||||
player->setVolume(50);
|
||||
player->play();
|
||||
|
||||
QTimer timer;
|
||||
timer.setInterval(1);
|
||||
timer.setSingleShot(true);
|
||||
|
||||
QEventLoop loop;
|
||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
|
||||
while (player->mediaStatus() == QMediaPlayer::LoadingMedia || player->mediaStatus() == QMediaPlayer::BufferingMedia || player->mediaStatus() == QMediaPlayer::BufferedMedia) {
|
||||
timer.start();
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
if(player->mediaStatus() == QMediaPlayer::EndOfMedia){
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ClimbingRace::setState(ScStw::RaceState newState) {
|
||||
if(newState != this->state) {
|
||||
this->state = newState;
|
||||
this->stateChanged(newState);
|
||||
}
|
||||
}
|
||||
|
||||
void ClimbingRace::refreshMode() {
|
||||
RaceMode newMode;
|
||||
if(this->scStwClient->getState() == ScStwClient::CONNECTED){
|
||||
newMode = REMOTE;
|
||||
}
|
||||
else {
|
||||
newMode = LOCAL;
|
||||
}
|
||||
|
||||
if(this->mode != newMode){
|
||||
|
||||
if(newMode == LOCAL){
|
||||
// if the new mode is local -> connection to base station has been lost
|
||||
|
||||
// reset race
|
||||
// reset state
|
||||
this->setState(ScStw::IDLE);
|
||||
|
||||
// reset timers
|
||||
// go back to one timer
|
||||
for (int i = 0;i<this->speedTimers.length();i++) {
|
||||
delete this->speedTimers[i];
|
||||
}
|
||||
|
||||
this->speedTimers.clear();
|
||||
|
||||
this->speedTimers.append(new SpeedTimer);
|
||||
}
|
||||
|
||||
this->mode = newMode;
|
||||
emit this->modeChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClimbingRace::refreshTimerText() {
|
||||
|
||||
// --- refresh timer text ---
|
||||
|
||||
QVariantList newTimerTextList;
|
||||
|
||||
foreach(SpeedTimer * timer, this->speedTimers){
|
||||
QVariantMap timerMap = {{"text",timer->getText()}, {"reacttime", timer->reactionTime}, {"state", timer->getState()}, {"id", this->speedTimers.indexOf(timer)}};
|
||||
newTimerTextList.append(timerMap);
|
||||
}
|
||||
|
||||
if(newTimerTextList != this->qmlTimers){
|
||||
this->qmlTimers = newTimerTextList;
|
||||
emit timerTextChanged();
|
||||
}
|
||||
|
||||
// --- refresh next start action delay progress ---
|
||||
double nextStartActionRemainingDelay = 0;
|
||||
|
||||
switch (this->mode) {
|
||||
case LOCAL: {
|
||||
|
||||
// get remaining and total next start action delay time
|
||||
if(nextStartAction == 0){
|
||||
this->nextStartActionTotalDelay = appSettings->loadSetting("at_marks_delay").toDouble();
|
||||
}
|
||||
else if (nextStartAction == 1) {
|
||||
this->nextStartActionTotalDelay = appSettings->loadSetting("ready_delay").toDouble();
|
||||
}
|
||||
|
||||
nextStartActionRemainingDelay = this->nextStartActionTimer->remainingTime();
|
||||
|
||||
break;
|
||||
}
|
||||
case REMOTE: {
|
||||
|
||||
// calculate remaining next start action delay time
|
||||
nextStartActionRemainingDelay = this->nextStartActionTotalDelay - ( this->date->currentMSecsSinceEpoch() - this->nextStartActionDelayStartedAt );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate next start action delay progress
|
||||
if(nextStartActionRemainingDelay > 0){
|
||||
this->nextStartActionDelayProgress = nextStartActionRemainingDelay / this->nextStartActionTotalDelay;
|
||||
emit this->nextStartActionDelayProgressChanged();
|
||||
}
|
||||
else {
|
||||
this->nextStartActionDelayProgress = 0;
|
||||
emit this->nextStartActionDelayProgressChanged();
|
||||
}
|
||||
|
||||
|
||||
/*if (this->mode == REMOTE && this->state == ScStw::IDLE) {
|
||||
this->nextStartActionDelayProgress = 0;
|
||||
emit this->nextStartActionDelayProgressChanged();
|
||||
}*/
|
||||
|
||||
this->timerTextRefreshTimer->start();
|
||||
}
|
||||
|
||||
bool ClimbingRace::pairConnectedUsbExtensions() {
|
||||
QVariantMap ret = this->scStwClient->sendCommand(5002, "", 10000);
|
||||
qDebug() << ret;
|
||||
return ret["status"] == 200;
|
||||
}
|
||||
|
||||
// - athlete management -
|
||||
|
||||
QVariant ClimbingRace::getAthletes() {
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4003);
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
qDebug() << "+ --- error getting athletes: " << reply["status"];
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariantMap tmpAthletes = reply["data"].toMap();
|
||||
|
||||
//qDebug() << tmpAthletes;
|
||||
|
||||
return tmpAthletes;
|
||||
}
|
||||
|
||||
bool ClimbingRace::createAthlete(QString userName, QString fullName) {
|
||||
|
||||
QVariant requestData = QVariantMap({{"fullName", fullName}, {"userName", userName}});
|
||||
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4001, requestData.toJsonValue());
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
qDebug() << "+ --- error creating athlete: " << reply["status"];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClimbingRace::deleteAthlete( QString userName ){
|
||||
|
||||
QVariant requestData = QVariantMap({{"userName", userName}});
|
||||
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4002, requestData.toJsonValue());
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
qDebug() << "+ --- error deleting athlete: " << reply["status"];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool ClimbingRace::selectAthlete( QString userName, int timerId ){
|
||||
|
||||
QVariant requestData = QVariantMap({{"userName", userName}, {"timerId", timerId}});
|
||||
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4000, requestData.toJsonValue());
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
qDebug() << "+ --- error selecting athlete: " << reply["status"];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
QVariant ClimbingRace::getResults( QString userName ){
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4004, userName);
|
||||
|
||||
if(reply["status"] != 200){
|
||||
//handle Error!!
|
||||
qDebug() << "+ --- error getting results: " << reply["status"];
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariantList tmpAthletes = reply["data"].toList();
|
||||
|
||||
//qDebug() << tmpAthletes;
|
||||
|
||||
return tmpAthletes;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// --- functions for qml ---
|
||||
// -------------------------
|
||||
|
||||
int ClimbingRace::getState() {
|
||||
return this->state;
|
||||
}
|
||||
|
||||
int ClimbingRace::getMode() {
|
||||
return this->mode;
|
||||
}
|
||||
|
||||
QVariant ClimbingRace::getTimerTextList() {
|
||||
return this->qmlTimers;
|
||||
}
|
||||
|
||||
double ClimbingRace::getNextStartActionDelayProgress() {
|
||||
return this->nextStartActionDelayProgress;
|
||||
}
|
||||
|
||||
int ClimbingRace::getNextStartAction() {
|
||||
return this->nextStartAction;
|
||||
}
|
||||
|
||||
void ClimbingRace::writeSetting(QString key, QVariant value) {
|
||||
if(this->mode == REMOTE && ScStw::baseStationSettingFromString(key) != ScStw::InvalidSetting ){
|
||||
this->scStwClient->writeRemoteSetting(ScStw::baseStationSettingFromString(key), value.toString());
|
||||
}
|
||||
else {
|
||||
this->appSettings->writeSetting(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ClimbingRace::writeSetting(ScStw::BaseStationSetting key, QVariant value) {
|
||||
if(ScStw::baseStationSettingToString(key) != "Invalid" ){
|
||||
this->writeSetting(ScStw::baseStationSettingToString(key), value);
|
||||
}
|
||||
}
|
||||
|
||||
QString ClimbingRace::readSetting(QString key) {
|
||||
if(this->mode == REMOTE && ScStw::baseStationSettingFromString(key) != ScStw::InvalidSetting){
|
||||
return this->scStwClient->readRemoteSetting(ScStw::baseStationSettingFromString(key));
|
||||
}
|
||||
else {
|
||||
return this->appSettings->loadSetting(key);
|
||||
}
|
||||
}
|
||||
|
||||
QString ClimbingRace::readSetting(ScStw::BaseStationSetting key) {
|
||||
if(ScStw::baseStationSettingToString(key) != "Invalid") {
|
||||
return this->readSetting(ScStw::baseStationSettingToString(key));
|
||||
}
|
||||
return "false";
|
||||
}
|
||||
|
||||
void ClimbingRace::connectBaseStation() {
|
||||
this->reloadBaseStationIpAdress();
|
||||
this->scStwClient->connectToHost();
|
||||
}
|
||||
|
||||
void ClimbingRace::disconnectBaseStation() {
|
||||
this->scStwClient->closeConnection();
|
||||
}
|
||||
|
||||
QString ClimbingRace::getBaseStationState() {
|
||||
switch (this->scStwClient->getState()) {
|
||||
case ScStwClient::CONNECTED:
|
||||
return "connected";
|
||||
case ScStwClient::CONNECTING:
|
||||
return "connecting";
|
||||
case ScStwClient::DISCONNECTED:
|
||||
return "disconnected";
|
||||
case ScStwClient::INITIALISING:
|
||||
return "initialising";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QVariant ClimbingRace::getBaseStationConnections() {
|
||||
return scStwClient->getConnections();
|
||||
}
|
||||
|
||||
QVariantMap ClimbingRace::getBaseStationProperties() {
|
||||
QVariantMap firmware = {{"version", this->scStwClient->getFirmwareVersion()}, {"upToDate", this->scStwClient->isFirmwareUpToDate()}};
|
||||
return {{"firmware", firmware}, {"timeOffset", this->scStwClient->getTimeOffset()}};
|
||||
}
|
||||
|
||||
bool ClimbingRace::updateBasestationFirmware() {
|
||||
return this->scStwClient->updateFirmware();
|
||||
}
|
||||
|
||||
bool ClimbingRace::updateBasestationTime() {
|
||||
return this->scStwClient->updateTime();
|
||||
}
|
||||
|
||||
bool ClimbingRace::reloadBaseStationIpAdress() {
|
||||
if(this->scStwClient->getState() == ScStwClient::DISCONNECTED){
|
||||
this->scStwClient->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -58,6 +58,7 @@
|
|||
#include <scstwtimer.h>
|
||||
#include <scstwrace.h>
|
||||
#include <ScStw.hpp>
|
||||
#include <scstwtimer.h>
|
||||
#include <QTranslator>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -93,6 +94,7 @@ int main(int argc, char *argv[])
|
|||
qmlRegisterType<AppTheme>("com.itsblue.speedclimbingstopwatch", 2, 0, "AppTheme");
|
||||
//qmlRegisterUncreatableType<ScStw>("com.itsblue.speedclimbingstopwatch", 2, 0, "ScStw", "This is a static class and therefore not instantiable");
|
||||
qmlRegisterType<ScStw>("com.itsblue.speedclimbingstopwatch", 2, 0, "ScStw");
|
||||
qmlRegisterType<ScStwClient>("com.itsblue.speedclimbingstopwatch", 2, 0, "ScStwClient");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||
|
|
|
@ -5,6 +5,7 @@ ScStwAppBackend::ScStwAppBackend(QObject *parent) : QObject(parent)
|
|||
this->appSettings = new AppSettings(this);
|
||||
this->scStwClient = new ScStwClient();
|
||||
this->localRace = new ScStwRace(this);
|
||||
this->remoteRace = new ScStwRemoteMonitorRace(this->scStwClient, this);
|
||||
|
||||
this->scStwClient->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
||||
connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwAppBackend::baseStationStateChanged);
|
||||
|
@ -22,86 +23,6 @@ ScStwAppBackend::ScStwAppBackend(QObject *parent) : QObject(parent)
|
|||
this->refreshTimerText();
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// --- Base Station sync ---
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @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 ScStwAppBackend::handleBaseStationSignal(ScStw::SignalKey key, QVariant data) {
|
||||
qDebug() << "got signal: " << data;
|
||||
switch (key) {
|
||||
case ScStw::RaceStateChanged:
|
||||
{
|
||||
// the remote race state has changed
|
||||
this->setState( ScStw::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.toMap()["nextActionDelay"].toDouble();
|
||||
this->nextStartActionDelayStartedAt = this->date->currentMSecsSinceEpoch() - (this->nextStartActionTotalDelay * data.toMap()["nextActionDelayProg"].toDouble());
|
||||
this->nextStartAction = ScStw::NextStartAction( data.toMap()["nextAction"].toInt() );
|
||||
|
||||
emit this->nextStartActionChanged();
|
||||
break;
|
||||
}
|
||||
case ScStw::ExtensionsChanged:
|
||||
{
|
||||
emit this->baseStationConnectionsChanged();
|
||||
break;
|
||||
}
|
||||
case ScStw::InvalidSignal:
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ScStwAppBackend::refreshRemoteTimers(QVariantList timers) {
|
||||
|
||||
if(timers.length() != speedTimers.length()){
|
||||
// local timers are out of sync
|
||||
|
||||
// delete all current timers
|
||||
foreach(SpeedTimer * locTimer, this->speedTimers){
|
||||
delete locTimer;
|
||||
}
|
||||
|
||||
speedTimers.clear();
|
||||
|
||||
foreach(QVariant remTimer, timers){
|
||||
// create a local timer for each remote timer
|
||||
this->speedTimers.append(new SpeedTimer(this));
|
||||
}
|
||||
}
|
||||
|
||||
foreach(QVariant remTimer, timers){
|
||||
int currId = remTimer.toMap()["id"].toInt();
|
||||
speedTimers[currId]->startTime = this->date->currentMSecsSinceEpoch() - remTimer.toMap()["currentTime"].toDouble();
|
||||
speedTimers[currId]->stoppedTime = remTimer.toMap()["currentTime"].toDouble();
|
||||
speedTimers[currId]->reactionTime = remTimer.toMap()["reactionTime"].toDouble();
|
||||
|
||||
speedTimers[currId]->setState(SpeedTimer::timerState(remTimer.toMap()["state"].toInt()));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
*/
|
||||
// ------------------------
|
||||
// --- helper functions ---
|
||||
// ------------------------
|
||||
|
@ -126,6 +47,8 @@ void ScStwAppBackend::refreshMode() {
|
|||
|
||||
this->mode = newMode;
|
||||
emit this->modeChanged();
|
||||
emit this->raceChanged();
|
||||
emit this->getRace()->stateChanged(this->getRace()->getState());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -145,14 +68,9 @@ void ScStwAppBackend::refreshTimerText() {
|
|||
this->timerTextRefreshTimer->start();
|
||||
}
|
||||
|
||||
bool ScStwAppBackend::pairConnectedUsbExtensions() {
|
||||
QVariantMap ret = this->scStwClient->sendCommand(5002, "", 10000);
|
||||
qDebug() << ret;
|
||||
return ret["status"] == 200;
|
||||
}
|
||||
|
||||
// - athlete management -
|
||||
|
||||
// TODO: move to client
|
||||
QVariant ScStwAppBackend::getAthletes() {
|
||||
QVariantMap reply = this->scStwClient->sendCommand(4003);
|
||||
|
||||
|
@ -240,9 +158,14 @@ ScStwRace* ScStwAppBackend::getRace() {
|
|||
switch (this->mode) {
|
||||
case LOCAL:
|
||||
return this->localRace;
|
||||
default:
|
||||
return nullptr;
|
||||
case REMOTE:
|
||||
return this->remoteRace;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScStwClient* ScStwAppBackend::getScStwClient() {
|
||||
return this->scStwClient;
|
||||
}
|
||||
|
||||
int ScStwAppBackend::getMode() {
|
||||
|
@ -258,6 +181,7 @@ void ScStwAppBackend::writeSetting(QString key, QVariant value) {
|
|||
}
|
||||
|
||||
this->reloadRaceSettings();
|
||||
this->reloadBaseStationIpAdress();
|
||||
}
|
||||
|
||||
void ScStwAppBackend::writeSetting(ScStw::BaseStationSetting key, QVariant value) {
|
||||
|
@ -298,50 +222,14 @@ void ScStwAppBackend::reloadRaceSettings() {
|
|||
this->getRace()->setSoundVolume(1);
|
||||
|
||||
}
|
||||
void ScStwAppBackend::connectBaseStation() {
|
||||
this->reloadBaseStationIpAdress();
|
||||
this->scStwClient->connectToHost();
|
||||
}
|
||||
|
||||
void ScStwAppBackend::disconnectBaseStation() {
|
||||
this->scStwClient->closeConnection();
|
||||
}
|
||||
|
||||
QString ScStwAppBackend::getBaseStationState() {
|
||||
switch (this->scStwClient->getState()) {
|
||||
case ScStwClient::CONNECTED:
|
||||
return "connected";
|
||||
case ScStwClient::CONNECTING:
|
||||
return "connecting";
|
||||
case ScStwClient::DISCONNECTED:
|
||||
return "disconnected";
|
||||
case ScStwClient::INITIALISING:
|
||||
return "initialising";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QVariant ScStwAppBackend::getBaseStationConnections() {
|
||||
return scStwClient->getConnections();
|
||||
}
|
||||
|
||||
// TODO: move to client
|
||||
/*
|
||||
QVariantMap ScStwAppBackend::getBaseStationProperties() {
|
||||
QVariantMap firmware = {{"version", this->scStwClient->getFirmwareVersion()}, {"upToDate", this->scStwClient->isFirmwareUpToDate()}};
|
||||
return {{"firmware", firmware}, {"timeOffset", this->scStwClient->getTimeOffset()}};
|
||||
}
|
||||
|
||||
bool ScStwAppBackend::updateBasestationFirmware() {
|
||||
return this->scStwClient->updateFirmware();
|
||||
}
|
||||
|
||||
bool ScStwAppBackend::updateBasestationTime() {
|
||||
return this->scStwClient->updateTime();
|
||||
}
|
||||
|
||||
bool ScStwAppBackend::reloadBaseStationIpAdress() {
|
||||
if(this->scStwClient->getState() == ScStwClient::DISCONNECTED){
|
||||
this->scStwClient->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
void ScStwAppBackend::reloadBaseStationIpAdress() {
|
||||
this->scStwClient->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
||||
}
|
||||
|
|
|
@ -1,211 +0,0 @@
|
|||
#include "headers/speedtimer.h"
|
||||
|
||||
SpeedTimer::SpeedTimer(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
this->date = new QDateTime;
|
||||
|
||||
this->startTime = 0;
|
||||
this->stopTime = 0;
|
||||
this->stoppedTime = 0;
|
||||
this->reactionTime = 0;
|
||||
this->state = IDLE;
|
||||
}
|
||||
|
||||
bool SpeedTimer::start(bool force) {
|
||||
if(this->state != STARTING && !force){
|
||||
return false;
|
||||
}
|
||||
qDebug() << "starting timer";
|
||||
if(!force){
|
||||
this->stopTime = 0;
|
||||
this->stoppedTime = 0;
|
||||
this->reactionTime = 0;
|
||||
this->startTime = this->date->currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
this->setState(RUNNING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpeedTimer::stop(int type, bool force) {
|
||||
|
||||
// type can be:
|
||||
// 0: stopped
|
||||
// 1: cancelled
|
||||
// 2: failed (fase start)
|
||||
|
||||
if( ( this->state != SpeedTimer::STARTING && this->state != SpeedTimer::RUNNING && this->state ) && !force ){
|
||||
return false;
|
||||
}
|
||||
|
||||
//qDebug() << "Stopping: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
{
|
||||
this->stopTime = this->date->currentMSecsSinceEpoch();
|
||||
this->stoppedTime = this->stopTime - this->startTime;
|
||||
this->setState(WON);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
this->stoppedTime = 0;
|
||||
this->setState(CANCELLED);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
this->stoppedTime = this->reactionTime;
|
||||
this->setState(FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||
|
||||
return true;
|
||||
//this->startPad->appendCommand("SET_LED_STARTING");
|
||||
}
|
||||
|
||||
bool SpeedTimer::reset(bool force){
|
||||
if( ( this->state < WON ) && !force){
|
||||
return false;
|
||||
}
|
||||
|
||||
this->startTime = 0;
|
||||
this->stopTime = 0;
|
||||
this->stoppedTime = 0;
|
||||
this->reactionTime = 0;
|
||||
this->setState(IDLE);
|
||||
|
||||
return true;
|
||||
//this->startPad->appendCommand("SET_LED_STARTING");
|
||||
}
|
||||
|
||||
void SpeedTimer::setState(timerState newState){
|
||||
if(this->state != newState){
|
||||
this->state = newState;
|
||||
qDebug() << "+--- timer state changed: " << newState;
|
||||
emit this->stateChanged(newState);
|
||||
}
|
||||
}
|
||||
|
||||
QString SpeedTimer::getState(){
|
||||
switch(state){
|
||||
case IDLE:
|
||||
return "IDLE";
|
||||
case STARTING:
|
||||
return "STARTING";
|
||||
case WAITING:
|
||||
return "WAITING";
|
||||
case RUNNING:
|
||||
return "RUNNING";
|
||||
case WON:
|
||||
return "WON";
|
||||
case LOST:
|
||||
return "LOST";
|
||||
case FAILED:
|
||||
return "FAILED";
|
||||
case CANCELLED:
|
||||
return "CANCELLED";
|
||||
case DISABLED:
|
||||
return "DISABLED";
|
||||
}
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
double SpeedTimer::getCurrTime() {
|
||||
double currTime;
|
||||
if(this->state == RUNNING && this->startTime > 0){
|
||||
currTime = this->date->currentMSecsSinceEpoch() - this->startTime;
|
||||
}
|
||||
else {
|
||||
currTime = this->stoppedTime;
|
||||
}
|
||||
|
||||
return(currTime);
|
||||
}
|
||||
|
||||
QString SpeedTimer::getText() {
|
||||
//qDebug() << this->getState();
|
||||
QString newText;
|
||||
switch (this->state) {
|
||||
case SpeedTimer::IDLE:
|
||||
newText = "0.000 sec";
|
||||
break;
|
||||
case SpeedTimer::STARTING:
|
||||
newText = "0.000 sec";
|
||||
break;
|
||||
case SpeedTimer::WAITING:
|
||||
newText = "please wait...";
|
||||
break;
|
||||
case SpeedTimer::RUNNING:
|
||||
newText = QString::number( this->getCurrTime() / 1000.0, 'f', 3 ) + " sec";
|
||||
break;
|
||||
case SpeedTimer::WON:
|
||||
newText = QString::number( this->stoppedTime / 1000.0, 'f', 3 ) + " sec";
|
||||
break;
|
||||
case SpeedTimer::LOST:
|
||||
newText = QString::number( this->stoppedTime / 1000.0, 'f', 3 ) + " sec";
|
||||
break;
|
||||
case SpeedTimer::FAILED:
|
||||
newText = "false start";
|
||||
break;
|
||||
case SpeedTimer::CANCELLED:
|
||||
newText = "cancelled";
|
||||
break;
|
||||
case SpeedTimer::DISABLED:
|
||||
newText = "---";
|
||||
break;
|
||||
}
|
||||
|
||||
return newText;
|
||||
}
|
||||
|
||||
void SpeedTimer::delay(int mSecs){
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
|
||||
timer.setSingleShot(true);
|
||||
// quit the loop when the timer times out
|
||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
//quit the loop when the connection was established
|
||||
// start the timer before starting to connect
|
||||
timer.start(mSecs);
|
||||
//connect
|
||||
|
||||
//wait for the connection to finish (programm gets stuck in here)
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
SpeedTimer::timerState SpeedTimer::stateFromString(QString state){
|
||||
|
||||
if(state == "IDLE"){
|
||||
return IDLE;
|
||||
}
|
||||
else if (state == "STARTING") {
|
||||
return STARTING;
|
||||
}
|
||||
else if (state == "RUNNING") {
|
||||
return RUNNING;
|
||||
}
|
||||
else if (state == "WON") {
|
||||
return WON;
|
||||
}
|
||||
else if (state == "LOST") {
|
||||
return LOST;
|
||||
}
|
||||
else if (state == "FAILED") {
|
||||
return FAILED;
|
||||
}
|
||||
else if(state == "DISABLED") {
|
||||
return DISABLED;
|
||||
}
|
||||
else {
|
||||
return CANCELLED;
|
||||
}
|
||||
}
|
||||
|
Reference in a new issue