Compare commits
9 Commits
b25b66395f
...
43f60251ef
Author | SHA1 | Date | |
---|---|---|---|
43f60251ef | |||
226dbbd050 | |||
6cd14d6559 | |||
4c8c3ed3c0 | |||
7258976528 | |||
d7a4d98a29 | |||
c339941585 | |||
744ad52c89 | |||
87ce6a7d54 |
@ -1,6 +1,6 @@
|
||||
QT += core
|
||||
|
||||
TARGET = update_sync_cust_repo
|
||||
TARGET = ATBUpdateSync
|
||||
|
||||
VERSION="1.0.0"
|
||||
win32 {
|
||||
@ -64,9 +64,19 @@ contains( CONFIG, DesktopLinux ) {
|
||||
}
|
||||
|
||||
SOURCES += \
|
||||
main.cpp
|
||||
main.cpp \
|
||||
message_handler.cpp \
|
||||
../common/src/utils_internal.cpp \
|
||||
../common/src/command.cpp \
|
||||
sync_command.cpp
|
||||
|
||||
# HEADERS += \
|
||||
|
||||
|
||||
HEADERS += \
|
||||
message_handler.h \
|
||||
../common/include/utils_internal.h \
|
||||
../common/include/command.h \
|
||||
sync_command.h
|
||||
|
||||
##########################################################################################
|
||||
# for running program on target through QtCreator
|
||||
|
@ -9,6 +9,28 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "utils_internal.h"
|
||||
#include "sync_command.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
QByteArray const value = qgetenv("LC_ALL");
|
||||
if (value.isEmpty() || value != "C") {
|
||||
qputenv("LC_ALL", "C");
|
||||
}
|
||||
|
||||
openlog("ATB-UPDATE-SYNC", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
|
||||
|
||||
QCoreApplication a(argc, argv);
|
||||
QCoreApplication::setApplicationName("ATBUpdateSync");
|
||||
QCoreApplication::setApplicationVersion(APP_VERSION);
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(nullptr);
|
||||
//atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
97
Sync/message_handler.cpp
Executable file
97
Sync/message_handler.cpp
Executable file
@ -0,0 +1,97 @@
|
||||
#include "message_handler.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <cstring>
|
||||
#include <QString>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageLogContext>
|
||||
|
||||
|
||||
static char const *DBG_NAME[] = { "DBG ", "WARN ", "CRIT ", "FATAL", "INFO " };
|
||||
static bool installedMsgHandler = false;
|
||||
static int debugLevel = LOG_NOTICE;
|
||||
|
||||
int getDebugLevel() { return debugLevel; }
|
||||
void setDebugLevel(int newDebugLevel) {
|
||||
debugLevel = newDebugLevel;
|
||||
}
|
||||
|
||||
bool messageHandlerInstalled() {
|
||||
return installedMsgHandler;
|
||||
}
|
||||
|
||||
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
|
||||
installedMsgHandler = (handler != 0);
|
||||
static QtMessageHandler prevHandler = nullptr;
|
||||
if (handler) {
|
||||
prevHandler = qInstallMessageHandler(handler);
|
||||
return prevHandler;
|
||||
} else {
|
||||
return qInstallMessageHandler(prevHandler);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Print message according to given debug level.
|
||||
///
|
||||
/// \note Install this function using qInstallMsgHandler().
|
||||
///
|
||||
/// int main(int argc, char **argv) {
|
||||
/// installMsgHandler(atbDebugOutput);
|
||||
/// QApplication app(argc, argv);
|
||||
/// ...
|
||||
/// return app.exec();
|
||||
/// }
|
||||
///
|
||||
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
Q_UNUSED(context);
|
||||
QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
|
||||
|
||||
switch (debugLevel) {
|
||||
case LOG_DEBUG: { // debug-level message
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
} break;
|
||||
case LOG_INFO: { // informational message
|
||||
if (type != QtDebugMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_NOTICE: { // normal, but significant, condition
|
||||
if (type != QtDebugMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_WARNING: { // warning conditions
|
||||
if (type != QtInfoMsg && type != QtDebugMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_ERR: { // error conditions
|
||||
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_CRIT: { // critical conditions
|
||||
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_ALERT: { // action must be taken immediately
|
||||
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
case LOG_EMERG: { // system is unusable
|
||||
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
|
||||
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
//fprintf(stderr, "%s No ErrorLevel defined! %s\n",
|
||||
// datetime.toStdString().c_str(), msg.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
23
Sync/message_handler.h
Executable file
23
Sync/message_handler.h
Executable file
@ -0,0 +1,23 @@
|
||||
#ifndef MESSAGE_HANDLER_H_INCLUDED
|
||||
#define MESSAGE_HANDLER_H_INCLUDED
|
||||
|
||||
#include <QtGlobal>
|
||||
#ifdef __linux__
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
int getDebugLevel();
|
||||
void setDebugLevel(int newDebugLevel);
|
||||
|
||||
bool messageHandlerInstalled();
|
||||
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
// typedef void (*QtMessageHandler)(QtMsgType, const char *);
|
||||
void atbDebugOutput(QtMsgType type, const char *msg);
|
||||
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
// typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
|
||||
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
#endif
|
||||
|
||||
#endif // MESSAGE_HANDLER_H_INCLUDED
|
18
Sync/sync_command.cpp
Normal file
18
Sync/sync_command.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "sync_command.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "utils_internal.h"
|
||||
using namespace internal;
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QFlags>
|
||||
#include <QRegularExpression>
|
||||
|
||||
SyncCommand::SyncCommand() {
|
||||
}
|
||||
|
||||
bool SyncCommand::exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout, int finish_timeout) {
|
||||
return false;
|
||||
}
|
14
Sync/sync_command.h
Normal file
14
Sync/sync_command.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SYNC_COMMAND_H_INCLUDED
|
||||
#define SYNC_COMMAND_H_INCLUDED
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class SyncCommand {
|
||||
public:
|
||||
SyncCommand();
|
||||
|
||||
bool exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout = 100000, int finish_timeout = 100000);
|
||||
};
|
||||
|
||||
#endif // SYNC_COMMAND_H_INCLUDED
|
@ -218,6 +218,7 @@ EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
|
||||
|
||||
# INCLUDEPATH += plugins
|
||||
INCLUDEPATH += plugins \
|
||||
$${_PRO_FILE_PWD_}/../common/ \
|
||||
$${_PRO_FILE_PWD_}/../common/include
|
||||
|
||||
CONFIG += c++17
|
||||
@ -294,7 +295,11 @@ SOURCES += \
|
||||
worker.cpp \
|
||||
commandline_parser.cpp \
|
||||
work_process_list.cpp \
|
||||
../common/src/utils_internal.cpp
|
||||
$${_PRO_FILE_PWD_}/../common/src/utils_internal.cpp \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.cpp \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.cpp \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
update.h \
|
||||
@ -319,7 +324,11 @@ HEADERS += \
|
||||
worker.h \
|
||||
commandline_parser.h \
|
||||
work_process_list.h \
|
||||
../common/include/utils_internal.h
|
||||
$${_PRO_FILE_PWD_}/../common/include/utils_internal.h \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.h \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.h \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ISMASData.h \
|
||||
$${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.h
|
||||
|
||||
|
||||
OTHER_FILES += \
|
||||
|
@ -49,17 +49,6 @@
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#endif
|
||||
|
||||
//QString Orientation(Qt::ScreenOrientation orientation) {
|
||||
// switch (orientation) {
|
||||
// case Qt::PrimaryOrientation : return "Primary";
|
||||
// case Qt::LandscapeOrientation : return "Landscape";
|
||||
// case Qt::PortraitOrientation : return "Portrait";
|
||||
// case Qt::InvertedLandscapeOrientation : return "Inverted landscape";
|
||||
// case Qt::InvertedPortraitOrientation : return "Inverted portrait";
|
||||
// default : return "Unknown";
|
||||
// }
|
||||
//}
|
||||
|
||||
// argv[1]: file to send to dc
|
||||
int main(int argc, char *argv[]) {
|
||||
QByteArray const value = qgetenv("LC_ALL");
|
||||
@ -82,15 +71,6 @@ int main(int argc, char *argv[]) {
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
//qCritical() << "Number of screens:" << QGuiApplication::screens().size();
|
||||
//qCritical() << "Primary screen:" << QGuiApplication::primaryScreen()->name();
|
||||
|
||||
//foreach (QScreen *screen, QGuiApplication::screens()) {
|
||||
// qDebug() << "Information for screen:" << screen->name();
|
||||
// qDebug() << " Orientation:" << Orientation(screen->orientation());
|
||||
//}
|
||||
//return 0;
|
||||
|
||||
CommandLineParser parser;
|
||||
parser.process(a);
|
||||
parser.readSettings();
|
||||
|
@ -107,9 +107,9 @@ void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
|
||||
|
||||
if (m_command.contains("ATBDownloadDCJsonFiles")) {
|
||||
m_worker->dcUpdate();
|
||||
}
|
||||
//if (m_command.contains("ATBDownloadDCJsonFiles")) {
|
||||
// m_worker->dcUpdate();
|
||||
//}
|
||||
}
|
||||
|
||||
// TODO: nach UpdateCommand ziehen
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "update_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
@ -19,20 +20,13 @@ bool UpdateCommand::stopUpdateOnFailure() {
|
||||
}
|
||||
|
||||
void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << m_command
|
||||
<< "exitCode" << exitCode
|
||||
<< "exitStatus" << exitStatus;
|
||||
|
||||
QProcess *p = qobject_cast<QProcess *>(sender());
|
||||
if (p) {
|
||||
// read all remaining data sent to the process, just in case
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << s;
|
||||
m_commandResult += s;
|
||||
}
|
||||
qCritical() << __func__ << ":" << __LINE__ << "next command" << m_nextCommandIndex;
|
||||
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
@ -40,13 +34,101 @@ void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
}
|
||||
|
||||
if (!m_worker->workList().empty()) {
|
||||
|
||||
//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};
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << m_command
|
||||
<< "exitCode" << exitCode
|
||||
<< "exitStatus" << exitStatus;
|
||||
|
||||
if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit) {
|
||||
qCritical() << __func__ << ":" << __LINE__;
|
||||
if (m_command.contains("ATBUpdateCheck")) {
|
||||
|
||||
// TODO: resultCodes richtig eintragen
|
||||
|
||||
if (m_command.contains("--ismas-connected")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_CHECK_ISMAS_CONNECIVITY,
|
||||
0,
|
||||
"ATBUpdateCheck --ismas-connected",
|
||||
"ISMAS connected");
|
||||
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("--update-requested")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_CHECK_UPDATE_REQUEST,
|
||||
0,
|
||||
"ATBUpdateCheck --update-requested",
|
||||
"update not necessary");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
}
|
||||
} else
|
||||
if (m_command.contains("ATBUpdateGit")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_CHECK_CUSTOMER_REPOSITORY,
|
||||
0,
|
||||
"ATBUpdateGit",
|
||||
"customer repository clean and up-to-date");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("ATBUpdateOpkg")) {
|
||||
if (m_command.contains("--noaction")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_INSTALL_SW_PACKETS_NOACTION,
|
||||
0,
|
||||
"ATBUpdateOpkg --noaction",
|
||||
"execute opkg-commands (dry-run)");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_INSTALL_SW_PACKETS,
|
||||
0,
|
||||
"ATBUpdateOpkg",
|
||||
"execute opkg-commands");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
}
|
||||
} else
|
||||
if (m_command.contains("ATBDownloadDCJsonFiles")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_INSTALL_DC_CONFIGURATION,
|
||||
0,
|
||||
"ATBDownloadDCJsonFiles",
|
||||
"download json-files to device controller");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("ATBUpdateSync")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_SYNCHRONIZE_REPO_AND_FILESYS,
|
||||
0,
|
||||
"ATBUpdateSync",
|
||||
"sync customer repository with /etc");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("ATBDownloadDCFirmware")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_UPDATE_DC,
|
||||
0,
|
||||
"ATBDownloadDCFirmware",
|
||||
"downloaded new dc-firmware. about to reboot...");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("ATBUpdateShowPSAInstalled")) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (m_worker->workList().nextExec()) {
|
||||
m_worker->workList().exec();
|
||||
}
|
||||
} else {
|
||||
qCritical() << __func__ << ":" << __LINE__;
|
||||
bool execShowStatus = true;
|
||||
m_worker->workList().exec(execShowStatus);
|
||||
}
|
||||
|
@ -244,27 +244,27 @@ Worker::Worker(int customerNr,
|
||||
// *** send json files down to device controller ***
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateJsonCommand>(
|
||||
QString("echo UpdateJsonCommand")
|
||||
QString("echo ATBDownloadDCJsonFiles")
|
||||
//QString("/opt/app/tools/atbupdate/ATBDownloadDCJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
|
||||
, this, ++next, false));
|
||||
|
||||
// sync json files in repo etc-directory with /etc fs-directory
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateFileSystemCommand>(
|
||||
QString("echo UpdateFileSystemCommand")
|
||||
QString("echo ATBUpdateSync")
|
||||
, this, ++next));
|
||||
|
||||
// send device-controller firmware down to device-controller-hardware
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateDCCommand>(
|
||||
QString("echo UpdateDCCommand")
|
||||
QString("echo ATBDownloadDCFirmware")
|
||||
// QString("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")
|
||||
, this, ++next));
|
||||
|
||||
// show/send software-status
|
||||
m_workList.push_back(
|
||||
std::make_unique<ShowSoftwareStatusCommand>(
|
||||
QString("echo ShowSoftwareStatusCommand")
|
||||
QString("echo ATBUpdateShowPSAInstalled")
|
||||
, this, -1));
|
||||
|
||||
// reboot machine
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "git/git_client.h"
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "ismas/ApismClientForUpdate.h"
|
||||
#include "utils.h"
|
||||
#include "work_process_list.h"
|
||||
|
||||
@ -199,6 +200,7 @@ class Worker : public QThread{
|
||||
QString m_apismVersion;
|
||||
|
||||
WorkList m_workList;
|
||||
ApismClientForUpdate m_clForUpdate;
|
||||
|
||||
bool executeOpkgCommand(QString opkgCommand);
|
||||
bool cleanUpOpkgCache();
|
||||
@ -402,6 +404,9 @@ public:
|
||||
return m_ismasClient;
|
||||
}
|
||||
|
||||
ApismClientForUpdate &clientForUpdate() { return m_clForUpdate; }
|
||||
ApismClientForUpdate const &clientForUpdate() const { return m_clForUpdate; }
|
||||
|
||||
Worker *GUI(QStringList const &lst = QStringList()) {
|
||||
m_guiMsg = lst;
|
||||
return this;
|
||||
|
@ -26,6 +26,20 @@ namespace internal {
|
||||
static constexpr const char *UPDATE_DC_FIRMARE_SUCCESS{"success"};
|
||||
|
||||
static constexpr const char *OPKG_MARKER{"<OPKG>"};
|
||||
static constexpr const char *SYNC_MARKER{"<SYNC>"};
|
||||
static constexpr const char *DC_MARKER{"<DC>"};
|
||||
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();
|
||||
|
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