- update file structure

- the base statio firmware updater is now fully working
This commit is contained in:
dorian 2019-11-02 15:22:50 +01:00
parent 496d274780
commit 049f678b11
90 changed files with 553 additions and 286 deletions

View file

@ -12,6 +12,7 @@
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
#include <string.h>
#include <QByteArray>
#include "headers/appsettings.h"
#include "headers/speedtimer.h"
@ -37,9 +38,11 @@ public:
//---general status values---//
// some meta data of the base
QString version;
QString firmwareVersion;
bool firmwareUpToDate;
double timeOffset;
// the current state
QString state;
// can be:
@ -90,32 +93,41 @@ signals:
void gotError(QString error);
void propertiesChanged();
public slots:
Q_INVOKABLE void connectToHost();
void connectToHost();
//function to connect to the base station
void connectionTimeout();
Q_INVOKABLE bool init();
Q_INVOKABLE void deInit();
bool init();
void deInit();
Q_INVOKABLE void closeConnection();
void closeConnection();
void gotError(QAbstractSocket::SocketError err);
// --- socket communication handling ---
Q_INVOKABLE QVariantMap sendCommand(int header, QJsonValue data = "");
QVariantMap sendCommand(int header, QJsonValue data = "", bool useTerminationKeys = true, int timeout = 3000);
// --- updater functions ---
bool updateTime();
bool updateFirmware();
bool isFirmwareUpToDate();
// --- helper functions ---
Q_INVOKABLE int writeRemoteSetting(QString key, QString value);
int writeRemoteSetting(QString key, QString value);
Q_INVOKABLE bool refreshConnections();
bool refreshConnections();
void setConnections(QVariantList connections);
// functions for the qml adapter
QString getIP() const;
void setIP(const QString &ipAdress);

View file

@ -20,6 +20,7 @@ class ClimbingRace : public QObject
Q_PROPERTY(QVariant baseStationConnections READ getBaseStationConnections NOTIFY baseStationConnectionsChanged)
Q_PROPERTY(double nextStartActionDelayProgress READ getNextStartActionDelayProgress NOTIFY nextStartActionDelayProgressChanged)
Q_PROPERTY(int nextStartAction READ getNextStartAction NOTIFY nextStartActionChanged)
Q_PROPERTY(QVariantMap baseStationProperties READ getBaseStationProperties NOTIFY baseStationPropertiesChanged)
public:
explicit ClimbingRace(QObject *parent = nullptr);
@ -76,6 +77,7 @@ signals:
void timerTextChanged();
void baseStationStateChanged();
void baseStationConnectionsChanged();
void baseStationPropertiesChanged();
public slots:
Q_INVOKABLE int startRace();
@ -99,6 +101,10 @@ public slots:
Q_INVOKABLE void disconnectBaseStation();
Q_INVOKABLE QString getBaseStationState();
Q_INVOKABLE QVariant getBaseStationConnections();
Q_INVOKABLE QVariantMap getBaseStationProperties();
Q_INVOKABLE bool updateBasestationFirmware();
Q_INVOKABLE bool updateBasestationTime();
// athlete management
Q_INVOKABLE QVariant getAthletes();

View file

@ -1,218 +0,0 @@
import QtQuick 2.9
import QtMultimedia 5.8
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls.Styles 1.4
import "../components"
Column {
id: control
property string title: qsTr("base station")
spacing: parentObj.rowSpacing
property bool baseConnected: speedBackend.baseStationState === "connected"
property var parentObj
opacity: 0
ConnectionDelegate {
id: connectToBaseDel
text: status.status === "connected" ? qsTr("disconnect"): status.status === "disconnected" ? qsTr("connect"):qsTr("connecting...")
status: { "status": speedBackend.baseStationState, "progress": 100 }
connect: speedBackend.connectBaseStation
disconnect: speedBackend.disconnectBaseStation
type: "baseStation"
width: parent.width
height: parentObj.delegateHeight
}
Loader {
id: baseStationOptionsLd
property alias parentComp: control
property alias baseConnected: control.baseConnected
onBaseConnectedChanged: {
disappearAnim.start()
}
Component.onCompleted: {
baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp
item.opacity = 1
item.scale = 1
}
sourceComponent: null
ParallelAnimation {
id: disappearAnim
NumberAnimation {
property: "opacity"
to: 0
duration: 100
target: baseStationOptionsLd.item
}
NumberAnimation {
property: "scale"
to: 0.95
duration: 100
target: baseStationOptionsLd.item
}
onRunningChanged: {
if(!running) {
baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp
appearAnim.start()
}
}
}
ParallelAnimation {
id: appearAnim
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
target: baseStationOptionsLd.item
}
NumberAnimation {
property: "scale"
from: 0.95
to: 1
duration: 100
target: baseStationOptionsLd.item
}
}
}
Component {
id: baseStationDisconnectedOptionsComp
Column {
id: baseStationDisconnectedOptions
width: parentComp.width
opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd
scale: 0.95
InputDelegate {
id: baseStationIpDel
text: qsTr("IP")
inputHint: "IP"
inputText: speedBackend.readSetting("baseStationIpAdress")
inputTextFieldWidth: width * 0.7
onInputTextChanged: {
speedBackend.writeSetting("baseStationIpAdress", inputText)
speedBackend.reloadBaseStationIpAdress()
}
width: parent.width
height: parentObj.delegateHeight
visible: height > 5
Behavior on height {
NumberAnimation {
duration: 400
easing.type: Easing.Linear
}
}
}
SmoothItemDelegate {
id: baseStationHelpDel
width: parent.width
height: parentObj.delegateHeight
text: qsTr("what is this for?")
onClicked: {
Qt.openUrlExternally("https://itsblue.de/index.php/speed-climbing?ref=ScStwApp")
}
}
}
}
Component {
id: baseStationConnectedOptionsComp
Column {
id: baseStationConnectedOptions
width: parentComp.width
opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd
scale: 0.95
SmoothSliderDelegate {
id: baseStationVolumeDel
text: qsTr("volume")
width: parent.width
height: parentObj.delegateHeight
sliderValue: 0
onSliderFinished: {
speedBackend.writeSetting("soundVolume", sliderValue)
}
Component.onCompleted: {
var val = speedBackend.readSetting("soundVolume")
console.log(val)
if(val !== "false"){
sliderValue = parseFloat(val)
}
}
Behavior on height {
NumberAnimation {
duration: 400
easing.type: Easing.Linear
}
}
}
NextPageDelegate {
id: baseStationConnectionsDel
text: qsTr("connected extensions")
width: parent.width
height: parentObj.delegateHeight
visible: height > 5
onClicked: {
parentObj.push(baseStationConnections)
}
Behavior on height {
NumberAnimation {
duration: 400
easing.type: Easing.Linear
}
}
}
}
}
}

View file

@ -0,0 +1,407 @@
import QtQuick 2.9
import QtMultimedia 5.8
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls.Styles 1.4
import QtQuick.Templates 2.12 as T
import "../components"
Column {
id: control
property string title: qsTr("base station")
property bool baseConnected: speedBackend.baseStationState === "connected"
property var parentObj
opacity: 0
function doFirmwareUpdate() {
doFirmwareUpdateTimer.start()
}
Timer {
id: doFirmwareUpdateTimer
interval: 10
repeat: false
running: false
onTriggered: {
busyDl.open()
var ret = speedBackend.updateBasestationFirmware()
busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
}
}
ConnectionDelegate {
id: connectToBaseDel
text: status.status === "connected" ? qsTr("disconnect"): status.status === "disconnected" ? qsTr("connect"):qsTr("connecting...")
status: { "status": speedBackend.baseStationState, "progress": 100 }
connect: speedBackend.connectBaseStation
disconnect: speedBackend.disconnectBaseStation
type: "baseStation"
width: parent.width
height: parentObj.delegateHeight
}
Loader {
id: baseStationOptionsLd
property alias parentComp: control
property alias baseConnected: control.baseConnected
onBaseConnectedChanged: {
disappearAnim.start()
}
Component.onCompleted: {
baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp
item.opacity = 1
item.scale = 1
}
sourceComponent: null
ParallelAnimation {
id: disappearAnim
NumberAnimation {
property: "opacity"
to: 0
duration: 100
target: baseStationOptionsLd.item
}
NumberAnimation {
property: "scale"
to: 0.95
duration: 100
target: baseStationOptionsLd.item
}
onRunningChanged: {
if(!running) {
baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp
appearAnim.start()
}
}
}
ParallelAnimation {
id: appearAnim
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
target: baseStationOptionsLd.item
}
NumberAnimation {
property: "scale"
from: 0.95
to: 1
duration: 100
target: baseStationOptionsLd.item
}
}
}
Component {
id: baseStationDisconnectedOptionsComp
Column {
id: baseStationDisconnectedOptions
width: parentComp.width
opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd
scale: 0.95
InputDelegate {
id: baseStationIpDel
text: qsTr("IP")
inputHint: "IP"
inputText: speedBackend.readSetting("baseStationIpAdress")
inputTextFieldWidth: width * 0.7
onInputTextChanged: {
speedBackend.writeSetting("baseStationIpAdress", inputText)
speedBackend.reloadBaseStationIpAdress()
}
width: parent.width
height: parentObj.delegateHeight
visible: height > 5
Behavior on height {
NumberAnimation {
duration: 400
easing.type: Easing.Linear
}
}
}
SmoothItemDelegate {
id: baseStationHelpDel
width: parent.width
height: parentObj.delegateHeight
text: qsTr("what is this for?")
onClicked: {
Qt.openUrlExternally("https://itsblue.de/index.php/speed-climbing?ref=ScStwApp")
}
}
}
}
Component {
id: baseStationConnectedOptionsComp
ScrollView{
contentHeight: baseStationConnectedOptions.childrenRect.height
contentWidth: -1
width: parentComp.width
height: control.height - baseStationOptionsLd.y
clip: true
opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd
scale: 0.95
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
Column {
id: baseStationConnectedOptions
width: parentComp.width
SmoothSliderDelegate {
id: baseStationVolumeDel
text: qsTr("volume")
width: parent.width
height: parentObj.delegateHeight
sliderValue: 0
onSliderFinished: {
enabled = false
speedBackend.writeSetting("soundVolume", sliderValue)
enabled = true
}
Component.onCompleted: {
var val = speedBackend.readSetting("soundVolume")
if(val !== "false"){
sliderValue = parseFloat(val)
}
}
}
NextPageDelegate {
id: baseStationConnectionsDel
text: qsTr("connected extensions")
width: parent.width
height: parentObj.delegateHeight
visible: height > 5
onClicked: {
parentObj.push(baseStationConnections)
}
}
SmoothItemDelegate {
id: baseStationUpdateDel
// 0: hidden 1: update firmware 2: sync time
property int mode: speedBackend.baseStationProperties["firmware"]["upToDate"] ?
(Math.abs(parseInt(speedBackend.baseStationProperties["timeOffset"])) > 10000 ? 2:0)
:1
width: parent.width
height: mode > 0 ? parentObj.delegateHeight:0
visible: height > 5
text: mode === 2 ? qsTr("sync time"):qsTr("update firmware")
onClicked: {
if(mode === 1) {
control.doFirmwareUpdate()
}
else if(mode === 2){
busyDl.open()
var ret = speedBackend.updateBasestationTime()
busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" )
}
}
}
Rectangle {
anchors.left: parent.left
width: parent.width
height: 1
color: appTheme.style.lineColor
}
Item {
anchors.left: parent.left
width: parent.width
height: parentObj.delegateHeight * 0.5
Label {
anchors {
top: parent.top
left: parent.left
}
width: parent.width * 0.5
height: parent.height * 0.5
verticalAlignment: Text.AlignTop
horizontalAlignment: Text.AlignLeft
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
color: appTheme.style.lineColor
text: "version: " + speedBackend.baseStationProperties["firmware"]["version"]
}
Label {
property var date: new Date(new Date().getTime() + parseInt(speedBackend.baseStationProperties["timeOffset"]))
anchors {
top: parent.top
right: parent.right
}
width: parent.width * 0.5
height: parent.height
verticalAlignment: Text.AlignTop
horizontalAlignment: Text.AlignRight
fontSizeMode: Text.Fit
minimumPixelSize: 1
font.pixelSize: height
color: appTheme.style.lineColor
text: date.toLocaleDateString() + "\n" + date.toLocaleTimeString()
}
}
}
}
}
Popup {
id: busyDl
property string message: ""
property color messageColor: "transparent"
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height - height) / 2)
width: app.width
height: app.height
modal: true
dim: true
closePolicy: Dialog.NoAutoClose
function displayMessageAndClose(message, messageColor) {
busyDl.message = message
busyDl.messageColor = messageColor
closeDelayTimer.start()
}
Timer {
id: closeDelayTimer
interval: 1000
repeat: false
running: false
onTriggered: {
busyDl.close()
busyDl.message = ""
busyDl.messageColor = "transparent"
}
}
background: Item {
FancyBusyIndicator {
anchors.centerIn: parent
opacity: busyDl.message === "" ? 1:0
lineColor: "white"
Behavior on opacity { NumberAnimation { duration: 150 } }
}
Label {
anchors.centerIn: parent
width: parent.width * 0.5
height: parent.height * 0.5
opacity: busyDl.message === "" ? 0:1
color: busyDl.messageColor
text: busyDl.message
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
Behavior on opacity { NumberAnimation { duration: 150 } }
}
}
T.Overlay.modal: Rectangle {
id: modalRect
color: "#80404040"
Behavior on opacity { NumberAnimation { duration: 150 } }
}
}
}

View file

@ -182,6 +182,7 @@ Popup {
SettingsStack {
id: options_stack
width: headlineUnderline.width
enabled: opacity !== 0 //disable when not visible
@ -192,6 +193,7 @@ Popup {
leftMargin: ( parent.width - headlineUnderline.width ) / 2
topMargin: headlineUnderline.anchors.topMargin * 0.95
bottom: parent.bottom
bottomMargin: anchors.topMargin
}
Behavior on opacity {

View file

@ -10,7 +10,7 @@ import "../components"
StackView {
id: control
property int delegateHeight: height * 0.2
property int delegateHeight: height * 0.25
property int rowSpacing: height * 0.01
initialItem: settings

View file

@ -16,7 +16,9 @@ Column {
property var parentObj
function updateSetting(key, val, del){
del.busy = true
speedBackend.writeSetting(key, val)
del.busy = false
}
function loadSetting(key, del){
@ -26,31 +28,37 @@ Column {
SmoothSwitchDelegate {
id: ready_del
property bool busy: false
width: parent.width
height: parentObj.delegateHeight
enabled: !busy
text: qsTr("say 'ready'")
checked: parent.loadSetting("ready_en", ready_del) === "true"
onCheckedChanged: {
parent.updateSetting("ready_en",checked, ready_del)
parent.updateSetting("ready_en", checked, ready_del)
}
}
InputDelegate {
id: ready_delay_del
property bool busy: false
width: parent.width
height: parentObj.delegateHeight
enabled: ready_del.checked
enabled: !busy && ready_del.checked
text: qsTr("delay (ms)")
inputHint: qsTr("time")
inputMethodHints: Qt.ImhFormattedNumbersOnly
inputText: control.loadSetting("ready_delay", ready_del)
inputText: control.loadSetting("ready_delay", ready_delay_del)
onInputFinished: {
control.updateSetting("ready_delay", inputText, ready_delay_del)
@ -60,9 +68,13 @@ Column {
SmoothSwitchDelegate {
id: at_marks_del
property bool busy: false
width: parent.width
height: parentObj.delegateHeight
enabled: !busy
text: qsTr("say 'at your marks'")
checked: control.loadSetting("at_marks_en", ready_del) === "true"
@ -75,6 +87,8 @@ Column {
InputDelegate {
id: at_marks_delay_del
property bool busy: false
width: parent.width
height: parentObj.delegateHeight
@ -82,7 +96,7 @@ Column {
inputHint: qsTr("time")
inputMethodHints: Qt.ImhFormattedNumbersOnly
enabled: at_marks_del.checked
enabled: !busy && at_marks_del.checked
inputText: control.loadSetting("at_marks_delay", at_marks_delay_del)

View file

@ -5,7 +5,10 @@ import QtQuick.Controls.Styles 1.2
BusyIndicator {
id: control
property double animationSpeed: 0.5
property double animationSpeed: 1000
property double formFactor: 4.5
property color lineColor: "#21be2b"
contentItem: Item {
implicitWidth: 64
@ -14,54 +17,20 @@ BusyIndicator {
Item {
id: item
x: parent.width / 2 - 32
y: parent.height / 2 - 32
width: 64
height: 64
opacity: control.running ? 1 : 0
anchors.fill: parent
property int currentHeight: 0
onCurrentHeightChanged: {
}
Behavior on opacity {
OpacityAnimator {
duration: 250
}
}
SequentialAnimation {
running: control.running
loops: Animation.Infinite
running: true
NumberAnimation {
target: item
duration: 2000 * 1/control.animationSpeed
to: 1000
properties: "currentHeight"
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: item
duration: 2000 * 1/control.animationSpeed
to: 0
properties: "currentHeight"
easing.type: Easing.InOutQuad
property: "currentHeight"
from: 0
to: 800
duration: control.animationSpeed
}
}
@ -77,7 +46,7 @@ BusyIndicator {
Rectangle {
property double heightMultiplier: Math.abs( Math.sin(( (item.currentHeight + (index*20))*0.01) * (Math.PI/2) ) )
property double heightMultiplier: Math.abs( Math.sin( ( ((item.currentHeight/100) + (index*(control.formFactor/repeater.model)))) * (Math.PI/8) ) )
anchors.verticalCenter: parent.verticalCenter
@ -86,7 +55,8 @@ BusyIndicator {
radius: width * 0.5
color: "#21be2b"
color: control.lineColor
}
}
}

View file

@ -426,7 +426,7 @@ Window {
cornerRadius: startButtBackground.radius
anchors.fill: startButtBackground
scale: 0.75
opacity: Math.pow( control.opacity, 100 )
opacity: Math.pow( startButt.opacity, 100 )
}
Rectangle {

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 126 B

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 158 B

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 383 B

View file

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 311 KiB

View file

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 324 KiB

View file

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

View file

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -25,5 +25,6 @@
<file>graphics/icons/user_black.png</file>
<file>graphics/icons/ok.png</file>
<file>sounds/IFSC_STARTSIGNAL_SINE.wav</file>
<file>ScStwBasestation.sb64</file>
</qresource>
</RCC>

View file

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -51,24 +51,28 @@ bool BaseConn::init() {
// init remote session
QJsonArray updateSubs = {"onRaceStateChanged", "onTimersChanged", "onExtensionConnectionsChanged", "onNextStartActionChanged"};
QJsonObject sessionParams = {{"updateSubs", updateSubs}, {"init", true}};
QJsonObject sessionParams = {{"updateSubs", updateSubs}, {"init", true}, {"usingTerminationKeys", true}};
QVariantMap initResponse = this->sendCommand(1, sessionParams);
QVariantMap initResponse = this->sendCommand(1, sessionParams, false);
if(initResponse["status"] != 200) {
return false;
}
this->version = initResponse["data"].toMap()["version"].toString();
this->firmwareVersion = initResponse["data"].toMap()["version"].toString();
this->timeOffset = initResponse["data"].toMap()["time"].toDouble() - this->date->currentMSecsSinceEpoch();
this->firmwareUpToDate = this->isFirmwareUpToDate();
qDebug() << "[INFO][BaseStation] Init done! version: " << this->version << " time offset: " << this->timeOffset;
emit this->propertiesChanged();
qDebug() << "[INFO][BaseStation] Init done! firmware: version: " << this->firmwareVersion << " up-to-date: " << this->firmwareUpToDate << " time offset: " << this->timeOffset;
return true;
}
void BaseConn::deInit() {
this->connections.clear();
this->setState("disconnected");
}
void BaseConn::closeConnection()
@ -127,7 +131,7 @@ void BaseConn::socketStateChanged(QAbstractSocket::SocketState socketState) {
switch (socketState) {
case QAbstractSocket::UnconnectedState:
{
this->setState("disconnected");
this->deInit();
break;
}
case QAbstractSocket::ConnectedState:
@ -146,7 +150,7 @@ void BaseConn::socketStateChanged(QAbstractSocket::SocketState socketState) {
}
}
QVariantMap BaseConn::sendCommand(int header, QJsonValue data){
QVariantMap BaseConn::sendCommand(int header, QJsonValue data, bool useTerminationKeys, int timeout) {
if(this->state != "connected"){
return {{"status", 910}, {"data", "not connected"}};
}
@ -175,10 +179,15 @@ QVariantMap BaseConn::sendCommand(int header, QJsonValue data){
// quit the loop when the connection was established
// loop.connect(this, &BaseConn::gotReply, &loop, &QEventLoop::quit);
// start the timer before starting to connect
timer->start(3000);
timer->start(timeout);
//write data
socket->write(jsonRequest.toLatin1());
if(useTerminationKeys) {
socket->write("<message>" + jsonRequest.toLatin1() + "</message>");
}
else {
socket->write(jsonRequest.toLatin1());
}
//wait for an answer to finish (programm gets stuck in here)
loop->exec();
@ -226,7 +235,7 @@ void BaseConn::readyRead() {
processSocketMessage(reply);
}
void BaseConn::processSocketMessage(QString message){
void BaseConn::processSocketMessage(QString message) {
QString startKey = "<message>";
QString endKey = "</message>";
@ -312,6 +321,55 @@ void BaseConn::socketReplyRecieved(QString reply) {
emit gotUnexpectedReply(reply);
}
// -------------------------
// --- updater functions ---
// -------------------------
bool BaseConn::updateTime() {
if(abs(this->timeOffset) < 10000000) {
// the time is already up-to-date
return true;
}
// NOT IMPLEMENTED YET
return false;
}
bool BaseConn::updateFirmware() {
QString file = ":/ScStwBasestation.sb64";
QFile f(file);
if (!f.open(QFile::ReadOnly)) return false;
QString fileContents = f.readAll();
if(this->firmwareUpToDate) {
return true;
}
QVariantMap ret = this->sendCommand(5000, fileContents, true, 15000);
return ret["status"].toInt() == 200;
}
bool BaseConn::isFirmwareUpToDate() {
QString file = ":/ScStwBasestation.sb64";
QFile f(file);
if (!f.open(QFile::ReadOnly)) return false;
QString fileContents = f.readAll();
QString newFirmwareVersion = fileContents.split("<VER>")[1].split("</VER>")[0];
int newFirmwareVersionMajor = newFirmwareVersion.split(".")[0].toInt();
int newFirmwareVersionMinor = newFirmwareVersion.split(".")[1].toInt();
int newFirmwareVersionPatch = newFirmwareVersion.split(".")[2].toInt();
QString currentFirmwareVersion = this->firmwareVersion;
int currentFirmwareVersionMajor = currentFirmwareVersion.split(".")[0].toInt();
int currentFirmwareVersionMinor = currentFirmwareVersion.split(".")[1].toInt();
int currentFirmwareVersionPatch = currentFirmwareVersion.split(".")[2].toInt();
return newFirmwareVersionMajor < currentFirmwareVersionMajor || newFirmwareVersionMinor < currentFirmwareVersionMinor || newFirmwareVersionPatch <= currentFirmwareVersionPatch;
}
// ------------------------
// --- helper functions ---
// ------------------------

View file

@ -23,6 +23,7 @@ ClimbingRace::ClimbingRace(QObject *parent) : QObject(parent)
connect(this->baseConn, &BaseConn::stateChanged, this, &ClimbingRace::refreshMode);
connect(this->baseConn, &BaseConn::connectionsChanged, this, &ClimbingRace::baseStationConnectionsChanged);
connect(this->baseConn, &BaseConn::gotUpdate, this, &ClimbingRace::handleBaseStationUpdate);
connect(this->baseConn, &BaseConn::propertiesChanged, this, &ClimbingRace::baseStationPropertiesChanged);
this->speedTimers.append( new SpeedTimer(this) );
@ -620,6 +621,19 @@ QVariant ClimbingRace::getBaseStationConnections() {
return baseConn->getConnections();
}
QVariantMap ClimbingRace::getBaseStationProperties() {
QVariantMap firmware = {{"version", this->baseConn->firmwareVersion}, {"upToDate", this->baseConn->firmwareUpToDate}};
return {{"firmware", firmware}, {"timeOffset", this->baseConn->timeOffset}};
}
bool ClimbingRace::updateBasestationFirmware() {
return this->baseConn->updateFirmware();
}
bool ClimbingRace::updateBasestationTime() {
return this->baseConn->updateTime();
}
bool ClimbingRace::reloadBaseStationIpAdress() {
if(this->baseConn->state == "disconnected"){
this->baseConn->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));

View file

@ -40,8 +40,8 @@ HEADERS += \
headers/apptheme.h
RESOURCES += \
shared.qrc \
qml/qml.qrc
resources/shared/shared.qrc \
resources/qml/qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =