added first class
This commit is contained in:
parent
4e0ae972b4
commit
fd5c1dc122
6 changed files with 669 additions and 2 deletions
15
ScStwLibraries/ScStwLibraries.pri
Normal file
15
ScStwLibraries/ScStwLibraries.pri
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
!isEmpty(SCSTWLIBRARIES_LIB):error("ScStwLibraries.pri already included")
|
||||||
|
SCSTWLIBRARIES_LIB = 1
|
||||||
|
|
||||||
|
#DEPENDS
|
||||||
|
CONFIG(release, debug|release): {
|
||||||
|
SCSTWLIBRARIES_LIB_OUTPUT_DIR="$$PWD/build/release"
|
||||||
|
} else {
|
||||||
|
SCSTWLIBRARIES_LIB_OUTPUT_DIR="$$PWD/build/debug"
|
||||||
|
}
|
||||||
|
|
||||||
|
unix:LIBS += -L$$SCSTWLIBRARIES_LIB_OUTPUT_DIR -lScStwLibraries
|
||||||
|
|
||||||
|
win32:LIBS += -L$$SCSTWLIBRARIES_LIB_OUTPUT_DIR -lScStwLibraries1
|
||||||
|
|
||||||
|
INCLUDEPATH += "$$PWD"
|
|
@ -1,7 +1,8 @@
|
||||||
QT -= gui
|
QT -= gui
|
||||||
|
QT += network
|
||||||
|
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
DEFINES += SCSTWCLIENT_LIBRARY
|
DEFINES += SCSTWLIBRARIES_LIBRARY
|
||||||
|
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
|
@ -20,9 +21,16 @@ SOURCES += \
|
||||||
scstwclient.cpp
|
scstwclient.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
ScStwClient_global.h \
|
ScStwLibraries_global.h \
|
||||||
scstwclient.h
|
scstwclient.h
|
||||||
|
|
||||||
|
#DEPENDS
|
||||||
|
CONFIG(release, debug|release): {
|
||||||
|
DESTDIR="$$PWD/build/release"
|
||||||
|
} else {
|
||||||
|
DESTDIR="$$PWD/build/debug"
|
||||||
|
}
|
||||||
|
|
||||||
# Default rules for deployment.
|
# Default rules for deployment.
|
||||||
unix {
|
unix {
|
||||||
target.path = /usr/lib
|
target.path = /usr/lib
|
21
ScStwLibraries/ScStwLibraries_global.h
Normal file
21
ScStwLibraries/ScStwLibraries_global.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef SCSTWLIBRARIES_GLOBAL_H
|
||||||
|
#define SCSTWLIBRARIES_GLOBAL_H
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#if defined(SCSTWLIBRARIES_LIBRARY)
|
||||||
|
# define SCSTWLIBRARIES_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
# define SCSTWLIBRARIES_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some global enums
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum raceState { IDLE, STARTING, WAITING, RUNNING, STOPPED };
|
||||||
|
enum signalKey { RaceStateChanged, TimersChanged, ExtensionsChanged, NextStartActionChanged /*, ProfilesChanged*/ };
|
||||||
|
enum nextStartAction { AtYourMarks, Ready, Start, None };
|
||||||
|
|
||||||
|
#endif // SCSTWCLIENT_GLOBAL_H
|
450
ScStwLibraries/scstwclient.cpp
Normal file
450
ScStwLibraries/scstwclient.cpp
Normal file
|
@ -0,0 +1,450 @@
|
||||||
|
#include "scstwclient.h"
|
||||||
|
|
||||||
|
ScStwClient * pGlobalScStwClient = nullptr;
|
||||||
|
|
||||||
|
ScStwClient::ScStwClient(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
pGlobalScStwClient = this;
|
||||||
|
|
||||||
|
socket = new QTcpSocket(this);
|
||||||
|
|
||||||
|
this->timeoutTimer = new QTimer(this);
|
||||||
|
this->timeoutTimer->setSingleShot(true);
|
||||||
|
|
||||||
|
this->state = "disconnected";
|
||||||
|
|
||||||
|
connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||||
|
this, SLOT(gotError(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
|
connect(this->socket, &QAbstractSocket::stateChanged, this, &ScStwClient::socketStateChanged);
|
||||||
|
|
||||||
|
this->nextConnectionId = 1;
|
||||||
|
this->connections = QVariantList({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::connectToHost() {
|
||||||
|
qDebug() << "connecting";
|
||||||
|
setState("connecting");
|
||||||
|
|
||||||
|
connect(this->timeoutTimer, SIGNAL(timeout()), this, SLOT(connectionTimeout()));
|
||||||
|
|
||||||
|
//connect
|
||||||
|
this->socket->connectToHost(this->ip, this->port);
|
||||||
|
|
||||||
|
timeoutTimer->start(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::connectionTimeout() {
|
||||||
|
this->socket->abort();
|
||||||
|
disconnect(this->timeoutTimer, SIGNAL(timeout()), this, SLOT(connectionTimeout()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwClient::init() {
|
||||||
|
disconnect(this->timeoutTimer, SIGNAL(timeout()), this, SLOT(connectionTimeout()));
|
||||||
|
this->timeoutTimer->stop();
|
||||||
|
|
||||||
|
connect(this->socket, &QTcpSocket::readyRead, this, &ScStwClient::readyRead);
|
||||||
|
this->setState("connected");
|
||||||
|
|
||||||
|
// init remote session
|
||||||
|
QJsonArray updateSubs = {"onRaceStateChanged", "onTimersChanged", "onExtensionConnectionsChanged", "onNextStartActionChanged"};
|
||||||
|
QJsonObject sessionParams = {{"updateSubs", updateSubs}, {"init", true}, {"usingTerminationKeys", true}};
|
||||||
|
|
||||||
|
QVariantMap initResponse = this->sendCommand(1, sessionParams, false);
|
||||||
|
|
||||||
|
if(initResponse["status"] != 200) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->firmwareVersion = initResponse["data"].toMap()["version"].toString();
|
||||||
|
this->timeOffset = initResponse["data"].toMap()["time"].toDouble() - this->date->currentMSecsSinceEpoch();
|
||||||
|
this->firmwareUpToDate = this->isFirmwareUpToDate();
|
||||||
|
|
||||||
|
emit this->propertiesChanged();
|
||||||
|
|
||||||
|
qDebug() << "[INFO][BaseStation] Init done! firmware: version: " << this->firmwareVersion << " up-to-date: " << this->firmwareUpToDate << " time offset: " << this->timeOffset;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::deInit() {
|
||||||
|
this->connections.clear();
|
||||||
|
emit this->connectionsChanged();
|
||||||
|
this->setState("disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::closeConnection()
|
||||||
|
{
|
||||||
|
this->connections = QVariantList({});
|
||||||
|
emit this->connectionsChanged();
|
||||||
|
|
||||||
|
qDebug() << "closing connection";
|
||||||
|
switch (socket->state())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
socket->abort();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
socket->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState("disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::gotError(QAbstractSocket::SocketError err)
|
||||||
|
{
|
||||||
|
//qDebug() << "got error";
|
||||||
|
QString strError = "unknown";
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
strError = "Connection was refused";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strError = "Remote host closed the connection";
|
||||||
|
this->closeConnection();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strError = "Host address was not found";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
strError = "Connection timed out";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strError = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
emit gotError(strError);
|
||||||
|
qDebug() << "got socket error: " << strError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// --- socket communication handling ---
|
||||||
|
// -------------------------------------
|
||||||
|
|
||||||
|
void ScStwClient::socketStateChanged(QAbstractSocket::SocketState socketState) {
|
||||||
|
switch (socketState) {
|
||||||
|
case QAbstractSocket::UnconnectedState:
|
||||||
|
{
|
||||||
|
this->deInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QAbstractSocket::ConnectedState:
|
||||||
|
{
|
||||||
|
if(!this->init()) {
|
||||||
|
this->closeConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
//qDebug() << "+ --- UNKNOWN SOCKET STATE: " << socketState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap ScStwClient::sendCommand(int header, QJsonValue data, bool useTerminationKeys, int timeout) {
|
||||||
|
if(this->state != "connected"){
|
||||||
|
return {{"status", 910}, {"data", "not connected"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate id and witing requests entry
|
||||||
|
int thisId = nextConnectionId;
|
||||||
|
//qDebug() << "sending command: " << header << " with data: " << data << " and id: " << thisId;
|
||||||
|
nextConnectionId ++;
|
||||||
|
|
||||||
|
QEventLoop *loop = new QEventLoop(this);
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
QJsonObject reply;
|
||||||
|
|
||||||
|
this->waitingRequests.append({thisId, loop, reply});
|
||||||
|
|
||||||
|
QJsonObject requestObj;
|
||||||
|
requestObj.insert("id", thisId);
|
||||||
|
requestObj.insert("header", header);
|
||||||
|
requestObj.insert("data", data);
|
||||||
|
|
||||||
|
QString jsonRequest = QJsonDocument(requestObj).toJson();
|
||||||
|
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
// quit the loop when the timer times out
|
||||||
|
loop->connect(timer, SIGNAL(timeout()), loop, SLOT(quit()));
|
||||||
|
// quit the loop when the connection was established
|
||||||
|
// loop.connect(this, &ScStwClient::gotReply, &loop, &QEventLoop::quit);
|
||||||
|
// start the timer before starting to connect
|
||||||
|
timer->start(timeout);
|
||||||
|
|
||||||
|
//write data
|
||||||
|
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();
|
||||||
|
|
||||||
|
bool replyFound = false;
|
||||||
|
|
||||||
|
// find reply and delete the request from waiting list
|
||||||
|
for(int i = 0; i<this->waitingRequests.length(); i++){
|
||||||
|
if(this->waitingRequests[i].id == thisId){
|
||||||
|
// request was found
|
||||||
|
replyFound = true;
|
||||||
|
// delete event loop
|
||||||
|
if(this->waitingRequests[i].loop != nullptr) {
|
||||||
|
delete this->waitingRequests[i].loop;
|
||||||
|
}
|
||||||
|
// store reply
|
||||||
|
reply = this->waitingRequests[i].reply;
|
||||||
|
// remove reply from waiting list
|
||||||
|
this->waitingRequests.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!replyFound) {
|
||||||
|
// some internal error occured
|
||||||
|
return {{"status", 900}, {"data", ""}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(timer->remainingTime() == -1){
|
||||||
|
//the time has been triggered -> timeout
|
||||||
|
return {{"status", 911}, {"data", ""}};
|
||||||
|
}
|
||||||
|
|
||||||
|
delete timer;
|
||||||
|
return {{"status", reply.value("header").toInt()}, {"data", reply.value("data").toVariant()}};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::readyRead() {
|
||||||
|
|
||||||
|
//qDebug() << "ready to ready " << socket->bytesAvailable() << " bytes" ;
|
||||||
|
QString reply = socket->readAll();
|
||||||
|
|
||||||
|
//qWarning() << "socket read: " << reply;
|
||||||
|
|
||||||
|
processSocketMessage(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::processSocketMessage(QString message) {
|
||||||
|
QString startKey = "<message>";
|
||||||
|
QString endKey = "</message>";
|
||||||
|
|
||||||
|
//qWarning() << "... processing message now ... : " << message;
|
||||||
|
|
||||||
|
if(message == ""){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((message.startsWith(startKey) && message.endsWith(endKey)) && (message.count(startKey) == 1 && message.count(endKey) == 1)){
|
||||||
|
// non-split message ( e.g.: <message>123456789</message>
|
||||||
|
}
|
||||||
|
else if(!message.contains(endKey) && (!this->readBuffer.isEmpty() || message.startsWith(startKey))){
|
||||||
|
// begin of a split message ( e.g.: <message>123 )
|
||||||
|
// or middle of a split message ( e.g.: 456 )
|
||||||
|
//qWarning() << "this is a begin or middle of split a message";
|
||||||
|
this->readBuffer += message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(!message.contains(startKey) && message.endsWith(endKey)) {
|
||||||
|
// end of a split message ( e.g.: 789</message> )
|
||||||
|
|
||||||
|
if(!this->readBuffer.isEmpty()){
|
||||||
|
message = readBuffer + message;
|
||||||
|
readBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((message.count(startKey) > 1 || message.count(endKey) > 1) || (message.contains(endKey) && !message.endsWith(endKey) && message.contains(startKey) && !message.startsWith(startKey))) {
|
||||||
|
// multiple messages in one packet ( e.g.: <message>123456789</message><message>987654321</message> )
|
||||||
|
// or multiple message fragments in one message ( e.g.: 56789</message><message>987654321</message> or 56789</message><message>98765 )
|
||||||
|
//qDebug() << "detected multiple messages";
|
||||||
|
|
||||||
|
int startOfSecondMessage = message.lastIndexOf(startKey);
|
||||||
|
// process first part of message
|
||||||
|
QString firstMessage = message.left(startOfSecondMessage);
|
||||||
|
this->processSocketMessage(firstMessage);
|
||||||
|
// process second part of message
|
||||||
|
QString secondMessage = message.right(message.length() - startOfSecondMessage);
|
||||||
|
this->processSocketMessage(secondMessage);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// invalid message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qWarning() << "... done processing, message: " << message;
|
||||||
|
this->socketReplyRecieved(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::socketReplyRecieved(QString reply) {
|
||||||
|
reply.replace("<message>", "");
|
||||||
|
reply.replace("</message>", "");
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
|
QJsonDocument jsonReply = QJsonDocument::fromJson(reply.toUtf8());
|
||||||
|
QJsonObject replyObj = jsonReply.object();
|
||||||
|
|
||||||
|
if(!replyObj.isEmpty()){
|
||||||
|
id = replyObj.value("id").toInt();
|
||||||
|
|
||||||
|
if(id == -1) {
|
||||||
|
// this message is an update!!
|
||||||
|
emit this->gotUpdate(replyObj.toVariantMap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this message is the reply to a command!
|
||||||
|
for(int i = 0; i < this->waitingRequests.length(); i++){
|
||||||
|
if(this->waitingRequests[i].id == id){
|
||||||
|
this->waitingRequests[i].reply = replyObj;
|
||||||
|
if(this->waitingRequests[i].loop != nullptr){
|
||||||
|
this->waitingRequests[i].loop->quit();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
latestReadReply = reply;
|
||||||
|
emit gotUnexpectedReply(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// --- updater functions ---
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
bool ScStwClient::updateTime() {
|
||||||
|
if(abs(this->timeOffset) < 10000) {
|
||||||
|
// the time is already up-to-date
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap ret = this->sendCommand(5001, this->date->currentSecsSinceEpoch());
|
||||||
|
qDebug() << ret;
|
||||||
|
|
||||||
|
return ret["status"].toInt() == 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwClient::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 ScStwClient::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();
|
||||||
|
|
||||||
|
qDebug() << "App firmware version is: " << newFirmwareVersion;
|
||||||
|
|
||||||
|
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 ---
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
int ScStwClient::writeRemoteSetting(QString key, QString value) {
|
||||||
|
QJsonArray requestData;
|
||||||
|
requestData.append(key);
|
||||||
|
requestData.append(value);
|
||||||
|
return this->sendCommand(3000, requestData)["status"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::setIP(QString ipAdress){
|
||||||
|
this->ip = ipAdress;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScStwClient::getIP()
|
||||||
|
{
|
||||||
|
return this->ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScStwClient::getState()
|
||||||
|
{
|
||||||
|
return this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::setState(QString newState){
|
||||||
|
if(this->state != newState) {
|
||||||
|
qDebug() << "+--- ScStwClient state changed: " << newState;
|
||||||
|
this->state = newState;
|
||||||
|
emit stateChanged();
|
||||||
|
if(this->state == "disconnected") {
|
||||||
|
this->deInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScStwClient::refreshConnections() {
|
||||||
|
/*
|
||||||
|
"id": "id of the extention (int)",
|
||||||
|
"type": "type of the extention (can be: 'STARTPAD', 'TOPPAD')",
|
||||||
|
"name": "name of the extention",
|
||||||
|
"ip": "ip-adress of he extention (string)",
|
||||||
|
"state": "state of the extention (can be: 'disconnected', 'connecting', 'connected')"
|
||||||
|
*/
|
||||||
|
QVariantMap reply = this->sendCommand(2006);
|
||||||
|
|
||||||
|
if(reply["status"] != 200){
|
||||||
|
//handle Error!!
|
||||||
|
if(reply["status"] == 910){
|
||||||
|
this->connections = QVariantList({});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
qDebug() << "+ --- error refreshing connections: " << reply["status"];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList tmpConnections = reply["data"].toList();
|
||||||
|
|
||||||
|
if(this->connections != reply["data"].toList()){
|
||||||
|
this->connections = reply["data"].toList();
|
||||||
|
emit this->connectionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ScStwClient::getConnections() {
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStwClient::setConnections(QVariantList connections) {
|
||||||
|
if(this->connections != connections){
|
||||||
|
this->connections = connections;
|
||||||
|
emit this->connectionsChanged();
|
||||||
|
}
|
||||||
|
}
|
173
ScStwLibraries/scstwclient.h
Normal file
173
ScStwLibraries/scstwclient.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#ifndef SCSTWCLIENT_H
|
||||||
|
#define SCSTWCLIENT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QSemaphore>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
#include <string.h>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to connect and talk to the ScStw basestation.
|
||||||
|
*
|
||||||
|
* @brief The ScStwClient class
|
||||||
|
* @author Dorian Zedler
|
||||||
|
*/
|
||||||
|
class ScStwClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor
|
||||||
|
*
|
||||||
|
* @brief ScStwClient
|
||||||
|
*/
|
||||||
|
explicit ScStwClient();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// values for the socket connection
|
||||||
|
QString ip;
|
||||||
|
ushort port = 3563;
|
||||||
|
int errors;
|
||||||
|
int errors_until_disconnect = 4;
|
||||||
|
|
||||||
|
QVariant connections;
|
||||||
|
|
||||||
|
QString latestReadReply;
|
||||||
|
|
||||||
|
//---general status values---//
|
||||||
|
|
||||||
|
// some meta data of the base
|
||||||
|
QString firmwareVersion;
|
||||||
|
bool firmwareUpToDate;
|
||||||
|
double timeOffset;
|
||||||
|
|
||||||
|
|
||||||
|
// the current state
|
||||||
|
QString state;
|
||||||
|
// can be:
|
||||||
|
// - 'disconnected'
|
||||||
|
// - 'connecting'
|
||||||
|
// - 'connected'
|
||||||
|
|
||||||
|
QDateTime *date;
|
||||||
|
//to get the current time
|
||||||
|
|
||||||
|
QTcpSocket *socket;
|
||||||
|
//socket for communication with the extention
|
||||||
|
|
||||||
|
QTimer *timeoutTimer;
|
||||||
|
|
||||||
|
QString readBuffer;
|
||||||
|
|
||||||
|
int nextConnectionId;
|
||||||
|
|
||||||
|
struct waitingRequest {
|
||||||
|
int id;
|
||||||
|
QEventLoop * loop;
|
||||||
|
QJsonObject reply;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<waitingRequest> waitingRequests;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Is emitted, when the connection state changes
|
||||||
|
*
|
||||||
|
* @brief stateChanged
|
||||||
|
*/
|
||||||
|
void stateChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is emitted, whenever a reply is recieved which does not match any requests
|
||||||
|
*
|
||||||
|
* @brief gotUnexpectedReply
|
||||||
|
* @param reply contains the reply
|
||||||
|
*/
|
||||||
|
void gotUnexpectedReply(QString reply);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is emitted, when an update signal from the basestation is recieved
|
||||||
|
*
|
||||||
|
* @brief gotUpdate
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
void gotUpdate(QVariant data);
|
||||||
|
|
||||||
|
void connectionsChanged();
|
||||||
|
|
||||||
|
void connectionSlotReleased();
|
||||||
|
|
||||||
|
void nextRemoteActionChanged();
|
||||||
|
|
||||||
|
void nextRemoteActionDelayProgChanged();
|
||||||
|
|
||||||
|
void gotError(QString error);
|
||||||
|
|
||||||
|
void propertiesChanged();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void connectToHost();
|
||||||
|
//function to connect to the base station
|
||||||
|
|
||||||
|
void connectionTimeout();
|
||||||
|
|
||||||
|
void closeConnection();
|
||||||
|
|
||||||
|
void gotError(QAbstractSocket::SocketError err);
|
||||||
|
|
||||||
|
// --- socket communication handling ---
|
||||||
|
|
||||||
|
QVariantMap sendCommand(int header, QJsonValue data = "", bool useTerminationKeys = true, int timeout = 3000);
|
||||||
|
|
||||||
|
// --- updater functions ---
|
||||||
|
|
||||||
|
bool updateTime();
|
||||||
|
bool updateFirmware();
|
||||||
|
bool isFirmwareUpToDate();
|
||||||
|
|
||||||
|
// --- helper functions ---
|
||||||
|
|
||||||
|
int writeRemoteSetting(QString key, QString value);
|
||||||
|
|
||||||
|
bool refreshConnections();
|
||||||
|
|
||||||
|
// functions for the qml adapter
|
||||||
|
QString getIP();
|
||||||
|
void setIP(QString ipAdress);
|
||||||
|
|
||||||
|
QString getState();
|
||||||
|
void setState(QString newState);
|
||||||
|
|
||||||
|
int getProgress();
|
||||||
|
|
||||||
|
QVariant getConnections();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
void deInit();
|
||||||
|
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
void processSocketMessage(QString message);
|
||||||
|
|
||||||
|
void socketReplyRecieved(QString reply);
|
||||||
|
|
||||||
|
void socketStateChanged(QAbstractSocket::SocketState socketState);
|
||||||
|
|
||||||
|
void setConnections(QVariantList connections);
|
||||||
|
};
|
||||||
|
extern ScStwClient * pGlobalScStwClient;
|
||||||
|
|
||||||
|
#endif // SCSTWCLIENT_H
|
Reference in a new issue