/*
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 .
*/
#include "headers/buzzerconn.h"
BuzzerConn::BuzzerConn(QObject *parent, QString ip, int port) : QObject(parent)
{
this->networkManager = new QNetworkAccessManager();
this->reloadNetworkManager = new QNetworkAccessManager();
this->socket = new QTcpSocket();
this->date = new QDateTime;
this->latest_button_pressed = 0;
this->connected = false;
this->ip = ip;
this->port = port;
// "http://192.168.4.1"
}
bool BuzzerConn::connect()
{
qDebug() << "connecting...";
//wait until the request has finished
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
loop.connect(this->socket, SIGNAL(connected()), &loop, SLOT(quit()));
timer.start(3000);
this->socket->connectToHost(this->ip, this->port);
loop.exec();
timer.stop();
if(timer.remainingTime() == 0){
//the time has been triggered -> timeout
return(false);
}
QList times = gettimes(2000);
qDebug() << times[0];
if(times[0] == 200.0){
this->latest_button_pressed = times[2];
for(int i=0;i<=100;i++){
this->connection_progress = i;
if(!calcoffset(this->gettimes(1000))){
this->connection_progress = 100;
this->connected = false;
return(false);
}
}
this->connected = true;
return(true);
}
else{
this->connected = false;
return(false);
}
}
bool BuzzerConn::calcoffset(QList times)
{
if(times.length() != 3){
return(false);
}
if(times[0] == 200.0){
this->latest_button_pressed = times[2];
double offset = date->currentMSecsSinceEpoch() - times[1];
if(this->latest_offsets.length()>=100){
this->latest_offsets.removeFirst();
}
this->latest_offsets.append(offset);
double mem = 0;
for(int i=0;ioffset = mem / double(latest_offsets.length());
qDebug("%20f", this->offset);
return(true);
}
else {
//this->connected = false;
return(false);
}
}
QList BuzzerConn::gettimes(int timeout)
{
// QList times;
// ReturnData_t ret = senddata(this->networkManager, QUrl(this->ip), timeout);
// times.append(double(ret.status_code));
// if(ret.status_code == 200){
// ret.text.replace("\n","");
// ret.text.replace("\r","");
// QStringList times_cache = ret.text.split("
");
// times.append(times_cache[0].toDouble());
// times.append(times_cache[1].toDouble());
// return(times);
// }
// else{
// return(times);
// }
QList times;
signed long ret;
ret = this->sendCommand("GET_TIMESTAMP", timeout);
if(ret >= 0){
times.append(double(200));
times.append(double(ret));
ret = this->sendCommand("GET_LASTPRESSED", timeout);
if(ret >= 0){
times.append(double(ret));
return(times);
}
else {
times[0] = ret;
}
}
else {
times.append(ret);
}
return(times);
}
bool BuzzerConn::buzzer_triggered()
{
if(!this->connected){
return(false);
}
if(pending_commands.length() > 0){
QString command = this->pending_commands.first();
signed long retval = this->sendCommand(command, 800);
if(retval > 0){
this->pending_commands.removeFirst();
}
}
QList times = this->gettimes(1000);
if(times[0] == 200.0){
if(times[2] > this->latest_button_pressed){
this->latest_button_pressed = times[2];
return(true);
}
else {
return(false);
}
}
else{
//this->connected = false;
return(false);
}
}
bool BuzzerConn::start()
{
if(!this->connected){
return(false);
}
QList times = this->gettimes(1000);
if(times[0] == 200.0 && this->connected){
this->latest_button_pressed = times[2];
return(true);
}
else{
this->connected = false;
return(false);
}
}
double BuzzerConn::get(QString key)
{
if(key == "offset"){
return(this->offset);
}
else if (key == "lastpressed") {
return(this->latest_button_pressed);
}
else if( key == "currtime") {
return(this->date->currentMSecsSinceEpoch());
}
else if( key == "connection_progress") {
return(this->connection_progress);
}
else if( key == "connected") {
if(this->connected){
return(1);
}
return(0);
}
}
QString BuzzerConn::test()
{
ReturnData_t ret = this->senddata(this->networkManager, QUrl("http://www.google.de"), 500);
return(ret.text);
}
bool BuzzerConn::refresh()
{
if(!this->connected){
return(false);
}
// QList times;
// ReturnData_t ret = senddata(this->reloadNetworkManager, QUrl(this->ip), 1000);
// times.append(double(ret.status_code));
// if(ret.status_code == 200){
// ret.text.replace("\n","");
// ret.text.replace("\r","");
// QStringList times_cache = ret.text.split("
");
// times.append(times_cache[0].toDouble());
// times.append(times_cache[1].toDouble());
// calcoffset(times);
// return(true);
// }
// else{
// //this->connected = false;
// return(false);
// }
if(pending_commands.length() > 0){
QString command = this->pending_commands.first();
signed long retval = this->sendCommand(command, 800);
if(retval > 0){
this->pending_commands.removeFirst();
}
}
//refresh the times
QList ret = this->gettimes(800);
if(ret[0] >= 0){
this->errors = 0;
return(this->calcoffset(ret));
}
else {
this->errors ++;
if(this->errors > errors_until_disconnect){
this->socket->disconnectFromHost();
this->connected = false;
}
return(false);
}
}
ReturnData_t BuzzerConn::senddata(QNetworkAccessManager * NetMan, QUrl serviceUrl, int timeout)
{
ReturnData_t ret; //this is a custom type to store the returned data
// Call the webservice
QNetworkRequest request(serviceUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
//send a POST request with the given url and data to the server
QUrlQuery pdata;
QNetworkReply* reply;
//wait until the request has finished
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
loop.connect(NetMan, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));
timer.start(timeout);
reply = NetMan->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
loop.exec();
timer.stop();
//get the status code
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
ret.status_code = status_code.toInt();
if(ret.status_code == 0){ //if the statuscode is zero, the connecion to the server was not possible
ret.status_code = 444;
}
//get the full text response
ret.text = QString::fromUtf8(reply->readAll());
//return the data
return(ret);
}
signed long BuzzerConn::sendCommand(QString command, int timeout){
//if there is any data in the storage, clear it
if(this->socket->bytesAvailable() > 0){
this->socket->readAll();
}
//send request to the socket server
QByteArray arrBlock;
QDataStream out(&arrBlock, QIODevice::WriteOnly);
//out.setVersion(QDataStream::Qt_5_10);
out << quint16(0) << command;
out.device()->seek(0);
out << quint16(arrBlock.size() - sizeof(quint16));
this->socket->write(arrBlock);
//now wait for the server of the sensor to answer
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
loop.connect(socket, SIGNAL(readyRead()), &loop, SLOT(quit()));
timer.start(timeout);
loop.exec();
//loop finished
timer.stop();
if(timer.remainingTime() == 0){
//the time has been triggered -> timeout
return(-1);
}
//if the data is not 4 bites long if is invalid -> clear and terminate
if(this->socket->bytesAvailable() != 4){
this->socket->readAll();
return(-2);
}
long data = 0;
this->socket->read((char*)&data,4);
qDebug() << data;
qDebug() << this->socket->bytesAvailable();
return data;
}
void BuzzerConn::appendCommand(QString command){
this->pending_commands.append(command);
}