shared-libraries/ScStwLibraries/headers/client/scstwclient.h

334 lines
9.5 KiB
C++

/****************************************************************************
** ScStw Libraries
** Copyright (C) 2020 Itsblue development
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#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>
#include "ScStw.hpp"
#include "scstwsettings.h"
/*!
* This class is used to connect and talk to the ScStw basestation.
*
* \code{.cpp}
* ScStwClient * client = new ScStwClient();
* client->setIp("192.168.4.1");
* client->connectToHost();
* \endcode
*
* \brief The ScStwClient class
* \author Dorian Zedler
*/
class ScStwClient : public QObject
{
Q_OBJECT
Q_PROPERTY(State state READ getState NOTIFY stateChanged)
Q_PROPERTY(QVariantMap extensions READ getExtensions NOTIFY extensionsChanged)
Q_PROPERTY(QString ipAddress READ getIP WRITE setIP)
public:
/*!
* The constructor
*
* \brief ScStwClient
*/
explicit ScStwClient(
QObject *parent = nullptr,
QList<ScStw::SignalKey> signalSubscriptions = {ScStw::ExtensionsChanged}
);
enum State {DISCONNECTED, CONNECTING, INITIALISING, CONNECTED};
Q_ENUM(State);
const QString API_VERSION = "1.0.0";
private:
// values for the socket connection
QString ip;
ushort port = 3563;
int errors;
const static int ERRORS_UNTIL_DISCONNECT = 4;
QVariantMap extensions;
QList<ScStw::SignalKey> signalSubscriptions;
//---general status values---//
// some meta data of the base station
QString firmwareVersion;
QString apiVersion;
double timeOffset;
// the current state
ScStwClient::State state;
QDateTime *date;
//to get the current time
QTcpSocket *socket;
//socket for communication with the extention
QTimer *timeoutTimer;
QString readBuffer;
unsigned int currentRequestId;
struct WaitingRequest {
QEventLoop * loop;
QJsonObject reply;
};
QMap<int, WaitingRequest> waitingRequests;
public slots:
/*!
* \brief Function to connect to the base station
*/
void connectToHost();
/*!
* \brief Function to disconnect from the basestation
*/
void closeConnection();
/*! socket communication handling */
/*!
* \brief Funtion to send a command to the server (for internal use)
* \param header the command to send
* \param data the data to send
* \param timeout the timeout
* \param useTerminationKeys wether to use the termination keys defined in
*
* \return a variant map containing the Keys "status" and "data"
*/
QVariantMap sendCommand(int header, QJsonValue data = "", int timeout = 3000);
/*! helper functions */
/*!
* \brief Function to write a setting on the base station
* \param key the key to write to
* \param value the value to write to
* \return the status code returned by the command
*/
ScStw::StatusCode writeRemoteSetting(ScStwSettings::BaseStationSetting key, QVariant value);
/*!
* \brief Function to read a setting on the base station
* \param key the key to read from
* \return the value of the key or "false" if the key is not found or an error occured
*/
QVariant readRemoteSetting(ScStwSettings::BaseStationSetting key, ScStw::StatusCode* status = nullptr);
/*! Getter fuctions */
/*!
* \brief Function to get the ip the client will try to connect to.
* \see setIP()
* \return the ip
*/
QString getIP();
/*!
* \brief Function to get the current state of the client
* \return the current state
*/
ScStwClient::State getState();
/*!
* \brief Function to get the extensions and their state from the base station
* \return a list with all configured extensions and their state
*/
QVariantMap getExtensions();
/*!
* \brief Function to get the time offset of the base station relative to the clients time
* \see updateTime()
* \return the time offset in milliseconds
*/
int getTimeOffset();
/*!
* \brief Function to get the current firmware version of the base station
* \see updateFirmware()
* \see isFirmwareUpToDate()
* \return Firmware version as string encoded as <major>.<minor>.<patch>
*/
QString getFirmwareVersion();
/*!
* \brief Function to get the current API version of the base station
* \return
*/
QString getApiVersion();
/*! setter functions */
/*!
* \brief Function to set the ip to connect to
* \see getIP()
* \param ipAdress
*/
void setIP(QString ipAdress);
void addSignalSubscription(ScStw::SignalKey key);
private slots:
/*!
* \brief called when timeout timer times out
*/
void connectionTimeout();
/*!
* \brief Function that is connected to the QAbstractSocket::error slot and used to handle upcoming errors
* \param err the error that occurred
*/
void handleError(QAbstractSocket::SocketError err);
/*!
* \brief Function to init a session at the base station
* \return true or false
*/
bool init();
/*!
* \brief Function to end a session on the base station
*/
void deInit();
/*!
* \brief Funtion to send a command to the server (for internal use)
* \param header the command to send
* \param data the data to send
* \param timeout the timeout
* \param useTerminationKeys wether to use the termination keys defined in
* ScStw::SOCKET_MESSAGE_START_KEY and ScStw::SOCKET_MESSAGE_END_KEY
* \return a variant map containing the Keys "status" and "data"
*/
QVariantMap sendCommand(int header, QJsonValue data, int timeout, bool useTerminationKeys);
/*!
* \brief Function connected to the QAbstractSocket::readyRead signal
*/
void handleReadyRead();
/*!
* \brief Function to process an incoming string and parse the messages contained in it.
* \param message the message sting to parse
*/
void processSocketMessage(QString message);
/*!
* \brief Function that handles a parsed message
* \details This fuction looks up the id of the incoming message and tries to find the according waiting request.
* If it is unable to find an accordin request, the signal ScStwClient::gotUnexpectedMessage(QString message) is called.
* If the recieved message is a signal, the ScStwClient::handleSignal() function is called.
* \see gotUnexpectedMessage()
* \see handleSignal()
* \param reply the massage that needs to be handles
*/
void handleSocketMessage(QString reply);
/*!
* \brief Function to handle a change of the state of the tcp socket
* \details it is connected to the QAbstractSocket::stateChanged signal
* \see stateChanged()
* \param socketState
*/
void handleSocketStateChange(QAbstractSocket::SocketState socketState);
/*!
* \brief Function to handle a signal from the base station.
* \details Called by the ScStwClient::handleSocketMessage function
* \see handleSocketMessage()
* \param data
*/
void handleSignal(QVariantMap data);
/*! Helper Functions */
/*!
* \brief Function used to set the local cache of the baseStation connections.
* \details emits ScStwClient::gotSignal() with a ScStw::ExtensionsChanged signal.
* \see gotSignal()
* \param connections the list to set the chache to
*/
void setExtensions(QVariantMap extensions);
/*!
* \brief Function to set the local state.
* \details emits ScStwClient::stateChanged() when the new state does not match the old one.
* \see stateChanged()
* \param newState the state to change to
*/
void setState(ScStwClient::State newState);
signals:
/*!
* \brief Is emitted, when the connection state changes
*/
void stateChanged();
/*!
* \brief Is emitted, whenever a reply is recieved which does not match any requests
*
* \param reply contains the reply
*/
void gotUnexpectedMessage(QString message);
/*!
* \brief Is emitted, when an update signal from the basestation is recieved
*
* \param data
*/
void gotSignal(ScStw::SignalKey key, QVariant data);
/*!
* \brief Is emitted, when there is any network error
* \param error
*/
void gotError(QAbstractSocket::SocketError error);
/*!
* \brief Is emitted, when the extensions of the base station changed
*/
void extensionsChanged();
};
extern ScStwClient * pGlobalScStwClient;
#endif // SCSTWCLIENT_H