changed internal structure completely to be more flexible and reliable
This commit is contained in:
parent
88cf8a4328
commit
9260358e11
18 changed files with 854 additions and 1274 deletions
|
@ -20,12 +20,6 @@ class BaseConn : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QString ipAdress WRITE setIP READ getIP)
|
|
||||||
Q_PROPERTY(QString state READ getState NOTIFY stateChanged)
|
|
||||||
Q_PROPERTY(int progress READ getProgress NOTIFY progressChanged)
|
|
||||||
Q_PROPERTY(QStringList connections READ getConnections NOTIFY connectionsChanged)
|
|
||||||
Q_PROPERTY(QString nextRemoteAction READ getNextRemoteAction NOTIFY nextRemoteActionChanged)
|
|
||||||
Q_PROPERTY(float nextRemoteActionDelayProg READ getNextRemoteActionDelayProg NOTIFY nextRemoteActionDelayProgChanged)
|
|
||||||
public:
|
public:
|
||||||
explicit BaseConn(QObject *parent = nullptr);
|
explicit BaseConn(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
@ -43,7 +37,7 @@ public:
|
||||||
// - 'connecting'
|
// - 'connecting'
|
||||||
// - 'connected'
|
// - 'connected'
|
||||||
|
|
||||||
QStringList connections;
|
QVariant connections;
|
||||||
|
|
||||||
QString latestReadReply;
|
QString latestReadReply;
|
||||||
|
|
||||||
|
@ -57,9 +51,6 @@ private:
|
||||||
QTcpSocket *socket;
|
QTcpSocket *socket;
|
||||||
//socket for communication with the extention
|
//socket for communication with the extention
|
||||||
|
|
||||||
QList<SpeedTimer*> speedTimers;
|
|
||||||
|
|
||||||
QTimer *refreshTimer;
|
|
||||||
QSemaphore remoteSessions;
|
QSemaphore remoteSessions;
|
||||||
|
|
||||||
int nextConnectionId;
|
int nextConnectionId;
|
||||||
|
@ -72,10 +63,6 @@ private:
|
||||||
|
|
||||||
QList<waitingRequest> waitingRequests;
|
QList<waitingRequest> waitingRequests;
|
||||||
|
|
||||||
QString nextRemoteAction;
|
|
||||||
|
|
||||||
float nextRemoteActionDelayProg;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
//is emitted, when the connection state changes
|
//is emitted, when the connection state changes
|
||||||
|
@ -104,20 +91,12 @@ public slots:
|
||||||
|
|
||||||
void gotError(QAbstractSocket::SocketError err);
|
void gotError(QAbstractSocket::SocketError err);
|
||||||
|
|
||||||
Q_INVOKABLE QVariantMap sendCommand(int header, QJsonValue data);
|
Q_INVOKABLE QVariantMap sendCommand(int header, QJsonValue data = "");
|
||||||
|
|
||||||
Q_INVOKABLE int writeRemoteSetting(QString key, QString value);
|
Q_INVOKABLE int writeRemoteSetting(QString key, QString value);
|
||||||
|
|
||||||
Q_INVOKABLE bool refreshConnections();
|
Q_INVOKABLE bool refreshConnections();
|
||||||
|
|
||||||
void refreshTimers();
|
|
||||||
|
|
||||||
bool startTimers();
|
|
||||||
|
|
||||||
bool stopTimers(QString type);
|
|
||||||
|
|
||||||
bool resetTimers();
|
|
||||||
|
|
||||||
// functions for the qml adapter
|
// functions for the qml adapter
|
||||||
QString getIP() const;
|
QString getIP() const;
|
||||||
void setIP(const QString &ipAdress);
|
void setIP(const QString &ipAdress);
|
||||||
|
@ -127,14 +106,11 @@ public slots:
|
||||||
|
|
||||||
int getProgress() const;
|
int getProgress() const;
|
||||||
|
|
||||||
QStringList getConnections();
|
QVariant getConnections();
|
||||||
|
|
||||||
QString getNextRemoteAction();
|
|
||||||
|
|
||||||
float getNextRemoteActionDelayProg();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyRead();
|
void readyRead();
|
||||||
};
|
};
|
||||||
|
extern BaseConn * pGlobalBaseConn;
|
||||||
|
|
||||||
#endif // BASECONN_H
|
#endif // BASECONN_H
|
||||||
|
|
|
@ -1,131 +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>
|
|
||||||
#include <QtConcurrent/qtconcurrentthreadengine.h>
|
|
||||||
|
|
||||||
#include "appsettings.h"
|
|
||||||
|
|
||||||
//typedef struct strReturnData{
|
|
||||||
// int status_code;
|
|
||||||
// QString text;
|
|
||||||
//}ReturnData_t;
|
|
||||||
|
|
||||||
class BuzzerConn : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(double lastTriggered READ getLastTriggered NOTIFY triggered)
|
|
||||||
Q_PROPERTY(QString ipAdress WRITE setIP READ getIP)
|
|
||||||
Q_PROPERTY(QString state READ getState NOTIFY stateChanged)
|
|
||||||
Q_PROPERTY(int progress READ getProgress NOTIFY progressChanged)
|
|
||||||
Q_PROPERTY(double offset READ getOffset NOTIFY offsetChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit BuzzerConn(QObject *parent = nullptr, QString ip = "http://192.168.4.1", int port = 80);
|
|
||||||
|
|
||||||
// values for the time calculation
|
|
||||||
double offset;
|
|
||||||
QList<double> latest_offsets;
|
|
||||||
double latest_button_pressed;
|
|
||||||
|
|
||||||
// double starttime;
|
|
||||||
// bool connected;
|
|
||||||
|
|
||||||
// values for the socket connection
|
|
||||||
int connection_progress;
|
|
||||||
QString ip;
|
|
||||||
int port;
|
|
||||||
int errors;
|
|
||||||
int errors_until_disconnect = 4;
|
|
||||||
|
|
||||||
// the current state
|
|
||||||
QString state;
|
|
||||||
// can be:
|
|
||||||
// - 'disconnected'
|
|
||||||
// - 'connecting'
|
|
||||||
// - 'connected'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
QDateTime *date;
|
|
||||||
//to get the current time
|
|
||||||
|
|
||||||
QTcpSocket *socket;
|
|
||||||
//socket for communication with the extention
|
|
||||||
|
|
||||||
QStringList pending_commands;
|
|
||||||
//commands to send to the extention
|
|
||||||
//one command is being sent whenever refresh() is called
|
|
||||||
signals:
|
|
||||||
void triggered();
|
|
||||||
//is emitted when the device is triggered
|
|
||||||
|
|
||||||
void stateChanged();
|
|
||||||
//is emitted, when the connection state changes
|
|
||||||
|
|
||||||
void progressChanged();
|
|
||||||
//is emmited during the connection process when the progress changes
|
|
||||||
|
|
||||||
void offsetChanged();
|
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
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, bool bothTimes = true);
|
|
||||||
//function to get the times from the buzzer as a list
|
|
||||||
//if bothTimes is true the current and the last-pressed timestamp will be returned
|
|
||||||
//else only the current timestamp will be returned
|
|
||||||
|
|
||||||
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 double get(QString key);
|
|
||||||
//can return some things (offset, lastpressed, currtime, connection_progress, connected)
|
|
||||||
|
|
||||||
Q_INVOKABLE bool refresh();
|
|
||||||
//- refreshes the connection to the buzzer
|
|
||||||
//- checks if it was triggered, if so 'triggered()' is emitted
|
|
||||||
//- sends one command from the pending commans list
|
|
||||||
|
|
||||||
Q_INVOKABLE void appendCommand(QString command);
|
|
||||||
//appends a command to the pending commnds list
|
|
||||||
|
|
||||||
|
|
||||||
// functions for the qml adapter
|
|
||||||
QString getIP() const;
|
|
||||||
void setIP(const QString &ipAdress);
|
|
||||||
|
|
||||||
QString getState() const;
|
|
||||||
void setState(QString newState);
|
|
||||||
|
|
||||||
int getProgress() const;
|
|
||||||
|
|
||||||
double getOffset() const;
|
|
||||||
|
|
||||||
double getLastTriggered() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BUZZERCONN_H
|
|
90
headers/climbingrace.h
Normal file
90
headers/climbingrace.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#ifndef CLIMBINGRACE_H
|
||||||
|
#define CLIMBINGRACE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSound>
|
||||||
|
#include <QSoundEffect>
|
||||||
|
#include <QMediaPlayer>
|
||||||
|
#include "headers/baseconn.h"
|
||||||
|
#include "headers/appsettings.h"
|
||||||
|
#include "headers/speedtimer.h"
|
||||||
|
|
||||||
|
class ClimbingRace : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||||
|
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)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ClimbingRace(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
enum raceState { IDLE, STARTING, RUNNING, STOPPED };
|
||||||
|
raceState state;
|
||||||
|
|
||||||
|
enum raceMode { LOCAL, REMOTE };
|
||||||
|
raceMode mode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppSettings * appSettings;
|
||||||
|
BaseConn * baseConn;
|
||||||
|
|
||||||
|
QMediaPlayer * player;
|
||||||
|
|
||||||
|
QTimer * baseStationSyncTimer;
|
||||||
|
QTimer * timerTextRefreshTimer;
|
||||||
|
QTimer * nextStartActionTimer;
|
||||||
|
|
||||||
|
QList<SpeedTimer *> speedTimers;
|
||||||
|
|
||||||
|
int nextStartAction;
|
||||||
|
// 0 : 'at your marks'
|
||||||
|
// 1 : 'ready'
|
||||||
|
// 2 : 'start'
|
||||||
|
|
||||||
|
double nextStartActionDelayProgress;
|
||||||
|
|
||||||
|
// helper vars
|
||||||
|
QVariantList qmlTimers;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// helper functions
|
||||||
|
void playSoundsAndStartRace();
|
||||||
|
bool playSound(QString path);
|
||||||
|
void setState(raceState newState);
|
||||||
|
void refreshMode();
|
||||||
|
void refreshTimerText();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void nextStartActionChanged(int nextStartAction);
|
||||||
|
void nextStartActionDelayProgressChanged();
|
||||||
|
|
||||||
|
void stateChanged(int state);
|
||||||
|
void timerTextChanged();
|
||||||
|
void baseStationStateChanged();
|
||||||
|
void baseStationConnectionsChanged();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
Q_INVOKABLE int startRace();
|
||||||
|
Q_INVOKABLE int stopRace(int type);
|
||||||
|
Q_INVOKABLE int resetRace();
|
||||||
|
|
||||||
|
void syncWithBaseStation();
|
||||||
|
|
||||||
|
// functions for qml
|
||||||
|
Q_INVOKABLE int getState();
|
||||||
|
Q_INVOKABLE QVariant getTimerTextList();
|
||||||
|
Q_INVOKABLE double getNextStartActionDelayProgress();
|
||||||
|
|
||||||
|
Q_INVOKABLE void writeSetting(QString key, QVariant value);
|
||||||
|
Q_INVOKABLE QString readSetting(QString key);
|
||||||
|
|
||||||
|
Q_INVOKABLE bool connectBaseStation();
|
||||||
|
Q_INVOKABLE QString getBaseStationState();
|
||||||
|
Q_INVOKABLE QVariant getBaseStationConnections();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLIMBINGRACE_H
|
|
@ -13,7 +13,7 @@ class SpeedTimer : public QObject
|
||||||
public:
|
public:
|
||||||
explicit SpeedTimer(QObject *parent = nullptr);
|
explicit SpeedTimer(QObject *parent = nullptr);
|
||||||
|
|
||||||
enum timerState { IDLE, STARTING, RUNNING, STOPPED };
|
enum timerState { IDLE, STARTING, RUNNING, STOPPED, FAILED, CANCELLED };
|
||||||
timerState state;
|
timerState state;
|
||||||
|
|
||||||
// variables for capturing the time
|
// variables for capturing the time
|
||||||
|
@ -22,20 +22,19 @@ public:
|
||||||
double stoppedTime;
|
double stoppedTime;
|
||||||
double reactionTime;
|
double reactionTime;
|
||||||
|
|
||||||
bool remoteControlled;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stateChanged(timerState newState);
|
void stateChanged(timerState newState);
|
||||||
void startCanceled(bool falseStart);
|
void startCanceled(bool falseStart);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
bool start(bool force = false);
|
||||||
void stop(QString type);
|
bool stop(int type, bool force = false);
|
||||||
void reset();
|
bool reset(bool force = false);
|
||||||
|
|
||||||
void setState(timerState newState);
|
void setState(timerState newState);
|
||||||
QString getState();
|
QString getState();
|
||||||
double getCurrTime();
|
double getCurrTime();
|
||||||
|
QString getText();
|
||||||
|
|
||||||
//void handleStartpadTrigger();
|
//void handleStartpadTrigger();
|
||||||
//void handleToppadTrigger();
|
//void handleToppadTrigger();
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
#ifndef SPEEDTIMERQMLADAPTER_H
|
|
||||||
#define SPEEDTIMERQMLADAPTER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QTimer>
|
|
||||||
#include "speedtimer.h"
|
|
||||||
|
|
||||||
class SpeedTimerQmlAdapter : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(QString state READ getState NOTIFY stateChanged)
|
|
||||||
//Q_PROPERTY(int currtime READ getCurrTime)
|
|
||||||
Q_PROPERTY(QString text READ getText NOTIFY textChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit SpeedTimerQmlAdapter(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
SpeedTimer::timerState state;
|
|
||||||
|
|
||||||
// variables for capturing the time
|
|
||||||
double startTime;
|
|
||||||
double stopTime;
|
|
||||||
double stoppedTime;
|
|
||||||
double reactionTime;
|
|
||||||
|
|
||||||
QString text;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void stateChanged(SpeedTimer::timerState newState);
|
|
||||||
Q_SIGNAL void startCanceled(bool falseStart);
|
|
||||||
void textChanged();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
Q_INVOKABLE bool setStarting();
|
|
||||||
Q_INVOKABLE bool start();
|
|
||||||
Q_INVOKABLE bool stop(QString type);
|
|
||||||
Q_INVOKABLE bool reset();
|
|
||||||
|
|
||||||
void setState(SpeedTimer::timerState newState);
|
|
||||||
Q_INVOKABLE QString getState();
|
|
||||||
Q_INVOKABLE QString getText();
|
|
||||||
|
|
||||||
// double getCurrTime();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QTimer * refreshTimer;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void refreshValues();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SPEEDTIMERQMLADAPTER_H
|
|
|
@ -124,7 +124,7 @@ Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
options_stack.depth > 1 ? options_stack.pop():root.close()
|
options_stack.depth > 1 ? options_stack.pop():root.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
|
@ -169,7 +169,7 @@ Popup {
|
||||||
/*----Connect to external devices----*/
|
/*----Connect to external devices----*/
|
||||||
NextPageDelegate {
|
NextPageDelegate {
|
||||||
id: connect_del
|
id: connect_del
|
||||||
text: qsTr("extentions")
|
text: qsTr("Base Station")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
options_stack.push(connect)
|
options_stack.push(connect)
|
||||||
}
|
}
|
||||||
|
@ -226,39 +226,29 @@ Popup {
|
||||||
id: connect
|
id: connect
|
||||||
Column {
|
Column {
|
||||||
id: connect_col
|
id: connect_col
|
||||||
property string title: qsTr("extentions")
|
property string title: qsTr("Base Station")
|
||||||
property int delegateHeight: height*0.18
|
property int delegateHeight: height*0.18
|
||||||
|
|
||||||
|
ConnectionDelegate {
|
||||||
|
id: connect_base_del
|
||||||
|
text: "connect"
|
||||||
|
|
||||||
|
status: { "status": speedBackend.baseStationState }
|
||||||
|
connect: speedBackend.connectBaseStation
|
||||||
|
type: "baseStation"
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
font.pixelSize: options_stack.text_pixelSize
|
||||||
|
}
|
||||||
|
|
||||||
NextPageDelegate {
|
NextPageDelegate {
|
||||||
id: baseConn_del
|
id: baseStationConnections_del
|
||||||
text: qsTr("Base Station")
|
text: qsTr("connected extentions")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
options_stack.push(baseStation)
|
options_stack.push(baseStationConnections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionDelegate {
|
|
||||||
id: connect_buzz_del
|
|
||||||
|
|
||||||
status: root.connections.buzzer
|
|
||||||
connect: root.connect
|
|
||||||
type: "buzzer"
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
font.pixelSize: options_stack.text_pixelSize
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionDelegate {
|
|
||||||
id: connect_stap_del
|
|
||||||
|
|
||||||
status: root.connections.startpad
|
|
||||||
connect: root.connect
|
|
||||||
type: "startpad"
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
font.pixelSize: options_stack.text_pixelSize
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,12 +263,7 @@ Popup {
|
||||||
function updateSetting(key, val, del){
|
function updateSetting(key, val, del){
|
||||||
del.enabled = false
|
del.enabled = false
|
||||||
|
|
||||||
if(baseConn.state === "connected"){
|
speedBackend.writeSetting(key, val)
|
||||||
baseConn.writeRemoteSetting(key, val)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_cppAppSettings.writeSetting(key, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
del.enabled = true
|
del.enabled = true
|
||||||
}
|
}
|
||||||
|
@ -286,12 +271,8 @@ Popup {
|
||||||
function loadSetting(key, del){
|
function loadSetting(key, del){
|
||||||
del.enabled = false
|
del.enabled = false
|
||||||
var val
|
var val
|
||||||
if(baseConn.state === "connected"){
|
|
||||||
val = baseConn.sendCommand(3001, key)["data"]
|
val = speedBackend.readSetting(key)
|
||||||
}
|
|
||||||
else {
|
|
||||||
val = _cppAppSettings.loadSetting(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
del.enabled = true
|
del.enabled = true
|
||||||
return val
|
return val
|
||||||
|
@ -407,70 +388,24 @@ Popup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----Page to connect to and manage the Base Station----*/
|
|
||||||
Component {
|
|
||||||
id: baseStation
|
|
||||||
Column {
|
|
||||||
id: baseStation_col
|
|
||||||
property string title: qsTr("Base Station")
|
|
||||||
property int delegateHeight: height*0.18
|
|
||||||
|
|
||||||
ConnectionDelegate {
|
|
||||||
id: connect_base_del
|
|
||||||
text: "connect"
|
|
||||||
|
|
||||||
status: root.connections.baseStation
|
|
||||||
connect: root.connect
|
|
||||||
type: "baseStation"
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
font.pixelSize: options_stack.text_pixelSize
|
|
||||||
}
|
|
||||||
|
|
||||||
NextPageDelegate {
|
|
||||||
id: baseStationConnections_del
|
|
||||||
text: qsTr("connected extentions")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
baseConn.refreshConnections()
|
|
||||||
options_stack.push(baseStationConnections)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----Page to view devices that core connected to the pase startion-----*/
|
/*-----Page to view devices that core connected to the pase startion-----*/
|
||||||
Component{
|
Component{
|
||||||
id: baseStationConnections
|
id: baseStationConnections
|
||||||
ListView {
|
ListView {
|
||||||
function getModel(){
|
id: baseStationConnections_list
|
||||||
var keys = Object.keys(baseConn.connections);
|
property string title: qsTr("connections")
|
||||||
|
property int delegateHeight: height*0.18
|
||||||
|
model: speedBackend.baseStationConnections.length
|
||||||
|
delegate: ConnectionDelegate {
|
||||||
|
enabled: false
|
||||||
|
font.pixelSize: options_stack.text_pixelSize
|
||||||
|
width: parent.width
|
||||||
|
height: baseStationConnections_list.delegateHeight
|
||||||
|
|
||||||
var len = keys.length
|
text: speedBackend.baseStationConnections[index]["name"]
|
||||||
return(len)
|
status: {'status': speedBackend.baseStationConnections[index]["state"], 'progress': speedBackend.baseStationConnections[index]["progress"]}
|
||||||
}
|
|
||||||
|
|
||||||
function getDetails(index){
|
|
||||||
var ret = baseConn.connections[index]
|
|
||||||
var details = ret.split("|")
|
|
||||||
return(details)
|
|
||||||
}
|
|
||||||
|
|
||||||
id: baseStationConnections_list
|
|
||||||
property string title: qsTr("connections")
|
|
||||||
property int delegateHeight: height*0.18
|
|
||||||
model: getModel()
|
|
||||||
delegate: ConnectionDelegate {
|
|
||||||
enabled: false
|
|
||||||
font.pixelSize: options_stack.text_pixelSize
|
|
||||||
width: parent.width
|
|
||||||
height: baseStationConnections_list.delegateHeight
|
|
||||||
|
|
||||||
text: baseStationConnections_list.getDetails(index)[2]
|
|
||||||
status: {'status': baseStationConnections_list.getDetails(index)[4], 'progress': 0}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----Custom animations-----*/
|
/*-----Custom animations-----*/
|
||||||
|
|
|
@ -48,7 +48,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
SpeedTimerBackend {
|
SpeedTimerBackend {
|
||||||
id: timerBackend
|
id: timerBackend
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ Item {
|
||||||
console.log("start cnaceled")
|
console.log("start cnaceled")
|
||||||
control.startCanceled(falseStart)
|
control.startCanceled(falseStart)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
function getState(){
|
function getState(){
|
||||||
return(timerBackend.getState())
|
return(timerBackend.getState())
|
||||||
|
|
|
@ -12,7 +12,7 @@ ItemDelegate {
|
||||||
enabled: status.status === "disconnected"
|
enabled: status.status === "disconnected"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
connect(type)
|
connect()
|
||||||
if(status.status !== "connected"){
|
if(status.status !== "connected"){
|
||||||
statusIndicator.color_override = "red"
|
statusIndicator.color_override = "red"
|
||||||
shortDelay.start()
|
shortDelay.start()
|
||||||
|
|
330
qml/main.qml
330
qml/main.qml
|
@ -24,7 +24,7 @@ import "./components"
|
||||||
import "./styles"
|
import "./styles"
|
||||||
//import QtQuick.Layouts 1.11
|
//import QtQuick.Layouts 1.11
|
||||||
|
|
||||||
import com.itsblue.speedclimbingstopwatch 1.0
|
import com.itsblue.speedclimbingstopwatch 2.0
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
visible: true
|
visible: true
|
||||||
|
@ -46,20 +46,6 @@ Window {
|
||||||
property double stoppedTime: 0
|
property double stoppedTime: 0
|
||||||
property double currTime
|
property double currTime
|
||||||
|
|
||||||
property double buzzer_offset: buzzerConn.offset
|
|
||||||
property double last_button_pressed: buzzerConn.lastTriggered
|
|
||||||
|
|
||||||
property var last_run : {
|
|
||||||
'stop_type': "", 'time': 0, 'react_time': 0
|
|
||||||
}
|
|
||||||
|
|
||||||
//array that contains all connections an their atatus
|
|
||||||
property var connections: {
|
|
||||||
'buzzer': buzzerConn.status,
|
|
||||||
'startpad': startpadConn.status,
|
|
||||||
'baseStation': baseConn.status
|
|
||||||
}
|
|
||||||
|
|
||||||
//set default state to IDLE
|
//set default state to IDLE
|
||||||
state: "IDLE"
|
state: "IDLE"
|
||||||
|
|
||||||
|
@ -69,174 +55,28 @@ Window {
|
||||||
color: StyleSettings.backgroundColor
|
color: StyleSettings.backgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
SpeedBackend {
|
||||||
id: connections
|
id: speedBackend
|
||||||
|
|
||||||
BuzzerConn {
|
onStateChanged: {
|
||||||
id: buzzerConn
|
var stateString
|
||||||
ipAdress: "192.168.4.10"
|
switch (state){
|
||||||
property var status: {'status': buzzerConn.state, 'progress': buzzerConn.progress}
|
case 0:
|
||||||
onLastTriggeredChanged: {
|
stateString = "IDLE"
|
||||||
timer_1.handleToppad()
|
break;
|
||||||
}
|
case 1:
|
||||||
}
|
stateString = "STARTING"
|
||||||
|
break;
|
||||||
Timer {
|
case 2:
|
||||||
id: buzzerRefreshTimer
|
stateString = "RUNNING"
|
||||||
running: buzzerConn.state === "connected"
|
break;
|
||||||
interval: root.state === "RUNNING" ? 1:1000
|
case 3:
|
||||||
repeat: false
|
stateString = "STOPPED"
|
||||||
onTriggered: {
|
|
||||||
buzzerConn.refresh()
|
|
||||||
this.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StartpadConn {
|
|
||||||
id: startpadConn
|
|
||||||
ipAdress: "192.168.4.11"
|
|
||||||
property var status: {'status': startpadConn.state, 'progress': startpadConn.progress}
|
|
||||||
property string color: root.state === "RUNNING" ? "SET_LED_RUNNING":"SET_LED_STARTING"
|
|
||||||
onColorChanged: {
|
|
||||||
appendCommand(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
onLastTriggeredChanged: {
|
|
||||||
timer_1.handleStartpad()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: startpadRefreshTimer
|
|
||||||
running: startpadConn.state === "connected"
|
|
||||||
interval: root.state === "RUNNING" || root.state === "STARTING" ? 1:1000
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
startpadConn.refresh()
|
|
||||||
this.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseStationConn {
|
|
||||||
id: baseConn
|
|
||||||
ipAdress: "192.168.4.1"
|
|
||||||
|
|
||||||
property var status: {'status': baseConn.state, 'progress': baseConn.progress, 'connections': baseConn.connections}
|
|
||||||
|
|
||||||
onNextRemoteActionChanged: {
|
|
||||||
switch(nextRemoteAction){
|
|
||||||
case "0":
|
|
||||||
timer_1.text = "at your\nmarks"
|
|
||||||
break
|
|
||||||
case "1":
|
|
||||||
timer_1.text = "ready"
|
|
||||||
break
|
|
||||||
case "2":
|
|
||||||
timer_1.text = "0.000 sec"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onNextRemoteActionDelayProgChanged: {
|
|
||||||
prog.progress = baseConn.nextRemoteActionDelayProg * 100
|
|
||||||
}
|
}
|
||||||
|
root.state = stateString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: next_actionTimer
|
|
||||||
|
|
||||||
property string action
|
|
||||||
property double started_at
|
|
||||||
|
|
||||||
running: false
|
|
||||||
repeat: false
|
|
||||||
onRunningChanged: {
|
|
||||||
if(!running){
|
|
||||||
started_at = 0
|
|
||||||
if(action == "NONE"){
|
|
||||||
timer_1.text = "0.000 sec"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if(action === "at_marks"){
|
|
||||||
started_at = new Date().getTime()
|
|
||||||
timer_1.text = "at your\nmarks"
|
|
||||||
}
|
|
||||||
else if(action === "ready"){
|
|
||||||
started_at = new Date().getTime()
|
|
||||||
timer_1.text = "ready"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onTriggered: {
|
|
||||||
if(action === "at_marks"){
|
|
||||||
at_marksSound.play()
|
|
||||||
}
|
|
||||||
else if(action === "ready"){
|
|
||||||
action = "NONE"
|
|
||||||
readySound.play()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: sounds
|
|
||||||
SoundEffect {
|
|
||||||
id: at_marksSound
|
|
||||||
source: "qrc:/sounds/at_marks_1.wav"
|
|
||||||
|
|
||||||
onPlayingChanged: {
|
|
||||||
if(!playing && root.state==="STARTING"){
|
|
||||||
if(_cppAppSettings.loadSetting("ready_en") === "true"){
|
|
||||||
next_actionTimer.action = "ready"
|
|
||||||
next_actionTimer.interval = _cppAppSettings.loadSetting("ready_delay")>0 ? _cppAppSettings.loadSetting("ready_delay"):1
|
|
||||||
next_actionTimer.start()
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
startSound.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundEffect {
|
|
||||||
id: readySound
|
|
||||||
source: "qrc:/sounds/ready_1.wav"
|
|
||||||
onPlayingChanged: {
|
|
||||||
if(!playing && root.state==="STARTING"){
|
|
||||||
|
|
||||||
startSound.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundEffect {
|
|
||||||
//start sound
|
|
||||||
id: startSound
|
|
||||||
source: "qrc:/sounds/OFFICAL_IFSC_STARTIGNAL.wav"
|
|
||||||
|
|
||||||
onPlayingChanged: {
|
|
||||||
if(!playing && root.state==="STARTING"){
|
|
||||||
root.state = "RUNNING"
|
|
||||||
}
|
|
||||||
else if(playing) {
|
|
||||||
console.log("start sound started")
|
|
||||||
|
|
||||||
timer_1.start(3100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundEffect {
|
|
||||||
//false-start sound
|
|
||||||
id: falseSound
|
|
||||||
source: "qrc:/sounds/false.wav"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*------------------------
|
/*------------------------
|
||||||
Timer text an upper line
|
Timer text an upper line
|
||||||
------------------------*/
|
------------------------*/
|
||||||
|
@ -256,84 +96,36 @@ Window {
|
||||||
color: StyleSettings.menuColor
|
color: StyleSettings.menuColor
|
||||||
}
|
}
|
||||||
|
|
||||||
SpeedTimer {
|
Label {
|
||||||
id: timer_1
|
id: timer_1
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
elide: "ElideRight"
|
elide: "ElideRight"
|
||||||
color: StyleSettings.textColor
|
color: StyleSettings.textColor
|
||||||
toppadConn: buzzerConn
|
|
||||||
baseConn: baseConn
|
|
||||||
startpadConn: startpadConn
|
|
||||||
|
|
||||||
text: "0.000 sec"
|
font.pixelSize: 100
|
||||||
|
|
||||||
onStateChanged: {
|
text: speedBackend.timers[0]["text"]
|
||||||
root.state = timer_1.getState()
|
|
||||||
}
|
|
||||||
|
|
||||||
onStopped: {
|
Behavior on text {
|
||||||
root.state = "STOPPED"
|
enabled: root.state !== "RUNNING"
|
||||||
}
|
FadeAnimation {
|
||||||
|
target: timer_1
|
||||||
onStartCanceled: {
|
|
||||||
root.state = "STOPPED"
|
|
||||||
next_actionTimer.stop()
|
|
||||||
at_marksSound.stop()
|
|
||||||
readySound.stop()
|
|
||||||
startSound.stop()
|
|
||||||
if(falseStart && baseConn.state !== "connected"){
|
|
||||||
falseSound.play()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: react_time
|
id: react_time
|
||||||
property int rtime: root.last_run.react_time
|
property int rtime: speedBackend.timers[0]["reacttime"]
|
||||||
text: qsTr("reaction time (ms): ") + Math.round(rtime)
|
text: qsTr("reaction time (ms): ") + Math.round(rtime)
|
||||||
opacity: (root.state === "RUNNING" || root.sate === "STARTING" || root.state === "STOPPED") && rtime !== 0 ? 1:0
|
opacity: (root.state === "RUNNING" || root.state === "STOPPED") && rtime !== 0 ? 1:0
|
||||||
color: StyleSettings.textColor
|
color: StyleSettings.textColor
|
||||||
anchors {
|
anchors {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
top: timer_1.bottom
|
top: timer_1.bottom
|
||||||
topMargin: parent.height * 0.1
|
topMargin: parent.height * 0.1
|
||||||
}
|
}
|
||||||
Timer {
|
|
||||||
running: root.state === "RUNNING" || root.sate === "STARTING" || root.state === "STOPPED"
|
|
||||||
repeat: true
|
|
||||||
interval: 1
|
|
||||||
onTriggered: {
|
|
||||||
react_time.rtime = root.last_run.react_time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionIcon {
|
|
||||||
id: buzzerLogo
|
|
||||||
source: "qrc:/graphics/icons/buzzer_black.png"
|
|
||||||
status: root.connections["buzzer"].status
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: 10
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 10
|
|
||||||
}
|
|
||||||
height: root.landscape()? root.height*0.1:root.width*0.1
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionIcon {
|
|
||||||
id: startpadLogo
|
|
||||||
source: "qrc:/graphics/icons/startpad_black.png"
|
|
||||||
status: root.connections["startpad"].status
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: 10
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 5 + buzzerLogo.width
|
|
||||||
}
|
|
||||||
height: root.landscape()? root.height*0.1:root.width*0.1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -395,7 +187,7 @@ Window {
|
||||||
root.start()
|
root.start()
|
||||||
break
|
break
|
||||||
case "RUNNING":
|
case "RUNNING":
|
||||||
root.stop("manual")
|
root.stop(0)
|
||||||
break
|
break
|
||||||
case "STOPPED":
|
case "STOPPED":
|
||||||
root.reset()
|
root.reset()
|
||||||
|
@ -407,31 +199,22 @@ Window {
|
||||||
ProgressCircle {
|
ProgressCircle {
|
||||||
id: prog
|
id: prog
|
||||||
anchors.fill: startButt
|
anchors.fill: startButt
|
||||||
opacity: baseConn.state !== "connected" ?
|
opacity: root.state === "STARTING" || root.state === "IDLE" ? 1:0
|
||||||
next_actionTimer.started_at > 0 ? 1:0
|
|
||||||
:progress > 0 ? 1:0
|
|
||||||
lineWidth: 5
|
lineWidth: 5
|
||||||
property int progress: 0
|
|
||||||
arcBegin: 0
|
arcBegin: 0
|
||||||
arcEnd: baseConn.state !== "connected" ? 360 * (( next_actionTimer.interval - ( new Date().getTime() - next_actionTimer.started_at ) ) / next_actionTimer.interval)
|
arcEnd: 360 * speedBackend.nextStartActionDelayProgress
|
||||||
:(360/100) * progress
|
|
||||||
colorCircle: "grey"
|
colorCircle: "grey"
|
||||||
onProgressChanged: {
|
|
||||||
//console.log(progress)
|
|
||||||
}
|
|
||||||
|
|
||||||
animationDuration: baseConn.state === "connected" ? 150:0
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
Timer {
|
duration: 200
|
||||||
id: prog_refresh
|
|
||||||
running: parent.opacity === 1 && baseConn.state !== "connected"
|
|
||||||
interval: 1
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
prog.arcEnd = 360 * (( next_actionTimer.interval - ( new Date().getTime() - next_actionTimer.started_at ) ) / next_actionTimer.interval)
|
|
||||||
prog_refresh.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animationDuration: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------
|
/*----------------------
|
||||||
|
@ -455,7 +238,7 @@ Window {
|
||||||
enabled: root.state === "STARTING"
|
enabled: root.state === "STARTING"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.stop("cancel")
|
root.stop(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on scale {
|
Behavior on scale {
|
||||||
|
@ -634,7 +417,7 @@ Window {
|
||||||
State {
|
State {
|
||||||
name: "IDLE"
|
name: "IDLE"
|
||||||
//state for the start page
|
//state for the start page
|
||||||
PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 }
|
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 }
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: time_container;
|
target: time_container;
|
||||||
anchors.bottomMargin: root.landscape() ? undefined:parent.height * 0.1;
|
anchors.bottomMargin: root.landscape() ? undefined:parent.height * 0.1;
|
||||||
|
@ -656,14 +439,14 @@ Window {
|
||||||
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
||||||
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.1 //put the button lower to hide the menu (only in portrait mode)
|
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.1 //put the button lower to hide the menu (only in portrait mode)
|
||||||
}
|
}
|
||||||
PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
||||||
PropertyChanges { target: cancelButt; scale: 1}
|
PropertyChanges { target: cancelButt; scale: 1}
|
||||||
PropertyChanges { target: menu_container; }
|
PropertyChanges { target: menu_container; }
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "RUNNING"
|
name: "RUNNING"
|
||||||
//state when the timer is running
|
//state when the timer is running
|
||||||
PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
||||||
PropertyChanges { target: startButt; enabled: true;
|
PropertyChanges { target: startButt; enabled: true;
|
||||||
text: "stop"
|
text: "stop"
|
||||||
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
||||||
|
@ -677,7 +460,7 @@ Window {
|
||||||
//state when the meassuring is over
|
//state when the meassuring is over
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: timer_1;
|
target: timer_1;
|
||||||
pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1;
|
font.pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1;
|
||||||
scale: 1
|
scale: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
|
@ -726,7 +509,12 @@ Window {
|
||||||
|
|
||||||
/*----Functions to control the stopwatch----*/
|
/*----Functions to control the stopwatch----*/
|
||||||
function start(){
|
function start(){
|
||||||
if(baseConn.state === "connected"){
|
var ret = speedBackend.startRace()
|
||||||
|
if(ret !== 200){
|
||||||
|
console.log("+ --- error starting race: "+ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(baseConn.state === "connected"){
|
||||||
baseConn.startTimers()
|
baseConn.startTimers()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -745,10 +533,18 @@ Window {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
startSound.play()
|
startSound.play()*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop(type){
|
function stop(type){
|
||||||
|
|
||||||
|
var ret = speedBackend.stopRace(type)
|
||||||
|
|
||||||
|
if(ret !== 200){
|
||||||
|
console.log("+ --- error stopping race: "+ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if(baseConn.state === "connected"){
|
if(baseConn.state === "connected"){
|
||||||
baseConn.stopTimers(type)
|
baseConn.stopTimers(type)
|
||||||
}
|
}
|
||||||
|
@ -761,9 +557,18 @@ Window {
|
||||||
}
|
}
|
||||||
//root.state = "STOPPED"
|
//root.state = "STOPPED"
|
||||||
//timer_1.stop(type)
|
//timer_1.stop(type)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset(){
|
function reset(){
|
||||||
|
|
||||||
|
var ret = speedBackend.resetRace()
|
||||||
|
|
||||||
|
if(ret !== 200){
|
||||||
|
console.log("+ --- error resetting race: "+ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if(baseConn.state === "connected"){
|
if(baseConn.state === "connected"){
|
||||||
baseConn.resetTimers()
|
baseConn.resetTimers()
|
||||||
}
|
}
|
||||||
|
@ -773,6 +578,7 @@ Window {
|
||||||
|
|
||||||
//
|
//
|
||||||
//root.state = "IDLE"
|
//root.state = "IDLE"
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,10 +113,10 @@ Item {
|
||||||
case "Default":
|
case "Default":
|
||||||
theme = Dark
|
theme = Dark
|
||||||
break
|
break
|
||||||
case "Dark":
|
case "Dark":
|
||||||
theme = Light
|
theme = Light
|
||||||
break
|
break
|
||||||
case "Light":
|
case "Light":
|
||||||
theme = Default
|
theme = Default
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -142,13 +142,13 @@ Item {
|
||||||
_cppAppSettings.writeSetting("theme", "Dark")
|
_cppAppSettings.writeSetting("theme", "Dark")
|
||||||
theme = Dark
|
theme = Dark
|
||||||
break
|
break
|
||||||
case "Dark":
|
case "Dark":
|
||||||
_cppAppSettings.writeSetting("theme", "Light")
|
_cppAppSettings.writeSetting("theme", "Light")
|
||||||
theme = Light
|
theme = Light
|
||||||
break
|
break
|
||||||
case "Light":
|
case "Light":
|
||||||
_cppAppSettings.writeSetting("theme", "Default")
|
_cppAppSettings.writeSetting("theme", "Default")
|
||||||
theme = Default
|
theme = Default
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ AppSettings::AppSettings(QObject* parent)
|
||||||
this->setDefaultSetting("at_marks_delay", 0);
|
this->setDefaultSetting("at_marks_delay", 0);
|
||||||
|
|
||||||
this->setDefaultSetting("theme", "Default");
|
this->setDefaultSetting("theme", "Default");
|
||||||
|
|
||||||
|
pGlobalAppSettings = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AppSettings::loadSetting(const QString &key)
|
QString AppSettings::loadSetting(const QString &key)
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#include "headers/baseconn.h"
|
#include "headers/baseconn.h"
|
||||||
|
|
||||||
|
BaseConn * pGlobalBaseConn = nullptr;
|
||||||
|
|
||||||
BaseConn::BaseConn(QObject *parent) : QObject(parent)
|
BaseConn::BaseConn(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
pGlobalBaseConn = this;
|
||||||
socket = new QTcpSocket();
|
socket = new QTcpSocket();
|
||||||
this->setState("disconnected");
|
this->setState("disconnected");
|
||||||
|
|
||||||
|
@ -9,14 +12,6 @@ BaseConn::BaseConn(QObject *parent) : QObject(parent)
|
||||||
this, SLOT(gotError(QAbstractSocket::SocketError)));
|
this, SLOT(gotError(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
this->nextConnectionId = 1;
|
this->nextConnectionId = 1;
|
||||||
|
|
||||||
this->speedTimers.append(pGlobalSpeedTimer);
|
|
||||||
|
|
||||||
this->refreshTimer = new QTimer();
|
|
||||||
refreshTimer->setInterval(1);
|
|
||||||
refreshTimer->setSingleShot(true);
|
|
||||||
refreshTimer->connect(this->refreshTimer, &QTimer::timeout, this, &BaseConn::refreshTimers);
|
|
||||||
refreshTimer->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConn::connectToHost() {
|
bool BaseConn::connectToHost() {
|
||||||
|
@ -53,7 +48,6 @@ bool BaseConn::connectToHost() {
|
||||||
connect(this->socket, &QTcpSocket::readyRead, this, &BaseConn::readyRead);
|
connect(this->socket, &QTcpSocket::readyRead, this, &BaseConn::readyRead);
|
||||||
this->connection_progress = 100;
|
this->connection_progress = 100;
|
||||||
setState("connected");
|
setState("connected");
|
||||||
this->speedTimers[0]->remoteControlled = true;
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +100,7 @@ void BaseConn::gotError(QAbstractSocket::SocketError err)
|
||||||
qDebug() << "got socket error: " << strError;
|
qDebug() << "got socket error: " << strError;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap BaseConn::sendCommand(int header, QJsonValue data = ""){
|
QVariantMap BaseConn::sendCommand(int header, QJsonValue data){
|
||||||
if(this->state != "connected"){
|
if(this->state != "connected"){
|
||||||
return {{"status", 910}, {"data", "not connected"}};
|
return {{"status", 910}, {"data", "not connected"}};
|
||||||
}
|
}
|
||||||
|
@ -230,162 +224,6 @@ int BaseConn::writeRemoteSetting(QString key, QString value) {
|
||||||
return this->sendCommand(3000, requestData)["status"].toInt();
|
return this->sendCommand(3000, requestData)["status"].toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseConn::refreshTimers(){
|
|
||||||
if(this->state != "connected"){
|
|
||||||
this->refreshTimer->start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap tmpReply = this->sendCommand(2000);
|
|
||||||
|
|
||||||
if(tmpReply["status"] != 200){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remoteRaceState = tmpReply["data"].toInt();
|
|
||||||
|
|
||||||
switch (remoteRaceState) {
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
// case IDLE
|
|
||||||
if(speedTimers[0]->state != 0){
|
|
||||||
speedTimers[0]->setState(SpeedTimer::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// case STARTING
|
|
||||||
if(speedTimers[0]->state != 1){
|
|
||||||
speedTimers[0]->setState(SpeedTimer::STARTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpReply = sendCommand(2004);
|
|
||||||
if(tmpReply["status"] != 200){
|
|
||||||
//handle Error!!
|
|
||||||
qDebug() << "+--- getting next start action from basestation failed: " << tmpReply["status"];
|
|
||||||
this->refreshTimer->start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(this->nextRemoteAction != tmpReply["data"].toString()){
|
|
||||||
this->nextRemoteAction = tmpReply["data"].toString();
|
|
||||||
this->nextRemoteActionChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpReply = sendCommand(2005);
|
|
||||||
if(tmpReply["status"] != 200){
|
|
||||||
//handle error!!
|
|
||||||
qDebug() << "+--- getting next start action progress from basestation failed";
|
|
||||||
this->refreshTimer->start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(this->nextRemoteActionDelayProg != tmpReply["data"].toFloat()){
|
|
||||||
this->nextRemoteActionDelayProg = tmpReply["data"].toFloat();
|
|
||||||
this->nextRemoteActionDelayProgChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// case RUNNING
|
|
||||||
if(speedTimers[0]->state != 2){
|
|
||||||
speedTimers[0]->setState(SpeedTimer::RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get current time
|
|
||||||
tmpReply = sendCommand(2001, 0);
|
|
||||||
if(tmpReply["status"] != 200){
|
|
||||||
//handle error!!
|
|
||||||
qDebug() << "+--- getting current time (timer 0) from basestation failed";
|
|
||||||
this->refreshTimer->start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
speedTimers[0]->stoppedTime = tmpReply["data"].toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
// case STOPPED
|
|
||||||
if(speedTimers[0]->state != 3){
|
|
||||||
speedTimers[0]->setState(SpeedTimer::STOPPED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get current time
|
|
||||||
tmpReply = sendCommand(2001, 0);
|
|
||||||
if(tmpReply["status"] != 200){
|
|
||||||
//handle error!!
|
|
||||||
qDebug() << "+--- getting current time (timer 0) from basestation failed";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
speedTimers[0]->stoppedTime = tmpReply["data"].toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// some error
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->refreshTimer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseConn::startTimers(){
|
|
||||||
qDebug() << "starting timers";
|
|
||||||
|
|
||||||
QVariantMap reply = this->sendCommand(1000);
|
|
||||||
|
|
||||||
if(reply["status"] != 200){
|
|
||||||
//handle Error!!
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->speedTimers[0]->setState(SpeedTimer::STARTING);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseConn::stopTimers(QString type){
|
|
||||||
qDebug() << "stopping timers";
|
|
||||||
|
|
||||||
QVariantMap reply = this->sendCommand(1001);
|
|
||||||
|
|
||||||
if(reply["status"] != 200){
|
|
||||||
//handle Error!!
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->speedTimers[0]->stop(type);
|
|
||||||
qDebug() << "stopped timers";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseConn::resetTimers(){
|
|
||||||
qDebug() << "resetting timers";
|
|
||||||
|
|
||||||
QVariantMap reply = this->sendCommand(1002);
|
|
||||||
|
|
||||||
if(reply["status"] != 200){
|
|
||||||
//handle Error!!
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->speedTimers[0]->reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseConn::setIP(const QString &ipAdress){
|
void BaseConn::setIP(const QString &ipAdress){
|
||||||
this->ip = ipAdress;
|
this->ip = ipAdress;
|
||||||
}
|
}
|
||||||
|
@ -415,23 +253,18 @@ bool BaseConn::refreshConnections() {
|
||||||
|
|
||||||
if(reply["status"] != 200){
|
if(reply["status"] != 200){
|
||||||
//handle Error!!
|
//handle Error!!
|
||||||
qDebug() << "+--- error refreshing connections: " << reply["status"];
|
qDebug() << "+ --- error refreshing connections: " << reply["status"];
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
connections = reply["data"].toString().split("|||");
|
|
||||||
|
QVariantList tmpConnections = reply["data"].toList();
|
||||||
|
|
||||||
|
this->connections = reply["data"].toList();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList BaseConn::getConnections() {
|
QVariant BaseConn::getConnections() {
|
||||||
return(connections);
|
return(connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BaseConn::getNextRemoteAction() {
|
|
||||||
return this->nextRemoteAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
float BaseConn::getNextRemoteActionDelayProg(){
|
|
||||||
return this->nextRemoteActionDelayProg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,360 +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)
|
|
||||||
{
|
|
||||||
// initialize TcpSocket for communication with the extentions
|
|
||||||
this->socket = new QTcpSocket();
|
|
||||||
|
|
||||||
// initialize Qdate
|
|
||||||
this->date = new QDateTime;
|
|
||||||
this->latest_button_pressed = 0;
|
|
||||||
|
|
||||||
// set ip and port
|
|
||||||
this->ip = ip;
|
|
||||||
this->port = port;
|
|
||||||
|
|
||||||
//standard state: disconnected
|
|
||||||
this->setState("disconnected");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuzzerConn::connect()
|
|
||||||
{
|
|
||||||
// function to connect to buzzer
|
|
||||||
|
|
||||||
qDebug() << "connecting...";
|
|
||||||
|
|
||||||
setState("connecting");
|
|
||||||
|
|
||||||
//setup loop to wait until the connection has finished
|
|
||||||
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
|
|
||||||
loop.connect(this->socket, SIGNAL(connected()), &loop, SLOT(quit()));
|
|
||||||
// start the timer before starting to connect
|
|
||||||
timer.start(3000);
|
|
||||||
//connect
|
|
||||||
this->socket->connectToHost(this->ip, this->port);
|
|
||||||
|
|
||||||
//wait for the connection to finish (programm gets stuck in here)
|
|
||||||
loop.exec();
|
|
||||||
|
|
||||||
//loop finished
|
|
||||||
if(timer.remainingTime() == -1){
|
|
||||||
//the time has been triggered -> timeout
|
|
||||||
setState("disconnected");
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop the timer as the connection has been established
|
|
||||||
timer.stop();
|
|
||||||
|
|
||||||
// get the timestamps ( last_pressed and current_timestamp ) from the extention
|
|
||||||
QList<double> times = gettimes(2000, true);
|
|
||||||
|
|
||||||
if(times[0] == 200.0){
|
|
||||||
//if the request was successfull, set last_triggered and
|
|
||||||
this->latest_button_pressed = times[2];
|
|
||||||
for(int i=0;i<=100;i++){
|
|
||||||
// middle the offset 100 times
|
|
||||||
this->connection_progress = i;
|
|
||||||
emit this->progressChanged();
|
|
||||||
if(!calcoffset(this->gettimes(1000, false))){
|
|
||||||
// if a request fails, cancle the connection process
|
|
||||||
this->connection_progress = 100;
|
|
||||||
setState("disconnected");
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// after middeling the offset for 100 times set the state to connected and quit
|
|
||||||
setState("connected");
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
//if not, cancel
|
|
||||||
setState("disconnected");
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuzzerConn::calcoffset(QList<double> times)
|
|
||||||
{
|
|
||||||
//function that recieves the current time of the extention,
|
|
||||||
//puts it into the latest offsets list and
|
|
||||||
//calculates the avarage offset
|
|
||||||
|
|
||||||
//if there are not enoug items in the list (0=status of the request (200 = success ...); 1 = timestamp that has to be added to the list)
|
|
||||||
if(times.length() != 2){
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(times[0] == 200.0){
|
|
||||||
// if the given request was a successfull request, calculate the offset
|
|
||||||
double offset = date->currentMSecsSinceEpoch() - times[1];
|
|
||||||
//check if the list contains more than or 100 values
|
|
||||||
if(this->latest_offsets.length()>=100){
|
|
||||||
//if so, delete the first (oldest) one
|
|
||||||
this->latest_offsets.removeFirst();
|
|
||||||
}
|
|
||||||
//append the new offset to the list
|
|
||||||
this->latest_offsets.append(offset);
|
|
||||||
//variable to store the avarage
|
|
||||||
double mem = 0;
|
|
||||||
for(int i=0;i<latest_offsets.length();i++){
|
|
||||||
//go through the list and add all offsets
|
|
||||||
mem += latest_offsets[i];
|
|
||||||
}
|
|
||||||
//calculate the avarage
|
|
||||||
this->offset = mem / double(latest_offsets.length());
|
|
||||||
|
|
||||||
//emit that the offset has changed
|
|
||||||
emit offsetChanged();
|
|
||||||
//qDebug("%20f", this->offset);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//if the given request was not valid, return false
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<double> BuzzerConn::gettimes(int timeout, bool bothTimes)
|
|
||||||
{
|
|
||||||
// function to recieve the timestamps (last_triggered, current_timestamp) from the extentions
|
|
||||||
|
|
||||||
//list to store the return code of the request and the timestamps
|
|
||||||
QList<double> times;
|
|
||||||
//variable to store answer of the extention
|
|
||||||
signed long ret;
|
|
||||||
//send request to extention
|
|
||||||
ret = this->sendCommand("GET_TIMESTAMP", timeout);
|
|
||||||
if(ret >= 0){
|
|
||||||
// if it is higer than 0 (=success) append the return code
|
|
||||||
times.append(double(200));
|
|
||||||
//and the timestamp
|
|
||||||
times.append(double(ret));
|
|
||||||
|
|
||||||
if(bothTimes){
|
|
||||||
//if both timstamps were requested do the same thing again for the other one (last_triggered)
|
|
||||||
ret = this->sendCommand("GET_LASTPRESSED", timeout);
|
|
||||||
|
|
||||||
if(ret >= 0){
|
|
||||||
//if the reuest was successfull, append the value to the list
|
|
||||||
times.append(double(ret));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if not, change the return code
|
|
||||||
times[0] = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if not, append the return code
|
|
||||||
times.append(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
//return the list
|
|
||||||
return(times);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
double BuzzerConn::get(QString key)
|
|
||||||
{
|
|
||||||
// function to get all kinds of data
|
|
||||||
|
|
||||||
if(key == "offset"){
|
|
||||||
// get the offset of the extention
|
|
||||||
return(this->offset);
|
|
||||||
}
|
|
||||||
else if (key == "lastpressed") {
|
|
||||||
// get the last_triggered timestamp of the extention
|
|
||||||
return(this->latest_button_pressed);
|
|
||||||
}
|
|
||||||
else if( key == "currtime") {
|
|
||||||
// get the current time
|
|
||||||
return(this->date->currentMSecsSinceEpoch());
|
|
||||||
}
|
|
||||||
else if( key == "connection_progress") {
|
|
||||||
//get the connection progress
|
|
||||||
return(this->connection_progress);
|
|
||||||
}
|
|
||||||
else if( key == "connected") {
|
|
||||||
// get the state of the connection
|
|
||||||
if(this->state == "connected"){
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuzzerConn::refresh()
|
|
||||||
{
|
|
||||||
// function that has to be called frequently to refresh the connection
|
|
||||||
// check if the extention has been triggered
|
|
||||||
// sends one command the pending command list
|
|
||||||
// and calculates the offset once
|
|
||||||
|
|
||||||
if(this->state != "connected"){
|
|
||||||
// if the extention is not connected return
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//send one of the pending commands
|
|
||||||
if(pending_commands.length() > 0){
|
|
||||||
//get the irst command in the list
|
|
||||||
QString command = this->pending_commands.first();
|
|
||||||
//send the command
|
|
||||||
signed long retval = this->sendCommand(command, 2000);
|
|
||||||
|
|
||||||
if(retval > 0){
|
|
||||||
//if the request has been successfull, remove the command from the list
|
|
||||||
this->pending_commands.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the timestamps from the extention
|
|
||||||
QList<double> ret = this->gettimes(2000);
|
|
||||||
|
|
||||||
if(ret[0] >= 0){
|
|
||||||
//if the request has been successfull check if the last_triggered timestamp has changed
|
|
||||||
if(ret[2] > this->latest_button_pressed){
|
|
||||||
// if it has, set it
|
|
||||||
this->latest_button_pressed = ret[2];
|
|
||||||
//and emit the trggered signal
|
|
||||||
emit triggered();
|
|
||||||
}
|
|
||||||
// as the requst as been sucessfull, reset the error counter
|
|
||||||
this->errors = 0;
|
|
||||||
// calculate the offset on time and return
|
|
||||||
return(this->calcoffset(ret));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if not add one to the error conter
|
|
||||||
this->errors ++;
|
|
||||||
|
|
||||||
if(this->errors > errors_until_disconnect){
|
|
||||||
// if the error counter is too high, disconnect
|
|
||||||
this->socket->disconnectFromHost();
|
|
||||||
this->setState("disconnected");
|
|
||||||
}
|
|
||||||
|
|
||||||
// return false
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
signed long BuzzerConn::sendCommand(QString command, int timeout){
|
|
||||||
//function to send a commnd to the extention
|
|
||||||
|
|
||||||
//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 << quint16(0) << command;
|
|
||||||
|
|
||||||
out.device()->seek(0);
|
|
||||||
out << quint16(arrBlock.size() - sizeof(quint16));
|
|
||||||
|
|
||||||
this->socket->write(arrBlock);
|
|
||||||
|
|
||||||
//now wait for the extention to answer
|
|
||||||
QEventLoop loop;
|
|
||||||
QTimer timer;
|
|
||||||
|
|
||||||
timer.setSingleShot(true);
|
|
||||||
//quit the loop if the timer times out
|
|
||||||
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
|
||||||
//or if the request is anwered
|
|
||||||
loop.connect(socket, SIGNAL(readyRead()), &loop, SLOT(quit()));
|
|
||||||
|
|
||||||
//start the timer
|
|
||||||
timer.start(timeout);
|
|
||||||
//start the loop
|
|
||||||
loop.exec();
|
|
||||||
|
|
||||||
//loop finished
|
|
||||||
if(timer.remainingTime() == -1){
|
|
||||||
//the time has been triggered -> timeout
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
// stop the timer
|
|
||||||
timer.stop();
|
|
||||||
|
|
||||||
|
|
||||||
//if the data is not 4 bytes long it is invalid -> clear and terminate
|
|
||||||
if(this->socket->bytesAvailable() != 4){
|
|
||||||
this->socket->readAll();
|
|
||||||
return(-2);
|
|
||||||
}
|
|
||||||
long data = 0;
|
|
||||||
// read four bytes and cast them as a double
|
|
||||||
this->socket->read((char*)&data,4);
|
|
||||||
|
|
||||||
//return the data
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuzzerConn::appendCommand(QString command){
|
|
||||||
this->pending_commands.append(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuzzerConn::setIP(const QString &ipAdress){
|
|
||||||
this->ip = ipAdress;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BuzzerConn::getIP() const
|
|
||||||
{
|
|
||||||
return(this->ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BuzzerConn::getState() const
|
|
||||||
{
|
|
||||||
return(this->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuzzerConn::setState(QString newState){
|
|
||||||
this->state = newState;
|
|
||||||
emit stateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
int BuzzerConn::getProgress() const
|
|
||||||
{
|
|
||||||
return(connection_progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
double BuzzerConn::getOffset() const
|
|
||||||
{
|
|
||||||
return(this->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
double BuzzerConn::getLastTriggered() const
|
|
||||||
{
|
|
||||||
return(this->latest_button_pressed);
|
|
||||||
}
|
|
549
sources/climbingrace.cpp
Normal file
549
sources/climbingrace.cpp
Normal file
|
@ -0,0 +1,549 @@
|
||||||
|
#include "headers/climbingrace.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* manages:
|
||||||
|
* - global state
|
||||||
|
* - timers
|
||||||
|
* - sounds
|
||||||
|
* - next start action
|
||||||
|
* - next start action delay progress
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
ClimbingRace::ClimbingRace(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
this->state = IDLE;
|
||||||
|
this->mode = LOCAL;
|
||||||
|
|
||||||
|
this->appSettings = new AppSettings;
|
||||||
|
this->baseConn = new BaseConn;
|
||||||
|
|
||||||
|
this->baseConn->setIP("192.168.4.1");
|
||||||
|
connect(this->baseConn, &BaseConn::stateChanged, this, &ClimbingRace::baseStationStateChanged);
|
||||||
|
|
||||||
|
this->speedTimers.append( new SpeedTimer );
|
||||||
|
|
||||||
|
this->player = new QMediaPlayer;
|
||||||
|
|
||||||
|
this->baseStationSyncTimer = new QTimer();
|
||||||
|
this->baseStationSyncTimer->setInterval(10);
|
||||||
|
this->baseStationSyncTimer->setSingleShot(true);
|
||||||
|
this->baseStationSyncTimer->connect(this->baseStationSyncTimer, &QTimer::timeout, this, &ClimbingRace::syncWithBaseStation);
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
|
||||||
|
this->timerTextRefreshTimer = new QTimer();
|
||||||
|
this->timerTextRefreshTimer->setInterval(1);
|
||||||
|
this->timerTextRefreshTimer->setSingleShot(true);
|
||||||
|
this->timerTextRefreshTimer->connect(this->timerTextRefreshTimer, &QTimer::timeout, this, &ClimbingRace::refreshTimerText);
|
||||||
|
this->refreshTimerText();
|
||||||
|
|
||||||
|
this->nextStartActionTimer = new QTimer(this);
|
||||||
|
nextStartActionTimer->setSingleShot(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// --- Main Functionality ---
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
int ClimbingRace::startRace() {
|
||||||
|
|
||||||
|
if(this->state != IDLE) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->refreshMode();
|
||||||
|
|
||||||
|
qDebug() << "+ --- starting race";
|
||||||
|
|
||||||
|
int returnCode = 900;
|
||||||
|
|
||||||
|
switch (this->mode) {
|
||||||
|
case LOCAL:
|
||||||
|
{
|
||||||
|
|
||||||
|
this->setState(STARTING);
|
||||||
|
|
||||||
|
this->nextStartAction = -1;
|
||||||
|
this->playSoundsAndStartRace();
|
||||||
|
|
||||||
|
returnCode = 200;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REMOTE:
|
||||||
|
{
|
||||||
|
QVariantMap reply = this->baseConn->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 != RUNNING && this->state != STARTING) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
// type can be:
|
||||||
|
// 0: stopp
|
||||||
|
// 1: cancel
|
||||||
|
// 2: fail (fase start)
|
||||||
|
|
||||||
|
this->refreshMode();
|
||||||
|
|
||||||
|
qDebug() << "+ --- stopping race";
|
||||||
|
|
||||||
|
int returnCode = 900;
|
||||||
|
|
||||||
|
switch (this->mode) {
|
||||||
|
case LOCAL:
|
||||||
|
{
|
||||||
|
|
||||||
|
if(type == 1){
|
||||||
|
this->nextStartActionTimer->stop();
|
||||||
|
this->player->stop();
|
||||||
|
this->nextStartAction = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
returnCode = this->speedTimers[0]->stop(type) ? 200:904;
|
||||||
|
|
||||||
|
if(returnCode == 200) {
|
||||||
|
this->setState(STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REMOTE:
|
||||||
|
{
|
||||||
|
QVariantMap reply = this->baseConn->sendCommand(1001);
|
||||||
|
|
||||||
|
if(reply["status"] != 200){
|
||||||
|
//handle Error!!
|
||||||
|
returnCode = reply["status"].toInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
returnCode = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClimbingRace::resetRace() {
|
||||||
|
|
||||||
|
if(this->state != STOPPED) {
|
||||||
|
return 904;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->refreshMode();
|
||||||
|
|
||||||
|
qDebug() << "+ --- resetting race";
|
||||||
|
|
||||||
|
int returnCode = 900;
|
||||||
|
|
||||||
|
|
||||||
|
switch (this->mode) {
|
||||||
|
case LOCAL:
|
||||||
|
{
|
||||||
|
returnCode = this->speedTimers[0]->reset() ? 200:904;
|
||||||
|
|
||||||
|
if(returnCode == 200){
|
||||||
|
this->setState(IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REMOTE:
|
||||||
|
{
|
||||||
|
|
||||||
|
QVariantMap reply = this->baseConn->sendCommand(1002);
|
||||||
|
|
||||||
|
if(reply["status"] != 200){
|
||||||
|
//handle Error!!
|
||||||
|
returnCode = reply["status"].toInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
returnCode = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// --- Base Station sync ---
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
void ClimbingRace::syncWithBaseStation() {
|
||||||
|
if(this->baseConn->state != "connected"){
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->baseConn->refreshConnections();
|
||||||
|
emit this->baseStationConnectionsChanged();
|
||||||
|
|
||||||
|
QVariantMap tmpReply = this->baseConn->sendCommand(2000);
|
||||||
|
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setState( raceState( tmpReply["data"].toInt() ) );
|
||||||
|
|
||||||
|
switch (this->state) {
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// case IDLE
|
||||||
|
if(speedTimers[0]->state != 0){
|
||||||
|
speedTimers[0]->setState(SpeedTimer::IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// case STARTING
|
||||||
|
if(speedTimers[0]->state != 1){
|
||||||
|
speedTimers[0]->setState(SpeedTimer::STARTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpReply = this->baseConn->sendCommand(2004);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle Error!!
|
||||||
|
qDebug() << "+ --- getting next start action from basestation failed: " << tmpReply["status"];
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(this->nextStartAction != tmpReply["data"].toInt()){
|
||||||
|
this->nextStartAction = tmpReply["data"].toInt();
|
||||||
|
this->nextStartActionChanged(this->nextStartAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpReply = this->baseConn->sendCommand(2005);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle error!!
|
||||||
|
qDebug() << "+ --- getting next start action progress from basestation failed";
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->nextStartActionDelayProgress = tmpReply["data"].toDouble() > 0 ? tmpReply["data"].toDouble():0;
|
||||||
|
this->nextStartActionDelayProgressChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
// case RUNNING
|
||||||
|
if(speedTimers[0]->state != 2){
|
||||||
|
speedTimers[0]->setState(SpeedTimer::RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current time
|
||||||
|
tmpReply = this->baseConn->sendCommand(2001, 0);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle error!!
|
||||||
|
qDebug() << "+ --- getting current time (timer 0) from basestation failed";
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speedTimers[0]->stoppedTime = tmpReply["data"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current time
|
||||||
|
tmpReply = this->baseConn->sendCommand(2003, 0);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle error!!
|
||||||
|
qDebug() << "+ --- getting reaction time (timer 0) from basestation failed";
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speedTimers[0]->reactionTime = tmpReply["data"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
// case STOPPED
|
||||||
|
if(speedTimers[0]->state != 3){
|
||||||
|
speedTimers[0]->setState(SpeedTimer::STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current time
|
||||||
|
tmpReply = this->baseConn->sendCommand(2001, 0);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle error!!
|
||||||
|
qDebug() << "+ --- getting current time (timer 0) from basestation failed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speedTimers[0]->stoppedTime = tmpReply["data"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current time
|
||||||
|
tmpReply = this->baseConn->sendCommand(2003, 0);
|
||||||
|
if(tmpReply["status"] != 200){
|
||||||
|
//handle error!!
|
||||||
|
qDebug() << "+ --- getting current time (timer 0) from basestation failed";
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speedTimers[0]->reactionTime = tmpReply["data"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->baseStationSyncTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------
|
||||||
|
// --- helper functions ---
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
void ClimbingRace::playSoundsAndStartRace() {
|
||||||
|
qDebug() << "next Action: " << nextStartAction;
|
||||||
|
|
||||||
|
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||||
|
|
||||||
|
switch (this->nextStartAction) {
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
if(!playSound("qrc:/sounds/at_marks_1.wav")){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(appSettings->loadSetting("ready_en") == "true"){
|
||||||
|
nextStartAction = 1;
|
||||||
|
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
nextStartAction = 2;
|
||||||
|
nextStartActionTimer->setInterval(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if(!playSound("qrc:/sounds/ready_1.wav")){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextStartAction = 2;
|
||||||
|
nextStartActionTimer->setInterval(1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if(!playSound("qrc:/sounds/OFFICAL_IFSC_STARTIGNAL.wav")){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextStartAction = -1;
|
||||||
|
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||||
|
|
||||||
|
this->setState(RUNNING);
|
||||||
|
speedTimers[0]->start();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
this->speedTimers[0]->setState(SpeedTimer::STARTING);
|
||||||
|
if(appSettings->loadSetting("at_marks_en") == "true"){
|
||||||
|
nextStartAction = 0;
|
||||||
|
nextStartActionTimer->setInterval(appSettings->loadSetting("at_marks_delay").toInt() <= 0 ? 1:appSettings->loadSetting("at_marks_delay").toInt());
|
||||||
|
}
|
||||||
|
else if(appSettings->loadSetting("ready_en") == "true"){
|
||||||
|
nextStartAction = 1;
|
||||||
|
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
nextStartAction = 2;
|
||||||
|
nextStartActionTimer->setInterval(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextStartActionTimer->connect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
||||||
|
nextStartActionTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClimbingRace::playSound(QString path) {
|
||||||
|
|
||||||
|
//connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
|
||||||
|
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(raceState newState) {
|
||||||
|
|
||||||
|
if(newState != this->state) {
|
||||||
|
this->state = newState;
|
||||||
|
this->stateChanged(newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClimbingRace::refreshMode() {
|
||||||
|
if(this->baseConn->state == "connected"){
|
||||||
|
this->mode = REMOTE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->mode = LOCAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClimbingRace::refreshTimerText() {
|
||||||
|
|
||||||
|
// --- refresh timer text ---
|
||||||
|
|
||||||
|
QVariantList newTimerTextList;
|
||||||
|
|
||||||
|
foreach(SpeedTimer * timer, this->speedTimers){
|
||||||
|
QVariantMap timerMap = {{"text",timer->getText()}, {"reacttime", timer->reactionTime}};
|
||||||
|
newTimerTextList.append(timerMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newTimerTextList != this->qmlTimers){
|
||||||
|
this->qmlTimers = newTimerTextList;
|
||||||
|
emit timerTextChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- refresh next start action delay progress ---
|
||||||
|
|
||||||
|
if(this->mode == LOCAL){
|
||||||
|
QString totalStr;
|
||||||
|
|
||||||
|
if(nextStartAction == 0){
|
||||||
|
totalStr = appSettings->loadSetting("at_marks_delay");
|
||||||
|
}
|
||||||
|
else if (nextStartAction == 1) {
|
||||||
|
totalStr = appSettings->loadSetting("ready_delay");
|
||||||
|
}
|
||||||
|
|
||||||
|
double remaining = this->nextStartActionTimer->remainingTime();
|
||||||
|
double total = totalStr.toDouble();
|
||||||
|
//qDebug() << "DELAY_PROG: " << "total: " << total << " remaining: " << remaining << " prog: " << remaining / total;
|
||||||
|
if(remaining > 0){
|
||||||
|
this->nextStartActionDelayProgress = remaining / total;
|
||||||
|
emit this->nextStartActionDelayProgressChanged();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->nextStartActionDelayProgress = 0;
|
||||||
|
emit this->nextStartActionDelayProgressChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->timerTextRefreshTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// --- functions for qml ---
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
int ClimbingRace::getState() {
|
||||||
|
return this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ClimbingRace::getTimerTextList() {
|
||||||
|
return this->qmlTimers;
|
||||||
|
// QVariantList test;
|
||||||
|
// QVariantMap test2 = {{"text", "1234"}, {"reacttime", 2.0}};
|
||||||
|
// test.append(test2);
|
||||||
|
// return test;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ClimbingRace::getNextStartActionDelayProgress() {
|
||||||
|
return this->nextStartActionDelayProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClimbingRace::writeSetting(QString key, QVariant value) {
|
||||||
|
this->refreshMode();
|
||||||
|
switch (this->mode) {
|
||||||
|
case LOCAL:
|
||||||
|
this->appSettings->writeSetting(key, value);
|
||||||
|
break;
|
||||||
|
case REMOTE:
|
||||||
|
this->baseConn->writeRemoteSetting(key, value.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClimbingRace::readSetting(QString key) {
|
||||||
|
this->refreshMode();
|
||||||
|
switch (this->mode) {
|
||||||
|
case LOCAL:
|
||||||
|
return this->appSettings->loadSetting(key);
|
||||||
|
case REMOTE:
|
||||||
|
QVariantMap reply = this->baseConn->sendCommand(3001, key);
|
||||||
|
if(reply["status"] != 200){
|
||||||
|
return "false";
|
||||||
|
}
|
||||||
|
return reply["data"].toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClimbingRace::connectBaseStation() {
|
||||||
|
return this->baseConn->connectToHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClimbingRace::getBaseStationState() {
|
||||||
|
return this->baseConn->getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ClimbingRace::getBaseStationConnections() {
|
||||||
|
return baseConn->getConnections();
|
||||||
|
}
|
|
@ -55,6 +55,7 @@
|
||||||
#include "headers/baseconn.h"
|
#include "headers/baseconn.h"
|
||||||
#include "headers/speedtimer.h"
|
#include "headers/speedtimer.h"
|
||||||
#include "headers/speedtimerqmladapter.h"
|
#include "headers/speedtimerqmladapter.h"
|
||||||
|
#include "headers/climbingrace.h"
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
static void connectToDatabase()
|
static void connectToDatabase()
|
||||||
|
@ -108,23 +109,20 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connectToDatabase();
|
connectToDatabase();
|
||||||
//BuzzerConn * pBuzzerConn = new BuzzerConn(nullptr, "192.168.4.10", 80);
|
|
||||||
//BuzzerConn * pStartpadConn = new BuzzerConn(nullptr, "192.168.4.11", 80);
|
|
||||||
AppSettings * pAppSettings = new AppSettings();
|
|
||||||
pGlobalAppSettings = pAppSettings;
|
|
||||||
|
|
||||||
SpeedTimer * pSpeedTimer = new SpeedTimer();
|
AppSettings * pAppSettings = new AppSettings();
|
||||||
pGlobalSpeedTimer = pSpeedTimer;
|
|
||||||
|
|
||||||
//setup the sql storage model as a qml model
|
//setup the sql storage model as a qml model
|
||||||
qmlRegisterType<SqlProfileModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel");
|
qmlRegisterType<SqlProfileModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel");
|
||||||
qmlRegisterType<SqlStorageModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlStorageModel");
|
qmlRegisterType<SqlStorageModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlStorageModel");
|
||||||
|
|
||||||
//setup the startpad and buzzer conn qml objects
|
//setup the startpad and buzzer conn qml objects
|
||||||
qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BuzzerConn");
|
//qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BuzzerConn");
|
||||||
qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "StartpadConn");
|
//qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "StartpadConn");
|
||||||
qmlRegisterType<BaseConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BaseStationConn");
|
//qmlRegisterType<BaseConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BaseStationConn");
|
||||||
qmlRegisterType<SpeedTimerQmlAdapter>("com.itsblue.speedclimbingstopwatch", 1, 0, "SpeedTimerBackend");
|
//qmlRegisterType<SpeedTimerQmlAdapter>("com.itsblue.speedclimbingstopwatch", 1, 0, "SpeedTimerBackend");
|
||||||
|
|
||||||
|
qmlRegisterType<ClimbingRace>("com.itsblue.speedclimbingstopwatch", 2, 0, "SpeedBackend");
|
||||||
|
|
||||||
//setup translation engine
|
//setup translation engine
|
||||||
//to the language of the system
|
//to the language of the system
|
||||||
|
@ -135,17 +133,15 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||||
|
|
||||||
|
QQmlContext *context = engine.rootContext();
|
||||||
|
context->setContextProperty("_cppAppSettings", pAppSettings);
|
||||||
|
|
||||||
if (engine.rootObjects().isEmpty())
|
if (engine.rootObjects().isEmpty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
engine.rootContext()->setContextProperty("_cppAppSettings", pAppSettings);
|
|
||||||
engine.rootContext()->setContextProperty("_cppSpeedTimer", pSpeedTimer);
|
|
||||||
|
|
||||||
int iRet = 0;
|
int iRet = 0;
|
||||||
iRet = app.exec();
|
iRet = app.exec();
|
||||||
|
|
||||||
//call the destructors of all objects
|
|
||||||
delete pAppSettings;
|
|
||||||
|
|
||||||
return iRet;
|
return iRet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,14 @@ SpeedTimer::SpeedTimer(QObject *parent) : QObject(parent)
|
||||||
this->stoppedTime = 0;
|
this->stoppedTime = 0;
|
||||||
this->reactionTime = 0;
|
this->reactionTime = 0;
|
||||||
this->state = IDLE;
|
this->state = IDLE;
|
||||||
this->remoteControlled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeedTimer::start() {
|
bool SpeedTimer::start(bool force) {
|
||||||
if(this->state != STARTING){
|
if(this->state != STARTING && !force){
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "starting timer";
|
qDebug() << "starting timer";
|
||||||
if(!this->remoteControlled){
|
if(!force){
|
||||||
this->stopTime = 0;
|
this->stopTime = 0;
|
||||||
this->stoppedTime = 0;
|
this->stoppedTime = 0;
|
||||||
this->reactionTime = 0;
|
this->reactionTime = 0;
|
||||||
|
@ -28,49 +27,55 @@ void SpeedTimer::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setState(RUNNING);
|
this->setState(RUNNING);
|
||||||
|
|
||||||
|
return true;
|
||||||
//this->startPad->appendCommand("SET_LED_RUNNING");
|
//this->startPad->appendCommand("SET_LED_RUNNING");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeedTimer::stop(QString type) {
|
bool SpeedTimer::stop(int type, bool force) {
|
||||||
if(this->state != SpeedTimer::STARTING && this->state != SpeedTimer::RUNNING){
|
|
||||||
return;
|
// 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;
|
//qDebug() << "Stopping: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||||
|
|
||||||
if(this->remoteControlled){
|
switch (type) {
|
||||||
if(type == "cancel"){
|
case 0:
|
||||||
emit startCanceled(false);
|
{
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(type == "cancel"){
|
|
||||||
emit startCanceled(false);
|
|
||||||
this->stoppedTime = 0;
|
|
||||||
}
|
|
||||||
else if(type == "manual"){
|
|
||||||
if(this->state == STARTING){
|
|
||||||
emit startCanceled(false);
|
|
||||||
}
|
|
||||||
this->stopTime = this->date->currentMSecsSinceEpoch();
|
this->stopTime = this->date->currentMSecsSinceEpoch();
|
||||||
this->stoppedTime = this->stopTime - this->startTime;
|
this->stoppedTime = this->stopTime - this->startTime;
|
||||||
|
this->setState(STOPPED);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if(type == "topPad"){
|
case 1:
|
||||||
//this->stopTime = this->topPad->latest_button_pressed + this->topPad->offset;
|
{
|
||||||
this->stoppedTime = this->stopTime - this->startTime;
|
this->stoppedTime = 0;
|
||||||
|
this->setState(CANCELLED);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if(type == "falseStart"){
|
case 2:
|
||||||
emit startCanceled(true);
|
{
|
||||||
this->stoppedTime = this->reactionTime;
|
this->stoppedTime = this->reactionTime;
|
||||||
|
this->setState(FAILED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setState(STOPPED);
|
|
||||||
qDebug() << "Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
qDebug() << "Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime;
|
||||||
|
|
||||||
|
return true;
|
||||||
//this->startPad->appendCommand("SET_LED_STARTING");
|
//this->startPad->appendCommand("SET_LED_STARTING");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeedTimer::reset(){
|
bool SpeedTimer::reset(bool force){
|
||||||
if(this->state != STOPPED){
|
if( ( this->state != STOPPED && this->state != FAILED && this->state != CANCELLED ) && !force){
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->startTime = 0;
|
this->startTime = 0;
|
||||||
|
@ -78,6 +83,8 @@ void SpeedTimer::reset(){
|
||||||
this->stoppedTime = 0;
|
this->stoppedTime = 0;
|
||||||
this->reactionTime = 0;
|
this->reactionTime = 0;
|
||||||
this->setState(IDLE);
|
this->setState(IDLE);
|
||||||
|
|
||||||
|
return true;
|
||||||
//this->startPad->appendCommand("SET_LED_STARTING");
|
//this->startPad->appendCommand("SET_LED_STARTING");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +109,7 @@ QString SpeedTimer::getState(){
|
||||||
|
|
||||||
double SpeedTimer::getCurrTime() {
|
double SpeedTimer::getCurrTime() {
|
||||||
double currTime;
|
double currTime;
|
||||||
if(this->state == RUNNING && !this->remoteControlled){
|
if(this->state == RUNNING && this->startTime > 0){
|
||||||
currTime = this->date->currentMSecsSinceEpoch() - this->startTime;
|
currTime = this->date->currentMSecsSinceEpoch() - this->startTime;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -112,6 +119,33 @@ double SpeedTimer::getCurrTime() {
|
||||||
return(currTime);
|
return(currTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SpeedTimer::getText() {
|
||||||
|
//qDebug() << this->getState();
|
||||||
|
QString newText;
|
||||||
|
switch (this->state) {
|
||||||
|
case SpeedTimer::IDLE:
|
||||||
|
newText = "Click Start to start";
|
||||||
|
break;
|
||||||
|
case SpeedTimer::STARTING:
|
||||||
|
newText = "0.000 sec";
|
||||||
|
break;
|
||||||
|
case SpeedTimer::RUNNING:
|
||||||
|
newText = QString::number( this->getCurrTime() / 1000.0, 'f', 3 ) + " sec";
|
||||||
|
break;
|
||||||
|
case SpeedTimer::STOPPED:
|
||||||
|
newText = QString::number( this->stoppedTime / 1000.0, 'f', 3 ) + " sec";
|
||||||
|
break;
|
||||||
|
case SpeedTimer::FAILED:
|
||||||
|
newText = "False Start";
|
||||||
|
break;
|
||||||
|
case SpeedTimer::CANCELLED:
|
||||||
|
newText = "Cancelled";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newText;
|
||||||
|
}
|
||||||
|
|
||||||
void SpeedTimer::delay(int mSecs){
|
void SpeedTimer::delay(int mSecs){
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QTimer timer;
|
QTimer timer;
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
#include "headers/speedtimerqmladapter.h"
|
|
||||||
|
|
||||||
SpeedTimerQmlAdapter::SpeedTimerQmlAdapter(QObject *parent) : QObject(parent)
|
|
||||||
{
|
|
||||||
this->state = SpeedTimer::IDLE;
|
|
||||||
connect(pGlobalSpeedTimer, &SpeedTimer::stateChanged, this, &SpeedTimerQmlAdapter::setState);
|
|
||||||
connect(pGlobalSpeedTimer, &SpeedTimer::startCanceled, this, &SpeedTimerQmlAdapter::startCanceled);
|
|
||||||
|
|
||||||
this->refreshTimer = new QTimer();
|
|
||||||
refreshTimer->setInterval(1);
|
|
||||||
refreshTimer->setSingleShot(true);
|
|
||||||
refreshTimer->connect(refreshTimer, &QTimer::timeout, this, &SpeedTimerQmlAdapter::refreshValues);
|
|
||||||
refreshTimer->start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SpeedTimerQmlAdapter::getState(){
|
|
||||||
switch(state){
|
|
||||||
case SpeedTimer::IDLE:
|
|
||||||
return("IDLE");
|
|
||||||
case SpeedTimer::STARTING:
|
|
||||||
return("STARTING");
|
|
||||||
case SpeedTimer::RUNNING:
|
|
||||||
return("RUNNING");
|
|
||||||
case SpeedTimer::STOPPED:
|
|
||||||
return("STOPPED");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedTimerQmlAdapter::setState(SpeedTimer::timerState newState){
|
|
||||||
|
|
||||||
this->state = newState;
|
|
||||||
emit this->stateChanged(newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SpeedTimerQmlAdapter::getText(){
|
|
||||||
return(this->text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedTimerQmlAdapter::refreshValues(){
|
|
||||||
//qDebug() << this->getState();
|
|
||||||
QString newText;
|
|
||||||
switch (this->state) {
|
|
||||||
case SpeedTimer::IDLE:
|
|
||||||
newText = "Click Start to start";
|
|
||||||
break;
|
|
||||||
case SpeedTimer::STARTING:
|
|
||||||
newText = "0.000 sec";
|
|
||||||
break;
|
|
||||||
case SpeedTimer::RUNNING:
|
|
||||||
newText = QString::number( pGlobalSpeedTimer->getCurrTime() / 1000.0, 'f', 3 ) + " sec";
|
|
||||||
break;
|
|
||||||
case SpeedTimer::STOPPED:
|
|
||||||
newText = QString::number( pGlobalSpeedTimer->stoppedTime / 1000.0, 'f', 3 ) + " sec";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this->text != newText){
|
|
||||||
this->text = newText;
|
|
||||||
emit textChanged();
|
|
||||||
}
|
|
||||||
//qDebug() << this->text;
|
|
||||||
refreshTimer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpeedTimerQmlAdapter::setStarting(){
|
|
||||||
if(pGlobalSpeedTimer->remoteControlled){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pGlobalSpeedTimer->setState(SpeedTimer::STARTING);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpeedTimerQmlAdapter::start(){
|
|
||||||
if(pGlobalSpeedTimer->remoteControlled){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pGlobalSpeedTimer->start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpeedTimerQmlAdapter::stop(QString type){
|
|
||||||
if(pGlobalSpeedTimer->remoteControlled){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pGlobalSpeedTimer->stop(type);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpeedTimerQmlAdapter::reset(){
|
|
||||||
if(pGlobalSpeedTimer->remoteControlled){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pGlobalSpeedTimer->reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
QT += quick sql
|
QT += quick sql multimedia
|
||||||
|
|
||||||
android {
|
android {
|
||||||
QT += androidextras
|
QT += androidextras
|
||||||
|
@ -23,20 +23,18 @@ SOURCES += \
|
||||||
sources/main.cpp \
|
sources/main.cpp \
|
||||||
sources/sqlstoragemodel.cpp \
|
sources/sqlstoragemodel.cpp \
|
||||||
sources/sqlprofilemodel.cpp \
|
sources/sqlprofilemodel.cpp \
|
||||||
sources/buzzerconn.cpp \
|
|
||||||
sources/appsettings.cpp \
|
sources/appsettings.cpp \
|
||||||
sources/baseconn.cpp \
|
sources/baseconn.cpp \
|
||||||
sources/speedtimer.cpp \
|
sources/speedtimer.cpp \
|
||||||
sources/speedtimerqmladapter.cpp
|
sources/climbingrace.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
headers/sqlstoragemodel.h \
|
headers/sqlstoragemodel.h \
|
||||||
headers/sqlprofilemodel.h \
|
headers/sqlprofilemodel.h \
|
||||||
headers/buzzerconn.h \
|
|
||||||
headers/appsettings.h \
|
headers/appsettings.h \
|
||||||
headers/baseconn.h \
|
headers/baseconn.h \
|
||||||
headers/speedtimer.h \
|
headers/speedtimer.h \
|
||||||
headers/speedtimerqmladapter.h
|
headers/climbingrace.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
shared.qrc \
|
shared.qrc \
|
||||||
|
|
Reference in a new issue