diff --git a/headers/baseconn.h b/headers/baseconn.h index be00d35..086cde9 100644 --- a/headers/baseconn.h +++ b/headers/baseconn.h @@ -7,6 +7,10 @@ #include #include #include +#include + +#include "headers/appsettings.h" +#include "headers/speedtimer.h" class BaseConn : public QObject { @@ -15,6 +19,7 @@ class BaseConn : public QObject 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) public: explicit BaseConn(QObject *parent = nullptr); @@ -32,7 +37,13 @@ public: // - 'connecting' // - 'connected' + QStringList connections; + QString latestReadReply; + + //---general status values---// + + private: QDateTime *date; //to get the current time @@ -40,7 +51,7 @@ private: QTcpSocket *socket; //socket for communication with the extention - + QList speedTimers; signals: void stateChanged(); @@ -51,6 +62,8 @@ signals: void gotReply(); + void connectionsChanged(); + public slots: Q_INVOKABLE bool connectToHost(); @@ -58,6 +71,16 @@ public slots: Q_INVOKABLE QString sendCommand(QString command); + Q_INVOKABLE bool refreshConnections(); + + void refreshTimers(); + + bool startTimers(); + + bool stopTimers(); + + bool resetTimers(); + // functions for the qml adapter QString getIP() const; void setIP(const QString &ipAdress); @@ -67,8 +90,14 @@ public slots: int getProgress() const; + QStringList getConnections(); + private slots: void readyRead(); + +private: + QTimer *refreshTimer; + QSemaphore remoteSessions; }; #endif // BASECONN_H diff --git a/headers/buzzerconn.h b/headers/buzzerconn.h index e2daa70..da68784 100644 --- a/headers/buzzerconn.h +++ b/headers/buzzerconn.h @@ -11,6 +11,8 @@ #include #include +#include "appsettings.h" + //typedef struct strReturnData{ // int status_code; // QString text; @@ -123,7 +125,6 @@ public slots: double getOffset() const; double getLastTriggered() const; - }; #endif // BUZZERCONN_H diff --git a/headers/speedtimer.h b/headers/speedtimer.h new file mode 100644 index 0000000..c0cad99 --- /dev/null +++ b/headers/speedtimer.h @@ -0,0 +1,47 @@ +#ifndef SPEEDTIMER_H +#define SPEEDTIMER_H + +#include +#include +#include +#include +#include + +class SpeedTimer : public QObject +{ + Q_OBJECT +public: + explicit SpeedTimer(QObject *parent = nullptr); + + enum timerState { IDLE, STARTING, RUNNING, STOPPED }; + timerState state; + + // variables for capturing the time + double startTime; + double stopTime; + double stoppedTime; + double reactionTime; + +signals: + void stateChanged(timerState newState); + void startCanceled(bool falseStart); + +public slots: + void start(); + void stop(QString type); + void reset(); + + void setState(timerState newState); + QString getState(); + double getCurrTime(); + + void handleStartpadTrigger(); + void handleToppadTrigger(); + + void delay(int mSecs); + +private: + QDateTime *date; +}; +extern SpeedTimer * pGlobalSpeedTimer; +#endif // SPEEDTIMER_H diff --git a/qml/SettingsDialog.qml b/qml/SettingsDialog.qml index 6bcb4f9..1f4b77b 100644 --- a/qml/SettingsDialog.qml +++ b/qml/SettingsDialog.qml @@ -165,59 +165,19 @@ Popup { id: settings_col /*----Connect to external devices----*/ - ItemDelegate { + NextPageDelegate { id: connect_del - text: qsTr("connections") - - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } - - width: parent.width - - Image { - id: connect_del_image - source: StyleSettings.backIcon - rotation: 180 - height: options_stack.text_pixelSize - width: height - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 10 - } - } + text: qsTr("extentions") onClicked: { options_stack.push(connect) } } /*----Automated Start----*/ - ItemDelegate { + NextPageDelegate { id: autostart_del text: qsTr("start sequence") - width: parent.width - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } - - Image { - id: autostart_del_image - source: StyleSettings.backIcon - rotation: 180 - height: options_stack.text_pixelSize - width: height - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 10 - } - } onClicked: { options_stack.push(autostart) } @@ -235,18 +195,6 @@ Popup { font.pixelSize: options_stack.text_pixelSize } - Image { - id: style_image - source: StyleSettings.backIcon - rotation: 180 - height: options_stack.text_pixelSize - width: height - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 10 - } - } onClicked: { StyleSettings.setTheme() } @@ -259,33 +207,13 @@ Popup { id: connect Column { id: connect_col - property string title: qsTr("connections") + property string title: qsTr("extentions") property int delegateHeight: height*0.18 - ItemDelegate { + NextPageDelegate { id: baseConn_del text: qsTr("Base Station") - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } - - width: parent.width - - Image { - id: connect_del_image - source: StyleSettings.backIcon - rotation: 180 - height: options_stack.text_pixelSize - width: height - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 10 - } - } onClicked: { options_stack.push(baseStation) } @@ -294,12 +222,6 @@ Popup { ConnectionDelegate { id: connect_buzz_del - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } - status: root.connections.buzzer connect: root.connect type: "buzzer" @@ -311,12 +233,6 @@ Popup { ConnectionDelegate { id: connect_stap_del - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } - status: root.connections.startpad connect: root.connect type: "startpad" @@ -335,6 +251,29 @@ Popup { property string title: "Autostart" property int delegateHeight: height*0.18 + function updateSett(key, val, del){ + del.enabled = false + _cppAppSettings.writeSetting(key, val) + if(baseConn.state === "connected"){ + switch(key){ + case "ready_en": + key = "READY_EN" + break + case "ready_delay": + key = "READY_DELAY" + break + case "at_marks_en": + key = "AT_MARKS_EN" + break + case "at_marks_delay": + key = "AT_MARKS_DELAY" + break + } + baseConn.sendCommand("SET_SETTING_"+key+"_"+val) + } + del.enabled = true + } + SwitchDelegate { id: ready_del text: qsTr("say 'ready'") @@ -351,7 +290,8 @@ Popup { font.pixelSize: options_stack.text_pixelSize onCheckedChanged: { - _cppAppSettings.writeSetting("ready_en",checked) + parent.updateSett("ready_en",checked, ready_del) + } indicator: SimpleIndicator{} @@ -383,7 +323,7 @@ Popup { text: _cppAppSettings.loadSetting("ready_delay") onTextChanged: { - _cppAppSettings.writeSetting("ready_delay", text) + autostart_col.updateSett("ready_delay", text, ready_delay_del) } } } @@ -404,7 +344,7 @@ Popup { font.pixelSize: options_stack.text_pixelSize onCheckedChanged: { - _cppAppSettings.writeSetting("at_marks_en",at_marks_del.checked) + parent.updateSett("at_marks_en",at_marks_del.checked, at_marks_del) } indicator: SimpleIndicator{} @@ -437,7 +377,7 @@ Popup { text: _cppAppSettings.loadSetting("at_marks_delay") onTextChanged: { - _cppAppSettings.writeSetting("at_marks_delay",text) + autostart_col.updateSett("at_marks_delay",text, at_marks_delay_del) } } } @@ -455,11 +395,6 @@ Popup { ConnectionDelegate { id: connect_base_del text: "connect" - contentItem: Text { - text: parent.text - color: StyleSettings.textColor - font.pixelSize: options_stack.text_pixelSize - } status: root.connections.baseStation connect: root.connect @@ -468,7 +403,50 @@ Popup { 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-----*/ + Component{ + id: baseStationConnections + ListView { + function getModel(){ + var keys = Object.keys(baseConn.connections); + + var len = keys.length + return(len) + } + + 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} + } + } } diff --git a/qml/SpeedTimer.qml b/qml/SpeedTimer.qml new file mode 100644 index 0000000..1027cc4 --- /dev/null +++ b/qml/SpeedTimer.qml @@ -0,0 +1,183 @@ +import QtQuick 2.9 +import QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.2 +import "." +import "./components" +import "./styles" + +Item { + id: control + property color color + property string text: qsTr("Click start to start") + property string elide + property int pixelSize: 100 + property int scale: 1 + + property var toppadConn + property var startpadConn + property var baseConn + + property double startTime: 0 + property double stopTime: 0 + property double stoppedTime: 0 + property double reactionTime: 0 + + property double currTime: 0 + + signal stopped() + signal startCanceled(bool falseStart) + anchors.fill: parent + state: "IDLE" + + Label { + id: time + text: parent.text + scale: parent.scale + anchors.centerIn: parent + font.pixelSize: parent.pixelSize + elide: parent.elide + color: StyleSettings.textColor + Behavior on text { + enabled: control.state !== "RUNNING" + FadeAnimation { + target: time + } + } + + } + + function setStarting(){ + control.state = "STARTING" + } + + function start(inMilliSeconds){ + + control.state = "STARTING" + control.startTime = new Date().getTime() + inMilliSeconds //set the startime to be 0 after the starttone + + startTimer.interval = inMilliSeconds + startTimer.start() + } + + function stop(type){ + //_cppStartpadConn.appendCommand("SET_LED_STARTING"); + switch(type){ + case "toppad": + //the buzzer was pushed + control.stopTime = control.toppadConn.lastTriggered + control.toppadConn.offset + control.stoppedTime = control.stopTime - control.startTime + control.stopped() + //time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec" + //console.log("STOPPED: "+control.stoppedTime + " started at: " + control.startTime + " offset: "+ control.buzzer_offset + "lastpressed: " + control.last_button_pressed) + break + case "manual": + //the stop button was pressed + if(baseConn.state === "connected"){ + control.stoppedTime = baseConn.getTime("raw") + time.text = (control.stoppedTime / 1000).toFixed(3) + " sec" + return + } + control.stopTime = new Date().getTime() + control.stoppedTime = control.stopTime - control.startTime + control.stopped() + break + case "false": + //there was a false start + control.stoppedTime = -1 + startTimer.stop() + control.state = "STOPPED" + control.startCanceled(true) + break + case "cancel": + //the cancel button was pressed + control.stoppedTime = 0 + startTimer.stop() + control.state = "STOPPED" + control.startCanceled(false) + break + } + control.state = "STOPPED" + } + + function reset(){ + + control.startTime = 0 + control.stopTime = 0 + control.stoppedTime = 0 + + if(baseConn.state === "connected"){ + var ret = baseConn.sendCommand("CMD_RESET_TIMER") + if(ret !== "OK"){ + control.state = "IDLE" + return + } + } + + control.state = "IDLE" + } + + function handleStartpad(){ + console.log("startpad triggered") + var offset = control.startpadConn.offset + var last_pressed = control.startpadConn.lastTriggered + var trigger_time = (last_pressed + offset) + control.reactionTime = trigger_time - control.startTime + if(trigger_time - control.startTime <= 0){ + stop("false") + } + } + + function handleToppad(){ + console.log(lastTriggered) + stop("toppad") + } + + Timer { + id: startTimer + running: false + repeat: false + onTriggered: { + console.log("started") + control.state = "RUNNING" + } + } + + Timer { + //timer that updates the currTime variable + running: true + repeat: true + interval: 1 + onTriggered: { + control.currTime = new Date().getTime() + } + } + + + states: [ + State { + name: "IDLE" + //state for the start page + PropertyChanges { target: time; text: qsTr("Click start to start");} + }, + State { + name: "STARTING" + //state for the start sequence + PropertyChanges { target: time; text: control.text;} + }, + State { + name: "RUNNING" + //state when the timer is running + PropertyChanges { target: time; text: Math.abs( ( ( control.currTime - control.startTime ) / 1000 ) ).toFixed(3) + " sec";} + }, + + State { + name: "STOPPED" + //state when the meassuring is over + PropertyChanges { + target: time; + text: control.stoppedTime >= 0 ? ( control.stoppedTime / 1000 ).toFixed(3) + " sec":qsTr("false start"); + } + } + ] +} diff --git a/qml/components/ConnectionDelegate.qml b/qml/components/ConnectionDelegate.qml index 0229e51..76b8448 100644 --- a/qml/components/ConnectionDelegate.qml +++ b/qml/components/ConnectionDelegate.qml @@ -1,5 +1,6 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 +import "../styles" ItemDelegate { id: control @@ -18,6 +19,12 @@ ItemDelegate { } } + contentItem: Text { + text: parent.text + color: StyleSettings.textColor + font.pixelSize: options_stack.text_pixelSize + } + Timer { id: shortDelay running: false diff --git a/qml/components/NextPageDelegate.qml b/qml/components/NextPageDelegate.qml new file mode 100644 index 0000000..2fe84af --- /dev/null +++ b/qml/components/NextPageDelegate.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.2 +import "../styles" + +ItemDelegate { + id: control + text: "" + font.pixelSize: options_stack.text_pixelSize + property color textColor: StyleSettings.textColor + + contentItem: Text { + text: parent.text + color: control.textColor + font.pixelSize: parent.font.pixelSize + } + + width: parent.width + + Image { + id: forwardImage + source: StyleSettings.backIcon + rotation: 180 + height: control.font.pixelSize + width: height + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 10 + } + } +} diff --git a/qml/main.qml b/qml/main.qml index 7a329c4..cbf274a 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -69,117 +69,141 @@ Window { color: StyleSettings.backgroundColor } - BuzzerConn { - id: buzzerConn - ipAdress: "192.168.4.10" - property var status: {'status': buzzerConn.state, 'progress': buzzerConn.progress} - onLastTriggeredChanged: { - console.log(lastTriggered) - root.stop("buzzer") - } - } + Item { + id: connections - Timer { - id: buzzerRefreshTimer - running: buzzerConn.state === "connected" - interval: root.state === "RUNNING" ? 1:1000 - repeat: false - 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: { - console.log("startpad triggered") - var offset = startpadConn.offset - var last_pressed = startpadConn.lastTriggered - var trigger_time = (last_pressed + offset) - root.last_run.react_time = trigger_time - root.startTime - if(trigger_time - root.startTime <= 0){ - root.stop("false") + BuzzerConn { + id: buzzerConn + ipAdress: "192.168.4.10" + property var status: {'status': buzzerConn.state, 'progress': buzzerConn.progress} + onLastTriggeredChanged: { + timer_1.handleToppad() } } - } - 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: "localhost" - property var status: {'status': baseConn.state, 'progress': baseConn.progress} - - function getTime(type){ - var time = parseInt(sendCommand("GET_CURRTIME")) - if(type === "readable"){ - return(time / 1000).toFixed(3) - } - else if(type === "raw"){ - return(time) + Timer { + id: buzzerRefreshTimer + running: buzzerConn.state === "connected" + interval: root.state === "RUNNING" ? 1:1000 + repeat: false + onTriggered: { + buzzerConn.refresh() + this.start() } } - } - Timer { - id: baseRefreshTimer - running: baseConn.state === "connected" - repeat: false - interval: 1 - onTriggered: { - if(root.state === "RUNNING"){ - var baseReactTime = parseInt(baseConn.sendCommand("GET_REACTTIME")) - if(baseReactTime !== 0){ - root.last_run.react_time = baseReactTime + 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: "localhost"//"raspberrypi.local" + + property var status: {'status': baseConn.state, 'progress': baseConn.progress, 'connections': baseConn.connections} + + + function getTime(type){ + var time = parseInt(sendCommand("GET_CURRTIME")) + if(type === "readable"){ + return(time / 1000).toFixed(3) } - time.text = baseConn.getTime("readable") + " sec" - if(baseConn.sendCommand("GET_TIMER_STATE") === "STOPPED"){ - root.stop("manual") + else if(type === "raw"){ + return(time) } } - if(root.state === "STARTING"){ - var baseReactTime = parseInt(baseConn.sendCommand("GET_REACTTIME")) - if(baseReactTime !== 0){ - root.last_run.react_time = baseReactTime - } - var baseState = baseConn.sendCommand("GET_TIMER_STATE") - if(baseState === "RUNNING"){ - root.state = "RUNNING"; - } - else if(baseState === "STOPPED"){ - root.state = "STOPPED" - } - } - start() } + + Timer { + id: baseRefreshTimer + running: baseConn.state === "connected" + repeat: false + + interval: 1 + onTriggered: { + switch(root.state){ + case "RUNNING": + var baseReactTime = parseInt(baseConn.sendCommand("GET_REACTTIME")) + console.log(baseReactTime) + if(baseReactTime !== 0){ + root.last_run.react_time = baseReactTime + } + timer_1.text = baseConn.getTime("readable") + " sec" + if(baseConn.sendCommand("GET_TIMER_STATE") === "STOPPED"){ + root.stop("manual") + } + break + case "STARTING": + var baseReactTime = parseInt(baseConn.sendCommand("GET_REACTTIME")) + if(baseReactTime !== 0){ + root.last_run.react_time = baseReactTime + } + + var baseNextAction = baseConn.sendCommand("GET_NEXT_ACTION") + + if(baseNextAction === "at_marks"){ + timer_1.text = qsTr("at your\nmarks") + var baseNextActionDelay = parseFloat(baseConn.sendCommand("GET_NEXT_ACTION_DELAY_PROG")) + prog.progress = baseNextActionDelay * 100 + } + else if(baseNextAction === "ready"){ + timer_1.text = qsTr("ready") + var baseNextActionDelay = parseFloat(baseConn.sendCommand("GET_NEXT_ACTION_DELAY_PROG")) + prog.progress = baseNextActionDelay * 100 + } + else if(baseNextAction === "start"){ + timer_1.text = "0.000 sec" + } + + + + var baseState = baseConn.sendCommand("GET_TIMER_STATE") + console.log(baseState) + if(baseState === "RUNNING"){ + timer_1.start(1) + root.state = "RUNNING"; + } + else if(baseState === "STOPPED"){ + var baseReactTime = parseInt(baseConn.sendCommand("GET_REACTTIME")) + if(baseReactTime<0){ + root.stop("false") + } + else{ + root.stop("cancel") + } + + + root.state = "STOPPED" + } + break + } + start() + } + } + } - Timer { - //timer that updates the currTime variable - running: true - repeat: true - interval: 1 - onTriggered: { - root.currTime = new Date().getTime() - } - } Timer { id: next_actionTimer @@ -193,18 +217,18 @@ Window { if(!running){ started_at = 0 if(action == "NONE"){ - time.text = "0.000 sec" + timer_1.text = "0.000 sec" } return } if(action === "at_marks"){ started_at = new Date().getTime() - time.text = "at your\nmarks" + timer_1.text = "at your\nmarks" } else if(action === "ready"){ started_at = new Date().getTime() - time.text = "ready" + timer_1.text = "ready" } } onTriggered: { @@ -219,62 +243,61 @@ Window { } } - SoundEffect { - id: at_marksSound - source: "qrc:/sounds/at_marks_1.wav" + 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() + 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() + } } - else{ + } + } + + SoundEffect { + id: readySound + source: "qrc:/sounds/ready_1.wav" + onPlayingChanged: { + if(!playing && root.state==="STARTING"){ + startSound.play() } } } - } - SoundEffect { - id: readySound - source: "qrc:/sounds/ready_1.wav" - onPlayingChanged: { - if(!playing && root.state==="STARTING"){ + SoundEffect { + //start sound + id: startSound + source: "qrc:/sounds/OFFICAL_IFSC_STARTIGNAL.wav" - startSound.play() + onPlayingChanged: { + if(!playing && root.state==="STARTING"){ + root.state = "RUNNING" + } + else if(playing) { + console.log("start sound started") + + timer_1.start(3100) + } } - } - } - SoundEffect { - //start sound - id: startSound - source: "qrc:/sounds/OFFICAL_IFSC_STARTIGNAL.wav" - - onPlayingChanged: { - if(!playing && root.state==="STARTING"){ - - console.log(root.startTime) - root.currTime = root.startTime - time.text = ( ( root.currTime - root.startTime ) / 1000 ).toFixed(3) + " sec" - root.state = "RUNNING" - } - else if(playing) { - console.log("start sound started") - root.startTime = new Date().getTime() + 3100 //set the startime to be 0 after the starttone - } } + SoundEffect { + //false-start sound + id: falseSound + source: "qrc:/sounds/false.wav" + } } - - SoundEffect { - //false-start sound - id: falseSound - source: "qrc:/sounds/false.wav" - } - /*------------------------ Timer text an upper line ------------------------*/ @@ -294,19 +317,29 @@ Window { color: StyleSettings.menuColor } - //height: root.landscape() ? undefined:parent.height * 0.15 - Label { - id: time - text: qsTr("Click start to start") - + SpeedTimer { + id: timer_1 anchors.centerIn: parent - //font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3 elide: "ElideRight" color: StyleSettings.textColor - Behavior on text { - enabled: root.state !== "RUNNING" - FadeAnimation { - target: time + toppadConn: buzzerConn + baseConn: baseConn + startpadConn: startpadConn + + text: "0.000 sec" + + onStopped: { + root.state = "STOPPED" + } + + onStartCanceled: { + root.state = "STOPPED" + next_actionTimer.stop() + at_marksSound.stop() + readySound.stop() + startSound.stop() + if(falseStart && baseConn.state !== "connected"){ + falseSound.play() } } } @@ -319,7 +352,7 @@ Window { color: StyleSettings.textColor anchors { horizontalCenter: parent.horizontalCenter - top: time.bottom + top: timer_1.bottom topMargin: parent.height * 0.1 } Timer { @@ -431,19 +464,21 @@ Window { ProgressCircle { id: prog anchors.fill: startButt - opacity: next_actionTimer.started_at > 0 ? 1:0 + opacity: baseConn.state !== "connected" ? + next_actionTimer.started_at > 0 ? 1:0 + :progress > 0 ? 1:0 lineWidth: 5 - + property int progress: 0 arcBegin: 0 - arcEnd: 360 * (( next_actionTimer.interval - ( new Date().getTime() - next_actionTimer.started_at ) ) / next_actionTimer.interval) - + arcEnd: baseConn.state !== "connected" ? 360 * (( next_actionTimer.interval - ( new Date().getTime() - next_actionTimer.started_at ) ) / next_actionTimer.interval) + :(360/100) * progress colorCircle: "grey" - animationDuration: 0 + animationDuration: baseConn.state === "connected" ? 150:0 Timer { id: prog_refresh - running: parent.opacity === 1 + running: parent.opacity === 1 && baseConn.state !== "connected" interval: 1 repeat: true onTriggered: { @@ -473,7 +508,7 @@ Window { enabled: root.state === "STARTING" onClicked: { - root.stop("false") + root.stop("cancel") } Behavior on scale { @@ -511,9 +546,9 @@ Window { case "startpad": startpadConn.connect() break - case "baseStation": - baseConn.connectToHost() - break + case "baseStation": + baseConn.connectToHost() + break } } } @@ -648,7 +683,7 @@ Window { State { name: "IDLE" //state for the start page - PropertyChanges { target: time; text: qsTr("Click start to start"); font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 } + PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 } PropertyChanges { target: time_container; anchors.bottomMargin: root.landscape() ? undefined:parent.height * 0.1; @@ -670,14 +705,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.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: time; text: "0.000 sec"; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 } + PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 } PropertyChanges { target: cancelButt; scale: 1} PropertyChanges { target: menu_container; } }, State { name: "RUNNING" //state when the timer is running - PropertyChanges { target: time; text: Math.abs( ( ( root.currTime - root.startTime ) / 1000 ) ).toFixed(3) + " sec"; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 } + PropertyChanges { target: timer_1; pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 } PropertyChanges { target: startButt; enabled: true; 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) @@ -690,9 +725,8 @@ Window { name: "STOPPED" //state when the meassuring is over PropertyChanges { - target: time; - text: root.stoppedTime > 0 ? ( root.stoppedTime / 1000 ).toFixed(3) + " sec":qsTr("false start"); - font.pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1; + target: timer_1; + pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1; scale: 1 } PropertyChanges { @@ -715,15 +749,15 @@ Window { ----------------------*/ transitions: [ Transition { - NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } + NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize,pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } }, Transition { to: "STOPPED" - NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } + NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize,pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } }, Transition { to: "IDLE" - NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } + NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize,pixelSize"; easing.type: Easing.InOutQuad; duration: 700 } }, Transition { @@ -745,12 +779,14 @@ Window { var ret = baseConn.sendCommand("CMD_START_TIMER") if(ret === "OK"){ root.state = "STARTING" + timer_1.setStarting() return } } root.state = "STARTING" + timer_1.setStarting() if(_cppAppSettings.loadSetting("at_marks_en") === "true"){ next_actionTimer.action = "at_marks" next_actionTimer.interval = _cppAppSettings.loadSetting("at_marks_delay")>0 ? _cppAppSettings.loadSetting("at_marks_delay"):1 @@ -768,58 +804,22 @@ Window { } function stop(type){ - //_cppStartpadConn.appendCommand("SET_LED_STARTING"); - switch(type){ - case "buzzer": - //the buzzer was pushed - root.buzzer_offset = buzzerConn.offset - root.last_button_pressed = buzzerConn.lastTriggered - root.stoppedTime = (root.last_button_pressed + root.buzzer_offset) - root.startTime - root.state = "STOPPED" - //time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec" - console.log("STOPPED: "+root.stoppedTime + " started at: " + root.startTime + " offset: "+ root.buzzer_offset + "lastpressed: " + root.last_button_pressed) - break - case "manual": - //the stop button was pressed - + if(type === "manual" || type === "cancel"){ if(baseConn.state === "connected"){ - - root.stoppedTime = baseConn.getTime("raw") - time.text = (root.stoppedTime / 1000).toFixed(3) + " sec" baseConn.sendCommand("CMD_STOP_TIMER") - root.state = "STOPPED" - return } - - root.stoppedTime = new Date().getTime() - root.startTime - time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec" - root.state = "STOPPED" - break - case "false": - //the cancel button was pressed - root.last_run.reaction_time = parseInt(baseConn.sendCommand("GET_REACTTIME")) - root.stoppedTime = 0 - time.text = "false start" - root.state = "STOPPED" - next_actionTimer.stop() - at_marksSound.stop() - readySound.stop() - startSound.stop() - falseSound.play() - break } + root.state = "STOPPED" + timer_1.stop(type) } function reset(){ if(baseConn.state === "connected"){ - var ret = baseConn.sendCommand("CMD_RESET_TIMER") - if(ret !== "OK"){ - return - } + baseConn.sendCommand("CMD_RESET_TIMER") } + timer_1.reset() root.state = "IDLE" - root.last_run.react_time = 0 } } } diff --git a/qml/qml.qrc b/qml/qml.qrc index d95c7a4..9474bf1 100644 --- a/qml/qml.qrc +++ b/qml/qml.qrc @@ -13,5 +13,7 @@ styles/Light.js styles/Default.js components/ConnectionIcon.qml + SpeedTimer.qml + components/NextPageDelegate.qml diff --git a/qml/styles/StyleSettings.qml b/qml/styles/StyleSettings.qml index 3ce4ea8..bc9308b 100644 --- a/qml/styles/StyleSettings.qml +++ b/qml/styles/StyleSettings.qml @@ -110,12 +110,15 @@ Item { function refreshTheme(){ switch(_cppAppSettings.loadSetting("theme")){ - case "Dark": + case "Default": theme = Dark break - case "Light": + case "Dark": theme = Light break + case "Light": + theme = Default + break } } @@ -135,13 +138,17 @@ Item { function setTheme() { switch(_cppAppSettings.loadSetting("theme")){ + case "Default": + _cppAppSettings.writeSetting("theme", "Dark") + theme = Dark + break case "Dark": _cppAppSettings.writeSetting("theme", "Light") theme = Light break case "Light": - _cppAppSettings.writeSetting("theme", "Dark") - theme = Dark + _cppAppSettings.writeSetting("theme", "Default") + theme = Default break } } diff --git a/sources/appsettings.cpp b/sources/appsettings.cpp index 66bda66..46b3ce5 100644 --- a/sources/appsettings.cpp +++ b/sources/appsettings.cpp @@ -17,6 +17,8 @@ #include "headers/appsettings.h" +AppSettings * pGlobalAppSettings = nullptr; + AppSettings::AppSettings(QObject* parent) :QObject(parent) { diff --git a/sources/baseconn.cpp b/sources/baseconn.cpp index 27da595..30e5bc8 100644 --- a/sources/baseconn.cpp +++ b/sources/baseconn.cpp @@ -4,10 +4,18 @@ BaseConn::BaseConn(QObject *parent) : QObject(parent) { socket = new QTcpSocket(); this->setState("disconnected"); + remoteSessions.release(2); + + this->speedTimers.append(pGlobalSpeedTimer); + + this->refreshTimer = new QTimer(); + refreshTimer->setInterval(1); + refreshTimer->setSingleShot(true); + refreshTimer->connect(this->refreshTimer, &QTimer::timeout, this, &BaseConn::refreshTimers); } bool BaseConn::connectToHost() { - + qDebug() << "connecting"; setState("connecting"); this->connection_progress = 0; QEventLoop loop; @@ -26,7 +34,7 @@ bool BaseConn::connectToHost() { //wait for the connection to finish (programm gets stuck in here) loop.exec(); - //loop finished + //loop finish if(timer.remainingTime() == -1){ //the time has been triggered -> timeout @@ -44,6 +52,10 @@ bool BaseConn::connectToHost() { } QString BaseConn::sendCommand(QString command){ + if(this->state != "connected"){ + return "ERR_NOT_CONNECTED"; + } + remoteSessions.acquire(1); QByteArray arrBlock; QDataStream out(&arrBlock, QIODevice::WriteOnly); //out.setVersion(QDataStream::Qt_5_10); @@ -79,12 +91,11 @@ QString BaseConn::sendCommand(QString command){ // stop the timer as the connection has been established timer.stop(); - + remoteSessions.release(1); return(this->latestReadReply); } void BaseConn::readyRead() { - qDebug() << "readyRead"; QDataStream in(socket); //in.setVersion(QDataStream::Qt_5_10); qint16 nextBlockSize = 0; @@ -112,6 +123,69 @@ void BaseConn::readyRead() { } } +/*-----Functions to control the local stopwatch-----*/ + +void BaseConn::refreshTimers(){ + if(this->state != "connected"){ + return; + } + + QString remoteState; + + switch (speedTimers[0]->state) { + case SpeedTimer::IDLE: + break; + case SpeedTimer::STARTING: + remoteState = sendCommand("GET_TIMER_STATE"); + if(remoteState == "RUNNING"){ + speedTimers[0]->start(); + } + else if (remoteState == "STOPPED") { + speedTimers[0]->stop("manual"); + } + break; + case SpeedTimer::RUNNING: + remoteState = sendCommand("GET_TIMER_STATE"); + if(remoteState == "STOPPED"){ + speedTimers[0]->stop("manual"); + } + break; + case SpeedTimer::STOPPED: + break; + } + + this->refreshTimer->start(); +} + +bool BaseConn::startTimers(){ + qDebug() << "starting timers"; + + QString ret = this->sendCommand("CMD_START_TIMER"); + + if(ret.startsWith("ERR")){ + //handle Error!! + return false; + } + + this->speedTimers[0]->setState(SpeedTimer::STARTING); + return true; +} + +bool BaseConn::stopTimers(){ + qDebug() << "stopping timers"; + + QString ret = this->sendCommand("CMD_STOP_TIMER"); + + if(ret.startsWith("ERR")){ + //handle Error! + return false; + } + + this->speedTimers[0]->stop("manual"); + return true; +} + + void BaseConn::setIP(const QString &ipAdress){ this->ip = ipAdress; } @@ -136,3 +210,17 @@ int BaseConn::getProgress() const return(connection_progress); } +bool BaseConn::refreshConnections() { + QString ret = this->sendCommand("GET_CONNECTIONS"); + if(ret.startsWith("ERR")){ + return false; + } + connections = ret.split("|||"); + return true; + +} + +QStringList BaseConn::getConnections() { + return(connections); +} + diff --git a/sources/main.cpp b/sources/main.cpp index fd6d55f..4c19591 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +//#include #include #include @@ -44,7 +44,7 @@ #include #include #include -#include +//#include #ifdef Q_OS_ANDROID #include #endif @@ -53,6 +53,7 @@ #include "headers/buzzerconn.h" #include "headers/appsettings.h" #include "headers/baseconn.h" +#include "headers/speedtimer.h" #include static void connectToDatabase() @@ -109,6 +110,10 @@ int main(int argc, char *argv[]) //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(); + pGlobalSpeedTimer = pSpeedTimer; //setup the sql storage model as a qml model qmlRegisterType("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel"); @@ -132,6 +137,7 @@ int main(int argc, char *argv[]) return -1; engine.rootContext()->setContextProperty("_cppAppSettings", pAppSettings); + engine.rootContext()->setContextProperty("_cppSpeedTimer", pSpeedTimer); int iRet = 0; iRet = app.exec(); diff --git a/sources/speedtimer.cpp b/sources/speedtimer.cpp new file mode 100644 index 0000000..b73b978 --- /dev/null +++ b/sources/speedtimer.cpp @@ -0,0 +1,115 @@ +#include "headers/speedtimer.h" + +SpeedTimer * pGlobalSpeedTimer = nullptr; + +SpeedTimer::SpeedTimer(QObject *parent) : QObject(parent) +{ + this->date = new QDateTime; + + this->startTime = 0; + this->stopTime = 0; + this->stoppedTime = 0; + this->reactionTime = 0; + this->state = IDLE; +} + +void SpeedTimer::start() { + if(this->state != STARTING){ + return; + } + this->stopTime = 0; + this->stoppedTime = 0; + this->reactionTime = 0; + this->startTime = this->date->currentMSecsSinceEpoch(); + this->setState(RUNNING); + //this->startPad->appendCommand("SET_LED_RUNNING"); +} + +void SpeedTimer::stop(QString type) { + if(this->state != SpeedTimer::STARTING && this->state != SpeedTimer::RUNNING){ + return; + } + + qDebug() << "Stopping: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime; + + if(type == "manual"){ + if(this->state == STARTING){ + emit startCanceled(false); + } + this->stopTime = this->date->currentMSecsSinceEpoch(); + this->stoppedTime = this->stopTime - this->startTime; + } + else if(type == "topPad"){ + //this->stopTime = this->topPad->latest_button_pressed + this->topPad->offset; + this->stoppedTime = this->stopTime - this->startTime; + } + else if(type == "falseStart"){ + emit startCanceled(true); + this->stoppedTime = this->reactionTime; + } + + this->setState(STOPPED); + qDebug() << "Stopped: " << "start Time: " << startTime << " stopTime: " << stopTime << " stoppedTime: " << stoppedTime << " reactionTime: " << reactionTime; + //this->startPad->appendCommand("SET_LED_STARTING"); +} + +void SpeedTimer::reset(){ + if(this->state != STOPPED){ + return; + } + this->startTime = 0; + this->stopTime = 0; + this->stoppedTime = 0; + this->reactionTime = 0; + this->setState(IDLE); + //this->startPad->appendCommand("SET_LED_STARTING"); +} + +void SpeedTimer::setState(timerState newState){ + + this->state = newState; + qDebug() << "tmer state changed: " << newState; + emit this->stateChanged(newState); +} + +QString SpeedTimer::getState(){ + switch(state){ + case IDLE: + return("IDLE"); + case STARTING: + return("STARTING"); + case RUNNING: + return("RUNNING"); + case STOPPED: + return("STOPPED"); + } +} + +double SpeedTimer::getCurrTime() { + double currTime; + if(this->state == RUNNING){ + currTime = this->date->currentMSecsSinceEpoch() - this->startTime; + } + else { + currTime = this->stoppedTime; + } + + return(currTime); +} + +void SpeedTimer::delay(int mSecs){ + QEventLoop loop; + QTimer timer; + + timer.setSingleShot(true); + // quit the loop when the timer times out + loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + //quit the loop when the connection was established + // start the timer before starting to connect + timer.start(mSecs); + //connect + + //wait for the connection to finish (programm gets stuck in here) + loop.exec(); +} + diff --git a/speedclimbing_stopwatch.pro b/speedclimbing_stopwatch.pro index 9d66e58..6226223 100644 --- a/speedclimbing_stopwatch.pro +++ b/speedclimbing_stopwatch.pro @@ -25,14 +25,16 @@ SOURCES += \ sources/sqlprofilemodel.cpp \ sources/buzzerconn.cpp \ sources/appsettings.cpp \ - sources/baseconn.cpp + sources/baseconn.cpp \ + sources/speedtimer.cpp HEADERS += \ headers/sqlstoragemodel.h \ headers/sqlprofilemodel.h \ headers/buzzerconn.h \ headers/appsettings.h \ - headers/baseconn.h + headers/baseconn.h \ + headers/speedtimer.h RESOURCES += \ shared.qrc \ @@ -51,7 +53,8 @@ QTPLUGIN += qtaudio_coreaudio # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin +#else: unix:!android: target.path = /opt/$${TARGET}/bin +else: unix:!android: target.path = /home/pi/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target DISTFILES += \