Add new constant for progress in percent.
This commit is contained in:
parent
c339941585
commit
d7a4d98a29
@ -31,6 +31,16 @@ namespace internal {
|
||||
static constexpr const char *GIT_MARKER{"<GIT>"};
|
||||
static constexpr const char *ISMAS_MARKER{"<ISMAS>"};
|
||||
|
||||
static constexpr const int PERCENT_CHECK_ISMAS_CONNECIVITY{10};
|
||||
static constexpr const int PERCENT_CHECK_UPDATE_REQUEST{20};
|
||||
static constexpr const int PERCENT_CHECK_CUSTOMER_REPOSITORY{30};
|
||||
static constexpr const int PERCENT_INSTALL_SW_PACKETS_NOACTION{40};
|
||||
static constexpr const int PERCENT_INSTALL_SW_PACKETS{50};
|
||||
static constexpr const int PERCENT_INSTALL_DC_CONFIGURATION{60};
|
||||
static constexpr const int PERCENT_SYNCHRONIZE_REPO_AND_FILESYS{70};
|
||||
static constexpr const int PERCENT_UPDATE_DC{80};
|
||||
static constexpr const int PERCENT_SHOW_FINAL_STATUS{90};
|
||||
|
||||
int read1stLineOfFile(QString fileName);
|
||||
QString customerRepoRoot();
|
||||
QString customerRepoDir();
|
||||
|
336
common/ismas/ApismClient.cpp
Normal file
336
common/ismas/ApismClient.cpp
Normal file
@ -0,0 +1,336 @@
|
||||
#include "ApismClient.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QListIterator>
|
||||
#include <QScopedPointer>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
|
||||
|
||||
ApismClient::ApismClient(QObject *parent)
|
||||
: QObject(parent)
|
||||
, lastError(0)
|
||||
, lastErrorDescription("")
|
||||
, currentRequest(ISMAS::REQUEST::NO_REQUEST)
|
||||
, retryCounter(0)
|
||||
, flagValidParameter(false)
|
||||
{
|
||||
this->apismTcpSendClient.reset(new ApismTcpClient("127.0.0.1", "7777", ApismTcpClient::ExpectedResponse::STATE, this));
|
||||
this->apismTcpRequestResponseClient.reset(new ApismTcpClient("127.0.0.1", "7778", ApismTcpClient::ExpectedResponse::JSON, this));
|
||||
|
||||
this->apismTcpRequestResponseClient->setResponseTimeout(30000);
|
||||
|
||||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::receivedData,
|
||||
this, &ApismClient::onReceivedResponse);
|
||||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::responseTimeout,
|
||||
this, &ApismClient::onRequestResponseClientResponseTimeout);
|
||||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectTimeout,
|
||||
this, &ApismClient::onRequestResponseClientConnectTimeout);
|
||||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionClosedByRemoteHost,
|
||||
this, &ApismClient::onRequestResponseClientConnectionClosedByRemoteHost);
|
||||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionRefusedError,
|
||||
this, &ApismClient::restartApism);
|
||||
|
||||
connect(apismTcpSendClient.get(), &ApismTcpClient::responseTimeout,
|
||||
this, &ApismClient::onSendClientResponseTimeout);
|
||||
connect(apismTcpSendClient.get(), &ApismTcpClient::connectionRefusedError,
|
||||
this, &ApismClient::restartApism);
|
||||
|
||||
|
||||
// not needed as APISM closes the socket after we send data, so readyRead()
|
||||
// might not even fire
|
||||
// connect(&m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
|
||||
|
||||
// defined for Qt >= 5.15, we have 5.12
|
||||
// qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||
// connect(&m_socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
|
||||
// this, SLOT(onSocketError(&QAbstractSocket::SocketError)));
|
||||
|
||||
// switch of DEBUG:
|
||||
this->apismTcpSendClient->setDebug(true);
|
||||
this->apismTcpRequestResponseClient->setDebug(true);
|
||||
}
|
||||
|
||||
ApismClient::~ApismClient() {
|
||||
}
|
||||
|
||||
void ApismClient::restartApism() {
|
||||
QProcess::startDetached("/bin/systemctl", {"restart", "apism"});
|
||||
}
|
||||
|
||||
|
||||
void ApismClient::sendSelfTest() {
|
||||
this->currentRequest = ISMAS::REQUEST::SELF;
|
||||
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_SELF#J={}");
|
||||
}
|
||||
|
||||
void ApismClient::sendRequestParameter() {
|
||||
this->currentRequest = ISMAS::REQUEST::PARAMETER;
|
||||
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_ISMASPARAMETER#J={}");
|
||||
}
|
||||
|
||||
void ApismClient::handleISMASResponseError()
|
||||
{
|
||||
switch (this->currentRequest) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: " << currentRequest;
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
//emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
//emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
//emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||
break;
|
||||
}
|
||||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||
}
|
||||
|
||||
|
||||
void ApismClient::handleISMASOfflineResponseError()
|
||||
{
|
||||
nsApismInterface::RESULT_STATE resultState;
|
||||
|
||||
if (this->retryCounter < 50) {
|
||||
resultState = nsApismInterface::RESULT_STATE::ERROR_RETRY;
|
||||
this->retryCounter++;
|
||||
}
|
||||
else {
|
||||
resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
|
||||
this->retryCounter = 0;
|
||||
}
|
||||
|
||||
qCritical() << "ApismClient::handleISMASOfflineResponseError(): currentRequest is " << this->currentRequest;
|
||||
|
||||
|
||||
switch (this->currentRequest) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
//emit this->sendMininformPingResponse(resultState, QJsonObject());
|
||||
//break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
emit this->sendReqSelfResponse(resultState, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
emit this->sendReqParameterResponse(resultState, QJsonObject());
|
||||
break;
|
||||
}
|
||||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||
|
||||
// note: this does not work here, because a new request within this error handling method
|
||||
// must use a new socket connection!
|
||||
// This does not work with an allready open socket connection.
|
||||
/* Communication to APISM must be in the following way:
|
||||
* 1) establish socket connection
|
||||
* 2) send your request to this socket
|
||||
* 3) wait for a possible answer
|
||||
* 4) receive the answer
|
||||
* 5) close socket connection
|
||||
*
|
||||
* => a request can only be sent to apsim if the socket is closed!
|
||||
* => apism (socket) is blocked systemwide until socket is closed!
|
||||
* =>
|
||||
*/
|
||||
|
||||
//this->sendSelfTest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ApismClient::private_handleErrorResponse(QString errorString)
|
||||
{
|
||||
qCritical() << "------------------------------------------------------";
|
||||
qCritical() << "ApismClient::private_handleErrorResponse(" << errorString << ")";
|
||||
qCritical() << " this->retryCounter = " << this->retryCounter;
|
||||
qCritical() << "------------------------------------------------------";
|
||||
|
||||
this->handleISMASOfflineResponseError();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
{\r\n \"REQ_START#53365_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||||
\r\n \"Response\": {\r\n \"Result\": \"ERR:Ung<6E>ltiger Datums-String: \"\r\n }\r\n}
|
||||
*/
|
||||
|
||||
/*
|
||||
: ISMAS received: "{\r\n \"REQ_PING#30844_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||||
"PING": { "IsAviable": "TRUE" }
|
||||
}"
|
||||
*/
|
||||
|
||||
//void ApismClient::onSendClientResponseTimeout()
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
void ApismClient::private_handleReqSelfResponse(QJsonObject response)
|
||||
{
|
||||
bool ismasConnected = response["ISMAS"].toBool();
|
||||
QString brokerConnectedString = response["Broker"].toString();
|
||||
|
||||
qCritical() << "ApismClient::handleReqSelfResponse() " << endl
|
||||
<< " ismasConnected = " << ismasConnected << endl
|
||||
<< " brokerConnectedString = " << brokerConnectedString;
|
||||
|
||||
/* possible values: "Restart connection"
|
||||
* "Connected"
|
||||
* "NOT CONNECTED"
|
||||
*/
|
||||
if (brokerConnectedString == "NOT CONNECTED") {
|
||||
qCritical() << "ApismClient: \"NOT CONNECTED\": restart APISM";
|
||||
this->restartApism();
|
||||
}
|
||||
|
||||
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* sample parameter response:
|
||||
{
|
||||
"REQ_ISMASPARAMETER#4210959_Response": {
|
||||
"Aknoledge": "OK"
|
||||
},
|
||||
"Dev_ID": {
|
||||
"Device_Type": "2020",
|
||||
"Custom_ID": 332,
|
||||
"Device_ID": 99
|
||||
},
|
||||
"Fileupload": {
|
||||
"TRG": ""
|
||||
},
|
||||
"Parameter": {
|
||||
"Location": "An Der Bahn 11",
|
||||
"Group": "Group1",
|
||||
"Zone": "Zone1",
|
||||
"Name": "PSA",
|
||||
"SecNumber": "0",
|
||||
"LastAcc": "0",
|
||||
"GPSLat": "49.6062",
|
||||
"GPSLon": "12.1244",
|
||||
"TarifID": "none",
|
||||
"UserTextID": "1"
|
||||
"TERMINALID": "",
|
||||
"TERMINALKEY": ""
|
||||
},
|
||||
"Lock": {
|
||||
"Locked": "0"
|
||||
}
|
||||
}
|
||||
*/
|
||||
void ApismClient::private_handleParameterResponse(QJsonObject response)
|
||||
{
|
||||
// extract location info and store location info in persistent data:
|
||||
QJsonValue jsonSubVal_Location;
|
||||
jsonSubVal_Location = response["Location"];
|
||||
|
||||
QString locationString = jsonSubVal_Location.toString("no location");
|
||||
|
||||
//this->persistentData->setParameter("Location", locationString);
|
||||
|
||||
// feature UserText
|
||||
QJsonValue jsonSubVal_UserText;
|
||||
jsonSubVal_UserText = response["UserTextID"];
|
||||
QString userTextIdString = jsonSubVal_UserText.toString("0");
|
||||
//this->persistentData->setParameter("UserTextID", userTextIdString);
|
||||
|
||||
// TERMINALID
|
||||
//QJsonValue jsonSubVal_TERMINALID;
|
||||
//jsonSubVal_TERMINALID = response["TERMINALID"];
|
||||
//QString terminalIdString = jsonSubVal_TERMINALID.toString("");
|
||||
//QString terminalIdFile = this->m_config->getSystemDataPath() + "TERMINALID";
|
||||
//QString terminalIdStringOrigin = ATBSystem::readPSAConfigString(terminalIdFile);
|
||||
//if ( (terminalIdString.size() > 1) &&
|
||||
// (terminalIdString != terminalIdStringOrigin))
|
||||
//{
|
||||
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALID: " << terminalIdString;
|
||||
// ATBSystem::setPSAConfigString(terminalIdFile, terminalIdString);
|
||||
//}
|
||||
|
||||
// TERMINALKEY
|
||||
//QJsonValue jsonSubVal_TERMINALKEY;
|
||||
//jsonSubVal_TERMINALKEY = response["TERMINALKEY"];
|
||||
//QString terminalKeyString = jsonSubVal_TERMINALKEY.toString("");
|
||||
//QString terminalJeyFile = this->m_config->getSystemDataPath() + "TERMINALKEY";
|
||||
//QString terminalKeyStringOrigin = ATBSystem::readPSAConfigString(terminalJeyFile);
|
||||
//if ( (terminalKeyString.size() > 1) &&
|
||||
// (terminalKeyString != terminalKeyStringOrigin))
|
||||
//{
|
||||
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALKEY: " << terminalKeyString;
|
||||
//
|
||||
|
||||
// ATBSystem::setPSAConfigString(terminalJeyFile, terminalKeyString);
|
||||
//}
|
||||
|
||||
|
||||
//qCritical() << "ApismClient::handleParameterResponse() " << endl
|
||||
// << " Location = " << locationString << endl
|
||||
// << " UserTextID = " << userTextIdString << endl
|
||||
// << " TERMINALID = " << terminalIdString << endl
|
||||
// << " TERMINALKEY = " << terminalKeyString;
|
||||
|
||||
|
||||
if (locationString != "no location") {
|
||||
this->flagValidParameter = true;
|
||||
emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||
}
|
||||
}
|
||||
|
||||
void ApismClient::private_handleFileUploadResponse(QJsonObject response) {
|
||||
QJsonValue jsonSubVal_TRG{response["TRG"]};
|
||||
if (jsonSubVal_TRG.isUndefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool updateRequested = (jsonSubVal_TRG.toString("") == "WAIT");
|
||||
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* operators
|
||||
*/
|
||||
QDebug operator<< (QDebug debug, ISMAS::REQUEST request)
|
||||
{
|
||||
switch(request) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
debug << QString("ISMAS::REQUEST::NO_REQUEST");
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
debug << QString("ISMAS::REQUEST::PING");
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
debug << QString("ISMAS::REQUEST::SELF");
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
debug << QString("ISMAS::REQUEST::PARAMETER");
|
||||
break;
|
||||
}
|
||||
return debug;
|
||||
}
|
||||
|
||||
QString& operator<< (QString& str, ISMAS::REQUEST request)
|
||||
{
|
||||
switch(request) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
str = QString("ISMAS::REQUEST::NO_REQUEST");
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
str = QString("ISMAS::REQUEST::PING");
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
str = QString("ISMAS::REQUEST::SELF");
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
str = QString("ISMAS::REQUEST::PARAMETER");
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
99
common/ismas/ApismClient.h
Normal file
99
common/ismas/ApismClient.h
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef APISM_CLIENT_H_INCLUDED
|
||||
#define APISM_CLIENT_H_INCLUDED
|
||||
|
||||
#include "ISMASData.h"
|
||||
#include "ApismTcpClient.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
#include <QTcpSocket>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonValue>
|
||||
#include <QScopedPointer>
|
||||
|
||||
|
||||
QDebug operator<<(QDebug debug, ISMAS::REQUEST request);
|
||||
QString& operator<<(QString& str, ISMAS::REQUEST request);
|
||||
|
||||
namespace nsApismInterface {
|
||||
enum class RESULT_STATE : quint8 {
|
||||
SUCCESS = 1,
|
||||
ERROR_BACKEND = 2, // error from backand (e.g. backend replies with error)
|
||||
ERROR_NETWORK = 3, // error from network (e.g. host not available)
|
||||
ERROR_TIMEOUT = 4, // the operation timed out
|
||||
ERROR_PROCESS = 5, // internal plugin error (e.g. bug in implementation)
|
||||
ERROR_RETRY = 6, // retry operation
|
||||
INFO = 7
|
||||
};
|
||||
}
|
||||
|
||||
// class ISMAS::EventData;
|
||||
class ApismClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ApismClient(QObject *parent = 0);
|
||||
virtual ~ApismClient() = 0;
|
||||
|
||||
quint32 getLastError();
|
||||
const QString & getLastErrorDescription();
|
||||
|
||||
ISMAS::REQUEST getCurrentRequest() const { return currentRequest; }
|
||||
void setCurrentRequest(ISMAS::REQUEST r) { currentRequest = r; }
|
||||
|
||||
void resetRetryCounter() { retryCounter = 0; }
|
||||
int getRetryCounter() const { return retryCounter; }
|
||||
int incrRetryCounter() { return ++retryCounter; }
|
||||
|
||||
ApismTcpClient *tcpSendClient() { return apismTcpSendClient.get(); }
|
||||
ApismTcpClient *tcpRequestResponseClient() { return apismTcpRequestResponseClient.get(); }
|
||||
|
||||
public slots:
|
||||
void sendSelfTest();
|
||||
void sendRequestParameter();
|
||||
void restartApism();
|
||||
|
||||
signals:
|
||||
void sendReqSelfResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||
void sendReqParameterResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||
|
||||
private slots:
|
||||
virtual void onReceivedResponse(QByteArray response) = 0;
|
||||
virtual void onSendClientResponseTimeout() = 0;
|
||||
virtual void onRequestResponseClientResponseTimeout() = 0;
|
||||
virtual void onRequestResponseClientConnectTimeout() = 0;
|
||||
virtual void onRequestResponseClientConnectionClosedByRemoteHost() = 0;
|
||||
|
||||
private:
|
||||
QScopedPointer<ApismTcpClient> apismTcpSendClient;
|
||||
QScopedPointer<ApismTcpClient> apismTcpRequestResponseClient;
|
||||
|
||||
quint32 lastError;
|
||||
QString lastErrorDescription;
|
||||
|
||||
ISMAS::REQUEST currentRequest;
|
||||
|
||||
// counter, incremented if we get an offline response from ISMAS
|
||||
// causes a resend of the currentRequest.
|
||||
int retryCounter;
|
||||
|
||||
// true, if ISMAS REQ_ISAMASPARAMETER got a valid response
|
||||
bool flagValidParameter;
|
||||
|
||||
void private_handlePingResponse(QJsonObject response);
|
||||
void private_handleReqSelfResponse(QJsonObject response);
|
||||
void private_handleReqPingResponse(QJsonObject response);
|
||||
void private_handleParameterResponse(QJsonObject response);
|
||||
void private_handleFileUploadResponse(QJsonObject response);
|
||||
void private_handleErrorResponse(QString errorString);
|
||||
|
||||
public:
|
||||
void handleISMASResponseError();
|
||||
void handleISMASOfflineResponseError();
|
||||
};
|
||||
|
||||
#endif // APISM_CLIENT_H_INCLUDED
|
216
common/ismas/ApismClientForUpdate.cpp
Normal file
216
common/ismas/ApismClientForUpdate.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
#include "ApismClientForUpdate.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
ApismClientForUpdate::ApismClientForUpdate(QObject *parent)
|
||||
: ApismClient(parent) {
|
||||
|
||||
}
|
||||
|
||||
ApismClientForUpdate::~ApismClientForUpdate() {
|
||||
|
||||
}
|
||||
|
||||
void ApismClientForUpdate::sendCmdEvent(ISMAS::EventData eventData) {
|
||||
// QScopedPointer<ISMAS::EventData> eventData(new ISMAS::EventData());
|
||||
/*
|
||||
struct EventData : public QJsonObject {
|
||||
struct : public QJsonObject {
|
||||
QJsonValue reason;
|
||||
QJsonValue timestamp;
|
||||
QJsonValue eventID;
|
||||
QJsonValue event;
|
||||
QJsonValue eventState;
|
||||
struct : public QJsonObject {
|
||||
QJsonValue percent;
|
||||
QJsonValue resultCode;
|
||||
QJsonValue step;
|
||||
QJsonValue stepResult;
|
||||
QJsonValue Version;
|
||||
} parameter;
|
||||
} newsToIsmas;
|
||||
};
|
||||
|
||||
"\"REASON\":\"SW_UP\","
|
||||
"\"TIMESTAMP\":\"%s\","
|
||||
"\"EVENT_ID\":\"0\","
|
||||
"\"EVENT\":\"%s\","
|
||||
"\"EVENTSTATE\":1,"
|
||||
"\"PARAMETER\": {"
|
||||
"\"PERCENT\" : %d,"
|
||||
"\"RESULTCODE\" : %d,"
|
||||
"\"STEP\" : \"%s\","
|
||||
"\"STEP_RESULT\" : \"%s\","
|
||||
"\"VERSION\" : \"%s\""
|
||||
"}"
|
||||
"}", ts.toStdStr
|
||||
|
||||
*/
|
||||
//eventData->newsToIsmas.reason = data.newsToIsmas;
|
||||
eventData.insert("REASON", eventData.newsToIsmas.reason);
|
||||
eventData.insert("TIMESTAMP", eventData.newsToIsmas.timestamp);
|
||||
eventData.insert("EVENT_ID", eventData.newsToIsmas.eventID);
|
||||
eventData.insert("EVENT", eventData.newsToIsmas.event);
|
||||
eventData.insert("EVENT_STATE", eventData.newsToIsmas.eventState);
|
||||
|
||||
QJsonObject parameterJsonObject;
|
||||
parameterJsonObject.insert("PERCENT", eventData.newsToIsmas.parameter.percent);
|
||||
parameterJsonObject.insert("RESULTCODE", eventData.newsToIsmas.parameter.resultCode);
|
||||
parameterJsonObject.insert("STEP", eventData.newsToIsmas.parameter.step);
|
||||
parameterJsonObject.insert("STEP_RESULT", eventData.newsToIsmas.parameter.stepResult);
|
||||
parameterJsonObject.insert("VERSION", eventData.newsToIsmas.parameter.version);
|
||||
|
||||
eventData.insert("PARAMETER", parameterJsonObject);
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << eventData;
|
||||
|
||||
QJsonDocument jsonDoc(eventData);
|
||||
QByteArray data = "#M=APISM#C=CMD_EVENT#J=";
|
||||
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << data;
|
||||
|
||||
tcpSendClient()->sendData(data);
|
||||
}
|
||||
|
||||
|
||||
void ApismClientForUpdate::onReceivedResponse(QByteArray response) {
|
||||
// get the root object
|
||||
QJsonParseError jsonParseError;
|
||||
QJsonDocument responseDoc = QJsonDocument::fromJson(response, &jsonParseError);
|
||||
|
||||
if (jsonParseError.error != QJsonParseError::NoError) {
|
||||
qCritical() << "ApismClient::onReceivedResponse() response is no json data:";
|
||||
qCritical() << " Error: " << jsonParseError.errorString();
|
||||
|
||||
// workaround for REQ_SELF and offline
|
||||
if (this->getCurrentRequest() == ISMAS::REQUEST::SELF) {
|
||||
if (response.contains("Connecting...")) {
|
||||
qCritical() << " -> Connecting...";
|
||||
return;
|
||||
}
|
||||
if (response.contains("ISMAS is offline")) {
|
||||
this->restartApism();
|
||||
qCritical() << " -> Workaround: restart APISM";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.contains("ISMAS is offline")) {
|
||||
this->handleISMASOfflineResponseError();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
this->handleISMASResponseError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject rootObject = responseDoc.object();
|
||||
QStringList rootObjectKeys = rootObject.keys();
|
||||
|
||||
// DEBUG
|
||||
qCritical() << "ApismClient::onReceivedResponse(): objects: " << rootObjectKeys;
|
||||
// results to:
|
||||
// ApismClient::onReceivedResponse(): objects: ("REQ_START#60044_Response", "Response")
|
||||
|
||||
if(rootObjectKeys.indexOf(QRegularExpression("^CMD_GET_APISMSTATUS.*")) >= 0) {
|
||||
resetRetryCounter();
|
||||
//this->private_handleReqSelfResponse(rootObject["CMD_GET_APISMSTATUS_RESPONSE#0"].toObject());
|
||||
}
|
||||
else
|
||||
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_ISMASPARAMETER.*")) >= 0) {
|
||||
resetRetryCounter();
|
||||
//this->private_handleParameterResponse(rootObject["Parameter"].toObject());
|
||||
}
|
||||
else
|
||||
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_PING.*")) >= 0) {
|
||||
resetRetryCounter();
|
||||
//this->private_handleReqPingResponse(rootObject["PING"].toObject());
|
||||
}
|
||||
else
|
||||
if(rootObjectKeys.indexOf(QRegularExpression("^error")) >= 0) {
|
||||
// handle error objects
|
||||
//this->private_handleErrorResponse(rootObject["error"].toString());
|
||||
}
|
||||
else {
|
||||
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: ";
|
||||
qCritical() << " currentRequestName: " << getCurrentRequest();
|
||||
qCritical() << " rootObject.keys(): " << rootObjectKeys;
|
||||
this->handleISMASResponseError();
|
||||
return;
|
||||
}
|
||||
|
||||
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
|
||||
}
|
||||
|
||||
void ApismClientForUpdate::onSendClientResponseTimeout() {
|
||||
|
||||
}
|
||||
|
||||
void ApismClientForUpdate::onRequestResponseClientResponseTimeout() {
|
||||
qCritical() << "ApismClient::onRequestResponseClientResponseTimeout(): currentRequest is " << this->getCurrentRequest();
|
||||
|
||||
switch (this->getCurrentRequest()) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
//emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
//emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
//emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||
break;
|
||||
}
|
||||
|
||||
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
|
||||
}
|
||||
|
||||
void ApismClientForUpdate::onRequestResponseClientConnectTimeout() {
|
||||
|
||||
qCritical() << "ApismClient::onRequestResponseClientConnectTimeout(): currentRequest is " << this->getCurrentRequest();
|
||||
|
||||
nsApismInterface::RESULT_STATE resultState;
|
||||
|
||||
resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
|
||||
|
||||
switch (this->getCurrentRequest()) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
qCritical() << "ApismClient::onRequestResponseClientConnectTimeout() for unknown Request: " << getCurrentRequest();
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
//emit this->sendMininformPingResponse(resultState, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
//emit this->sendReqSelfResponse(resultState, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
//emit this->sendReqParameterResponse(resultState, QJsonObject());
|
||||
break;
|
||||
}
|
||||
|
||||
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
|
||||
}
|
||||
|
||||
void ApismClientForUpdate::onRequestResponseClientConnectionClosedByRemoteHost() {
|
||||
nsApismInterface::RESULT_STATE resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
|
||||
|
||||
switch (this->getCurrentRequest()) {
|
||||
case ISMAS::REQUEST::NO_REQUEST:
|
||||
qCritical() << "ApismClient::onRequestResponseClientConnectionClosedByRemoteHost() for unknown Request: " << getCurrentRequest();
|
||||
break;
|
||||
case ISMAS::REQUEST::PING:
|
||||
//emit this->sendMininformPingResponse(resultState, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::SELF:
|
||||
emit this->sendReqSelfResponse(resultState, QJsonObject());
|
||||
break;
|
||||
case ISMAS::REQUEST::PARAMETER:
|
||||
emit this->sendReqParameterResponse(resultState, QJsonObject());
|
||||
break;
|
||||
}
|
||||
|
||||
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
|
||||
}
|
24
common/ismas/ApismClientForUpdate.h
Normal file
24
common/ismas/ApismClientForUpdate.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef APISM_CLIENT_FOR_UPDATE_H_INCLUDED
|
||||
#define APISM_CLIENT_FOR_UPDATE_H_INCLUDED
|
||||
|
||||
#include "ApismClient.h"
|
||||
|
||||
class ApismClientForUpdate : public ApismClient {
|
||||
public:
|
||||
explicit ApismClientForUpdate(QObject *parent = 0);
|
||||
virtual ~ApismClientForUpdate();
|
||||
|
||||
public slots:
|
||||
void sendCmdEvent(ISMAS::EventData);
|
||||
|
||||
private slots:
|
||||
virtual void onReceivedResponse(QByteArray response) override;
|
||||
virtual void onSendClientResponseTimeout() override;
|
||||
virtual void onRequestResponseClientResponseTimeout() override;
|
||||
virtual void onRequestResponseClientConnectTimeout() override;
|
||||
virtual void onRequestResponseClientConnectionClosedByRemoteHost() override;
|
||||
|
||||
};
|
||||
|
||||
#endif // APISM_CLIENT_FOR_UPDATE_H_INCLUDED
|
||||
|
564
common/ismas/ApismTcpClient.cpp
Normal file
564
common/ismas/ApismTcpClient.cpp
Normal file
@ -0,0 +1,564 @@
|
||||
#include "ApismTcpClient.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QTimer>
|
||||
|
||||
ApismMessage::ApismMessage() : state(MessageState::INVALID) { }
|
||||
|
||||
|
||||
ApismTcpClient::ApismTcpClient(const QString & hostname,
|
||||
const QString & port,
|
||||
ExpectedResponse expectedResponse,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, hostname(hostname)
|
||||
, port(port)
|
||||
, responseTimerTimeoutCounter(0)
|
||||
, flag_selfClosed(false)
|
||||
, resendCounter(0)
|
||||
, connectionRefusedCounter(0)
|
||||
, expectedResponse(expectedResponse)
|
||||
, isDebug(false)
|
||||
{
|
||||
this->responseTimeoutTimer = new QTimer(this);
|
||||
this->responseTimeoutTimer->setInterval(10000);
|
||||
this->responseTimeoutTimer->setSingleShot(true);
|
||||
|
||||
connect(this->responseTimeoutTimer, SIGNAL(timeout()), this, SLOT(onResponseTimeoutTimerTimeout()));
|
||||
|
||||
this->connectTimeoutTimer = new QTimer(this);
|
||||
this->connectTimeoutTimer->setInterval(10000);
|
||||
this->connectTimeoutTimer->setSingleShot(true);
|
||||
|
||||
connect(this->connectTimeoutTimer, SIGNAL(timeout()), this, SLOT(onConnectTimeoutTimerTimeout()));
|
||||
|
||||
socket = new QTcpSocket(this);
|
||||
connect(socket, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));
|
||||
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onSocketBytesWritten(qint64)));
|
||||
// note: from Qt 5.15 onward a new signal "errorOccurred" will be introduced which could be used whithout this static_cast.
|
||||
// see e.g. https://stackoverflow.com/questions/35655512/compile-error-when-connecting-qtcpsocketerror-using-the-new-qt5-signal-slot
|
||||
connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), this, &ApismTcpClient::onSocketErrorOccured);
|
||||
connect(socket, &QTcpSocket::stateChanged, this, &ApismTcpClient::onSocketStateChanged);
|
||||
|
||||
this->currentMessage = ApismMessage();
|
||||
}
|
||||
|
||||
|
||||
void ApismTcpClient::setResponseTimeout(const quint32 timeout_ms)
|
||||
{
|
||||
this->responseTimeoutTimer->setInterval(timeout_ms);
|
||||
}
|
||||
|
||||
void ApismTcpClient::setDebug(bool debug)
|
||||
{
|
||||
this->isDebug = debug;
|
||||
}
|
||||
|
||||
void ApismTcpClient::connectToHost()
|
||||
{
|
||||
this->connectTimeoutTimer->start();
|
||||
int portNumber = this->port.toInt();
|
||||
this->socket->connectToHost(QHostAddress(this->hostname), portNumber);
|
||||
}
|
||||
|
||||
void ApismTcpClient::connectToHost(const QString & hostname, const QString & port)
|
||||
{
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::connectToHost(" << hostname << ", " << port << ")";
|
||||
|
||||
this->connectTimeoutTimer->start();
|
||||
int portNumber = port.toInt();
|
||||
socket->connectToHost(hostname, portNumber);
|
||||
}
|
||||
|
||||
void ApismTcpClient::closeConnection()
|
||||
{
|
||||
this->flag_selfClosed = true;
|
||||
socket->close();
|
||||
}
|
||||
|
||||
bool ApismTcpClient::isConnected()
|
||||
{
|
||||
bool result = false;
|
||||
QAbstractSocket::SocketState socketState = socket->state();
|
||||
|
||||
switch (socketState) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
/* FALLTHRU */
|
||||
case QAbstractSocket::HostLookupState:
|
||||
/* FALLTHRU */
|
||||
case QAbstractSocket::ConnectingState:
|
||||
result = false;
|
||||
break;
|
||||
case QAbstractSocket::ConnectedState:
|
||||
/* FALLTHRU */
|
||||
case QAbstractSocket::BoundState:
|
||||
result = true;
|
||||
break;
|
||||
case QAbstractSocket::ClosingState:
|
||||
/* FALLTHRU */
|
||||
case QAbstractSocket::ListeningState:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief ApismTcpClient::sendData
|
||||
* @param message
|
||||
*
|
||||
* Enqueue message, and try to send it
|
||||
*/
|
||||
void ApismTcpClient::sendData(const QByteArray &message)
|
||||
{
|
||||
if (this->isDebug) {
|
||||
qCritical() << "ApismTcpClient::sendData(" << message << ")";
|
||||
}
|
||||
|
||||
this->sendQueue.enqueue(message);
|
||||
|
||||
this->sendData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ApismTcpClient::sendData
|
||||
*
|
||||
* Check connection and try to send message from queue.
|
||||
*/
|
||||
void ApismTcpClient::sendData()
|
||||
{
|
||||
if (this->sendQueue.size() == 0) {
|
||||
if (this->isDebug) {
|
||||
qCritical() << "ApismTcpClient::sendData()" << "no messages in send queue";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
if (this->isDebug) {
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::sendData() sendQueue.size() = " << this->sendQueue.size();
|
||||
}
|
||||
|
||||
switch (this->currentMessage.state) {
|
||||
case ApismMessage::MessageState::INVALID:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::NEW:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::RESEND:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::ANSWERED:
|
||||
// allow send message
|
||||
if (this->isConnected()) {
|
||||
this->private_sendData();
|
||||
}
|
||||
else {
|
||||
this->connectToHost();
|
||||
}
|
||||
break;
|
||||
case ApismMessage::MessageState::SENT:
|
||||
// wait for answer...
|
||||
if (this->isDebug) {
|
||||
qCritical() << " ... wait for answer";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ApismTcpClient::private_sendData
|
||||
*
|
||||
* Precondition:
|
||||
* - queue is not empty,
|
||||
* - socket state is connected
|
||||
* - current message is ANSWERED or INVALID
|
||||
*/
|
||||
void ApismTcpClient::private_sendData()
|
||||
{
|
||||
// take message from queue
|
||||
this->currentMessage.data = this->sendQueue.dequeue();
|
||||
this->currentMessage.state = ApismMessage::MessageState::SENT;
|
||||
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::send: " << QString(this->currentMessage.data);
|
||||
|
||||
socket->write(this->currentMessage.data);
|
||||
socket->flush();
|
||||
|
||||
// start timeoutTimer
|
||||
this->responseTimeoutTimer->start();
|
||||
}
|
||||
|
||||
|
||||
void ApismTcpClient::onSocketConnected()
|
||||
{
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << "): Connected!";
|
||||
|
||||
this->connectTimeoutTimer->stop();
|
||||
this->connectionRefusedCounter = 0;
|
||||
|
||||
switch (this->currentMessage.state) {
|
||||
case ApismMessage::MessageState::INVALID:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::NEW:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::RESEND:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::ANSWERED:
|
||||
// allow send next message
|
||||
if (this->sendQueue.size() > 0) {
|
||||
this->private_sendData();
|
||||
}
|
||||
break;
|
||||
case ApismMessage::MessageState::SENT:
|
||||
// wait for answer...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketDisconnected()
|
||||
{
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << "): Disconnected!";
|
||||
|
||||
if (!this->flag_selfClosed) {
|
||||
qCritical() << " -> SocketErrorString: " << socket->errorString();
|
||||
}
|
||||
this->flag_selfClosed = false;
|
||||
|
||||
if ( (socket->error() == QAbstractSocket::SocketError::RemoteHostClosedError) &&
|
||||
(this->responseTimeoutTimer->isActive()) )
|
||||
{
|
||||
this->responseTimeoutTimer->stop();
|
||||
qCritical() << " -> still waiting for response ";
|
||||
|
||||
switch (this->expectedResponse) {
|
||||
case ApismTcpClient::ExpectedResponse::STATE:
|
||||
// try resend:
|
||||
this->currentMessage.state = ApismMessage::MessageState::RESEND;
|
||||
// enqeue current message for resend:
|
||||
this->sendQueue.prepend(this->currentMessage.data);
|
||||
|
||||
this->sendData();
|
||||
break;
|
||||
case ApismTcpClient::ExpectedResponse::JSON:
|
||||
this->currentMessage.state = ApismMessage::MessageState::INVALID;
|
||||
emit this->connectionClosedByRemoteHost();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketBytesWritten(qint64 bytes)
|
||||
{
|
||||
if (this->isDebug) {
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onSocketBytesWritten() -> " << bytes << " bytes written";
|
||||
}
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketReadyRead()
|
||||
{
|
||||
QByteArray readData;
|
||||
|
||||
// stop timeoutTimer
|
||||
this->responseTimeoutTimer->stop();
|
||||
|
||||
readData = socket->readAll();
|
||||
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::received: " << QString(readData);
|
||||
|
||||
switch (this->expectedResponse) {
|
||||
case ApismTcpClient::ExpectedResponse::JSON:
|
||||
this->private_handleJSONResponse(readData);
|
||||
break;
|
||||
case ApismTcpClient::ExpectedResponse::STATE:
|
||||
this->private_handleStateResponse(readData);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (this->sendQueue.size() > 0) {
|
||||
QTimer::singleShot(1000,
|
||||
this,
|
||||
[this]() { this->sendData(); }
|
||||
);
|
||||
}
|
||||
else {
|
||||
this->flag_selfClosed = true;
|
||||
this->socket->close();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* response handler:
|
||||
*/
|
||||
void ApismTcpClient::private_handleJSONResponse(QByteArray & responseMessage)
|
||||
{
|
||||
emit this->receivedData(responseMessage);
|
||||
|
||||
// allow send next message:
|
||||
this->currentMessage.state = ApismMessage::MessageState::ANSWERED;
|
||||
this->resendCounter = 0;
|
||||
}
|
||||
|
||||
/* possible answers:
|
||||
* "RECORD SAVED" --> everything is ok
|
||||
* "RECORD WRITE ABORTED" --> initiate a (delayed) resend
|
||||
*
|
||||
*/
|
||||
void ApismTcpClient::private_handleStateResponse(QByteArray & responseMessage)
|
||||
{
|
||||
QString responseMessageString = QString(responseMessage);
|
||||
|
||||
if (responseMessageString.contains("ABORTED")) {
|
||||
// Try to resend later:
|
||||
this->currentMessage.state = ApismMessage::MessageState::RESEND;
|
||||
// enqeue current message for resend:
|
||||
this->sendQueue.prepend(this->currentMessage.data);
|
||||
}
|
||||
else
|
||||
if (responseMessageString.contains("RECORD SAVED")) {
|
||||
// allow send next message:
|
||||
this->currentMessage.state = ApismMessage::MessageState::ANSWERED;
|
||||
this->resendCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ApismTcpClient::onResponseTimeoutTimerTimeout()
|
||||
{
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onResponseTimeoutTimerTimeout():";
|
||||
|
||||
|
||||
switch (this->currentMessage.state) {
|
||||
case ApismMessage::MessageState::INVALID:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::NEW:
|
||||
/* FALLTHROUGH */
|
||||
case ApismMessage::MessageState::ANSWERED:
|
||||
// ignore
|
||||
qCritical() << " -> ignore timeout";
|
||||
return;
|
||||
break;
|
||||
case ApismMessage::MessageState::RESEND:
|
||||
qCritical() << " -> timeout (RESEND)";
|
||||
qCritical() << " -> resendCounter = " << this->resendCounter;
|
||||
switch (this->expectedResponse) {
|
||||
case ApismTcpClient::ExpectedResponse::STATE:
|
||||
// try resend:
|
||||
this->currentMessage.state = ApismMessage::MessageState::RESEND;
|
||||
// enqeue current message for resend:
|
||||
this->sendQueue.prepend(this->currentMessage.data);
|
||||
|
||||
this->sendData();
|
||||
break;
|
||||
case ApismTcpClient::ExpectedResponse::JSON:
|
||||
this->currentMessage.state = ApismMessage::MessageState::INVALID;
|
||||
emit this->responseTimeout();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ApismMessage::MessageState::SENT:
|
||||
// we still do not have a response:
|
||||
|
||||
switch (this->expectedResponse) {
|
||||
case ApismTcpClient::ExpectedResponse::STATE:
|
||||
// try resend:
|
||||
this->currentMessage.state = ApismMessage::MessageState::RESEND;
|
||||
// enqeue current message for resend:
|
||||
this->sendQueue.prepend(this->currentMessage.data);
|
||||
|
||||
this->sendData();
|
||||
break;
|
||||
case ApismTcpClient::ExpectedResponse::JSON:
|
||||
this->currentMessage.state = ApismMessage::MessageState::INVALID;
|
||||
emit this->responseTimeout();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// count resends
|
||||
this->resendCounter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ApismTcpClient::onConnectTimeoutTimerTimeout()
|
||||
{
|
||||
if (this->sendQueue.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onConnectTimeoutTimerTimeout() -> sendQueue.size() = " << this->sendQueue.size();
|
||||
|
||||
emit this->connectTimeout();
|
||||
}
|
||||
|
||||
|
||||
void ApismTcpClient::onSocketStateChanged(QAbstractSocket::SocketState socketState)
|
||||
{
|
||||
QString msg;
|
||||
|
||||
switch (socketState) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
msg = "UnconnectedState";
|
||||
break;
|
||||
case QAbstractSocket::HostLookupState:
|
||||
msg = "HostLookupState";
|
||||
break;
|
||||
case QAbstractSocket::ConnectingState:
|
||||
msg = "ConnectingState";
|
||||
break;
|
||||
case QAbstractSocket::ConnectedState:
|
||||
msg = "ConnectedState";
|
||||
break;
|
||||
case QAbstractSocket::BoundState:
|
||||
msg = "BoundState";
|
||||
break;
|
||||
case QAbstractSocket::ClosingState:
|
||||
msg = "ClosingState";
|
||||
break;
|
||||
case QAbstractSocket::ListeningState:
|
||||
msg = "ListeningState";
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->isDebug) {
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onSocketStateChanged() to: " << msg;
|
||||
}
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketErrorOccured(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
QString msg;
|
||||
bool flagReconnect = false;
|
||||
|
||||
switch (socketError) {
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
msg = "ConnectionRefusedError";
|
||||
flagReconnect = true;
|
||||
this->private_handleConnectionRefusedError();
|
||||
break;
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
msg = "RemoteHostClosedError";
|
||||
break;
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
msg = "HostNotFoundError";
|
||||
break;
|
||||
case QAbstractSocket::SocketAccessError:
|
||||
msg = "SocketAccessError";
|
||||
break;
|
||||
case QAbstractSocket::SocketResourceError:
|
||||
msg = "SocketResourceError";
|
||||
break;
|
||||
case QAbstractSocket::SocketTimeoutError:
|
||||
msg = "SocketTimeoutError";
|
||||
break;
|
||||
case QAbstractSocket::DatagramTooLargeError:
|
||||
msg = "DatagramTooLargeError";
|
||||
break;
|
||||
case QAbstractSocket::NetworkError:
|
||||
msg = "NetworkError";
|
||||
break;
|
||||
case QAbstractSocket::AddressInUseError:
|
||||
msg = "AddressInUseError";
|
||||
break;
|
||||
case QAbstractSocket::SocketAddressNotAvailableError:
|
||||
msg = "SocketAddressNotAvailableError";
|
||||
break;
|
||||
case QAbstractSocket::UnsupportedSocketOperationError:
|
||||
msg = "UnsupportedSocketOperationError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
||||
msg = "ProxyAuthenticationRequiredError";
|
||||
break;
|
||||
case QAbstractSocket::SslHandshakeFailedError:
|
||||
msg = "SslHandshakeFailedError";
|
||||
break;
|
||||
case QAbstractSocket::UnfinishedSocketOperationError:
|
||||
msg = "UnfinishedSocketOperationError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyConnectionRefusedError:
|
||||
msg = "ProxyConnectionRefusedError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyConnectionClosedError:
|
||||
msg = "ProxyConnectionClosedError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||
msg = "ProxyConnectionTimeoutError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyNotFoundError:
|
||||
msg = "ProxyNotFoundError";
|
||||
break;
|
||||
case QAbstractSocket::ProxyProtocolError:
|
||||
msg = "ProxyProtocolError";
|
||||
break;
|
||||
case QAbstractSocket::OperationError:
|
||||
msg = "OperationError";
|
||||
break;
|
||||
case QAbstractSocket::SslInternalError:
|
||||
msg = "SslInternalError";
|
||||
break;
|
||||
case QAbstractSocket::SslInvalidUserDataError:
|
||||
msg = "SslInvalidUserDataError";
|
||||
break;
|
||||
case QAbstractSocket::TemporaryError:
|
||||
msg = "TemporaryError";
|
||||
break;
|
||||
case QAbstractSocket::UnknownSocketError:
|
||||
msg = "UnknownSocketError";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::ApismTcpClient::onSocketErrorOccured() -> " << msg;
|
||||
|
||||
if (flagReconnect) {
|
||||
// try to reconnect for sending:
|
||||
if (this->sendQueue.size() > 0) {
|
||||
QTimer::singleShot(1000,
|
||||
this,
|
||||
[this]() { this->connectToHost(); }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ApismTcpClient::private_handleConnectionRefusedError()
|
||||
{
|
||||
if (this->connectionRefusedCounter > 5) {
|
||||
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::ApismTcpClient::connectionRefusedError()";
|
||||
this->connectionRefusedCounter = 0;
|
||||
emit this->connectionRefusedError();
|
||||
}
|
||||
else {
|
||||
this->connectionRefusedCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QDebug operator<<(QDebug debug, ApismTcpClient::ExpectedResponse response)
|
||||
{
|
||||
switch (response) {
|
||||
case ApismTcpClient::ExpectedResponse::JSON:
|
||||
debug << "JSON";
|
||||
break;
|
||||
case ApismTcpClient::ExpectedResponse::STATE:
|
||||
debug << "STATE";
|
||||
break;
|
||||
}
|
||||
return debug;
|
||||
}
|
116
common/ismas/ApismTcpClient.h
Normal file
116
common/ismas/ApismTcpClient.h
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef APISMTCPCLIENT_H
|
||||
#define APISMTCPCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QAbstractSocket>
|
||||
#include <QByteArray>
|
||||
#include <QQueue>
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
||||
class ApismMessage
|
||||
{
|
||||
public:
|
||||
|
||||
enum class MessageState {
|
||||
INVALID,
|
||||
NEW,
|
||||
SENT,
|
||||
ANSWERED,
|
||||
RESEND
|
||||
};
|
||||
MessageState state;
|
||||
|
||||
QByteArray data;
|
||||
|
||||
ApismMessage();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class ApismTcpClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class ExpectedResponse {
|
||||
JSON,
|
||||
STATE
|
||||
};
|
||||
|
||||
explicit ApismTcpClient(const QString & hostname, const QString & port, ExpectedResponse expectedResponse, QObject *parent = nullptr);
|
||||
bool isConnected();
|
||||
|
||||
void connectToHost();
|
||||
void connectToHost(const QString & hostname, const QString & port);
|
||||
void setResponseTimeout(const quint32 timeout_ms);
|
||||
|
||||
// socket is implicitely closed by APISM
|
||||
void closeConnection();
|
||||
|
||||
void sendData(const QByteArray & message);
|
||||
void sendData();
|
||||
|
||||
void setDebug(bool debug);
|
||||
|
||||
private slots:
|
||||
// socket interface
|
||||
void onSocketConnected();
|
||||
void onSocketDisconnected();
|
||||
void onSocketBytesWritten(qint64 bytes);
|
||||
void onSocketReadyRead();
|
||||
void onSocketStateChanged(QAbstractSocket::SocketState socketState);
|
||||
void onSocketErrorOccured(QAbstractSocket::SocketError socketError);
|
||||
|
||||
signals:
|
||||
void receivedData(QByteArray response);
|
||||
|
||||
void responseTimeout();
|
||||
void connectTimeout();
|
||||
void connectionClosedByRemoteHost();
|
||||
void connectionRefusedError();
|
||||
|
||||
private:
|
||||
QTcpSocket *socket;
|
||||
|
||||
QQueue<QByteArray> sendQueue;
|
||||
ApismMessage currentMessage;
|
||||
|
||||
QString hostname;
|
||||
QString port;
|
||||
|
||||
QTimer *responseTimeoutTimer;
|
||||
quint8 responseTimerTimeoutCounter;
|
||||
|
||||
QTimer *connectTimeoutTimer;
|
||||
|
||||
void private_sendData();
|
||||
bool flag_selfClosed;
|
||||
|
||||
int resendCounter;
|
||||
int connectionRefusedCounter;
|
||||
|
||||
ExpectedResponse expectedResponse;
|
||||
|
||||
void private_handleJSONResponse(QByteArray & responseMessage);
|
||||
void private_handleTextResponse(QByteArray & responseMessage);
|
||||
void private_handleStateResponse(QByteArray & responseMessage);
|
||||
|
||||
void private_handleConnectionRefusedError();
|
||||
|
||||
bool isDebug;
|
||||
|
||||
public slots:
|
||||
void onResponseTimeoutTimerTimeout();
|
||||
void onConnectTimeoutTimerTimeout();
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, ApismTcpClient::ExpectedResponse response);
|
||||
|
||||
|
||||
#endif // APISMTCPCLIENT_H
|
106
common/ismas/ISMASData.h
Normal file
106
common/ismas/ISMASData.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef ISMASDATA_H
|
||||
#define ISMASDATA_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace ISMAS {
|
||||
|
||||
static QString computeTimeStamp() {
|
||||
QDateTime const local(QDateTime::currentDateTime());
|
||||
|
||||
QDateTime utc(local);
|
||||
utc.setTimeSpec(Qt::UTC);
|
||||
|
||||
int const diff = (int)local.secsTo(utc); // diff between UTC and local time
|
||||
|
||||
QTime t(0, 0, 0);
|
||||
t = t.addSecs((uint)diff);
|
||||
|
||||
QString const st(QString("%1%2").arg(diff < 0 ? "-" : "+").arg(t.toString("hh:mm")));
|
||||
return QString (local.toString(Qt::ISODateWithMs) + st);
|
||||
}
|
||||
|
||||
//
|
||||
// Note:
|
||||
// ! After U0002 immer ein CMD_SENDVERSION
|
||||
// ! Only U0002 and U0003 finish the Update process.
|
||||
// ! U0001: Update finished but not activated
|
||||
// ! U0002: Update finished and activated
|
||||
// ! U0003: Update finished but FAILed.
|
||||
//
|
||||
// #define _ISMAS_DONE "U0001" // 100%, Check: Resultcode: 0
|
||||
// #define _ISMAS_SET_WAIT_OK "U0002" // empty WAIT-button (""), ResultCode: 0
|
||||
// #define _ISMAS_NO_UPDATE_NECESSARY "M0100" // empty WAIT-button (""), ResultCode: 0
|
||||
// #define _ISMAS_FAILURE "U0003" // FAIL
|
||||
// #define _ISMAS_CONTINUE "U0010" // %-values: update running, result codes according running step
|
||||
// #define _ISMAS_RESET_WAIT "ISMAS" // reset WAIT-button to "WAIT"
|
||||
// #define _ISMAS_TEST_TRIGGER "U0099" // check the WAIT-button
|
||||
|
||||
static constexpr const char *DONE {"U0001"};
|
||||
static constexpr const char *SET_WAIT_OK {"U0002"};
|
||||
static constexpr const char *NO_UPDATE_NECESSARY{"M0100"};
|
||||
static constexpr const char *FAILURE {"U0003"};
|
||||
static constexpr const char *CONTINUE {"U0010"};
|
||||
static constexpr const char *RESET_WAIT {"ISMAS"};
|
||||
static constexpr const char *TEST_TRIGGER {"U0099"};
|
||||
|
||||
struct EventData : public QJsonObject {
|
||||
struct : public QJsonObject {
|
||||
QJsonValue reason;
|
||||
QJsonValue timestamp;
|
||||
QJsonValue eventID;
|
||||
QJsonValue event;
|
||||
QJsonValue eventState;
|
||||
struct : public QJsonObject {
|
||||
QJsonValue percent;
|
||||
QJsonValue resultCode;
|
||||
QJsonValue step;
|
||||
QJsonValue stepResult;
|
||||
QJsonValue version;
|
||||
} parameter;
|
||||
} newsToIsmas;
|
||||
|
||||
explicit EventData(QString const &event,
|
||||
int percent,
|
||||
int resultCode,
|
||||
QString const &step,
|
||||
QString const &stepResult,
|
||||
QString const &version = "",
|
||||
QString const &reason = "SW_UP") {
|
||||
newsToIsmas.reason = reason;
|
||||
newsToIsmas.timestamp = computeTimeStamp();
|
||||
newsToIsmas.eventID = QString{"0"};
|
||||
newsToIsmas.event = event;
|
||||
newsToIsmas.eventState = 1;
|
||||
newsToIsmas.parameter.percent = percent;
|
||||
newsToIsmas.parameter.resultCode = resultCode;
|
||||
newsToIsmas.parameter.step = step;
|
||||
newsToIsmas.parameter.stepResult = stepResult;
|
||||
newsToIsmas.parameter.version = version;
|
||||
}
|
||||
};
|
||||
|
||||
struct StateData : public QJsonObject {
|
||||
QJsonValue Timestamp;
|
||||
QJsonArray HW_States;
|
||||
struct : public QJsonObject {
|
||||
QJsonValue name;
|
||||
QJsonValue value;
|
||||
QJsonValue unit;
|
||||
} machineState; //
|
||||
};
|
||||
|
||||
|
||||
enum class REQUEST : quint8 {
|
||||
NO_REQUEST,
|
||||
PING,
|
||||
SELF,
|
||||
PARAMETER
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // ISMASDATA_H
|
Loading…
x
Reference in New Issue
Block a user