started to implement connectivtx to a physical Buzzer

This commit is contained in:
Dorian Zedler 2018-07-25 00:32:20 +02:00
parent bc54bcd1ee
commit db94ba449d
8 changed files with 445 additions and 121 deletions

90
SettingsDialog.qml Normal file
View file

@ -0,0 +1,90 @@
import QtQuick 2.9
import QtMultimedia 5.8
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Dialog {
x: startButt.x
y: startButt.y
width: startButt.width
height: startButt.height
modal: false
enabled: false
enter: Transition {
NumberAnimation { properties: "scale"; from: 0; to: 1; duration: 500; easing.type: Easing.InCubic }
}
exit: Transition {
NumberAnimation { properties: "scale"; from: 1; to: 0; duration: 500; easing.type: Easing.OutCubic }
}
background: Rectangle {
radius: width * 0.5
color: "white"
border.color: "grey"
border.width: 1
Label {
text: "Options"
font.pixelSize: headlineUnderline.width * 0.1
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: headlineUnderline.anchors.topMargin / 2 - height / 2
}
}
Rectangle {
id: headlineUnderline
height: 1
width: parent.width
color: "grey"
anchors {
top: parent.top
left: parent.left
right: parent.right
topMargin: parent.height * 0.15
rightMargin: parent.radius - Math.sqrt(Math.pow(parent.radius,2)-Math.pow(parent.radius-anchors.topMargin,2))
leftMargin: parent.radius - Math.sqrt(Math.pow(parent.radius,2)-Math.pow(parent.radius-anchors.topMargin,2))
}
}
}
Column {
anchors.fill: parent
ItemDelegate {
id: connect_del
anchors.fill: parent
text: "connect"
onClicked: {
var i;
if(i === 100){
i = 0
running = false
}
var theUrl = "http://192.168.4.1";
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
xmlHttp.send( null );
var response = xmlHttp.responseText
var response_status = xmlHttp.status
connect_del.text = response
var res = response.split("<br>");
var time_now = new Date().getTime()
console.log(time_now)
console.log(res[1])
console.log(time_now-res[0])
root.buzzer_offset = time_now-res[0]
root.last_button_pressed = res[1]
console.log("buzzer_offset: "+root.buzzer_offset)
connect_del.text = response
}
}
}
}

94
buzzerconn.cpp Normal file
View file

@ -0,0 +1,94 @@
#include "buzzerconn.h"
BuzzerConn::BuzzerConn(QObject *parent) : QObject(parent)
{
this->networkManager = new QNetworkAccessManager();
connect();
}
bool BuzzerConn::connect()
{
QList<double> times = gettimes();
if(times[0] == 200.0){
this->connected = true;
calcoffset();
calcoffset();
calcoffset();
return(true);
}
else{
return(false);
}
}
void BuzzerConn::calcoffset()
{
QList<double> times = gettimes();
QDateTime * date = new QDateTime;
double offset = date->currentMSecsSinceEpoch() - times[2];
this->latest_offsets.append(offset);
double mem = 0;
for(int i=0;i<latest_offsets.length();i++){
qDebug()<<latest_offsets[i];
mem += latest_offsets[i];
}
this->offset = mem / double(latest_offsets.length());
}
QList<double> BuzzerConn::gettimes()
{
QList<double> times;
ReturnData_t ret = senddata(QUrl("http://192.168.4.1"));
times.append(double(ret.status_code));
if(ret.status_code == 200){
qDebug()<<ret.text;
ret.text.replace("\n","");
ret.text.replace("\r","");
QStringList times_cache = ret.text.split("<br>");
times.append(times_cache[0].toDouble());
times.append(times_cache[1].toDouble());
return(times);
}
else{
return(times);
}
}
ReturnData_t BuzzerConn::senddata(QUrl serviceUrl)
{
ReturnData_t ret; //this is a custom type to store the returned data
// Call the webservice
QNetworkRequest request(serviceUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
//set ssl configuration
//send a POST request with the given url and data to the server
QUrlQuery pdata;
QNetworkReply* reply;
reply = this->networkManager->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
//wait until the request has finished
QEventLoop loop;
loop.connect(this->networkManager, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));
loop.exec();
//get the status code
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
ret.status_code = status_code.toInt();
if(ret.status_code == 0){ //if tehstatus code is zero, the connecion to the server was not possible
ret.status_code = 444;
}
//get the full text response
ret.text = QString::fromUtf8(reply->readAll());
//return the data
return(ret);
}

39
buzzerconn.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef BUZZERCONN_H
#define BUZZERCONN_H
#include <QObject>
#include <QObject>
#include <QDir>
#include <QUrl>
#include <QtNetwork>
#include <QAuthenticator>
#include <QDesktopServices>
#include <QDateTime>
typedef struct strReturnData{
int status_code;
QString text;
}ReturnData_t;
class BuzzerConn : public QObject
{
Q_OBJECT
public:
explicit BuzzerConn(QObject *parent = nullptr);
double offset;
QList<double> latest_offsets;
bool connected;
private:
QNetworkAccessManager *networkManager;
signals:
public slots:
ReturnData_t senddata(QUrl serviceUrl);
QList<double> gettimes();
bool connect();
void calcoffset();
};
#endif // BUZZERCONN_H

View file

@ -6,11 +6,34 @@
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include <QtWebView/QtWebView>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QGuiApplication>
#include <QQuickView>
#include <QStandardPaths>
#include <QtQml>
#include <QtNetwork>
#include <QQmlApplicationEngine>
#include <QFile>
#include <QDesktopServices>
#include <QtCore/QUrl>
#include <QtCore/QCommandLineOption>
#include <QtCore/QCommandLineParser>
#include <QGuiApplication>
#include <QStyleHints>
#include <QScreen>
#include <QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <QtWebView/QtWebView>
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include <QtAndroidExtras> #include <QtAndroidExtras>
#endif #endif
#include "sqlstoragemodel.h" #include "sqlstoragemodel.h"
#include "sqlprofilemodel.h" #include "sqlprofilemodel.h"
#include "buzzerconn.h"
static void connectToDatabase() static void connectToDatabase()
{ {
@ -44,11 +67,15 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
QAndroidJniObject jactivity=QtAndroid::androidActivity(); #ifdef Q_OS_ANDROID
if(jactivity.isValid()) //set the standard volume to media
jactivity.callMethod<void>("setVolumeControlStream","(I)V",3); QAndroidJniObject jactivity=QtAndroid::androidActivity();
if(jactivity.isValid())
jactivity.callMethod<void>("setVolumeControlStream","(I)V",3);
#endif
connectToDatabase(); connectToDatabase();
BuzzerConn * pBuzzerConn = new BuzzerConn;
//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");
@ -59,5 +86,7 @@ int main(int argc, char *argv[])
if (engine.rootObjects().isEmpty()) if (engine.rootObjects().isEmpty())
return -1; return -1;
engine.rootContext()->setContextProperty("_cppBuzzerConn", pBuzzerConn);
return app.exec(); return app.exec();
} }

300
main.qml
View file

@ -23,6 +23,10 @@ Window {
property double stoppedTime: 0 property double stoppedTime: 0
property double currTime: new Date().getTime() property double currTime: new Date().getTime()
property double buzzer_offset
property double last_button_pressed
state: "IDLE" state: "IDLE"
Timer { Timer {
@ -32,6 +36,33 @@ Window {
interval: 1 interval: 1
onTriggered: { onTriggered: {
root.currTime = new Date().getTime() root.currTime = new Date().getTime()
}
}
Timer {
id: running_refresh_timer
running: root.state === "RUNNING"
repeat: true
interval: 1
onTriggered: {
var theUrl = "http://192.168.4.1";
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send( null );
var response = xmlHttp.responseText
var res = response.split("<br>");
startButt.text = res[0]
if(res[1]>root.last_button_pressed){
root.last_button_pressed = res[1]
root.stoppedTime = (root.last_button_pressed + root.buzzer_offset) - root.startTime
console.log("STOPPED: "+root.stoppedTime)
time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
root.state = "STOPPED"
}
} }
} }
@ -86,96 +117,100 @@ Window {
/*---------------------- /*----------------------
Start button Start button
----------------------*/ ----------------------*/
Rectangle { Button {
id: startButt id : startButt
property string text: "start" text: "start"
property int size: root.landscape() ? parent.width * 0.5:parent.height * 0.5 property int size: root.landscape() ? parent.width * 0.5:parent.height * 0.5
anchors { anchors {
bottom: parent.bottom bottom: parent.bottom
bottomMargin: parent.height * 0.5 - height * 0.5 bottomMargin: root.height * 0.5 - height * 0.5
right: parent.right right: parent.right
rightMargin: parent.width * 0.5 - width * 0.5 rightMargin: root.width * 0.5 - width * 0.5
}
contentItem: Text {
//make text disappear
} }
height: root.landscape() ? size > parent.height * 0.9 ? parent.height * 0.9:size : size height: root.landscape() ? size > parent.height * 0.9 ? parent.height * 0.9:size : size
width: root.landscape() ? size : size > parent.width * 0.9 ? parent.width * 0.9:size width: root.landscape() ? size : size > parent.width * 0.9 ? parent.width * 0.9:size
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Label {
id: startButt_text
text: parent.text
anchors.centerIn: parent
font.pixelSize: parent.height * 0.16
font.family: "Helvetica"
}
MouseArea {
enabled: startButt.enabled
anchors.fill: parent
onPressed: parent.color = "lightgrey"
onReleased: parent.color = "white"
onClicked: {
switch(root.state) {
case "":
root.state = "IDLE"
case "IDLE":
root.state = "STARTING"
startSound.play()
break
case "RUNNING":
root.stoppedTime = new Date().getTime() - root.startTime
time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
root.state = "STOPPED"
break
case "STOPPED":
root.state = "IDLE"
break
}
onPressedChanged: {
if(pressed){
background.color = "lightgrey"
}
else {
background.color = "white"
} }
} }
background: Rectangle {
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Label {
id: startButt_text
text: startButt.text
anchors.centerIn: parent
font.pixelSize: parent.height * 0.16
font.family: "Helvetica"
}
}
onClicked: {
switch(root.state) {
case "":
root.state = "IDLE"
case "IDLE":
root.state = "STARTING"
startSound.play()
break
case "RUNNING":
root.stoppedTime = new Date().getTime() - root.startTime
time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
root.state = "STOPPED"
break
case "STOPPED":
root.state = "IDLE"
break
}
}
} }
/*---------------------- /*----------------------
Cancel button Cancel button
----------------------*/ ----------------------*/
Rectangle { RoundButton {
id: cancelButt id: cancelButt
property string text: "cancel" text: "cancel"
anchors { anchors {
right: startButt.right right: startButt.right
bottom: startButt.bottom bottom: startButt.bottom
} }
contentItem: Text {
//make text disappear
}
height: startButt.height * 0.3 height: startButt.height * 0.3
scale: 0 scale: 0
width: height width: height
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Label { enabled: startSound.playing
id: cancelButt_text onPressedChanged: {
text: parent.text if(pressed){
anchors.centerIn: parent background.color = "lightgrey"
font.pixelSize: parent.height * 0.16
font.family: "Helvetica"
}
MouseArea {
enabled: startSound.playing
anchors.fill: parent
onPressed: parent.color = "lightgrey"
onReleased: parent.color = "white"
onClicked: {
startSound.stop()
root.stoppedTime = 0
time.text = "false start"
root.state = "STOPPED"
} }
else {
background.color = "white"
}
}
onClicked: {
startSound.stop()
root.stoppedTime = 0
time.text = "false start"
root.state = "STOPPED"
} }
Behavior on scale { Behavior on scale {
@ -183,8 +218,29 @@ Window {
duration: 200 duration: 200
} }
} }
background: Rectangle {
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Label {
id: cancelButt_text
text: cancelButt.text
anchors.centerIn: parent
font.pixelSize: parent.height * 0.16
font.family: "Helvetica"
}
}
} }
/*------
Popups
------*/
SettingsDialog{
id:settingsDialog
}
/*------------------- /*-------------------
lower line and menu lower line and menu
-------------------*/ -------------------*/
@ -208,10 +264,9 @@ Window {
leftMargin: root.landscape() ? parent.width * 0.05:0 leftMargin: root.landscape() ? parent.width * 0.05:0
} }
Rectangle { RoundButton {
id: settingsButt id: settingsButt
property string text: "cancel"
anchors { anchors {
//center //center
verticalCenter: root.landscape() ? undefined:parent.verticalCenter verticalCenter: root.landscape() ? undefined:parent.verticalCenter
@ -223,45 +278,52 @@ Window {
topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined
//align in portrait mode //align in portrait mode
leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3 leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3
} }
height: root.landscape() ? parent.width * 0.7:parent.height * 0.7 height: root.landscape() ? parent.width * 0.7:parent.height * 0.7
width: height width: height
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
onPressedChanged: {
Image { if(pressed){
id: settungsButt_Image background.color = "lightgrey"
source: "qrc:/graphics/icons/settings.png" }
anchors.centerIn: parent else {
height: parent.height * 0.7 background.color = "white"
width: parent.width * 0.7
mipmap: true
}
MouseArea {
enabled: root.state === "IDLE"
anchors.fill: parent
onPressed: parent.color = "lightgrey"
onReleased: parent.color = "white"
onClicked: {
} }
} }
Behavior on scale { onClicked: {
PropertyAnimation { if(settingsDialog.enabled === false){
duration: 200 settingsDialog.open()
settingsDialog.enabled = true
}
else {
settingsDialog.enabled = false
settingsDialog.close()
}
}
background: Rectangle {
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Image {
id: settungsButt_Image
source: "qrc:/graphics/icons/settings.png"
anchors.centerIn: parent
height: parent.height * 0.7
width: parent.width * 0.7
mipmap: true
} }
} }
} }
Rectangle {
RoundButton {
id: profilesButt id: profilesButt
property string text: "cancel"
anchors { anchors {
verticalCenter: root.landscape() ? undefined:parent.verticalCenter verticalCenter: root.landscape() ? undefined:parent.verticalCenter
horizontalCenter: root.landscape() ? parent.horizontalCenter:undefined horizontalCenter: root.landscape() ? parent.horizontalCenter:undefined
@ -270,39 +332,45 @@ Window {
topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined
leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3 leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3
} }
height: root.landscape() ? parent.width * 0.7:parent.height * 0.7 height: root.landscape() ? parent.width * 0.7:parent.height * 0.7
width: height width: height
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Image { onPressedChanged: {
id: profilesButt_Image if(pressed){
source: "qrc:/graphics/icons/user.png" background.color = "lightgrey"
anchors.centerIn: parent }
height: parent.height * 0.5 else {
width: parent.width * 0.5 background.color = "white"
mipmap: true
}
MouseArea {
enabled: root.state === "IDLE"
anchors.fill: parent
onPressed: parent.color = "lightgrey"
onReleased: parent.color = "white"
onClicked: {
} }
} }
Behavior on scale { onClicked: {
PropertyAnimation { var theUrl = "http://192.168.4.1";
duration: 200 var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send( null );
console.log(xmlHttp.responseText)
}
background: Rectangle {
color: "white"
border.color: "grey"
border.width: 1
radius: width / 2
Image {
id: profilesButt_Image
source: "qrc:/graphics/icons/user.png"
anchors.centerIn: parent
height: parent.height * 0.5
width: parent.width * 0.5
mipmap: true
} }
} }
} }
} }

View file

@ -2,5 +2,6 @@
<qresource prefix="/"> <qresource prefix="/">
<file>main.qml</file> <file>main.qml</file>
<file>FadeAnimation.qml</file> <file>FadeAnimation.qml</file>
<file>SettingsDialog.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -21,7 +21,8 @@ TARGET = speedclimbing_stw
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
sqlstoragemodel.cpp \ sqlstoragemodel.cpp \
sqlprofilemodel.cpp sqlprofilemodel.cpp \
buzzerconn.cpp
RESOURCES += qml.qrc \ RESOURCES += qml.qrc \
shared.qrc shared.qrc
@ -50,4 +51,5 @@ android {
HEADERS += \ HEADERS += \
sqlstoragemodel.h \ sqlstoragemodel.h \
sqlprofilemodel.h sqlprofilemodel.h \
buzzerconn.h

View file

@ -6,6 +6,7 @@
class SqlStorageModel : public QObject class SqlStorageModel : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SqlStorageModel(QObject *parent = nullptr); explicit SqlStorageModel(QObject *parent = nullptr);