Compare commits
126 Commits
b270a9f30e
...
dc-downloa
Author | SHA1 | Date | |
---|---|---|---|
0fe9ebef66 | |||
d15593c7aa | |||
6f60265c74 | |||
1c10d9bc14 | |||
0bca22f995 | |||
67eeade609 | |||
559298331b | |||
4f1efcf5cf | |||
3047df8130 | |||
c783b7a967 | |||
e4be41e670 | |||
b2ecd1b628 | |||
fb4da1f208 | |||
ec4e327899 | |||
8621c1dd17 | |||
0ddfc1d7e3 | |||
e95f034538 | |||
72fbd9089a | |||
3bdc117c01 | |||
12eafc2878 | |||
9abe718010 | |||
3b6f22e93b | |||
34cc077937 | |||
ba1b2263d2 | |||
1f99618ba5 | |||
df4e384d9d | |||
ede8a9519f | |||
903977bdd1 | |||
775e9b7b8a | |||
a8fdd29666 | |||
70d0ffb38d | |||
f623b36421 | |||
f415406672 | |||
2c1afa463f | |||
927b488582 | |||
7712803ad6 | |||
bc88a9b0be | |||
8b3f0991f7 | |||
8123526e11 | |||
57a093e9ae | |||
10536c81a5 | |||
659dc69831 | |||
a47dd60e9e | |||
575a740692 | |||
e22d78cba8 | |||
ad8b9f26c0 | |||
5b5a4504fa | |||
9ed8603dfb | |||
7d367f7fa9 | |||
fc306a45f7 | |||
df6f33a259 | |||
716543ec8c | |||
0f355c0c50 | |||
36a4d53df6 | |||
b9e9688269 | |||
f5611cf826 | |||
8d5831286d | |||
2ab485454c | |||
cbb81b7260 | |||
487bbb8160 | |||
d36c7c1f72 | |||
cf3e1d61dd | |||
e12181dc5a | |||
d1b3b81972 | |||
ac03f4ae91 | |||
0c0debb790 | |||
6fc62863c1 | |||
0dd731ff50 | |||
19445ec4f5 | |||
739010ba59 | |||
7ace073d12 | |||
e36ff70dd9 | |||
57e65e2234 | |||
79af890be6 | |||
24b83840cd | |||
53946457ab | |||
c3947e49ab | |||
7ecd45b547 | |||
e7d8365c62 | |||
c304d1a78b | |||
a8d4ae3aee | |||
0fe318b291 | |||
ec08e04f2c | |||
b26b65ee76 | |||
674b572da5 | |||
9a6ac85f99 | |||
ae582b75d5 | |||
3069c3bd65 | |||
b5067ce044 | |||
3573279dfa | |||
39b5551e90 | |||
05974fd8ee | |||
2189684cad | |||
f4d785ea9d | |||
5bae9fcdf1 | |||
eddf67739a | |||
cb28bd2a1f | |||
618430bcc5 | |||
037b91b889 | |||
96e3b606ef | |||
5d3849dcf3 | |||
8c66e03ea3 | |||
43f60251ef | |||
226dbbd050 | |||
6cd14d6559 | |||
4c8c3ed3c0 | |||
7258976528 | |||
d7a4d98a29 | |||
c339941585 | |||
744ad52c89 | |||
87ce6a7d54 | |||
b25b66395f | |||
de9182bdc9 | |||
af83c11f73 | |||
7cdefc9b49 | |||
dd0d7790e0 | |||
b23314a1f3 | |||
9f1f41e4b6 | |||
522f86aaac | |||
13259ba86e | |||
63a959315b | |||
c05db3b323 | |||
bc21ede1a1 | |||
8db818f6cd | |||
ef9cc23093 | |||
3a259f8a22 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
tags
|
||||
*.tags
|
||||
*.user
|
||||
documentation/
|
||||
|
@@ -1,5 +1,5 @@
|
||||
[REPOSITORY_URL]
|
||||
repository-url="gitea@ptu-config.atb-comm.de:ATB/"
|
||||
repository-url="gitea@ptu-config.atb-comm.de:ATB"
|
||||
|
||||
[DIRECTORIES]
|
||||
plugin-directory="/usr/lib/"
|
||||
@@ -19,3 +19,21 @@ yocto-version=false
|
||||
yocto-install=false
|
||||
always-download-config=true
|
||||
always-download-dc=false
|
||||
|
||||
|
||||
[ATBUpdateCheck]
|
||||
|
||||
[ATBUpdateDC]
|
||||
debug=true
|
||||
workingDir=/tmp
|
||||
libca=/usr/lib/libCAslave.so
|
||||
|
||||
[ATBUpdateGit]
|
||||
|
||||
[ATBUpdateJsonFiles]
|
||||
|
||||
[ATBUpdateOpkg]
|
||||
|
||||
[ATBUpdateShow]
|
||||
|
||||
[ATBUpdateSync]
|
||||
|
@@ -1,3 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
CONFIG += ordered
|
||||
SUBDIRS = Check Show DownloadDCFirmware DownloadDCJsonFiles Opkg Sync UpdatePTUDevCtrl
|
||||
SUBDIRS = Check Show DownloadDCFirmware DownloadDCJsonFiles Git Opkg Sync UpdatePTUDevCtrl
|
||||
|
@@ -65,11 +65,13 @@ contains( CONFIG, DesktopLinux ) {
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
ismas_client.cpp \
|
||||
message_handler.cpp
|
||||
message_handler.cpp \
|
||||
../common/src/utils_internal.cpp
|
||||
|
||||
HEADERS += \
|
||||
ismas_client.h \
|
||||
message_handler.h
|
||||
message_handler.h \
|
||||
../common/include/utils_internal.h
|
||||
|
||||
##########################################################################################
|
||||
# for running program on target through QtCreator
|
||||
|
@@ -112,19 +112,23 @@ void IsmasClient::printErrorMessage(int port,
|
||||
}
|
||||
|
||||
std::optional<QString>
|
||||
IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
IsmasClient::sendRequestReceiveResponse(int port, QString const &request, bool verbose) {
|
||||
|
||||
qInfo() << "REQUEST" << request;
|
||||
if (verbose) {
|
||||
qInfo() << "REQUEST" << request;
|
||||
}
|
||||
|
||||
int sockfd;
|
||||
int r;
|
||||
errno = 0;
|
||||
// socket create and verification
|
||||
if ((sockfd = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
qCritical().noquote()
|
||||
<< "\n"
|
||||
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
|
||||
<< "SOCKET CREATION FAILED (" << strerror(errno) << ")";
|
||||
if (verbose) {
|
||||
qCritical().noquote()
|
||||
<< "\n"
|
||||
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
|
||||
<< "SOCKET CREATION FAILED (" << strerror(errno) << ")";
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -137,10 +141,12 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
servAddr.sin_port = htons(port);
|
||||
// connect the client socket to server socket
|
||||
if ((r = ::connect(sockfd, (struct sockaddr *)(&servAddr), sizeof(servAddr))) != 0) {
|
||||
qCritical().noquote()
|
||||
<< "\n"
|
||||
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
|
||||
<< "CONNECTION WITH SERVER FAILED (" << strerror(r) << ")";
|
||||
if (verbose) {
|
||||
qCritical().noquote()
|
||||
<< "\n"
|
||||
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
|
||||
<< "CONNECTION WITH SERVER FAILED (" << strerror(r) << ")";
|
||||
}
|
||||
::close(sockfd);
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -155,7 +161,9 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, sizeof(clientIP));
|
||||
unsigned int clientPort = ntohs(clientAddr.sin_port);
|
||||
|
||||
printDebugMessage(port, clientIP, clientPort, QString("CONNECTED TO SERVER"));
|
||||
if (verbose) {
|
||||
printDebugMessage(port, clientIP, clientPort, QString("CONNECTED TO SERVER"));
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 10; /* 10 secs timeout for read and write */
|
||||
@@ -244,7 +252,9 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
// QString("CANNOT CLOSE WRITING END (") + strerror(errno) + ")");
|
||||
// }
|
||||
|
||||
printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT <<<") + buf + ">>>");
|
||||
if (verbose) {
|
||||
printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT <<<") + buf + ">>>");
|
||||
}
|
||||
|
||||
loop = 0;
|
||||
bzero(buf, sizeof(buf));
|
||||
@@ -325,7 +335,9 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
response = response.mid(0, idx);
|
||||
} else
|
||||
if (response.contains("RECORD")) { // RECORD SAVED or RECORD WRITE ABORTED
|
||||
printInfoMessage(port, clientIP, clientPort, QString("IGNORED '") + response + "' RESPONSE");
|
||||
if (verbose) {
|
||||
printInfoMessage(port, clientIP, clientPort, QString("IGNORED '") + response + "' RESPONSE");
|
||||
}
|
||||
::close(sockfd);
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -334,8 +346,10 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
QJsonDocument document(QJsonDocument::fromJson(response.toUtf8(), &parseError));
|
||||
if (parseError.error == QJsonParseError::NoError) {
|
||||
if (document.isObject()) { // done: received valid APISM response
|
||||
printInfoMessage(port, clientIP, clientPort,
|
||||
QString("VALID APISM RESPONSE .. \n") + response);
|
||||
if (verbose) {
|
||||
printInfoMessage(port, clientIP, clientPort,
|
||||
QString("VALID APISM RESPONSE .. \n") + response);
|
||||
}
|
||||
::close(sockfd);
|
||||
return response;
|
||||
} else {
|
||||
|
@@ -37,7 +37,7 @@ public:
|
||||
static char const *reason[REASON::ENTRIES];
|
||||
|
||||
static std::optional<QString>
|
||||
sendRequestReceiveResponse(int port, QString const &request);
|
||||
sendRequestReceiveResponse(int port, QString const &request, bool verbose=false);
|
||||
|
||||
private:
|
||||
static void printDebugMessage(int port, QString const &clientIP, int clientPort,
|
||||
|
149
Check/main.cpp
149
Check/main.cpp
@@ -9,8 +9,21 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "commandline_parser.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QRegularExpression>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "utils_internal.h"
|
||||
#include "ismas_client.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
QByteArray const value = qgetenv("LC_ALL");
|
||||
@@ -18,9 +31,6 @@ int main(int argc, char **argv) {
|
||||
qputenv("LC_ALL", "C");
|
||||
}
|
||||
|
||||
|
||||
// qputenv("XDG_RUNTIME_DIR", "/var/run/user/0");
|
||||
|
||||
openlog("ATB-UPDATE_CHECK", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
|
||||
|
||||
QCoreApplication a(argc, argv);
|
||||
@@ -33,19 +43,138 @@ int main(int argc, char **argv) {
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
int exitCode = 0;
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption ismasConnectOption("ismas-connected");
|
||||
QCommandLineOption updateRequestedOption("update-requested");
|
||||
QCommandLineOption verboseOption("verbose");
|
||||
parser.addOption(ismasConnectOption);
|
||||
parser.addOption(updateRequestedOption);
|
||||
parser.addOption(verboseOption);
|
||||
parser.process(a);
|
||||
|
||||
if (parser.isSet(ismasConnectOption)) {
|
||||
qCritical() << parser.isSet(ismasConnectOption);
|
||||
} else
|
||||
if (parser.isSet(updateRequestedOption)) {
|
||||
qCritical() << parser.isSet(updateRequestedOption);
|
||||
QString connectionStatus{internal::ISMAS_NOT_CONNECTED};
|
||||
QString updateRequestStatus{internal::UPDATE_NOT_REQUESTED};
|
||||
|
||||
{
|
||||
QDebug debug = qCritical();
|
||||
|
||||
int tries = 10;
|
||||
|
||||
while (--tries > 0) {
|
||||
if (std::optional<QString> result
|
||||
= IsmasClient::sendRequestReceiveResponse(
|
||||
IsmasClient::APISM::DIRECT_PORT,
|
||||
"#M=APISM#C=REQ_SELF#J={}")) {
|
||||
QJsonDocument d = QJsonDocument::fromJson(result.value().toUtf8());
|
||||
for (QString const &k : d.object().keys()) {
|
||||
if (k.contains("CMD_GET_APISMSTATUS_RESPONSE")) {
|
||||
QJsonObject o = d.object()[k].toObject();
|
||||
QJsonObject::const_iterator bit = o.find("Broker");
|
||||
QJsonObject::const_iterator ismit = o.find("ISMAS");
|
||||
if (bit != o.constEnd() && ismit != o.constEnd()) {
|
||||
// value for "Broker"
|
||||
QString const &v = bit->toString();
|
||||
bool ismas = ismit->toBool();
|
||||
if (ismas && v.contains(internal::BROKER_CONNECTED, Qt::CaseInsensitive)) {
|
||||
connectionStatus = internal::ISMAS_CONNECTED;
|
||||
break;
|
||||
} else
|
||||
if (v.contains(internal::BROKER_NOT_CONNECTED, Qt::CaseInsensitive)) {
|
||||
connectionStatus = internal::ISMAS_NOT_CONNECTED;
|
||||
} else
|
||||
if (v.contains(internal::BROKER_DISCONNECTED, Qt::CaseInsensitive)) {
|
||||
connectionStatus = internal::ISMAS_NOT_CONNECTED;
|
||||
} else
|
||||
if (v.contains(internal::BROKER_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
|
||||
connectionStatus = internal::ISMAS_NOT_CONNECTED;
|
||||
} else
|
||||
if (v.contains(internal::BROKER_DISCONNECTING, Qt::CaseInsensitive)) {
|
||||
connectionStatus = internal::ISMAS_NOT_CONNECTED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionStatus == internal::ISMAS_CONNECTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
QThread::sleep(5);
|
||||
}
|
||||
|
||||
if (connectionStatus != internal::ISMAS_CONNECTED) {
|
||||
if (internal::customerRepoExists() == false) {
|
||||
debug.noquote() << internal::NO_CUSTOMER_REPOSITORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(updateRequestedOption)) {
|
||||
if (internal::customerRepoExists() == false) {
|
||||
// if the customer repository does not exists, it does not matter is
|
||||
// ISMAS is connected or how the setting for the WAIT-button is.
|
||||
updateRequestStatus = internal::UPDATE_INITIAL;
|
||||
} else {
|
||||
if (connectionStatus == internal::ISMAS_CONNECTED) {
|
||||
if (std::optional<QString> result
|
||||
= IsmasClient::sendRequestReceiveResponse(
|
||||
IsmasClient::APISM::DIRECT_PORT,
|
||||
"#M=APISM#C=REQ_ISMASPARAMETER#J={}")) {
|
||||
|
||||
QJsonDocument d = QJsonDocument::fromJson(result.value().toUtf8());
|
||||
for (QString const &k : d.object().keys()) {
|
||||
if (k.contains("REQ_ISMASPARAMETER")) {
|
||||
QJsonObject o = d.object()[k].toObject();
|
||||
|
||||
QJsonObject::const_iterator it = o.find("Aknoledge");
|
||||
if (it == o.constEnd()) continue;
|
||||
|
||||
QString const &v = it->toString();
|
||||
if (v != "OK") break;
|
||||
|
||||
for (QString const &m : d.object().keys()) { // request ack
|
||||
if (!m.contains("FileUpload", Qt::CaseInsensitive)) continue;
|
||||
QJsonObject o2 = d.object()[m].toObject();
|
||||
|
||||
QJsonObject::const_iterator it2 = o2.find("TRG");
|
||||
if (it2 == o2.constEnd()) break;
|
||||
|
||||
QString const &v2 = it2->toString();
|
||||
if (v2 == "WAIT") {
|
||||
updateRequestStatus = internal::UPDATE_REQUESTED;
|
||||
} else {
|
||||
// the customer-repository does exist, and the ISMAS-trigger is
|
||||
// *NOT* "WAIT", but from 00:00:00 - 00:03:59 this counts as an
|
||||
// automatic update
|
||||
QDateTime const ¤t = QDateTime::currentDateTime();
|
||||
if (current.time().hour() < 4) {
|
||||
updateRequestStatus = internal::UPDATE_NOT_NECESSARY;
|
||||
} else {
|
||||
updateRequestStatus = internal::UPDATE_NOT_REQUESTED;
|
||||
exitCode = -2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// not connected (so its unknown if update has been requested),
|
||||
// and customer repository exists. Assume 'not requested'.
|
||||
updateRequestStatus = internal::UPDATE_NOT_REQUESTED;
|
||||
exitCode = -1;
|
||||
}
|
||||
}
|
||||
debug.noquote() << updateRequestStatus;
|
||||
} else
|
||||
if (parser.isSet(ismasConnectOption)) {
|
||||
debug.noquote() << connectionStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return exitCode;
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
QT += core gui
|
||||
QT += widgets serialport network
|
||||
QT += core serialport
|
||||
|
||||
TARGET = ATBDownloadDCFirmware
|
||||
TARGET = ATBUpdateDC
|
||||
|
||||
VERSION="0.1.0"
|
||||
win32 {
|
||||
@@ -77,21 +76,21 @@ contains( CONFIG, DesktopLinux ) {
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
../common/src/message_handler.cpp \
|
||||
../UpdatePTUDevCtrl/commandline_parser.cpp \
|
||||
../common/src/commandline_parser.cpp \
|
||||
update.cpp \
|
||||
dc_download.cpp \
|
||||
../common/src/System.cpp
|
||||
../common/src/System.cpp \
|
||||
../common/src/utils_internal.cpp \
|
||||
../common/src/command.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
../common/include/message_handler.h \
|
||||
../UpdatePTUDevCtrl/commandline_parser.h \
|
||||
../common/include/commandline_parser.h \
|
||||
update.h \
|
||||
dc_download.h \
|
||||
../common/include/System.h
|
||||
../common/include/System.h \
|
||||
../common/include/utils_internal.h \
|
||||
../common/include/command.h
|
||||
|
||||
|
||||
OTHER_FILES += \
|
||||
|
@@ -1,7 +1,6 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
|
||||
#include <QProcess>
|
||||
@@ -11,12 +10,13 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "commandline_parser.h"
|
||||
#include "utils.h"
|
||||
#include "utils_internal.h"
|
||||
#include "update.h"
|
||||
#include "mainwindow.h"
|
||||
#include "System.h"
|
||||
|
||||
#include <DeviceController/interfaces.h>
|
||||
@@ -54,19 +54,24 @@ int main(int argc, char **argv) {
|
||||
|
||||
openlog("DC", LOG_PERROR | LOG_CONS, LOG_USER);
|
||||
|
||||
QApplication a(argc, argv);
|
||||
QApplication::setApplicationName("ATBDownloadDCFirmware");
|
||||
QApplication::setApplicationVersion(APP_VERSION);
|
||||
QCoreApplication a(argc, argv);
|
||||
QCoreApplication::setOrganizationName("ATB Automatentechnik Baumann GmBH");
|
||||
QCoreApplication::setApplicationName("ATBUpdateDC");
|
||||
QCoreApplication::setApplicationVersion(APP_VERSION);
|
||||
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
//return 0;
|
||||
|
||||
CommandLineParser parser;
|
||||
parser.process(a);
|
||||
parser.readSettings();
|
||||
|
||||
/*
|
||||
QString repositoryUrl = parser.repositoryUrl();
|
||||
QString plugInDir = parser.plugInDir();
|
||||
QString plugInName = parser.plugInName();
|
||||
@@ -75,6 +80,7 @@ int main(int argc, char **argv) {
|
||||
QString psaTariffDir = parser.psaTariffDir();
|
||||
QString psaDcDir = parser.dcDir();
|
||||
QString iniFileName = parser.iniFileName();
|
||||
bool debug = parser.debug();
|
||||
bool const dryRun = parser.dryRun();
|
||||
bool const noUpdatePsaHardware = parser.noUpdatePsaHardware();
|
||||
bool const showYoctoVersion = parser.yoctoVersion();
|
||||
@@ -127,57 +133,98 @@ int main(int argc, char **argv) {
|
||||
|
||||
QString const &customerRepo
|
||||
= QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
|
||||
*/
|
||||
QString psaDcDir = internal::customerRepoDcDir();
|
||||
QString psaRepoRootDir = internal::customerRepoRoot();
|
||||
QString psaRepoDir = internal::customerRepoDir();
|
||||
QString branchName = internal::branchName();
|
||||
QString rootDir = "/etc/dc/";
|
||||
// bool usbDetected = false;
|
||||
// bool sdCardDetected = false;
|
||||
|
||||
bool debug = false;
|
||||
bool noaction = true;
|
||||
QString workingDir;
|
||||
QString libca;
|
||||
|
||||
std::unique_ptr<QSettings> settings = internal::readSettings();
|
||||
if (settings) {
|
||||
settings->beginGroup("ATBUpdateDC");
|
||||
debug = settings->value("debug", false).toBool();
|
||||
workingDir = settings->value("workingdir", "/tmp").toString();
|
||||
libca = settings->value("libca", "/usr/lib/libCAslave.so").toString();
|
||||
settings->endGroup();
|
||||
} else {
|
||||
qCritical() << "count not read ATBUpdateTool.ini";
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString dcDir = parser.dcDir();
|
||||
if (!dcDir.isEmpty()) {
|
||||
psaDcDir = dcDir;
|
||||
}
|
||||
debug = parser.debug();
|
||||
|
||||
if (debug) {
|
||||
qInfo() << " using dc directory: " << psaDcDir;
|
||||
qInfo() << "using psa repo root directory: " << psaRepoRootDir;
|
||||
qInfo() << " using customer repository: " << psaRepoDir;
|
||||
qInfo() << " using branch: " << branchName;
|
||||
}
|
||||
|
||||
// etc/dc: located under mount-path
|
||||
std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir);
|
||||
QFileInfo fi;
|
||||
if (mountPath.has_value()) {
|
||||
fi.setFile(mountPath.value(), System::getDCFileOnUsbStick(mountPath.value()));
|
||||
// usbDetected = true;
|
||||
// mountPath/etc/dc must exists !
|
||||
// cannot override with commandline parameter --dc-directory
|
||||
if (debug) {
|
||||
qInfo() << "using mount path (USB): " << mountPath.value();
|
||||
}
|
||||
} else
|
||||
if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) {
|
||||
fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value()));
|
||||
// sdCardDetected = true;
|
||||
// mountPath/etc/dc must exists !
|
||||
// cannot override with commandline parameter --dc-directory
|
||||
if (debug) {
|
||||
qInfo() << "using mount path (SD): " << mountPath.value();
|
||||
}
|
||||
} else {
|
||||
qInfo() << "using customer repository" << customerRepo;
|
||||
|
||||
QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/dc"));
|
||||
if (dir.exists()) {
|
||||
fi.setFile(dir, dir.absoluteFilePath("dc2c.bin"));
|
||||
} else {
|
||||
qCritical() << "DIRECTORY" << dir << "DOES NOT EXIST";
|
||||
return -1;
|
||||
rootDir = "";
|
||||
mountPath = QDir::cleanPath(psaRepoRootDir + QDir::separator() + psaDcDir);
|
||||
if (debug) {
|
||||
qInfo() << "using as dc-directory" << mountPath.value();
|
||||
}
|
||||
}
|
||||
|
||||
qInfo() << "downloading dc-firmware .." << fi.absoluteFilePath();
|
||||
qInfo() << "dc-firmware size (bytes) ." << fi.size();
|
||||
if (readDCVersion) {
|
||||
qInfo() << "dc-version ..............." << Update::dcVersion(fi.absoluteFilePath());
|
||||
if (debug) {
|
||||
qInfo() << "using as mount path: " << mountPath.value();
|
||||
}
|
||||
|
||||
QThread::currentThread()->setObjectName("main thread");
|
||||
// qInfo() << "Main thread" << QThread::currentThreadId();
|
||||
std::unique_ptr<QString> c = internal::dcCandidateToInstall(rootDir, mountPath.value());
|
||||
if (c) {
|
||||
fi.setFile(*c);
|
||||
if (fi.exists() == false) {
|
||||
qCritical() << "dc2c.bin candidate" << *c << "does not exist. STOP.";
|
||||
return -1;
|
||||
}
|
||||
qInfo() << "dc2c.bin canditate" << fi.absoluteFilePath();
|
||||
}
|
||||
|
||||
Update update(customerRepo,
|
||||
QString::number(customerNr),
|
||||
branchName,
|
||||
plugInDir,
|
||||
plugInName,
|
||||
workingDir,
|
||||
psaDcDir);
|
||||
if (debug) {
|
||||
qInfo() << "downloading dc-firmware" << fi.absoluteFilePath();
|
||||
qInfo() << "dc-firmware size (bytes)" << fi.size();
|
||||
qInfo() << "dc-version" << Update::dcVersion(fi.absoluteFilePath());
|
||||
}
|
||||
|
||||
update.doUpdate(fi.absoluteFilePath());
|
||||
// only for testing
|
||||
// return 0;
|
||||
|
||||
// MainWindow mw;
|
||||
|
||||
// mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
// mw.showFullScreen();
|
||||
|
||||
// qCritical() << "SHOW";
|
||||
|
||||
// mw.show();
|
||||
Update u(fi.absoluteFilePath(), libca, debug, noaction);
|
||||
u.run();
|
||||
|
||||
qInfo() << "<DC-UPDATE-FINISH>";
|
||||
|
||||
return 0;
|
||||
// return a.exec();
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QStatusBar>
|
||||
#include <QWidget>
|
||||
#include <QSerialPort>
|
||||
#include <QSerialPortInfo>
|
||||
|
||||
|
@@ -24,10 +24,14 @@
|
||||
#include <QMap>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QSerialPort>
|
||||
#include <QSerialPortInfo>
|
||||
#include <QSettings>
|
||||
|
||||
#define UPDATE_OPKG (1)
|
||||
#define UPDATE_DC (0)
|
||||
|
||||
|
||||
static const QMap<QString, int> baudrateMap = {
|
||||
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
|
||||
{"57600" , 4}, {"115200" , 5}
|
||||
@@ -35,48 +39,38 @@ static const QMap<QString, int> baudrateMap = {
|
||||
|
||||
QPluginLoader Update::pluginLoader;
|
||||
|
||||
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
hwinf *Update::loadDCPlugin(QString const &libCA /* absolute file path */) {
|
||||
hwinf *hw = nullptr;
|
||||
if (plugInDir.exists()) {
|
||||
QString pluginLibName(fname);
|
||||
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
|
||||
QFileInfo info(pluginLibName);
|
||||
if (info.exists()) {
|
||||
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
|
||||
pluginLoader.setFileName(pluginLibName);
|
||||
// static QPluginLoader pluginLoader(pluginLibName);
|
||||
if (!pluginLoader.load()) {
|
||||
qCritical() << "in directory" << plugInDir.absolutePath();
|
||||
qCritical() << "cannot load plugin" << pluginLoader.fileName();
|
||||
qCritical() << pluginLoader.errorString();
|
||||
return nullptr;
|
||||
}
|
||||
QFileInfo libCAInfo(libCA);
|
||||
if (libCAInfo.exists()) {
|
||||
pluginLoader.setFileName(libCA);
|
||||
// static QPluginLoader pluginLoader(pluginLibName);
|
||||
if (!pluginLoader.load()) {
|
||||
qCritical() << "cannot load plugin" << pluginLoader.fileName();
|
||||
qCritical() << pluginLoader.errorString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
qCritical() << "loadDCPlugin() plugin directory:" << plugInDir.absolutePath();
|
||||
qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName();
|
||||
// qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName();
|
||||
|
||||
if (!pluginLoader.isLoaded()) {
|
||||
qCritical() << pluginLoader.errorString();
|
||||
return nullptr;
|
||||
}
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (!plugin) {
|
||||
qCritical() << "cannot start instance";
|
||||
return nullptr;
|
||||
}
|
||||
if (! (hw = qobject_cast<hwinf *>(plugin))) {
|
||||
qCritical() << "cannot cast plugin" << plugin << "to hwinf";
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
qCritical() << pluginLibName << "does not exist";
|
||||
if (!pluginLoader.isLoaded()) {
|
||||
qCritical() << pluginLoader.errorString();
|
||||
return nullptr;
|
||||
}
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (!plugin) {
|
||||
qCritical() << "cannot start instance";
|
||||
return nullptr;
|
||||
}
|
||||
if (! (hw = qobject_cast<hwinf *>(plugin))) {
|
||||
qCritical() << "cannot cast plugin" << plugin << "to hwinf";
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
qCritical() << "plugins directory" << plugInDir.absolutePath()
|
||||
<< "does not exist";
|
||||
qCritical() << libCAInfo.absoluteFilePath() << "does not exist";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
@@ -107,40 +101,12 @@ QString Update::dcVersion(QString const &dcBinFile) {
|
||||
}
|
||||
|
||||
class hwapi;
|
||||
Update::Update(QString customerRepository,
|
||||
QString customerNrStr,
|
||||
QString branchName,
|
||||
QString plugInDir,
|
||||
QString pluginName,
|
||||
QString workingDir,
|
||||
QString psaDcDir,
|
||||
bool dryRun,
|
||||
QObject *parent,
|
||||
char const *serialInterface,
|
||||
char const *baudrate)
|
||||
: QObject(parent) {
|
||||
#if 0
|
||||
|
||||
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
|
||||
, m_serialInterface(serialInterface)
|
||||
, m_baudrate(baudrate)
|
||||
, m_customerRepository(customerRepository)
|
||||
, m_customerNrStr(customerNrStr)
|
||||
, m_branchName(branchName)
|
||||
, m_pluginName(pluginName)
|
||||
, m_workingDir(workingDir)
|
||||
, m_psaDcDir(psaDcDir)
|
||||
, m_dryRun(dryRun)
|
||||
, m_sys_areDCdataValid(false) {
|
||||
|
||||
if (!m_hw) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
|
||||
} else {
|
||||
|
||||
// carun stoppen
|
||||
}
|
||||
#endif
|
||||
m_start = QDateTime::currentDateTime();
|
||||
Update::Update(QString const &dcFileName, QString const &libCA, bool debug, bool noaction)
|
||||
: m_dcFileName(dcFileName)
|
||||
, m_hw(loadDCPlugin(libCA))
|
||||
, m_sys_areDCdataValid(false)
|
||||
, m_debug(debug)
|
||||
, m_noaction(noaction) {
|
||||
}
|
||||
|
||||
Update::~Update() {
|
||||
@@ -166,15 +132,15 @@ Update::sendNextAddress(int bNum) const {
|
||||
if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
|
||||
// qDebug() << "addr-block" << bNum << "...";
|
||||
while (noAnswerCount <= 250) {
|
||||
// TODO
|
||||
// m_hw->bl_sendAddress(bNum);
|
||||
|
||||
QThread::msleep(100);
|
||||
DownloadResult res = DownloadResult::OK;
|
||||
if (!m_debug) {
|
||||
m_hw->bl_sendAddress(bNum);
|
||||
|
||||
// TODO
|
||||
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK());
|
||||
|
||||
DownloadResult const res = DownloadResult::OK;
|
||||
QThread::msleep(10); //from 100ms to 20ms
|
||||
//###################################################################################
|
||||
res = sendStatus(m_hw->bl_wasSendingAddOK());
|
||||
}
|
||||
|
||||
if (res != DownloadResult::NOP) {
|
||||
if (res == DownloadResult::ERROR) {
|
||||
@@ -189,7 +155,7 @@ Update::sendNextAddress(int bNum) const {
|
||||
} else {
|
||||
noAnswerCount += 1; // no answer by now
|
||||
}
|
||||
}
|
||||
} // while
|
||||
// wait max. about 3 seconds
|
||||
return DownloadResult::TIMEOUT;
|
||||
}
|
||||
@@ -214,20 +180,20 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
|
||||
|
||||
qInfo() << s.toUtf8().constData();
|
||||
|
||||
QThread::msleep(200);
|
||||
return DownloadResult::OK;
|
||||
QThread::msleep(20); //reduce from 200 to 50 ms
|
||||
//############################################################################
|
||||
|
||||
// QByteArray b((const char *)(&local[0]), 64);
|
||||
// qCritical() << "SNDB" << bNum << b.size() << b.toHex();
|
||||
QByteArray b((const char *)(&local[0]), 64);
|
||||
qCritical() << "SNDB" << bNum << b.size() << b.toHex();
|
||||
|
||||
while (noAnswerCount <= 250) {
|
||||
// TODO
|
||||
// m_hw->bl_sendDataBlock(64, local);
|
||||
|
||||
// TODO
|
||||
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK());
|
||||
DownloadResult res = DownloadResult::OK;
|
||||
|
||||
DownloadResult const res = DownloadResult::OK;
|
||||
if (!m_debug) {
|
||||
m_hw->bl_sendDataBlock(64, local);
|
||||
res = sendStatus(m_hw->bl_wasSendingDataOK());
|
||||
}
|
||||
|
||||
if (res != DownloadResult::NOP) {
|
||||
if (res == DownloadResult::ERROR) {
|
||||
@@ -249,53 +215,63 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
|
||||
}
|
||||
|
||||
bool Update::startBootloader() const {
|
||||
QThread::msleep(1000);
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "starting bootloader ...done";
|
||||
return true;
|
||||
qDebug() << "starting bootloader...";
|
||||
|
||||
#if 0
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_startBL();
|
||||
QThread::msleep(5000);
|
||||
m_hw->bl_checkBL();
|
||||
if (m_hw->bl_isUp()) {
|
||||
qInfo() << "starting bootloader...OK";
|
||||
QThread::msleep(5000);
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "bootloader not up (" << nTry << ")";
|
||||
if (!m_debug) {
|
||||
int nTry = 10;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_startBL();
|
||||
QThread::msleep(1000);
|
||||
m_hw->bl_checkBL();
|
||||
if (m_hw->bl_isUp()) {
|
||||
qInfo() << "starting bootloader...OK";
|
||||
QThread::msleep(5000);
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "bootloader not up (" << nTry << ")";
|
||||
qCritical() << "IS BOOTLOADER INSTALLED ???";
|
||||
}
|
||||
}
|
||||
qCritical() << "starting bootloader...FAILED";
|
||||
return false;
|
||||
} else {
|
||||
QThread::msleep(1000);
|
||||
qInfo() << "starting bootloader...OK";
|
||||
}
|
||||
qCritical() << "starting bootloader...FAILED";
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Update::stopBootloader() const {
|
||||
QThread::msleep(1000);
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "stopping bootloader ...done";
|
||||
return true;
|
||||
|
||||
#if 0
|
||||
qDebug() << "stopping bootloader...";
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_stopBL();
|
||||
QThread::msleep(500);
|
||||
if (!m_hw->bl_isUp()) {
|
||||
qInfo() << "stopping bootloader...OK";
|
||||
return true;
|
||||
|
||||
if (!m_debug) {
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_stopBL();
|
||||
QThread::msleep(1000);
|
||||
if (!m_hw->bl_isUp()) {
|
||||
qInfo() << "stopping bootloader...OK";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
qCritical() << "stopping bootloader...FAILED";
|
||||
return false;
|
||||
|
||||
} else {
|
||||
QThread::msleep(1000);
|
||||
qInfo() << "stopping bootloader...OK";
|
||||
}
|
||||
qCritical() << "stopping bootloader...FAILED";
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Update::resetDeviceController() const {
|
||||
// TODO
|
||||
// m_hw->bl_rebootDC();
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "resetting device controller";
|
||||
|
||||
if (!m_debug) {
|
||||
m_hw->bl_rebootDC();
|
||||
}
|
||||
|
||||
// wait maximally 3 seconds, before starting bootloader
|
||||
QThread::sleep(1);
|
||||
@@ -313,12 +289,12 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const {
|
||||
if (!file.exists()) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
|
||||
<< file.fileName() << "does not exist";
|
||||
return QByteArray();
|
||||
return QByteArray{};
|
||||
}
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
|
||||
<< "cannot open file" << file.fileName();
|
||||
return QByteArray();
|
||||
return QByteArray{};
|
||||
}
|
||||
|
||||
qInfo() << nextTimePoint().toUtf8().constData()
|
||||
@@ -408,19 +384,26 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const {
|
||||
// There is no problem to repeat this command until the
|
||||
// bootloader is really not running anymore.
|
||||
*/
|
||||
bool Update::doUpdate(QString const &dcFileName) {
|
||||
qInfo() << "<DC-VERSION>" << Update::dcVersion(dcFileName);
|
||||
int Update::run() {
|
||||
if (!m_hw) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
|
||||
return -(int)Result::PLUGIN_LOAD_ERROR;
|
||||
}
|
||||
|
||||
m_dcFileName = dcFileName;
|
||||
m_start = QDateTime::currentDateTime();
|
||||
|
||||
//QString const &fToWorkOn = usbStickDetected ? QDir::cleanPath(it->trimmed())
|
||||
//: QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed());
|
||||
if (m_debug) {
|
||||
qInfo() << "start dc-update for" << m_dcFileName << "at" << m_start.toString(Qt::ISODate);
|
||||
qInfo() << "<DC-VERSION>" << Update::dcVersion(m_dcFileName);
|
||||
}
|
||||
|
||||
//if (!m_hw) {
|
||||
// qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
||||
// << "ERROR!!! m_hw == nullptr";
|
||||
// return false;
|
||||
//}
|
||||
if (!m_debug) {
|
||||
m_hw->dc_autoRequest(false);
|
||||
}
|
||||
|
||||
qInfo() << "DC auto request OFF";
|
||||
|
||||
qCritical() << "start dc-update for" << m_dcFileName << "at" << m_start.toString(Qt::ISODate);
|
||||
|
||||
QByteArray ba = loadBinaryDCFile(m_dcFileName);
|
||||
if (ba.size() > 0) {
|
||||
@@ -433,15 +416,14 @@ bool Update::doUpdate(QString const &dcFileName) {
|
||||
|
||||
resetDeviceController();
|
||||
if (startBootloader()) {
|
||||
|
||||
int currentBlock = 0;
|
||||
DownloadResult res = DownloadResult::OK;
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "64-byte block" << currentBlock;
|
||||
|
||||
while (res != DownloadResult::ERROR && currentBlock < m_totalBlocks) {
|
||||
while (res != DownloadResult::ERROR && currentBlock <= m_totalBlocks) {
|
||||
if ((res = sendNextAddress(currentBlock)) != DownloadResult::ERROR) {
|
||||
if ((res = sendNextDataBlock(ba, currentBlock)) != DownloadResult::ERROR) {
|
||||
// TODO
|
||||
// m_hw->dcDownloadSetCurrentBlockNumber(currentBlock);
|
||||
currentBlock += 1;
|
||||
} else break;
|
||||
}
|
||||
@@ -470,243 +452,26 @@ bool Update::doUpdate(QString const &dcFileName) {
|
||||
}
|
||||
stopBootloader(); // there is no harm in stopping the bootloader even
|
||||
// if starting the bootloader failed
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
|
||||
return true;
|
||||
|
||||
// check if update was successful
|
||||
if (!m_debug) {
|
||||
m_hw->dc_autoRequest(true); //restart dc_autoRequest after download else E255!
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
qInfo() << "waiting for device controller restart...(" << i << ")";
|
||||
QThread::sleep(20);
|
||||
|
||||
resetDeviceController();
|
||||
if (startBootloader()) {
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
|
||||
stopBootloader();
|
||||
return -(int)Result::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>";
|
||||
//To Do Error handling if Dc doesnt start after download
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool Update::checkJsonVersions(QStringList const& jsonFileNames) {
|
||||
if (!m_hw) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
||||
<< "ERROR!!! m_hw == nullptr";
|
||||
return false;
|
||||
}
|
||||
|
||||
int tries = 20;
|
||||
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
|
||||
// must deliver 'true', only then are all data from hwapi valid
|
||||
if (--tries < 0) {
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
||||
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED";
|
||||
return false;
|
||||
}
|
||||
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
||||
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED (" << tries << ")";
|
||||
m_hw->dc_autoRequest(true);
|
||||
QThread::msleep(500);
|
||||
}
|
||||
|
||||
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
|
||||
|
||||
uint8_t jsonNr = 0;
|
||||
|
||||
QString const &fName = jsonFileNames[i];
|
||||
|
||||
// send one request for every single version
|
||||
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
||||
// 6=printer template 1 ..... 36= template 32
|
||||
|
||||
if (fName.endsWith("conf.json")) {
|
||||
jsonNr = 1;
|
||||
} else
|
||||
if (fName.endsWith("device.json")) {
|
||||
jsonNr = 2;
|
||||
} else
|
||||
if (fName.endsWith("cash.json")) {
|
||||
jsonNr = 3;
|
||||
} else {
|
||||
QRegularExpressionMatch match;
|
||||
static const QRegularExpression re("^(.*print)([0-3][0-9])\\.json\\s*$");
|
||||
int idx = fName.indexOf(re, 0, &match);
|
||||
if (idx != -1) {
|
||||
QString captured = match.captured(match.lastCapturedIndex());
|
||||
bool ok = false;
|
||||
int n = captured.toInt(&ok);
|
||||
if (ok) {
|
||||
// note: use 5 (instead of 4 -> index has been shifted)
|
||||
jsonNr = n + 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonNr != 0) {
|
||||
// send one request for every single version
|
||||
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
||||
// 5=printer template 1 ..... 36= template 32
|
||||
|
||||
m_hw->sys_requestJsonVersions(jsonNr);
|
||||
QThread::msleep(500);
|
||||
|
||||
char buf[64];
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
m_hw->sys_getJsonVersions(jsonNr, buf);
|
||||
buf[16] = '\0'; // the DC only handles 16 bytes
|
||||
|
||||
static const QByteArray cb(16, (char)0xff);
|
||||
|
||||
QString const installedVersion(QString::fromStdString(buf));
|
||||
QString const fileVersion = getFileVersion(jsonFileNames[i]);
|
||||
|
||||
QFileInfo fi(jsonFileNames[i]);
|
||||
|
||||
qCritical() << endl;
|
||||
qCritical() << " json request nr:" << jsonNr;
|
||||
|
||||
if (installedVersion == fileVersion) {
|
||||
qCritical() << " json file:" << fi.fileName();
|
||||
qCritical() << " installed version in DC:" << installedVersion;
|
||||
} else
|
||||
if (cb == QByteArray(buf) && fileVersion == "") {
|
||||
qCritical() << "unknown json file (repo and DC):" << fi.fileName();
|
||||
} else {
|
||||
qCritical() << " json file:" << fi.fileName();
|
||||
qCritical() << " installed version in DC:" << installedVersion;
|
||||
qCritical() << " file version in repository:" << fileVersion;
|
||||
}
|
||||
|
||||
} else {
|
||||
qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QString Update::getFileVersion(QString const& jsonFileName) {
|
||||
// "version":"15.10.2023 14:55 02.00.06",
|
||||
static const QRegularExpression re("^.*(\\\"[Vv]ersion\\\":)([\\s\\\"]{0,})([^,\\\"]{0,}).*$");
|
||||
|
||||
QString fileVersion("");
|
||||
QFile inputFile(QDir::cleanPath(m_customerRepository + QDir::separator() + jsonFileName));
|
||||
|
||||
if (inputFile.exists()) {
|
||||
if (inputFile.open(QIODevice::ReadOnly)) {
|
||||
QTextStream in(&inputFile);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
|
||||
QRegularExpressionMatch match;
|
||||
int idx = line.indexOf(re, 0, &match);
|
||||
if (idx != -1) {
|
||||
int const lastCaptured = match.lastCapturedIndex();
|
||||
// the dc only sends 16 Byte
|
||||
fileVersion = match.captured(lastCaptured);
|
||||
fileVersion.truncate(16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
inputFile.close();
|
||||
}
|
||||
} else {
|
||||
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
|
||||
}
|
||||
|
||||
return fileVersion;
|
||||
}
|
||||
|
||||
bool Update::downloadJson(enum FileTypeJson type,
|
||||
int templateIdx,
|
||||
QString jsFileToSendToDC) const {
|
||||
|
||||
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
|
||||
qDebug() << "SET AUTO-REQUEST=TRUE";
|
||||
QThread::sleep(1); // make sure the auto-request flag is acknowledged
|
||||
|
||||
QStringList lst;
|
||||
bool ready = false;
|
||||
int nTry = 25;
|
||||
while ((ready = m_hw->sys_ready4sending()) == false) {
|
||||
QThread::msleep(200);
|
||||
if (--nTry <= 0) {
|
||||
qCritical() << "SYS NOT READY FOR SENDING AFTER 5 SECONDS";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
QString msg;
|
||||
lst.clear();
|
||||
if (ready) {
|
||||
QFile file(jsFileToSendToDC);
|
||||
QFileInfo fi(jsFileToSendToDC); // max. size of template file is 800 bytes
|
||||
if (file.exists()) {
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
if (fi.size() > 0 && fi.size() <= 800) {
|
||||
QByteArray ba = file.readAll();
|
||||
// kindOfFile: 1=config, 2=device, 3=cash, 4=serial, 5=time, 6=printer
|
||||
// nrOfTemplate=1...32 if kindOfFile==6
|
||||
// content = content of the Json file, max 800byte ascii signs
|
||||
if (m_hw->sys_sendJsonFileToDc((uint8_t)(type),
|
||||
templateIdx,
|
||||
(uint8_t *)ba.data())) {
|
||||
|
||||
/*
|
||||
* Note: the machine id is contained in DC2C_conf.json.
|
||||
* The idea was to use this to check if the download of
|
||||
* the json-file was correct. It did not work, as the
|
||||
* update of the PSA (to reflect a change in the
|
||||
* machine id) did not happen immediately.
|
||||
*
|
||||
m_hw->dc_autoRequest(true);
|
||||
QThread::msleep(500);
|
||||
|
||||
// testing
|
||||
m_hw->request_ReadbackMachineID();
|
||||
QThread::msleep(500);
|
||||
|
||||
uint8_t data[64];
|
||||
memset(data, 0x00, sizeof(data));
|
||||
uint8_t length = 0;
|
||||
|
||||
m_hw->readback_machineIDdata(&length, data);
|
||||
|
||||
QThread::msleep(500);
|
||||
|
||||
QByteArray ba((const char*)data, length);
|
||||
|
||||
qCritical() << length << "MACHINE ID =" << ba.toHex(':');
|
||||
*/
|
||||
|
||||
ret = true;
|
||||
} else {
|
||||
qCritical() << QString("ERROR SEND JSON-FILE %1 TO DC").arg(file.fileName());
|
||||
}
|
||||
} else {
|
||||
qCritical() << QString("SIZE OF %1 TOO BIG (%2 BYTES)").arg(jsFileToSendToDC).arg(fi.size());
|
||||
}
|
||||
} else {
|
||||
qCritical() << QString("CAN NOT OPEN ") + jsFileToSendToDC + " FOR READING";
|
||||
}
|
||||
} else {
|
||||
qCritical() << (QString(jsFileToSendToDC) + " DOES NOT EXIST");
|
||||
}
|
||||
}
|
||||
|
||||
m_hw->dc_autoRequest(false);
|
||||
qDebug() << "SET AUTO-REQUEST=FALSE";
|
||||
QThread::sleep(1); // make sure the auto-request flag is acknowledged
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Update::updatePrinterTemplate(int templateIdx, QString jsFile) const {
|
||||
return downloadJson(FileTypeJson::PRINTER, templateIdx, jsFile);
|
||||
}
|
||||
|
||||
bool Update::updateConfig(QString jsFile) {
|
||||
return downloadJson(FileTypeJson::CONFIG, 0, jsFile);
|
||||
}
|
||||
|
||||
bool Update::updateCashConf(QString jsFile) {
|
||||
return downloadJson(FileTypeJson::CASH, 0, jsFile);
|
||||
}
|
||||
|
||||
bool Update::updateDeviceConf(QString jsFile) {
|
||||
return downloadJson(FileTypeJson::DEVICE, 0, jsFile);
|
||||
}
|
||||
#endif
|
||||
|
@@ -17,26 +17,21 @@
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
#define BAUDRATE 115200
|
||||
#else
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#define BAUDRATE 115200
|
||||
#endif
|
||||
|
||||
class QSerialPort;
|
||||
class Update : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_dcFileName{};
|
||||
hwinf *m_hw = nullptr;
|
||||
char const *m_serialInterface;
|
||||
char const *m_baudrate;
|
||||
QString m_customerRepository;
|
||||
QString m_customerNrStr;
|
||||
QString m_branchName;
|
||||
QString m_pluginName;
|
||||
QString m_workingDir;
|
||||
QString m_psaDcDir;
|
||||
QString m_dcFileName;
|
||||
bool m_maintenanceMode;
|
||||
bool m_dryRun;
|
||||
bool m_sys_areDCdataValid;
|
||||
bool m_sys_areDCdataValid{};
|
||||
bool m_debug{false};
|
||||
bool m_noaction;
|
||||
|
||||
static QPluginLoader pluginLoader;
|
||||
|
||||
@@ -48,27 +43,16 @@ class Update : public QObject {
|
||||
|
||||
public:
|
||||
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
|
||||
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
|
||||
enum class Result {SUCCESS=0, PLUGIN_LOAD_ERROR};
|
||||
|
||||
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn);
|
||||
static hwinf *loadDCPlugin(QString const &libCA = "/usr/lib/libCAslave.so");
|
||||
static bool unloadDCPlugin();
|
||||
static QStringList split(QString line, QChar sep = ',');
|
||||
|
||||
explicit Update(QString customerRepository,
|
||||
QString customerNrStr,
|
||||
QString branchName,
|
||||
QString plugInDir,
|
||||
QString pluginName,
|
||||
QString workingDir,
|
||||
QString psaDcDir,
|
||||
bool dryRun = false,
|
||||
QObject *parent = nullptr,
|
||||
char const *serialInterface = SERIAL_PORT,
|
||||
char const *baudrate = "115200");
|
||||
|
||||
explicit Update(QString const &dcBinFile, QString const &libCA, bool debug, bool noaction);
|
||||
virtual ~Update() override;
|
||||
|
||||
bool doUpdate(QString const &dcFileName);
|
||||
int run();
|
||||
static QString dcVersion(QString const &dcBinFile);
|
||||
|
||||
private:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
QT += core
|
||||
QT += serialport network
|
||||
|
||||
TARGET = ATBDownloadDCJsonFiles
|
||||
TARGET = ATBUpdateJsonFiles
|
||||
|
||||
VERSION="0.1.0"
|
||||
win32 {
|
||||
@@ -79,13 +79,13 @@ contains( CONFIG, DesktopLinux ) {
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
../UpdatePTUDevCtrl/message_handler.cpp \
|
||||
../UpdatePTUDevCtrl/commandline_parser.cpp \
|
||||
../common/src/commandline_parser.cpp \
|
||||
update.cpp \
|
||||
../common/src/System.cpp
|
||||
|
||||
HEADERS += \
|
||||
../UpdatePTUDevCtrl/message_handler.h \
|
||||
../UpdatePTUDevCtrl/commandline_parser.h \
|
||||
../common/include/commandline_parser.h \
|
||||
update.h \
|
||||
../common/include/System.h
|
||||
|
||||
|
@@ -144,7 +144,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// qCritical() << "JSON FILES TO UPDATE" << filesToUpdate;
|
||||
qCritical() << __LINE__ << "JSON FILES TO UPDATE" << filesToUpdate;
|
||||
|
||||
Update update(customerRepo,
|
||||
QString::number(customerNr),
|
||||
@@ -153,8 +153,10 @@ int main(int argc, char **argv) {
|
||||
plugInName,
|
||||
workingDir);
|
||||
|
||||
update.doUpdate();
|
||||
// update.doUpdate(filesToUpdate, mountPath.has_value());
|
||||
if (!filesToUpdate.empty()) {
|
||||
update.doUpdate(filesToUpdate, mountPath.has_value());
|
||||
}
|
||||
|
||||
// update.checkJsonVersions();
|
||||
//update.checkJsonVersions(filesToUpdate);
|
||||
|
||||
|
@@ -107,7 +107,7 @@ Update::Update(QString customerRepository,
|
||||
char const *serialInterface,
|
||||
char const *baudrate)
|
||||
: QObject(parent)
|
||||
// , m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
|
||||
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
|
||||
, m_serialInterface(serialInterface)
|
||||
, m_baudrate(baudrate)
|
||||
, m_customerRepository(customerRepository)
|
||||
@@ -145,7 +145,8 @@ Update::~Update() {
|
||||
// unloadDCPlugin();
|
||||
}
|
||||
|
||||
bool Update::doUpdate() {
|
||||
#if 0
|
||||
bool Update::doUpdate() { // test function
|
||||
|
||||
int numberOfFiles = 3;
|
||||
|
||||
@@ -178,6 +179,7 @@ bool Update::doUpdate() {
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {
|
||||
|
||||
|
87
Git/Git.pro
Normal file
87
Git/Git.pro
Normal file
@@ -0,0 +1,87 @@
|
||||
QT += core
|
||||
|
||||
TARGET = ATBUpdateGit
|
||||
|
||||
VERSION="1.0.0"
|
||||
win32 {
|
||||
BUILD_DATE=$$system("date /t")
|
||||
BUILD_TIME=$$system("time /t")
|
||||
} else {
|
||||
BUILD_DATE=$$system("date +%d-%m-%y")
|
||||
BUILD_TIME=$$system("date +%H:%M:%S")
|
||||
}
|
||||
|
||||
GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
|
||||
|
||||
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
|
||||
|
||||
|
||||
INCLUDEPATH += plugins \
|
||||
$${INCLUDEINTERFACES}/ \
|
||||
$${_PRO_FILE_PWD_}/../common/ \
|
||||
$${_PRO_FILE_PWD_}/../common/include
|
||||
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
|
||||
DEFINES+=APP_BUILD_DATE=\\\"$$BUILD_DATE\\\"
|
||||
DEFINES+=APP_BUILD_TIME=\\\"$$BUILD_TIME\\\"
|
||||
DEFINES+=APP_EXTENDED_VERSION=\\\"$$EXTENDED_VERSION\\\"
|
||||
|
||||
# keep comments, as /* fall through */
|
||||
QMAKE_CXXFLAGS += -C
|
||||
QMAKE_CXXFLAGS += -g
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy -O
|
||||
|
||||
contains( CONFIG, PTU5 ) {
|
||||
CONFIG += link_pkgconfig
|
||||
QMAKE_CXXFLAGS += -O2 -std=c++17 # for GCC >= 4.7
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
PTU5BASEPATH = /opt/devel/ptu5
|
||||
|
||||
INCLUDEPATH += $$PTU5BASEPATH/qt/libs/devicecontroller/include
|
||||
LIBS += -L$$PTU5BASEPATH/qt/libs/devicecontroller/library
|
||||
|
||||
ARCH = PTU5
|
||||
DEFINES+=PTU5
|
||||
}
|
||||
contains( CONFIG, PTU5_YOCTO ) {
|
||||
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
PTU5BASEPATH = /opt/devel/ptu5
|
||||
ARCH = PTU5
|
||||
DEFINES+=PTU5
|
||||
}
|
||||
contains( CONFIG, DesktopLinux ) {
|
||||
# QMAKE_CC = ccache $$QMAKE_CC
|
||||
# QMAKE_CXX = ccache $$QMAKE_CXX
|
||||
QMAKE_CXXFLAGS += -std=c++17
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
|
||||
ARCH = DesktopLinux
|
||||
DEFINES+=DesktopLinux
|
||||
}
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
message_handler.cpp \
|
||||
../common/src/utils_internal.cpp \
|
||||
../common/src/command.cpp \
|
||||
../common/src/commandline_parser.cpp \
|
||||
git_command.cpp
|
||||
|
||||
HEADERS += \
|
||||
message_handler.h \
|
||||
../common/include/utils_internal.h \
|
||||
../common/include/command.h \
|
||||
../common/include/commandline_parser.h \
|
||||
git_command.h
|
||||
|
||||
##########################################################################################
|
||||
# for running program on target through QtCreator
|
||||
contains( CONFIG, PTU5 ) {
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/app/tools/atbupdate/
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
}
|
105
Git/git_command.cpp
Normal file
105
Git/git_command.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "git_command.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "utils_internal.h"
|
||||
using namespace internal;
|
||||
|
||||
#include <QProcess>
|
||||
#include <QByteArray>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
bool GitCommand::initEnv = false;
|
||||
static bool initEnv() {
|
||||
QString gitSSHCommand{""};
|
||||
QByteArray const v = qgetenv("GIT_SSH_COMMAND");
|
||||
if (v.isEmpty()) {
|
||||
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
|
||||
if (QFileInfo(sshKeyFile).exists()) {
|
||||
if (qgetenv("GIT_SSH_COMMAND").isNull()) {
|
||||
gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig";
|
||||
if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) {
|
||||
qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting...";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting...";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
gitSSHCommand = QString(v.toStdString().c_str());
|
||||
qCritical() << "WARNING GIT_SSH_COMMAND already set in enviroment:"
|
||||
<< gitSSHCommand;
|
||||
if (gitSSHCommand != "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig") {
|
||||
qCritical() << "ERROR" << gitSSHCommand << "wrong. Exiting...";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// qCritical() << __func__ << ":" << __LINE__ << gitSSHCommand;
|
||||
return true;
|
||||
}
|
||||
|
||||
GitCommand::GitCommand()
|
||||
: m_workingDirectory(customerRepoDir()) {
|
||||
// qCritical() << __func__ << ":" << __LINE__ << m_workingDirectory;
|
||||
if (!GitCommand::initEnv) {
|
||||
GitCommand::initEnv = ::initEnv();
|
||||
}
|
||||
}
|
||||
|
||||
bool GitCommand::exec(QStringList const &options, int start_timeout, int finish_timeout) {
|
||||
bool ret = false;
|
||||
if (GitCommand::initEnv) {
|
||||
Command cmd(QString("git"), options, m_workingDirectory,
|
||||
start_timeout, finish_timeout);
|
||||
ret = cmd.exec();
|
||||
//qCritical() << __func__ << ":" << __LINE__ << cmd.command()
|
||||
// << "," << cmd.args()
|
||||
// << ", result" << cmd.commandResult();
|
||||
m_commandResult = cmd.commandResult();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GitCommand::check(int start_timeout, int finish_timeout) {
|
||||
m_workingDirectory = customerRepoDir();
|
||||
QStringList const lst{"fsck"};
|
||||
return exec(lst, start_timeout, finish_timeout);
|
||||
}
|
||||
|
||||
bool GitCommand::checkout(int start_timeout, int finish_timeout) {
|
||||
m_workingDirectory = customerRepoDir();
|
||||
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
|
||||
if (zoneNr != -1) {
|
||||
QStringList const lst{"checkout", QString("zg1/zone%1").arg(zoneNr)};
|
||||
// qCritical() << __func__ << __LINE__ << lst;
|
||||
return exec(lst, start_timeout, finish_timeout);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitCommand::clone(int start_timeout, int finish_timeout) {
|
||||
m_workingDirectory = customerRepoRoot(); // /opt/app/tools/atbupdate !
|
||||
QDir const repoDir{customerRepoDir()};
|
||||
if (repoDir.exists() && repoDir.entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries).count() != 0) {
|
||||
qCritical() << "clone error:" << repoDir << "exists and is not empty";
|
||||
return false;
|
||||
}
|
||||
// git clone "gitea@ptu-config.atb-comm.de:ATB/customer_999"
|
||||
QStringList const lst{"clone", repositoryUrl() + customerRepoDirName()};
|
||||
return exec(lst, start_timeout, finish_timeout);
|
||||
}
|
||||
|
||||
bool GitCommand::pull(int start_timeout, int finish_timeout) {
|
||||
m_workingDirectory = customerRepoDir();
|
||||
QStringList const lst{"pull"};
|
||||
return exec(lst, start_timeout, finish_timeout);
|
||||
}
|
||||
|
||||
bool GitCommand::status(int start_timeout, int finish_timeout) {
|
||||
m_workingDirectory = customerRepoDir();
|
||||
QStringList const lst{"status"};
|
||||
return exec(lst, start_timeout, finish_timeout);
|
||||
}
|
30
Git/git_command.h
Normal file
30
Git/git_command.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef GIT_COMMAND_H_INCLUDED
|
||||
#define GIT_COMMAND_H_INCLUDED
|
||||
|
||||
#include <QStringList>
|
||||
#include <QScopedPointer>
|
||||
|
||||
class QProcess;
|
||||
class GitCommand {
|
||||
static bool initEnv;
|
||||
QString m_workingDirectory;
|
||||
|
||||
bool exec(QStringList const &options, int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
|
||||
QString m_commandResult{};
|
||||
|
||||
public:
|
||||
GitCommand();
|
||||
|
||||
void resetCommandResult() { m_commandResult.clear(); }
|
||||
QString const &commandResult() const { return m_commandResult; }
|
||||
|
||||
bool status(int start_timeout = 100000, int finish_timeout = 100000);
|
||||
bool check(int start_timeout = 100000, int finish_timeout = 100000);
|
||||
bool checkout(int start_timeout = 100000, int finish_timeout = 100000);
|
||||
bool clone(int start_timeout = 100000, int finish_timeout = 100000);
|
||||
bool pull(int start_timeout = 100000, int finish_timeout = 100000);
|
||||
};
|
||||
|
||||
#endif // GIT_COMMAND_H_INCLUDED
|
170
Git/main.cpp
Normal file
170
Git/main.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QByteArray>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QCommandLineParser>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QRegularExpression>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "utils_internal.h"
|
||||
#include "git_command.h"
|
||||
#include "commandline_parser.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-GIT", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
|
||||
|
||||
QCoreApplication a(argc, argv);
|
||||
QCoreApplication::setApplicationName("ATBUpdateGit");
|
||||
QCoreApplication::setApplicationVersion(APP_VERSION);
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(nullptr);
|
||||
//atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
CommandLineParser parser;
|
||||
parser.setApplicationDescription("git-commands for the update-system");
|
||||
|
||||
QCommandLineOption const checkCustomerRepositoryOption{"check"};
|
||||
QCommandLineOption const cloneCustomerRepositoryOption{"clone"};
|
||||
QCommandLineOption const pullBranchOption{"pull"};
|
||||
QCommandLineOption const checkoutBranchOption("checkout");
|
||||
|
||||
parser.addOption(checkCustomerRepositoryOption);
|
||||
parser.addOption(cloneCustomerRepositoryOption);
|
||||
parser.addOption(pullBranchOption);
|
||||
parser.addOption(checkoutBranchOption);
|
||||
|
||||
QCommandLineOption verboseOption{parser.addVersionOption()};
|
||||
parser.process(a);
|
||||
parser.readSettings();
|
||||
|
||||
#if 0
|
||||
// note: also used in initEnv().
|
||||
|
||||
QString repositoryUrl = parser.repositoryUrl();
|
||||
|
||||
if (repositoryUrl.endsWith('/')) {
|
||||
repositoryUrl.chop(1);
|
||||
}
|
||||
|
||||
if (!repositoryUrl.isEmpty()) {
|
||||
qInfo() << "customer repository url" << repositoryUrl;
|
||||
} else {
|
||||
qCritical() << "ERROR customer repository url empty. git commands might fail.";
|
||||
}
|
||||
|
||||
if (repositoryUrl.contains("ptu-config.atb-comm.de")) {
|
||||
QString gitSSHCommand("");
|
||||
QByteArray const v = qgetenv("GIT_SSH_COMMAND");
|
||||
if (v.isEmpty()) {
|
||||
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
|
||||
if (QFileInfo(sshKeyFile).exists()) {
|
||||
if (qgetenv("GIT_SSH_COMMAND").isNull()) {
|
||||
gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig";
|
||||
if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) {
|
||||
qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting...";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting...";
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
gitSSHCommand = QString(v.toStdString().c_str());
|
||||
qInfo() << "GIT_SSH_COMMAND already set in enviroment:" << gitSSHCommand;
|
||||
if (gitSSHCommand != "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig") {
|
||||
qCritical() << "ERROR" << gitSSHCommand << "wrong. Exiting...";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gitSSHCommand.isEmpty()) {
|
||||
qInfo() << "GIT_SSH_COMMAND .........." << gitSSHCommand;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parser.isSet(verboseOption)) {
|
||||
parser.showVersion();
|
||||
return 0;
|
||||
}
|
||||
|
||||
GitCommand gitCmd;
|
||||
|
||||
if (parser.isSet(checkCustomerRepositoryOption)) {
|
||||
if (!gitCmd.check()) {
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
if (parser.isSet(checkoutBranchOption)) {
|
||||
if (!gitCmd.checkout()) {
|
||||
return -2;
|
||||
}
|
||||
} else
|
||||
if (parser.isSet(cloneCustomerRepositoryOption)) {
|
||||
if (!gitCmd.clone()) {
|
||||
return -3;
|
||||
}
|
||||
} else
|
||||
if (parser.isSet(pullBranchOption)) {
|
||||
if (!gitCmd.pull()) {
|
||||
return -4;
|
||||
}
|
||||
} else {
|
||||
if (internal::customerRepoExists()) {
|
||||
if (!gitCmd.checkout()) {
|
||||
return -2;
|
||||
}
|
||||
if (!gitCmd.pull()) {
|
||||
return -4;
|
||||
}
|
||||
QString const result = gitCmd.commandResult().trimmed();
|
||||
if (result.contains("Already", Qt::CaseInsensitive)
|
||||
&& result.contains("up", Qt::CaseInsensitive)
|
||||
&& result.contains("to", Qt::CaseInsensitive)
|
||||
&& result.contains("date", Qt::CaseInsensitive)) {
|
||||
qCritical() << internal::GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY;
|
||||
return internal::GIT_NOT_NECESSARY_CODE;
|
||||
} else
|
||||
if (result.contains(QRegularExpression("[Uu]pdating\\s+[a-z0-9]{6,}\\.\\.[a-z0-9]{6,}"))) {
|
||||
// Updating 49a97f5..13a0321
|
||||
qCritical() << internal::GIT_CUSTOMER_REPO_UPDATED;
|
||||
return internal::GIT_UPDATED_CODE;
|
||||
}
|
||||
} else {
|
||||
if (!gitCmd.clone()) {
|
||||
return -3;
|
||||
}
|
||||
if (!gitCmd.checkout()) {
|
||||
return -2;
|
||||
}
|
||||
qCritical() << internal::GIT_CUSTOMER_REPO_CLONED;
|
||||
return internal::GIT_CLONED_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
97
Git/message_handler.cpp
Executable file
97
Git/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
Git/message_handler.h
Executable file
23
Git/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
|
@@ -1,6 +1,6 @@
|
||||
QT += core
|
||||
|
||||
TARGET = ExecOpkgCmds
|
||||
TARGET = ATBUpdateOpkg
|
||||
|
||||
VERSION="1.0.0"
|
||||
win32 {
|
||||
@@ -64,9 +64,17 @@ contains( CONFIG, DesktopLinux ) {
|
||||
}
|
||||
|
||||
SOURCES += \
|
||||
main.cpp
|
||||
main.cpp \
|
||||
message_handler.cpp \
|
||||
../common/src/utils_internal.cpp \
|
||||
../common/src/command.cpp \
|
||||
opkg_command.cpp
|
||||
|
||||
# HEADERS += \
|
||||
HEADERS += \
|
||||
message_handler.h \
|
||||
../common/include/utils_internal.h \
|
||||
../common/include/command.h \
|
||||
opkg_command.h
|
||||
|
||||
##########################################################################################
|
||||
# for running program on target through QtCreator
|
||||
|
@@ -4,11 +4,66 @@
|
||||
|
||||
#include <QProcess>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "utils_internal.h"
|
||||
#include "opkg_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-OPKG", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
|
||||
|
||||
QCoreApplication a(argc, argv);
|
||||
QCoreApplication::setApplicationName("ATBUpdateOpkg");
|
||||
QCoreApplication::setApplicationVersion(APP_VERSION);
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(nullptr);
|
||||
//atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
QString s = "<OPKG>\n\naaa<OPKG>bbb<OPKG>ccc<OPKG>\n";
|
||||
QString m_standardOutput{};
|
||||
if (!s.isEmpty()) {
|
||||
m_standardOutput += s.replace(QChar('\n'), "");
|
||||
qCritical() << m_standardOutput;
|
||||
|
||||
int startIndex, endIndex{};
|
||||
while (((startIndex = m_standardOutput.indexOf("<OPKG>")) == 0) &&
|
||||
((endIndex = m_standardOutput.indexOf("<OPKG>", 1)) != -1)) {
|
||||
QString str = m_standardOutput.mid(0, endIndex);
|
||||
qCritical() << "str" << str << str.mid(6);
|
||||
m_standardOutput = m_standardOutput.mid(endIndex);
|
||||
// qCritical() << "m" << m_standardOutput;
|
||||
}
|
||||
qCritical() << "m" << m_standardOutput;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption noactionOption("noaction");
|
||||
QCommandLineOption verboseOption("verbose");
|
||||
parser.addOption(noactionOption);
|
||||
parser.addOption(verboseOption);
|
||||
parser.process(a);
|
||||
|
||||
bool noaction = parser.isSet(noactionOption);
|
||||
OpkgCommand opkgCmd(noaction);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
97
Opkg/message_handler.cpp
Executable file
97
Opkg/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
Opkg/message_handler.h
Executable file
23
Opkg/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
|
176
Opkg/opkg_command.cpp
Normal file
176
Opkg/opkg_command.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "opkg_command.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "utils_internal.h"
|
||||
using namespace internal;
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QFlags>
|
||||
#include <QRegularExpression>
|
||||
|
||||
OpkgCommand::OpkgCommand(bool noaction, QString const &opkg_commands_filename)
|
||||
: m_noaction(noaction)
|
||||
, m_opkg_commands_filename(opkg_commands_filename) {
|
||||
cleanUpOpkgCache();
|
||||
execCommandsInternal();
|
||||
}
|
||||
|
||||
bool OpkgCommand::readCommands() {
|
||||
QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
|
||||
if (!opkgFile.exists()) {
|
||||
qCritical() << __func__ << ":" << __LINE__
|
||||
<< opkgFile.fileName() << "does not exists";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_commands.clear();
|
||||
|
||||
if (opkgFile.open(QIODevice::ReadOnly)) {
|
||||
QTextStream in(&opkgFile);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
// TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
|
||||
static const QRegularExpression comment("^\\s*[#].*$");
|
||||
static const QRegularExpression emptyLine("^\\s*$");
|
||||
if (line.indexOf(emptyLine, 0) == -1 &&
|
||||
line.indexOf(comment, 0) == -1) {
|
||||
QString const &commandLine = line.trimmed();
|
||||
if (!commandLine.isEmpty()) {
|
||||
m_commands << commandLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << __func__ << ":" << __LINE__
|
||||
<< "error opening" << opkgFile.fileName();
|
||||
}
|
||||
|
||||
return m_commands.size() > 0;
|
||||
}
|
||||
|
||||
bool OpkgCommand::execCommandsInternal() {
|
||||
if (readCommands()) {
|
||||
// command lines are located between markers: <OPKG>...<OPKG>
|
||||
// they are later removed when used by the update-tool.
|
||||
qCritical().noquote() << "<OPKG>";
|
||||
QListIterator<QString> it(m_commands);
|
||||
while (it.hasNext()) {
|
||||
QString command = it.next();
|
||||
QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
|
||||
if (cmdAndOptions.size() > 0) {
|
||||
QString const &cmd = cmdAndOptions.takeFirst();
|
||||
if (m_noaction) {
|
||||
if (cmd.contains("opkg")) {
|
||||
cmdAndOptions.prepend("--noaction");
|
||||
} else continue; // only opkg has the --noaction option
|
||||
}
|
||||
QStringList const &options = cmdAndOptions;
|
||||
if (exec(cmd, options)) {
|
||||
qCritical().noquote() << cmd << options.join(" ") << "ok" << "<OPKG>";
|
||||
} else {
|
||||
qCritical().noquote() << cmd << options.join(" ") << "FAIL" << "<OPKG>";
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool OpkgCommand::execCommands() {
|
||||
if (readCommands()) {
|
||||
QListIterator<QString> it(m_commands);
|
||||
while (it.hasNext()) {
|
||||
QString command = it.next();
|
||||
QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
|
||||
if (cmdAndOptions.size() > 0) {
|
||||
QString const &cmd = cmdAndOptions.takeFirst();
|
||||
if (m_noaction) {
|
||||
cmdAndOptions.prepend("--noaction");
|
||||
}
|
||||
QStringList const &options = cmdAndOptions;
|
||||
if (exec(cmd, options)) {
|
||||
qCritical().noquote() << cmd << options.join(" ");
|
||||
} else {
|
||||
qCritical().noquote() << cmd << options.join(" ") << "FAIL";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
|
||||
QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
|
||||
if (!opkgFile.exists()) {
|
||||
qCritical() << __func__ << ":" << __LINE__
|
||||
<< opkgFile.fileName() << "does not exists";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opkgFile.open(QIODevice::ReadOnly)) {
|
||||
QTextStream in(&opkgFile);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
// TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
|
||||
static const QRegularExpression comment("^\\s*[#].*$");
|
||||
static const QRegularExpression emptyLine("^\\s*$");
|
||||
if (line.indexOf(emptyLine, 0) == -1 &&
|
||||
line.indexOf(comment, 0) == -1) {
|
||||
QString const &commandLine = line.trimmed();
|
||||
if (!commandLine.isEmpty()) {
|
||||
QStringList cmdAndOptions = commandLine.split(u' ', QString::SkipEmptyParts);
|
||||
if (cmdAndOptions.size() > 0) {
|
||||
QString const &cmd = cmdAndOptions.takeFirst();
|
||||
if (m_noaction) {
|
||||
cmdAndOptions.prepend("--noaction");
|
||||
}
|
||||
QStringList const &options = cmdAndOptions;
|
||||
if (exec(cmd, options)) {
|
||||
qCritical().noquote() << cmd << options.join(" ") << "ok";
|
||||
} else {
|
||||
qCritical().noquote() << cmd << options.join(" ") << "FAIL";
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << __func__ << ":" << __LINE__
|
||||
<< "error opening" << opkgFile.fileName();
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OpkgCommand::exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout, int finish_timeout) {
|
||||
bool const verbose = false;
|
||||
return Command(cmd, options, "/tmp", verbose, start_timeout, finish_timeout).exec();
|
||||
}
|
||||
|
||||
bool OpkgCommand::cleanUpOpkgCache() {
|
||||
bool removedFiles = true;
|
||||
QDir dir("/var/cache/opkg/");
|
||||
if (dir.exists()) {
|
||||
dir.setNameFilters(QStringList() << ".gz" << ".ipk");
|
||||
dir.setFilter(QDir::Files);
|
||||
foreach(QString dirFile, dir.entryList()) {
|
||||
removedFiles &= dir.remove(dirFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (removedFiles == false) {
|
||||
qCritical() << "some errors while cleaning up opkg-cache";
|
||||
}
|
||||
|
||||
return removedFiles;
|
||||
}
|
29
Opkg/opkg_command.h
Normal file
29
Opkg/opkg_command.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef OPKG_COMMND_H_INCLUDED
|
||||
#define OPKG_COMMND_H_INCLUDED
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class OpkgCommand {
|
||||
QString const m_opkg_commands_dir{"/etc/psa_update/"};
|
||||
bool m_noaction;
|
||||
QString m_opkg_commands_filename;
|
||||
QStringList m_commands;
|
||||
|
||||
bool execCommands();
|
||||
bool execCommandsInternal();
|
||||
bool cleanUpOpkgCache();
|
||||
|
||||
public:
|
||||
OpkgCommand(bool noaction = false,
|
||||
QString const &opkg_commands_file_name="opkg_commands");
|
||||
|
||||
bool exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout = 100000, int finish_timeout = 100000);
|
||||
|
||||
QStringList commands() { return m_commands; }
|
||||
QStringList const &commands() const { return m_commands; }
|
||||
|
||||
bool readCommands();
|
||||
};
|
||||
|
||||
#endif // OPKG_COMMND_H_INCLUDED
|
@@ -1,6 +1,6 @@
|
||||
QT += core
|
||||
|
||||
TARGET = show_update
|
||||
TARGET = ATBUpdateShow
|
||||
|
||||
VERSION="1.0.0"
|
||||
win32 {
|
||||
|
@@ -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,86 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "utils_internal.h"
|
||||
#include "sync_command.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
|
||||
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);
|
||||
|
||||
QDebug debug = qCritical();
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(nullptr);
|
||||
//atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
if (internal::customerRepoExists() == false) {
|
||||
qCritical().noquote() << internal::NO_CUSTOMER_REPOSITORY;
|
||||
return internal::NO_CUSTOMER_REPOSITORY_CODE;
|
||||
}
|
||||
|
||||
QString const crd = internal::customerRepoDir();
|
||||
QString const etcInRepo = QDir::cleanPath(crd + QDir::separator() + "etc/");
|
||||
QString const optInRepo = QDir::cleanPath(crd + QDir::separator() + "opt/");
|
||||
|
||||
if (!QDir(etcInRepo).exists()) {
|
||||
qCritical().noquote() << internal::NO_ETC_CUSTOMER_REPOSITORY;
|
||||
return internal::NO_ETC_CUSTOMER_REPOSITORY_CODE;
|
||||
}
|
||||
|
||||
if (!QDir(optInRepo).exists()) {
|
||||
qCritical().noquote() << internal::NO_OPT_CUSTOMER_REPOSITORY;
|
||||
return internal::NO_OPT_CUSTOMER_REPOSITORY_CODE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
error codes for rsync:
|
||||
https://stackoverflow.com/questions/20737204/comprehensive-list-of-rsync-error-codes
|
||||
|
||||
0 Success
|
||||
1 Syntax or usage error
|
||||
2 Protocol incompatibility
|
||||
3 Errors selecting input/output files, dirs
|
||||
4 Requested action not supported: an attempt was made to manipulate 64-bit
|
||||
files on a platform that cannot support them; or an option was specified
|
||||
that is supported by the client and not by the server.
|
||||
5 Error starting client-server protocol
|
||||
6 Daemon unable to append to log-file
|
||||
10 Error in socket I/O
|
||||
11 Error in file I/O
|
||||
12 Error in rsync protocol data stream
|
||||
13 Errors with program diagnostics
|
||||
14 Error in IPC code
|
||||
20 Received SIGUSR1 or SIGINT
|
||||
21 Some error returned by waitpid()
|
||||
22 Error allocating core memory buffers
|
||||
23 Partial transfer due to error
|
||||
24 Partial transfer due to vanished source files
|
||||
25 The --max-delete limit stopped deletions
|
||||
30 Timeout in data send/receive
|
||||
35 Timeout waiting for daemon connection
|
||||
#endif
|
||||
|
||||
|
||||
QStringList options({"-v", "--recursive", "--progress", "--checksum",
|
||||
"--exclude=.*", "--include=*.bin", "--include=*.json",
|
||||
"--include=*.ini"});
|
||||
int ret = SyncCommand().exec("rsync", options << etcInRepo << "/etc");
|
||||
|
||||
if (ret == 0) {
|
||||
ret = SyncCommand().exec("rsync", options << optInRepo << "/opt");
|
||||
}
|
||||
return (ret > 0) ? -ret : ret;
|
||||
}
|
||||
|
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
|
21
Sync/sync_command.cpp
Normal file
21
Sync/sync_command.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "sync_command.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "utils_internal.h"
|
||||
using namespace internal;
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QFlags>
|
||||
#include <QRegularExpression>
|
||||
|
||||
SyncCommand::SyncCommand() {
|
||||
}
|
||||
|
||||
int SyncCommand::exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout, int finish_timeout) {
|
||||
Command c(cmd, options, internal::customerRepoDir(),
|
||||
start_timeout, finish_timeout);
|
||||
c.exec();
|
||||
return c.exitCode();
|
||||
}
|
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();
|
||||
|
||||
int exec(QString const &cmd, QStringList const &options,
|
||||
int start_timeout = 100000, int finish_timeout = 100000);
|
||||
};
|
||||
|
||||
#endif // SYNC_COMMAND_H_INCLUDED
|
@@ -147,7 +147,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||
# 1.5.5 : Call into binary ptuPackageVersion to get installed package
|
||||
# versions.
|
||||
# 1.5.6 : Show additional update progress info in status bar.
|
||||
VERSION="1.5.6"
|
||||
# 2.0.0 : Rewrite of UpdateTool.
|
||||
VERSION="2.0.0"
|
||||
# PLANNED TODOS:
|
||||
# 1: Das Repository wird repariert bwz. neu geklont. Unabhaengig vom WAIT.
|
||||
# 2: Wenn der WAIT-Button aktiv ist, dann wird ein Repository repariert (neu
|
||||
@@ -216,7 +217,10 @@ GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
|
||||
|
||||
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
|
||||
|
||||
INCLUDEPATH += plugins
|
||||
# INCLUDEPATH += plugins
|
||||
INCLUDEPATH += plugins \
|
||||
$${_PRO_FILE_PWD_}/../common/ \
|
||||
$${_PRO_FILE_PWD_}/../common/include
|
||||
|
||||
CONFIG += c++17
|
||||
# CONFIG -= app_bundle
|
||||
@@ -290,8 +294,13 @@ SOURCES += \
|
||||
process/show_software_status_command.cpp \
|
||||
message_handler.cpp \
|
||||
worker.cpp \
|
||||
commandline_parser.cpp \
|
||||
work_process_list.cpp
|
||||
work_process_list.cpp \
|
||||
$${_PRO_FILE_PWD_}/../common/src/utils_internal.cpp \
|
||||
$${_PRO_FILE_PWD_}/../common/src/commandline_parser.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 \
|
||||
@@ -314,8 +323,14 @@ HEADERS += \
|
||||
process/show_software_status_command.h \
|
||||
message_handler.h \
|
||||
worker.h \
|
||||
commandline_parser.h \
|
||||
work_process_list.h
|
||||
work_process_list.h \
|
||||
$${_PRO_FILE_PWD_}/../common/include/utils_internal.h \
|
||||
$${_PRO_FILE_PWD_}/../common/include/commandline_parser.h \
|
||||
$${_PRO_FILE_PWD_}/../common/include/log_line_entry.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 += \
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <QThread>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#if 0
|
||||
########################
|
||||
@@ -380,7 +381,7 @@ QString IsmasClient::updateNewsToIsmas(char const *event,
|
||||
"{"
|
||||
"\"REASON\":\"SW_UP\","
|
||||
"\"TIMESTAMP\":\"%s\","
|
||||
"\"EVENT_ID\":\"0\","
|
||||
"\"EVENT_ID\":\"%d\","
|
||||
"\"EVENT\":\"%s\","
|
||||
"\"EVENTSTATE\":1,"
|
||||
"\"PARAMETER\": {"
|
||||
@@ -390,7 +391,7 @@ QString IsmasClient::updateNewsToIsmas(char const *event,
|
||||
"\"STEP_RESULT\" : \"%s\","
|
||||
"\"VERSION\" : \"%s\""
|
||||
"}"
|
||||
"}", ts.toStdString().c_str(), event, percent, resultCode,
|
||||
"}", ts.toStdString().c_str(), static_cast<int>(QCoreApplication::applicationPid()), event, percent, resultCode,
|
||||
step, step_result, version);
|
||||
return buf;
|
||||
}
|
||||
|
1107
UpdatePTUDevCtrl/ismas/ismas_client.cpp.master
Normal file
1107
UpdatePTUDevCtrl/ismas/ismas_client.cpp.master
Normal file
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@
|
||||
#include <QThread>
|
||||
#include <QtWidgets>
|
||||
#include <QScopedPointer>
|
||||
#include <QScreen>
|
||||
|
||||
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
||||
#include <unistd.h>
|
||||
@@ -48,6 +49,36 @@
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @mainpage ATB-Update-Tool Documentation
|
||||
* \section intro_sec Introduction
|
||||
* The ATB update tool consistes of several binaries, which are executed in
|
||||
* order:
|
||||
* * \ref ATBUpdateTool
|
||||
* * \ref ATBUpdateCheck
|
||||
* * \ref ATBUpdateGit
|
||||
* * \ref ATBUpdateSync
|
||||
* * \ref ATBUpdateOpkg
|
||||
* * \ref ATBUpdateDC
|
||||
* * \ref ATBUpdateJsonFiles
|
||||
* * \ref ATBUpdateShow
|
||||
*
|
||||
* The binaries are started synchonously as child processes of \ref ATBUpdateTool:
|
||||
* each binary will finish before the next one is started.
|
||||
* The output for the child process is captured in \ref ATBUpdateTool, and
|
||||
* optionally shown in the GUI presemted to the user.
|
||||
*
|
||||
* - \page ATBUpdateTool
|
||||
* - \page ATBUpdateCheck
|
||||
* - \page ATBUpdateGit
|
||||
* - \page ATBUpdateSync
|
||||
* - \page ATBUpdateOpkg
|
||||
* - \page ATBUpdateDC
|
||||
* Typical call: ./ATBUpdateDC --dc-directory /etc/dc/ --debug true
|
||||
* - \page ATBUpdateJsonFiles
|
||||
* - \page ATBUpdateShow
|
||||
*/
|
||||
|
||||
// argv[1]: file to send to dc
|
||||
int main(int argc, char *argv[]) {
|
||||
QByteArray const value = qgetenv("LC_ALL");
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#include "ui_mainwindow.h"
|
||||
#include "worker.h"
|
||||
#include "utils.h"
|
||||
#include "utils_internal.h"
|
||||
#include "log_line_entry.h"
|
||||
#include "progress_event.h"
|
||||
#include "update_dc_event.h"
|
||||
#include "process/update_command.h"
|
||||
@@ -15,17 +17,89 @@
|
||||
#include <QColor>
|
||||
#include <QColorDialog>
|
||||
|
||||
#define CHECK_BACKEND_CONNECTION 0
|
||||
#define CHECK_UPDATE_REQUEST 1
|
||||
#define UPDATE_CUSTOMER_REPOSITORY 2
|
||||
#define INSTALL_SW_PACKETS_DRY_RUN 3
|
||||
#define INSTALL_SW_PACKETS 4
|
||||
#define UPDATE_DC 5
|
||||
#define SYNCHRONIZE_REPOSITORY 6
|
||||
#define INSTALL_DC_CONFIGURATION 7
|
||||
|
||||
#define CHECK_ISMAS_CONNECT_PERCENT_START ( 1)
|
||||
#define CHECK_ISMAS_CONNECT_PERCENT_END (10)
|
||||
|
||||
#define CHECK_UPDATE_REQUEST_PERCENT_START (10)
|
||||
#define CHECK_UPDATE_REQUEST_PERCENT_END (20)
|
||||
|
||||
#define UPDATE_GIT_PERCENT_START (20)
|
||||
#define UPDATE_GIT_PERCENT_END (21)
|
||||
|
||||
#define UPDATE_OPKG_NOACTION_PERCENT_START (21)
|
||||
#define UPDATE_OPKG_NOACTION_PERCENT_END (25)
|
||||
|
||||
#define UPDATE_OPKG_PERCENT_START (25)
|
||||
#define UPDATE_OPKG_PERCENT_END (40)
|
||||
|
||||
#define UPDATE_DOWNLOAD_DC_START (41)
|
||||
#define UPDATE_DOWNLOAD_DC_END (80)
|
||||
|
||||
#define UPDATE_SYNC_START (81)
|
||||
#define UPDATE_SYNC_END (90)
|
||||
|
||||
#define UPDATE_DOWNLOAD_JSON_START (91)
|
||||
#define UPDATE_DOWNLOAD_JSON_END (100)
|
||||
|
||||
|
||||
void MainWindow::onFileChanged(QString const& /*f*/) {
|
||||
static int i = 30;
|
||||
ui->updateProgress->setValue(++i);
|
||||
|
||||
// TODO: daten an ISMAS senden
|
||||
}
|
||||
|
||||
QProgressBar *MainWindow::progressBar() {
|
||||
return ui ? ui->updateProgress : nullptr;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
, m_worker(worker)
|
||||
, m_width(70)
|
||||
, m_width(60)
|
||||
, m_progressRunning(false)
|
||||
, m_updateStep(UpdateDcEvent::UpdateStep::NONE) {
|
||||
, m_updateStep(UpdateDcEvent::UpdateStep::NONE)
|
||||
, m_updateLog("/opt/app/tools/atbupdate/update.log") { // TODO: in ini-file eintragen
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
if (!m_updateLog.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
|
||||
qCritical() << "ERROR can not open" << m_updateLog.fileName();
|
||||
}
|
||||
|
||||
m_updateSteps.resize(8);
|
||||
m_updateSteps[CHECK_BACKEND_CONNECTION] = "Check backend connection (ISMAS) ";
|
||||
m_updateSteps[CHECK_UPDATE_REQUEST] = "Check update request ";
|
||||
m_updateSteps[UPDATE_CUSTOMER_REPOSITORY] = "Update customer repository ";
|
||||
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN] = "Install SW packets (dry run) ";
|
||||
m_updateSteps[INSTALL_SW_PACKETS] = "Install SW packets ";
|
||||
m_updateSteps[UPDATE_DC] = "Update DC ";
|
||||
m_updateSteps[SYNCHRONIZE_REPOSITORY] = "Synchronize repository/filesystem ";
|
||||
m_updateSteps[INSTALL_DC_CONFIGURATION] = "Install DC configuration ";
|
||||
|
||||
QString text{};
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
QString &tmp = m_updateSteps[i];
|
||||
int len = m_showLineLength - tmp.length();
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
}
|
||||
m_updateSteps[i] = tmp;
|
||||
text += m_updateSteps[i];
|
||||
}
|
||||
ui->stepLabel->setTextFormat(Qt::RichText);
|
||||
ui->stepLabel->setText(text);
|
||||
|
||||
this->setStatusBar(new QStatusBar(this));
|
||||
QFont f;
|
||||
f.setStyleHint(QFont::Monospace);
|
||||
@@ -44,7 +118,7 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
lst << QString("Update tool version : %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3);
|
||||
lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3);
|
||||
lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3);
|
||||
lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3);
|
||||
lst << QString("Zone number : %1 ").arg(m_worker->zoneNr()).leftJustified(m_width-3);
|
||||
lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3);
|
||||
lst << QString("").leftJustified(m_width-3, '=');
|
||||
|
||||
@@ -80,7 +154,12 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
m_statusTimer->start(1000);
|
||||
}
|
||||
|
||||
connect(m_worker->summaryTimer(), SIGNAL(timeout()), this, SLOT(onSummary()));
|
||||
m_worker->summaryTimer()->setSingleShot(true);
|
||||
m_worker->summaryTimer()->setInterval(5000);
|
||||
|
||||
connect(ui->exit, SIGNAL(clicked()),this,SLOT(onQuit()));
|
||||
connect(m_worker, SIGNAL(summary()),this,SLOT(onSummary()));
|
||||
connect(m_worker, SIGNAL(showSummary(QString)),this,SLOT(onShowSummary(QString)));
|
||||
connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit()));
|
||||
connect(m_worker, SIGNAL(showDcDownload(QString)),this,SLOT(onShowDcDownload(QString)));
|
||||
@@ -94,6 +173,8 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
connect(m_worker, SIGNAL(showUpdateRequest(QString)),this,SLOT(onShowUpdateRequest(QString)));
|
||||
connect(m_worker, SIGNAL(showCustRepoStatus(QString)),this,SLOT(onShowCustRepoStatus(QString)));
|
||||
connect(m_worker, SIGNAL(showExecOpkgStatus(QString)),this,SLOT(onShowExecOpkgStatus(QString)));
|
||||
connect(m_worker, SIGNAL(showExecOpkgCommand(QString)),this,SLOT(onShowExecOpkgCommand(QString)));
|
||||
connect(m_worker, SIGNAL(showExecOpkgOverallResult(QString, bool)),this,SLOT(onShowExecOpkgOverallResult(QString,bool)));
|
||||
connect(m_worker, SIGNAL(showDownloadDCJsonFilesStatus(QString)),this,SLOT(onShowDownloadDCJsonFilesStatus(QString)));
|
||||
connect(m_worker, SIGNAL(showSyncCustRepoStatus(QString)),this,SLOT(onShowSyncCustRepoStatus(QString)));
|
||||
connect(m_worker, SIGNAL(showUpdateDCFirmware(QString)),this,SLOT(onShowUpdateDCFirmware(QString)));
|
||||
@@ -111,8 +192,91 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
connect(m_worker, SIGNAL(replaceLast(QStringList,QString)),this, SLOT(onReplaceLast(QStringList,QString)));
|
||||
}
|
||||
|
||||
void MainWindow::onSummary() {
|
||||
QThread::sleep(3);
|
||||
|
||||
QString summary, first, second, line, tmp;
|
||||
QVector<QPair<QString, QString>> vec = Utils::installedPackages();
|
||||
|
||||
if (m_worker) {
|
||||
vec.append(Utils::installedTariffFiles(m_worker, m_worker->customerRepository()));
|
||||
vec.append(Utils::installedJsonFiles(m_worker, m_worker->customerRepository()));
|
||||
}
|
||||
int max_first = 0, max_second = 0;
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
max_first = std::max(max_first, vec[i].first.length());
|
||||
max_second = std::max(max_second, vec[i].second.length());
|
||||
}
|
||||
|
||||
max_first += 5;
|
||||
|
||||
summary = "UPDATE SUMMARY\n\n";
|
||||
|
||||
if (m_worker) {
|
||||
first = QString("%1").arg("start", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(m_worker->start().toString(Qt::ISODate));
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
first = QString("%1").arg("update tool version", max_first, QChar(' '));
|
||||
tmp = QString("%1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME);
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
if (m_worker) {
|
||||
first = QString("%1").arg("machine number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(m_worker->machineNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("customer number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(m_worker->customerNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("zone number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(m_worker->zoneNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
tmp = targetDcVersion();
|
||||
if (!tmp.isEmpty()) {
|
||||
first = QString("%1").arg("target device controller", max_first, QChar(' '));
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
if (m_worker) {
|
||||
first = QString("%1").arg("apism", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(m_worker->apismVersion());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
first = QString("%1").arg(vec[i].first, max_first, QChar(' '));
|
||||
second = QString("%1").arg(vec[i].second, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
if (m_worker) {
|
||||
emit m_worker->showSummary(summary);
|
||||
emit m_worker->enableExit();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onShowSummary(QString text) {
|
||||
|
||||
// QString s = ui->updateLabel->text();
|
||||
QString s("\n");
|
||||
|
||||
@@ -130,6 +294,9 @@ void MainWindow::onSetDcDownloadProgress(int v) {
|
||||
}
|
||||
|
||||
void MainWindow::onShowTariffUpdate(QString) {
|
||||
return;
|
||||
|
||||
|
||||
ui->exit->setEnabled(false);
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
@@ -146,55 +313,105 @@ void MainWindow::onShowTariffUpdate(QString) {
|
||||
}
|
||||
|
||||
void MainWindow::onShowISMASConnectivity(QString status) {
|
||||
// ausgabe: connected, not connected, connecting
|
||||
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
QString stepResult;
|
||||
QString s = m_updateSteps[CHECK_BACKEND_CONNECTION].trimmed();
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
|
||||
QString tmp("backend connection (ISMAS) ");
|
||||
int len = m_showLineLength - tmp.length();
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
}
|
||||
bool const custRepoExists = internal::customerRepoExists();
|
||||
|
||||
if (status.contains(UpdateCommand::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>connected</font><br />").arg(tmp);
|
||||
if (custRepoExists) {
|
||||
s += " <font color='Green'>connected</font>";
|
||||
stepResult = "ISMAS connected";
|
||||
} else {
|
||||
s += " <font color='Green'>connected (initial configuration)</font>";
|
||||
stepResult = "ISMAS connected (initial configuration)";
|
||||
}
|
||||
} else
|
||||
if (status.contains(UpdateCommand::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Blue'>NOT CONNECTED</font>";
|
||||
stepResult = "ISMAS not connected";
|
||||
} else
|
||||
if (status.contains(UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>connecting</font><br />").arg(tmp);
|
||||
s += " <font color='Green'>connecting</font>";
|
||||
stepResult = "connecting ISMAS";
|
||||
} else
|
||||
if (status.contains(UpdateCommand::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
|
||||
s += QString( "%1 <font color='Red'>NOT CONNECTED</font><br />").arg(tmp);
|
||||
if (custRepoExists) {
|
||||
s += " <font color='Red'>NOT CONNECTED. STOP</font>";
|
||||
stepResult = "ISMAS not connected";
|
||||
} else {
|
||||
s += " <font color='Red'>not connected. (initial configuration)</font>";
|
||||
stepResult = "ISMAS not connected (initial configuration)";
|
||||
}
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
stepResult = "unknown status";
|
||||
}
|
||||
|
||||
struct LogLineEntry logLine =
|
||||
initLogLineEntry(1, // receiver
|
||||
QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8().constData(),
|
||||
_ISMAS_CONTINUE,
|
||||
0, // eventState
|
||||
CHECK_ISMAS_CONNECT_PERCENT_START,
|
||||
ISMAS::RESULT_CODE::E_SUCCESS,
|
||||
"show ISMAS connectivity", // step
|
||||
stepResult.toUtf8().constData()); // stepResult
|
||||
|
||||
int w = 0;
|
||||
if ((w = m_updateLog.write((char *)(&logLine), sizeof(logLine))) != sizeof(logLine)) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "ERROR only" << w << "bytes written";
|
||||
}
|
||||
|
||||
m_updateSteps[CHECK_BACKEND_CONNECTION] = s;
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
ui->stepLabel->setText(s);
|
||||
|
||||
logLine =
|
||||
initLogLineEntry(1, // receiver
|
||||
QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8().constData(),
|
||||
_ISMAS_CONTINUE,
|
||||
0, // eventState
|
||||
CHECK_ISMAS_CONNECT_PERCENT_END,
|
||||
ISMAS::RESULT_CODE::E_SUCCESS,
|
||||
"show ISMAS connectivity", // step
|
||||
stepResult.toUtf8().constData()); // stepResult
|
||||
|
||||
if ((w = m_updateLog.write((char *)(&logLine), sizeof(logLine))) != sizeof(logLine)) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "ERROR only" << w << "bytes written";
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onShowCustRepoStatus(QString status) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
QString s = m_updateSteps[UPDATE_CUSTOMER_REPOSITORY].trimmed();
|
||||
|
||||
QString tmp("customer repository ");
|
||||
int len = m_showLineLength - tmp.length();
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
}
|
||||
|
||||
if (status.contains(UpdateCommand::GIT_CUSTOMER_REPO_UP_TO_DATE, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>up to date</font><br />").arg(tmp);
|
||||
if (status.contains(internal::GIT_CUSTOMER_REPO_UP_TO_DATE, Qt::CaseInsensitive)) {
|
||||
s += QString(" <font color='Green'>%1</font>").arg(internal::GIT_CUSTOMER_REPO_UP_TO_DATE);
|
||||
} else
|
||||
if (status.contains(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY, Qt::CaseInsensitive)) {
|
||||
s += QString(" <font color='Green'>%1</font>").arg(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
}
|
||||
|
||||
m_updateSteps[UPDATE_CUSTOMER_REPOSITORY] = s;
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
ui->stepLabel->setText(s);
|
||||
}
|
||||
|
||||
void MainWindow::onShowExecOpkgStatus(QString status) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
return;
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
|
||||
@@ -214,64 +431,102 @@ void MainWindow::onShowExecOpkgStatus(QString status) {
|
||||
ui->stepLabel->setText(s);
|
||||
}
|
||||
|
||||
void MainWindow::onShowDownloadDCJsonFilesStatus(QString status) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
void MainWindow::onShowExecOpkgCommand(QString cmd) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "cmd" << cmd;
|
||||
return;
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
|
||||
QString tmp = "configure device controller ";
|
||||
int len = m_showLineLength - tmp.length();
|
||||
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
if (cmd.back() != QChar('\n')) {
|
||||
cmd += "\n";
|
||||
}
|
||||
onInsertText(cmd);
|
||||
}
|
||||
|
||||
void MainWindow::onShowExecOpkgOverallResult(QString status, bool noaction) {
|
||||
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
QString s = noaction ?
|
||||
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN].trimmed() :
|
||||
m_updateSteps[INSTALL_SW_PACKETS].trimmed();
|
||||
|
||||
if (status.contains(internal::EXEC_OPKG_COMMANDS_SUCCESS, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Green'>success</font>";
|
||||
} else
|
||||
if (status.contains(internal::EXEC_OPKG_COMMANDS_FAIL, Qt::CaseInsensitive)) {
|
||||
s += QString(" <font color='Red'>%1</font>").arg(internal::EXEC_OPKG_COMMANDS_FAIL);
|
||||
} else {
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
}
|
||||
|
||||
if (noaction) {
|
||||
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN] = s;
|
||||
} else {
|
||||
m_updateSteps[INSTALL_SW_PACKETS] = s;
|
||||
}
|
||||
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
|
||||
ui->stepLabel->setText(s);
|
||||
}
|
||||
|
||||
void MainWindow::onShowDownloadDCJsonFilesStatus(QString status) {
|
||||
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
QString s = m_updateSteps[INSTALL_DC_CONFIGURATION].trimmed();
|
||||
|
||||
if (status.contains(UpdateCommand::UPDATE_DC_JSON_FILES_SUCCESS, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
|
||||
s += " <font color='Green'>success</font>";
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
}
|
||||
|
||||
m_updateSteps[INSTALL_DC_CONFIGURATION] = s;
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
ui->stepLabel->setText(s);
|
||||
}
|
||||
|
||||
void MainWindow::onShowSyncCustRepoStatus(QString status) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
|
||||
QString tmp = "synchronize repository/filesystem ";
|
||||
int len = m_showLineLength - tmp.length();
|
||||
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
}
|
||||
QString s = m_updateSteps[SYNCHRONIZE_REPOSITORY].trimmed();
|
||||
|
||||
if (status.contains(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_SUCCESS, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
|
||||
s += " <font color='Green'>success</font>";
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
}
|
||||
|
||||
m_updateSteps[SYNCHRONIZE_REPOSITORY] = s;
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
ui->stepLabel->setText(s);
|
||||
}
|
||||
|
||||
void MainWindow::onShowUpdateDCFirmware(QString status) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
QString s = m_updateSteps[UPDATE_DC].trimmed();
|
||||
|
||||
QString tmp = "device controller update ";
|
||||
int len = m_showLineLength - tmp.length();
|
||||
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
if (status.contains(internal::UPDATE_DC_FIRMARE_SUCCESS, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Green'>success</font>";
|
||||
} else {
|
||||
s += " <font color='Red'>UNKNOWN STATUS</font>";
|
||||
}
|
||||
|
||||
if (status.contains(UpdateCommand::UPDATE_DC_FIRMARE_SUCCESS, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
if (i != UPDATE_DC) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
} else {
|
||||
s += m_updateSteps[i];
|
||||
}
|
||||
}
|
||||
|
||||
ui->stepLabel->setText(s);
|
||||
@@ -279,37 +534,53 @@ void MainWindow::onShowUpdateDCFirmware(QString status) {
|
||||
|
||||
|
||||
void MainWindow::onShowUpdateRequest(QString status) {
|
||||
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
|
||||
//ui->updateProgress->setValue(CHECK_UPDATE_REQUEST_PERCENT_START);
|
||||
QString s = m_updateSteps[CHECK_UPDATE_REQUEST].trimmed();
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
|
||||
QString tmp = "update request ";
|
||||
int len = m_showLineLength - tmp.length();
|
||||
|
||||
while (--len > 0) {
|
||||
tmp += " ";
|
||||
}
|
||||
bool const custRepoExists = internal::customerRepoExists();
|
||||
|
||||
if (status.contains(UpdateCommand::UPDATE_NOT_REQUESTED, Qt::CaseInsensitive)) {
|
||||
s += QString( "%1 <font color='Red'>NOT REQUESTED</font><br />").arg(tmp);
|
||||
if (custRepoExists) {
|
||||
s += " <font color='Red'>NOT REQUESTED. STOP.</font>";
|
||||
} else {
|
||||
s += " <font color='Blue'>not requested (initial configuration)</font>";
|
||||
}
|
||||
} else
|
||||
if (status.contains(UpdateCommand::UPDATE_REQUESTED, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>requested</font><br />").arg(tmp);
|
||||
if (status.contains(internal::UPDATE_REQUESTED, Qt::CaseInsensitive)) {
|
||||
if (custRepoExists) {
|
||||
s += " <font color='Green'>requested</font>";
|
||||
} else {
|
||||
s += " <font color='Blue'>requested (initial configuration)</font>";
|
||||
}
|
||||
} else
|
||||
if (status.contains(UpdateCommand::UPDATE_NOT_NECESSARY, Qt::CaseInsensitive)) {
|
||||
s += QString("%1 <font color='Green'>not necessary</font><br />").arg(tmp);
|
||||
if (status.contains(internal::UPDATE_INITIAL, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Green'>requested (initial configuration)</font>";
|
||||
} else
|
||||
if (status.contains(internal::UPDATE_NOT_NECESSARY, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Green'>not necessary</font>";
|
||||
} else
|
||||
if (status.contains(internal::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
|
||||
s += " <font color='Blue'>UNKNOWN (ISMAS not connected)</font>";
|
||||
} else {
|
||||
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
|
||||
s += " <font color='Red'>UNKNOWN</font>";
|
||||
}
|
||||
|
||||
m_updateSteps[CHECK_UPDATE_REQUEST] = s;
|
||||
s.clear();
|
||||
for (int i = 0; i < m_updateSteps.size(); ++i) {
|
||||
s += m_updateSteps[i] + "<br />";
|
||||
}
|
||||
ui->stepLabel->setText(s);
|
||||
//ui->updateProgress->setValue(CHECK_UPDATE_REQUEST_PERCENT_END);
|
||||
}
|
||||
|
||||
void MainWindow::onShowISMASChecks(QString) {
|
||||
// deprecated
|
||||
|
||||
QString s = ui->stepLabel->text();
|
||||
return;
|
||||
|
||||
QString tmp("Check ISMAS connectivity ");
|
||||
int len = m_showLineLength - tmp.length();
|
||||
@@ -347,6 +618,9 @@ void MainWindow::onShowJsonDownload(QString) {
|
||||
}
|
||||
|
||||
void MainWindow::onShowDcDownload(QString version) {
|
||||
return;
|
||||
|
||||
|
||||
m_targetDcVersion = version;
|
||||
ui->exit->setEnabled(false);
|
||||
|
||||
|
@@ -4,6 +4,9 @@
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QStatusBar>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
#include <QProgressBar>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
@@ -37,6 +40,7 @@ public:
|
||||
void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; }
|
||||
|
||||
QString targetDcVersion() {return m_targetDcVersion; }
|
||||
QProgressBar *progressBar();
|
||||
|
||||
public slots:
|
||||
void onAppendText(QString, QString suffix = "");
|
||||
@@ -59,11 +63,15 @@ public slots:
|
||||
void onShowUpdateRequest(QString);
|
||||
void onShowCustRepoStatus(QString);
|
||||
void onShowExecOpkgStatus(QString);
|
||||
void onShowExecOpkgCommand(QString);
|
||||
void onShowExecOpkgOverallResult(QString,bool);
|
||||
void onShowDownloadDCJsonFilesStatus(QString);
|
||||
void onShowSyncCustRepoStatus(QString);
|
||||
void onShowUpdateDCFirmware(QString);
|
||||
void onSetDcDownloadProgress(int);
|
||||
void onShowSummary(QString);
|
||||
void onSummary();
|
||||
void onFileChanged(QString const&);
|
||||
#if EMERGENCY_LEAVE_BL==1
|
||||
void emergencyLeaveBL();
|
||||
#endif
|
||||
@@ -94,5 +102,10 @@ private:
|
||||
UpdateDcEvent::UpdateStep m_updateStep;
|
||||
QTimer *m_statusTimer;
|
||||
QString m_targetDcVersion;
|
||||
int m_stepLabelChopCount{};
|
||||
|
||||
QVector<QString> m_updateSteps{};
|
||||
|
||||
QFile m_updateLog;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
@@ -51,6 +51,9 @@
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
|
@@ -1,21 +1,63 @@
|
||||
#include "process/check_and_fetch_customer_repository_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
CheckAndFetchCustomerRepositoryCommand::CheckAndFetchCustomerRepositoryCommand(
|
||||
QString const &command, Worker *worker, int start_timeout, int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
QString const &command, Worker *worker, int nextCommandIndex,
|
||||
int start_timeout, int finish_timeout)
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void CheckAndFetchCustomerRepositoryCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << command() << exitCode << exitStatus;
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
switch (exitCode) {
|
||||
case internal::GIT_CHECKOUT_ERROR_CODE:
|
||||
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_CHECKOUT_ERROR);
|
||||
break;
|
||||
case internal::GIT_PULL_ERROR_CODE:
|
||||
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_PULL_ERROR);
|
||||
break;
|
||||
case internal::GIT_NOT_NECESSARY_CODE:
|
||||
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
|
||||
exitCode = 0;
|
||||
break;
|
||||
case internal::GIT_UPDATED_CODE:
|
||||
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED);
|
||||
exitCode = 0;
|
||||
break;
|
||||
case 0:
|
||||
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UP_TO_DATE);
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void CheckAndFetchCustomerRepositoryCommand::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
|
||||
// TODO
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
// static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
|
||||
emit w->showCustRepoStatus(UpdateCommand::GIT_CUSTOMER_REPO_UP_TO_DATE);
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
m_commandResult += s;
|
||||
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY)) {
|
||||
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
|
||||
m_commandResult.clear();
|
||||
} else
|
||||
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_UPDATED)) {
|
||||
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED);
|
||||
} else
|
||||
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_CLONED)) {
|
||||
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_CLONED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
|
||||
// emit w->showCustRepoStatus(UpdateCommand::GIT_CUSTOMER_REPO_UP_TO_DATE);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
@@ -7,10 +7,13 @@ class CheckAndFetchCustomerRepositoryCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit CheckAndFetchCustomerRepositoryCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
QString m_commandResult{};
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // CHECK_AND_FETCH_CUSTOMER_REPOSITORY_COMMAND_H_INCLUDED
|
||||
|
@@ -5,23 +5,34 @@
|
||||
|
||||
CheckIsmasConnectivityCommand::CheckIsmasConnectivityCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void CheckIsmasConnectivityCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void CheckIsmasConnectivityCommand::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
|
||||
// TODO
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
//static constexpr const char *ISMAS_CONNECTED{"connected"};
|
||||
//static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
|
||||
//static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
|
||||
emit w->showISMASConnectivity(UpdateCommand::ISMAS_CONNECTED);
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
if (s == UpdateCommand::ISMAS_CONNECTED) {
|
||||
emit w->showISMASConnectivity(UpdateCommand::ISMAS_CONNECTED);
|
||||
} else
|
||||
if (s == UpdateCommand::NO_CUSTOMER_REPOSITORY) {
|
||||
emit w->showISMASConnectivity(UpdateCommand::NO_CUSTOMER_REPOSITORY);
|
||||
} else
|
||||
if (s == UpdateCommand::ISMAS_NOT_CONNECTED) {
|
||||
emit w->showISMASConnectivity(UpdateCommand::ISMAS_NOT_CONNECTED);
|
||||
} else
|
||||
if (s == UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS) {
|
||||
emit w->showISMASConnectivity(UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,12 @@ class CheckIsmasConnectivityCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit CheckIsmasConnectivityCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // CHECK_ISMAS_CONNECTIVITY_COMMAND_H_INCLUDED
|
||||
|
@@ -1,27 +1,43 @@
|
||||
#include "process/check_update_activation_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
CheckUpdateActivationCommand::CheckUpdateActivationCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void CheckUpdateActivationCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qCritical() << __func__ << ":" << __LINE__ << command() << exitCode << exitStatus;
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void CheckUpdateActivationCommand::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
|
||||
// TODO
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
//static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
|
||||
//static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
|
||||
//static constexpr const char *UPDATE_REQUESTED{"requested"};
|
||||
emit w->showUpdateRequest(UpdateCommand::UPDATE_REQUESTED);
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
if (s == internal::UPDATE_REQUESTED) {
|
||||
emit w->showUpdateRequest(internal::UPDATE_REQUESTED);
|
||||
} else
|
||||
if (s == internal::UPDATE_NOT_NECESSARY) {
|
||||
emit w->showUpdateRequest(internal::UPDATE_NOT_NECESSARY);
|
||||
} else
|
||||
if (s == internal::UPDATE_NOT_REQUESTED) {
|
||||
emit w->showUpdateRequest(internal::UPDATE_NOT_REQUESTED);
|
||||
} else
|
||||
if (s == internal::NO_CUSTOMER_REPOSITORY) {
|
||||
emit w->showUpdateRequest(internal::NO_CUSTOMER_REPOSITORY);
|
||||
} else
|
||||
if (s == internal::UPDATE_INITIAL) {
|
||||
emit w->showUpdateRequest(internal::UPDATE_INITIAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,12 @@ class CheckUpdateActivationCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit CheckUpdateActivationCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // CHECK_UPDATE_ACTIVATION_COMMAND_H_INCLUDED
|
||||
|
@@ -50,7 +50,7 @@ void Command::readyReadStandardOutput() {
|
||||
s = s.mid(0, i).trimmed();
|
||||
}
|
||||
}
|
||||
emit m_worker->showDcDownload(s);
|
||||
// emit m_worker->showDcDownload(s);
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-PROGRESS>")) != -1) {
|
||||
bool ok;
|
||||
@@ -61,14 +61,15 @@ void Command::readyReadStandardOutput() {
|
||||
}
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-FINISH>")) != -1) {
|
||||
m_worker->summary();
|
||||
emit m_worker->summary();
|
||||
// qApp->exit(0);
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-SUCCESS>")) != -1) {
|
||||
m_worker->summary();
|
||||
// TODO
|
||||
emit m_worker->summary();
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-FAILURE>")) != -1) {
|
||||
m_worker->summary();
|
||||
emit m_worker->summary();
|
||||
//qApp->exit(-1);
|
||||
} else
|
||||
if ((i = s.indexOf("<JS-PROGRESS>")) != -1) {
|
||||
@@ -107,9 +108,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,25 +1,85 @@
|
||||
#include "process/exec_opkg_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
ExecOpkgCommand::ExecOpkgCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
bool noaction,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout)
|
||||
, m_noaction(noaction) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout)
|
||||
, m_noaction(noaction)
|
||||
, m_ok_count{0}
|
||||
, m_fail_count{0} {
|
||||
}
|
||||
|
||||
void ExecOpkgCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
if (m_fail_count == 0 && m_ok_count > 0) {
|
||||
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_SUCCESS, m_noaction);
|
||||
} else
|
||||
if (m_ok_count == 0 && m_fail_count > 0) {
|
||||
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_FAIL, m_noaction);
|
||||
} else {
|
||||
// TODO
|
||||
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_SUCCESS, m_noaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void ExecOpkgCommand::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
|
||||
// TODO
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
// static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
|
||||
emit w->showExecOpkgStatus(UpdateCommand::EXEC_OPKG_COMMANDS_SUCCESS);
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
m_standardOutput += s.replace(QChar('\n'), "");
|
||||
|
||||
// the command lines in etc/psa_update/opkg_commands are
|
||||
// separated by "<OPKG>" markers. Note that the file opkg_commands
|
||||
// itself is *not* changed, of course.
|
||||
|
||||
int startIndex, endIndex{};
|
||||
while (((startIndex = m_standardOutput.indexOf(internal::OPKG_MARKER)) == 0) &&
|
||||
((endIndex = m_standardOutput.indexOf(internal::OPKG_MARKER, 1)) != -1)) {
|
||||
|
||||
QString result = m_standardOutput.mid(0, endIndex).mid(6);
|
||||
m_standardOutput = m_standardOutput.mid(endIndex);
|
||||
|
||||
if (!s.isEmpty()) {
|
||||
QStringList const lst = result.split(u' ', QString::SkipEmptyParts);
|
||||
|
||||
if (lst.size() >= 2) {
|
||||
if (lst.last() == "ok") {
|
||||
m_ok_count += 1;
|
||||
if (lst.contains("noaction")) {
|
||||
emit w->showExecOpkgCommand(result);
|
||||
} else {
|
||||
emit w->showExecOpkgCommand(result);
|
||||
}
|
||||
} else {
|
||||
m_fail_count += 1;
|
||||
if (lst.contains("noaction")) {
|
||||
emit w->showExecOpkgCommand(result);
|
||||
} else {
|
||||
emit w->showExecOpkgCommand(result);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emit w->showExecOpkgCommand(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,14 +6,19 @@
|
||||
|
||||
class ExecOpkgCommand : public UpdateCommand {
|
||||
bool m_noaction{false};
|
||||
QString m_standardOutput{};
|
||||
int m_ok_count{};
|
||||
int m_fail_count{};
|
||||
public:
|
||||
explicit ExecOpkgCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
bool noaction,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // EXEC_OPKG_COMMAND_H_INCLUDED
|
||||
|
@@ -4,9 +4,14 @@
|
||||
|
||||
ShowSoftwareStatusCommand::ShowSoftwareStatusCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void ShowSoftwareStatusCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void ShowSoftwareStatusCommand::readyReadStandardOutput() {
|
||||
|
@@ -7,9 +7,11 @@ class ShowSoftwareStatusCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit ShowSoftwareStatusCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
#endif // SHOW_SOFTWARE_STATUS_COMMAND_H_INCLUDED
|
||||
|
@@ -1,14 +1,17 @@
|
||||
#include "update_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
|
||||
UpdateCommand::UpdateCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: Command(command, start_timeout, finish_timeout) {
|
||||
: Command(command, start_timeout, finish_timeout)
|
||||
, m_nextCommandIndex(nextCommandIndex) {
|
||||
setWorker(worker);
|
||||
}
|
||||
|
||||
@@ -17,15 +20,13 @@ bool UpdateCommand::stopUpdateOnFailure() {
|
||||
}
|
||||
|
||||
void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << m_command
|
||||
<< "exitCode" << exitCode
|
||||
<< "exitStatus" << exitStatus;
|
||||
|
||||
QProcess *p = (QProcess *)sender();
|
||||
QProcess *p = qobject_cast<QProcess *>(sender());
|
||||
if (p) {
|
||||
// read all remaining data sent to the process, just in case
|
||||
m_commandResult += p->readAllStandardOutput();
|
||||
QString s = p->readAllStandardOutput().trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
m_commandResult += s;
|
||||
}
|
||||
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
@@ -33,13 +34,108 @@ 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};
|
||||
|
||||
if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit) {
|
||||
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("ATBUpdateDC")) {
|
||||
ISMAS::EventData e(ISMAS::CONTINUE,
|
||||
internal::PERCENT_UPDATE_DC,
|
||||
0,
|
||||
"ATBUpdateDC",
|
||||
"downloaded new dc-firmware. about to reboot...");
|
||||
m_worker->clientForUpdate().sendCmdEvent(e);
|
||||
} else
|
||||
if (m_command.contains("ATBUpdateShow")) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (m_worker->workList().nextExec()) {
|
||||
m_worker->workList().exec();
|
||||
} else {
|
||||
// testing
|
||||
qCritical() << __func__ << ":" << __LINE__ << "TEST: SEND UPDATE SUCCEEDED TO ISMAS";
|
||||
m_worker->setLastFailedUpdateStep(Worker::UPDATE_STEP::NONE);
|
||||
Worker::UpdateProcessRunning _(m_worker);
|
||||
}
|
||||
} else {
|
||||
bool execShowStatus = true;
|
||||
m_worker->workList().exec(execShowStatus);
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT_X(false,
|
||||
QString("%1:%2").arg(__func__).arg(__LINE__).toUtf8().constData(),
|
||||
"empty worker list");
|
||||
}
|
||||
}
|
||||
|
@@ -5,11 +5,13 @@
|
||||
|
||||
class Worker;
|
||||
class UpdateCommand : public Command {
|
||||
int m_nextCommandIndex{0};
|
||||
public:
|
||||
|
||||
static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
|
||||
static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
|
||||
static constexpr const char *UPDATE_REQUESTED{"requested"};
|
||||
static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"};
|
||||
static constexpr const char *ISMAS_CONNECTED{"connected"};
|
||||
static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
|
||||
static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
|
||||
@@ -21,12 +23,15 @@ public:
|
||||
|
||||
explicit UpdateCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
|
||||
int nextCommandIndex() { return m_nextCommandIndex; }
|
||||
|
||||
virtual bool stopUpdateOnFailure();
|
||||
|
||||
private slots:
|
||||
public slots:
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
|
@@ -1,23 +1,65 @@
|
||||
#include "process/update_dc_command.h"
|
||||
#include "worker.h"
|
||||
#include "utils_internal.h"
|
||||
|
||||
UpdateDCCommand::UpdateDCCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void UpdateDCCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
w->summaryTimer()->start();
|
||||
}
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void UpdateDCCommand::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
|
||||
// TODO
|
||||
Worker *w = worker();
|
||||
if (w) {
|
||||
// static constexpr const char *UPDATE_DC_FIRMARE_SUCCESS"success"};
|
||||
emit w->showUpdateDCFirmware(UpdateCommand::UPDATE_DC_FIRMARE_SUCCESS);
|
||||
QString s = p->readAllStandardOutput();
|
||||
int i = -1;
|
||||
if ((i = s.indexOf("<DC-VERSION>")) != -1) {
|
||||
s = s.mid(i+12).trimmed();
|
||||
if ((i = s.indexOf("\"")) != -1) {
|
||||
s = s.mid(i+1);
|
||||
if ((i = s.indexOf("\"")) != -1) {
|
||||
s = s.mid(0, i).trimmed();
|
||||
}
|
||||
}
|
||||
// emit w->showDcDownload(s);
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-PROGRESS>")) != -1) {
|
||||
bool ok;
|
||||
int v = s.mid(i+13).trimmed().toInt(&ok);
|
||||
if (ok) {
|
||||
emit w->setDcDownloadProgress(v);
|
||||
emit w->insertText(s.mid(0,i) + "\n");
|
||||
}
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-FINISH>")) != -1) {
|
||||
emit w->showUpdateDCFirmware(internal::UPDATE_DC_FIRMARE_SUCCESS);
|
||||
// QThread::sleep(3);
|
||||
// emit w->summary();
|
||||
// qApp->exit(0);
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-SUCCESS>")) != -1) {
|
||||
// TODO
|
||||
emit w->summary();
|
||||
} else
|
||||
if ((i = s.indexOf("<DC-UPDATE-FAILURE>")) != -1) {
|
||||
emit w->summary();
|
||||
//qApp->exit(-1);
|
||||
} else {
|
||||
emit w->insertText(s);
|
||||
}
|
||||
m_commandResult += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,12 @@ class UpdateDCCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit UpdateDCCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
int finish_timeout = -1);
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // UPDATE_DC_COMMAND_H_INCLUDED
|
||||
|
@@ -3,9 +3,14 @@
|
||||
|
||||
UpdateFileSystemCommand::UpdateFileSystemCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
void UpdateFileSystemCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void UpdateFileSystemCommand::readyReadStandardOutput() {
|
||||
|
@@ -7,10 +7,12 @@ class UpdateFileSystemCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit UpdateFileSystemCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // UPDATE_FS_COMMAND_H_INCLUDED
|
||||
|
@@ -6,9 +6,15 @@
|
||||
|
||||
UpdateJsonCommand::UpdateJsonCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout,
|
||||
int finish_timeout)
|
||||
: UpdateCommand(command, worker, start_timeout, finish_timeout) {
|
||||
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
|
||||
}
|
||||
|
||||
|
||||
void UpdateJsonCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
return UpdateCommand::finished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void UpdateJsonCommand::readyReadStandardOutput() {
|
||||
|
@@ -7,10 +7,12 @@ class UpdateJsonCommand : public UpdateCommand {
|
||||
public:
|
||||
explicit UpdateJsonCommand(QString const &command,
|
||||
Worker *worker,
|
||||
int nextCommandIndex,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
protected slots:
|
||||
public slots:
|
||||
virtual void readyReadStandardOutput() override;
|
||||
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
|
||||
};
|
||||
|
||||
#endif // UPDATE_JSON_HANDLER_H_INCLUDED
|
||||
|
@@ -4,12 +4,12 @@
|
||||
#include <limits>
|
||||
#include <QDebug>
|
||||
|
||||
unsigned WorkList::nextExecIndex() const {
|
||||
if (m_workList.size() > 0 && m_workListIndex < (m_workList.size() - 1)) {
|
||||
return m_workListIndex + 1;
|
||||
}
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
//unsigned WorkList::nextExecIndex() const {
|
||||
// if (m_workList.size() > 0 && m_workListIndex < (m_workList.size() - 1)) {
|
||||
// return m_workListIndex + 1;
|
||||
// }
|
||||
// return std::numeric_limits<unsigned>::max();
|
||||
//}
|
||||
|
||||
bool WorkList::nextExec() const {
|
||||
return m_workListIndex < m_workList.size();
|
||||
@@ -17,12 +17,17 @@ bool WorkList::nextExec() const {
|
||||
|
||||
bool WorkList::exec(bool last) {
|
||||
if (last == false) {
|
||||
// if not the last entry in the worklist
|
||||
if (nextExec()) {
|
||||
// and there is a next entry (a binary) to execute, start the
|
||||
// binary if the specified working directory.
|
||||
m_workList[m_workListIndex]->start("/opt/app/tools/atbupdate");
|
||||
// update to point to next entry
|
||||
m_workListIndex += 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// start the last entry in the worklist
|
||||
m_workList.back()->start("/opt/app/tools/atbupdate");
|
||||
m_workListIndex = std::numeric_limits<unsigned>::max();
|
||||
return true;
|
||||
|
@@ -5,18 +5,42 @@
|
||||
#include <memory>
|
||||
|
||||
class UpdateCommand;
|
||||
|
||||
|
||||
/**
|
||||
* @brief This class is responsible for calling the several binaries
|
||||
* \ref ATBUpdateTool consists of.
|
||||
*
|
||||
* This class maintains a worklist, which conists of entries of type UpdateCommand.
|
||||
*
|
||||
* @see UpdateCommand
|
||||
*/
|
||||
class WorkList {
|
||||
public:
|
||||
/**
|
||||
* @brief Actual worklist of items to be eecuted.
|
||||
*/
|
||||
std::vector<std::unique_ptr<UpdateCommand>> m_workList;
|
||||
public:
|
||||
unsigned m_workListIndex{0};
|
||||
|
||||
WorkList() = default;
|
||||
|
||||
/**
|
||||
* \brief Put new work item into worklist.
|
||||
*
|
||||
* \tparam arg Work item to be added to worklist.
|
||||
*/
|
||||
template<typename T>
|
||||
void push_back(T&& arg) {
|
||||
m_workList.push_back(std::forward<T>(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if worklist is empty.
|
||||
*
|
||||
* \retval true if worklist is empty.
|
||||
* \retval false otherwise.
|
||||
*/
|
||||
bool empty() const { return m_workList.empty(); }
|
||||
|
||||
// move constructor: pass in classes derived from UpdateCommand
|
||||
@@ -28,9 +52,31 @@ public:
|
||||
// , m_workListIndex(0) {
|
||||
//}
|
||||
|
||||
unsigned nextExecIndex() const;
|
||||
///**
|
||||
// * \brief Put new work item into worklist.
|
||||
// *
|
||||
// */
|
||||
//unsigned nextExecIndex() const;
|
||||
|
||||
/**
|
||||
* \brief Put new work item into worklist.
|
||||
*
|
||||
*/
|
||||
bool nextExec() const;
|
||||
|
||||
/**
|
||||
* \brief Put new work item into worklist.
|
||||
*
|
||||
* \param last
|
||||
*/
|
||||
bool exec(bool last=false);
|
||||
|
||||
/**
|
||||
* \brief Get current size of worklist.
|
||||
*
|
||||
* \retval Current size of worklist.
|
||||
*/
|
||||
unsigned size() { return m_workList.size(); }
|
||||
};
|
||||
|
||||
#endif // WORK_LIST_H_INCLUDED
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <QScopedPointer>
|
||||
#include <QRegularExpression>
|
||||
#include <QJsonArray>
|
||||
#include <QProgressBar>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -27,7 +28,9 @@
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "progress_event.h"
|
||||
#include "mainwindow.h"
|
||||
#include "utils.h"
|
||||
#include "utils.h" // deprecated
|
||||
#include "utils_internal.h"
|
||||
#include "log_line_entry.h"
|
||||
#include "process/command.h"
|
||||
#include "process/update_command.h"
|
||||
#include "process/check_ismas_connectivity_command.h"
|
||||
@@ -184,7 +187,7 @@ Worker::Worker(int customerNr,
|
||||
, m_pluginVersionPrmCalcConfig(getPluginVersion("/opt/app/ATBAPP/plugins/libPRM_CalculatePricePlugin_ConfigUi.so"))
|
||||
, m_pluginVersionTcpZvt(getPluginVersion("/opt/app/ATBAPP/plugins/libTCP_ZVT_CCPlugin.so"))
|
||||
, m_ismasUpdateRequests(ISMAS_UPDATE_REQUESTS)
|
||||
, m_waitForNewUpdates(this)
|
||||
, m_summaryTimer(this)
|
||||
, m_filesToUpdate()
|
||||
, m_updateProcessRunning(true)
|
||||
, m_mainWindow(nullptr) /* contains plugin */
|
||||
@@ -192,62 +195,103 @@ Worker::Worker(int customerNr,
|
||||
, m_dcDownloadJsonFiles(new Command(
|
||||
QString("/opt/app/tools/atbupdate/ATBDownloadDCJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())))
|
||||
//, m_withoutIsmasDirectPort(true) /* useful for testing */ {
|
||||
, m_withoutIsmasDirectPort(false) /* useful for testing */ {
|
||||
, m_withoutIsmasDirectPort(false) /* useful for testing */
|
||||
, m_updateLog("/opt/app/tools/atbupdate/update.log") // TODO: in ini-file eintragen
|
||||
, m_updateLogBackup("/opt/app/tools/atbupdate/updateBackup.log") { // TODO: in ini-file eintragen
|
||||
|
||||
// check ISMAS connectivity
|
||||
if (!m_updateLog.exists()) {
|
||||
qCritical() << "ERROR" << m_updateLog.fileName() << "does not exist";
|
||||
} else {
|
||||
if (!m_updateLog.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
|
||||
qCritical() << "ERROR can not open" << m_updateLog.fileName();
|
||||
} else {
|
||||
m_updateLog.resize(0);
|
||||
m_fileWatcher.addPath(QFileInfo(m_updateLog).absoluteFilePath());
|
||||
connect(&m_fileWatcher, SIGNAL(fileChanged(QString const&)), this, SLOT(onFileChanged(QString const&)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_updateLogBackup.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
|
||||
qCritical() << "ERROR can not open" << m_updateLogBackup.fileName();
|
||||
} else {
|
||||
m_updateLogBackup.resize(0);
|
||||
m_updateLogBackup.close();
|
||||
}
|
||||
|
||||
// *** check ISMAS connectivity ***
|
||||
// NOTE: if the customer repository does not exist, then it does not matter
|
||||
// if there is a connection to ISMAS (via APISM).
|
||||
// NOTE: the several processes will be started WorkList::exec().
|
||||
int next = 1;
|
||||
m_workList.push_back(
|
||||
std::make_unique<CheckIsmasConnectivityCommand>(
|
||||
QString("echo CheckIsmasConnectivityCommand")
|
||||
, this));
|
||||
//QString("echo ATBUpdateCheck --ismas-connected")
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateCheck --ismas-connected")
|
||||
, this, ++next));
|
||||
|
||||
// check if update activated in ISMAS
|
||||
// *** check if update activated in ISMAS ***
|
||||
// NOTE: if the customer repository does not exist, then it does not matter
|
||||
// if the update has been activated via ISMAS.
|
||||
m_workList.push_back(
|
||||
std::make_unique<CheckUpdateActivationCommand>(
|
||||
QString("echo CheckUpdateActivationCommand")
|
||||
, this));
|
||||
// QString("echo ATBUpdateCheck --update-requested")
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateCheck --update-requested")
|
||||
, this, ++next));
|
||||
|
||||
// check and fetch git-customer repository
|
||||
// *** check and fetch git-customer repository ***
|
||||
// (1): if the customer repository does not exist, clone the repository.
|
||||
// (2): if the repository exists, pull the repository. Optionally, checkout
|
||||
// the corresponding branch, and check the integrity of the repository.
|
||||
m_workList.push_back(
|
||||
std::make_unique<CheckAndFetchCustomerRepositoryCommand>(
|
||||
QString("echo CheckAndFetchCustomerRepositoryCommand")
|
||||
, this));
|
||||
// QString("echo ATBUpdateGit")
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateGit")
|
||||
, this, ++next));
|
||||
|
||||
// exec opkg-commands
|
||||
// first with no action -> dry-run
|
||||
// *** exec opkg-commands (noaction) ***
|
||||
// NOTE: first run the opkg commands with no action -> dry-run
|
||||
m_workList.push_back(
|
||||
std::make_unique<ExecOpkgCommand>(
|
||||
QString("echo ExecOpkgCommand")
|
||||
, this, true));
|
||||
// QString("echo ATBUpdateOpkg --noaction")
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateOpkg --noaction")
|
||||
, this, ++next, true));
|
||||
|
||||
// exec opkg-commands
|
||||
// now with action -> no dry-run
|
||||
|
||||
// send json files down to device controller
|
||||
// *** exec opkg-commands ***
|
||||
// NOTE: first run the opkg commands with action -> no dry-run
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateJsonCommand>(
|
||||
QString("echo UpdateJsonCommand")
|
||||
//QString("/opt/app/tools/atbupdate/ATBDownloadDCJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
|
||||
, this, false));
|
||||
|
||||
// sync json files in repo etc-directory with /etc fs-directory
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateFileSystemCommand>(
|
||||
QString("echo UpdateFileSystemCommand")
|
||||
, this));
|
||||
|
||||
std::make_unique<ExecOpkgCommand>(
|
||||
QString("echo ExecOpkgCommand run")
|
||||
// QString("/opt/app/tools/atbupdate/ATBUpdateOpkg")
|
||||
, this, ++next, false));
|
||||
|
||||
// send device-controller firmware down to device-controller-hardware
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateDCCommand>(
|
||||
QString("echo UpdateDCCommand")
|
||||
// QString("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")
|
||||
, this));
|
||||
// QString("echo ATBUpdateDC")
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateDC")
|
||||
, this, ++next));
|
||||
|
||||
// sync json files in repo etc-directory with /etc fs-directory
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateFileSystemCommand>(
|
||||
QString("echo ATBUpdateSync")
|
||||
, this, ++next));
|
||||
|
||||
// *** send json files down to device controller ***
|
||||
m_workList.push_back(
|
||||
std::make_unique<UpdateJsonCommand>(
|
||||
//QString("echo ATBUpdateJsonFiles")
|
||||
//QString("/opt/app/tools/atbupdate/ATBUpdateJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
|
||||
|
||||
// use customer repo
|
||||
QString("/opt/app/tools/atbupdate/ATBUpdateJsonFiles").arg(QCoreApplication::applicationPid())
|
||||
, this, ++next, false));
|
||||
|
||||
// show/send software-status
|
||||
m_workList.push_back(
|
||||
std::make_unique<ShowSoftwareStatusCommand>(
|
||||
QString("echo ShowSoftwareStatusCommand")
|
||||
, this));
|
||||
QString("echo ATBUpdateShow")
|
||||
, this, -1));
|
||||
|
||||
// reboot machine
|
||||
///////////////////////////////////////////////////////////
|
||||
@@ -283,10 +327,91 @@ Worker::~Worker() {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct LogLineEntry {
|
||||
char receiver; // 1 receiver can be: ISMAS
|
||||
char reason[5]; // 6 SW_UP
|
||||
char timestamp[19]; // 25 ISO-format: 1900-xx-xxT00:00:00
|
||||
char eventId; // 26
|
||||
char event[5]; // 31
|
||||
/*
|
||||
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 laeuft, Resultcodes entsprechend laufender Schritt
|
||||
// #define _ISMAS_RESET_WAIT "ISMAS" // reset WAIT-button to "WAIT"
|
||||
// #define _ISMAS_TEST_TRIGGER "U0099" // check the WAIT-button
|
||||
char eventState; // 32
|
||||
char percent; // 33 percent in progressbar of update-tool
|
||||
char resultCode; // 34
|
||||
char step[40]; // 74 step executed
|
||||
char stepResult[40];// 114 result for step
|
||||
char version[14]; // 128
|
||||
};
|
||||
#endif
|
||||
|
||||
void Worker::onFileChanged(QString const& fname) {
|
||||
|
||||
QFile f(fname);
|
||||
//if (m_updateLog.fileName().contains(fname)) {
|
||||
// if (f.exists() && m_updateLogBackup.exists()) {
|
||||
if (!m_updateLogBackup.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
|
||||
qCritical() << "ERROR can not open" << m_updateLogBackup.fileName();
|
||||
return;
|
||||
}
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
QByteArray const &backup = m_updateLogBackup.readAll();
|
||||
QByteArray const &data = f.readAll();
|
||||
int const diff = data.size() - backup.size();
|
||||
if (diff > 0) {
|
||||
QByteArray const &newLines = data.mid(backup.size());
|
||||
int const size = newLines.size();
|
||||
if (size > 0) {
|
||||
LogLineEntry logLine;
|
||||
int pos = 0;
|
||||
while (pos < size) {
|
||||
QByteArray const &a = newLines.mid(pos, sizeof(logLine));
|
||||
if (a.size() == sizeof(logLine)) {
|
||||
memcpy(&logLine, a.data(), sizeof(logLine));
|
||||
|
||||
qCritical() << " reason:" << QString(QByteArray(logLine.reason, sizeof(logLine.reason)));
|
||||
qCritical() << " timestamp:" << QString(QByteArray(logLine.timestamp, sizeof(logLine.timestamp)));
|
||||
qCritical() << " event:" << QString(QByteArray(logLine.event, sizeof(logLine.event)));
|
||||
qCritical() << " step:" << QString(QByteArray(logLine.step, sizeof(logLine.step)));
|
||||
qCritical() << "stepResult:" << QString(QByteArray(logLine.stepResult, sizeof(logLine.stepResult)));
|
||||
qCritical() << " percent:" << (int)logLine.percent;
|
||||
|
||||
displayProgressInMainWindow(logLine.percent);
|
||||
}
|
||||
pos += sizeof(logLine);
|
||||
}
|
||||
m_updateLogBackup.write(newLines);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
//}
|
||||
m_updateLogBackup.close();
|
||||
// TODO: daten an ISMAS senden
|
||||
}
|
||||
|
||||
void Worker::displayProgressInMainWindow(int progress) {
|
||||
if (m_mainWindow) {
|
||||
QApplication::postEvent(m_mainWindow,
|
||||
new ProgressEvent(this, progress));
|
||||
QProgressBar *progressBar = m_mainWindow->progressBar();
|
||||
if (progressBar) {
|
||||
progressBar->setValue(progress);
|
||||
}
|
||||
//QApplication::postEvent(m_mainWindow,
|
||||
// new ProgressEvent(this, progress));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,12 +429,6 @@ void Worker::stopProgressLoop() {
|
||||
displayProgressInMainWindow(MainWindow::STOP_PROGRESS_LOOP);
|
||||
}
|
||||
|
||||
static std::once_flag once;
|
||||
void Worker::run() {
|
||||
// user should not start the update process several times
|
||||
std::call_once(once, &Worker::privateUpdate, this);
|
||||
}
|
||||
|
||||
bool Worker::isRepositoryCorrupted() {
|
||||
QDir customerRepository(m_customerRepository);
|
||||
if (customerRepository.exists()) {
|
||||
@@ -355,6 +474,7 @@ bool Worker::repairCorruptedRepository() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Worker::privateUpdate() {
|
||||
if (!m_mainWindow) {
|
||||
Utils::printCriticalErrorMsg("m_mainWindow NOT SET");
|
||||
@@ -632,6 +752,7 @@ void Worker::privateUpdate() {
|
||||
// final messages: see destructor of UpdateProcessRunning subclass
|
||||
m_lastFailedUpdateStep = UPDATE_STEP::NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Worker::updateTriggerSet() {
|
||||
// repository is existent and not corrupted. check now if the ISMAS-trigger
|
||||
@@ -1597,78 +1718,3 @@ bool Worker::jsUpdate() {
|
||||
bool Worker::dcUpdate() {
|
||||
return m_dcDownloadFirmware->start("/opt/app/tools/atbupdate");
|
||||
}
|
||||
|
||||
void Worker::summary() {
|
||||
|
||||
QString summary, first, second, line, tmp;
|
||||
QVector<QPair<QString, QString>> vec = Utils::installedPackages();
|
||||
|
||||
vec.append(Utils::installedTariffFiles(this, m_customerRepository));
|
||||
vec.append(Utils::installedJsonFiles(this, m_customerRepository));
|
||||
|
||||
int max_first = 0, max_second = 0;
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
max_first = std::max(max_first, vec[i].first.length());
|
||||
max_second = std::max(max_second, vec[i].second.length());
|
||||
}
|
||||
|
||||
max_first += 5;
|
||||
|
||||
summary = "UPDATE SUMMARY\n\n";
|
||||
|
||||
first = QString("%1").arg("start", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(start().toString(Qt::ISODate));
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("update tool version", max_first, QChar(' '));
|
||||
tmp = QString("%1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME);
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("machine number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(machineNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("customer number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(customerNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
first = QString("%1").arg("zone number", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(zoneNr());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
if (m_mainWindow) {
|
||||
tmp = m_mainWindow->targetDcVersion();
|
||||
if (!tmp.isEmpty()) {
|
||||
first = QString("%1").arg("target device controller", max_first, QChar(' '));
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
first = QString("%1").arg("apism", max_first, QChar(' '));
|
||||
tmp = QString("%1").arg(apismVersion());
|
||||
second = QString("%1").arg(tmp, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
first = QString("%1").arg(vec[i].first, max_first, QChar(' '));
|
||||
second = QString("%1").arg(vec[i].second, -max_second, QChar(' '));
|
||||
line = first + ": " + second;
|
||||
summary += line + "\n";
|
||||
}
|
||||
|
||||
emit showSummary(summary);
|
||||
emit enableExit();
|
||||
}
|
||||
|
@@ -13,12 +13,14 @@
|
||||
#include <QThread>
|
||||
#include <QByteArray>
|
||||
#include <QScopedPointer>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include <optional>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "git/git_client.h"
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "ismas/ApismClientForUpdate.h"
|
||||
#include "utils.h"
|
||||
#include "work_process_list.h"
|
||||
|
||||
@@ -141,7 +143,21 @@ class Command;
|
||||
class Update;
|
||||
class MainWindow;
|
||||
class hwinf;
|
||||
class Worker : public QThread{
|
||||
|
||||
/*!
|
||||
\class Worker
|
||||
\brief The worker class ties together the parts the update tool consists of:
|
||||
* ATBUpdateTool
|
||||
* ATBUpdateCheck
|
||||
* ATBUpdateGit
|
||||
* ATBUpdateSync
|
||||
* ATBUpdateOpkg
|
||||
* ATBUpdateDC
|
||||
* ATBUpdateJsonFiles
|
||||
* ATBUpdateShow
|
||||
*
|
||||
*/
|
||||
class Worker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
int const m_customerNr;
|
||||
@@ -177,7 +193,7 @@ class Worker : public QThread{
|
||||
QString const m_pluginVersionTcpZvt;
|
||||
|
||||
int m_ismasUpdateRequests;
|
||||
QTimer m_waitForNewUpdates;
|
||||
QTimer m_summaryTimer;
|
||||
|
||||
QStringList m_filesToUpdate;
|
||||
QStringList m_filesToDownload;
|
||||
@@ -199,6 +215,7 @@ class Worker : public QThread{
|
||||
QString m_apismVersion;
|
||||
|
||||
WorkList m_workList;
|
||||
ApismClientForUpdate m_clForUpdate;
|
||||
|
||||
bool executeOpkgCommand(QString opkgCommand);
|
||||
bool cleanUpOpkgCache();
|
||||
@@ -228,6 +245,7 @@ class Worker : public QThread{
|
||||
int sendUpdateSucceededAndActivated();
|
||||
int sendFinalResult();
|
||||
|
||||
public:
|
||||
struct UpdateProcessRunning {
|
||||
Worker *m_worker;
|
||||
|
||||
@@ -388,10 +406,15 @@ private:
|
||||
hwinf *m_hw = nullptr;
|
||||
UPDATE_STEP m_lastFailedUpdateStep = UPDATE_STEP::NONE;
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
public:
|
||||
UPDATE_STEP lastFailedUpdateStep() const {
|
||||
return m_lastFailedUpdateStep;
|
||||
}
|
||||
|
||||
void setLastFailedUpdateStep(UPDATE_STEP step) {
|
||||
m_lastFailedUpdateStep = step;
|
||||
}
|
||||
|
||||
QDebug CONSOLE(QStringList const &lst = QStringList()) {
|
||||
m_debugMsg = lst;
|
||||
return QDebug(QtMsgType::QtInfoMsg);
|
||||
@@ -402,6 +425,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;
|
||||
@@ -423,6 +449,29 @@ public:
|
||||
static const QString UPDATE_STEP_WRONG;
|
||||
static const QString UPDATE_STEP_SUCCESS;
|
||||
|
||||
/**
|
||||
* Create a new Worker object to be used as the controlling instance of the
|
||||
* update process.
|
||||
*
|
||||
* @brief Constructor
|
||||
* @param customerNr
|
||||
* @param machineNr
|
||||
* @param zoneNr
|
||||
* @param repositoryUrl
|
||||
* @param branchName
|
||||
* @param pluginDir
|
||||
* @param pluginName
|
||||
* @param workingDir
|
||||
* @param noUpdatePsaHardware
|
||||
* @param alwaysDownloadConfig
|
||||
* @param alwaysDownloadDC
|
||||
* @param dryRun
|
||||
* @param parent
|
||||
* @param serialInterface
|
||||
* @param baudrate
|
||||
*
|
||||
* @todo einige parameter werden wohl ueberfluessig
|
||||
*/
|
||||
explicit Worker(int customerNr, // 281
|
||||
int machineNr,
|
||||
int zoneNr,
|
||||
@@ -448,6 +497,8 @@ public:
|
||||
void setHW(hwinf *hw) { m_hw = hw; }
|
||||
hwinf *getHW() { return m_hw; }
|
||||
|
||||
QString customerRepository() { return m_customerRepository; }
|
||||
|
||||
IsmasClient &getIsmasClient() { return m_ismasClient; }
|
||||
IsmasClient const &getIsmasClient() const { return m_ismasClient; }
|
||||
|
||||
@@ -468,7 +519,6 @@ public:
|
||||
|
||||
bool jsUpdate();
|
||||
bool dcUpdate();
|
||||
void summary();
|
||||
QDateTime start() { return m_start; }
|
||||
|
||||
QByteArray standardOutput() const { return m_standardOutput; }
|
||||
@@ -476,6 +526,8 @@ public:
|
||||
WorkList const &workList() const { return m_workList; }
|
||||
WorkList &workList() { return m_workList; }
|
||||
|
||||
QTimer *summaryTimer() { return &m_summaryTimer; }
|
||||
|
||||
signals:
|
||||
void appendText(QString, QString suffix = "");
|
||||
void insertText(QString);
|
||||
@@ -497,9 +549,12 @@ signals:
|
||||
void showCustRepoStatus(QString);
|
||||
void showUpdateRequest(QString);
|
||||
void showExecOpkgStatus(QString);
|
||||
void showExecOpkgCommand(QString);
|
||||
void showExecOpkgOverallResult(QString,bool);
|
||||
void showDownloadDCJsonFilesStatus(QString);
|
||||
void showSyncCustRepoStatus(QString);
|
||||
void showUpdateDCFirmware(QString);
|
||||
void summary();
|
||||
void showSummary(QString);
|
||||
void setDcDownloadProgress(int);
|
||||
|
||||
@@ -511,6 +566,7 @@ private slots:
|
||||
bool syncCustomerRepositoryAndFS();
|
||||
// bool sendIsmasLastVersionNotification(int progress);
|
||||
bool saveLogFile();
|
||||
void onFileChanged(QString const&);
|
||||
|
||||
public slots:
|
||||
void readyReadStandardOutput();
|
||||
@@ -524,6 +580,9 @@ private:
|
||||
|
||||
QDateTime m_start;
|
||||
QByteArray m_standardOutput;
|
||||
QFileSystemWatcher m_fileWatcher;
|
||||
QFile m_updateLog;
|
||||
QFile m_updateLogBackup;
|
||||
|
||||
static const QMap<UPDATE_STEP, const char*> smap;
|
||||
|
||||
@@ -1625,8 +1684,12 @@ private:
|
||||
smap[UPDATE_STEP::UPDATE_FINALIZE],
|
||||
instance->m_ismasMsg.join(' ').toStdString().c_str(),
|
||||
instance->m_versionInfo.size() >= 1 ? instance->m_versionInfo.at(0).toUtf8().constData() : "N/A");
|
||||
ismasClient.sendRequestReceiveResponse(
|
||||
IsmasClient::APISM::DB_PORT, ismasUpdateNews);
|
||||
// send ACTIVATE message 3x -> reorder should be impossible now
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ismasClient.sendRequestReceiveResponse(
|
||||
IsmasClient::APISM::DB_PORT, ismasUpdateNews);
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
} break;
|
||||
case UPDATE_STEP::UPDATE_NOT_NECESSARY: {
|
||||
ismasClient.setProgressInPercent(_UPDATE_NOT_NECESSARY + _UPDATE_NOT_NECESSARY_CORRECTION);
|
||||
|
49
common/include/command.h
Normal file
49
common/include/command.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef COMMAND_H_INCLUDED
|
||||
#define COMMAND_H_INCLUDED
|
||||
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
#include <QScopedPointer>
|
||||
|
||||
class Command : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_command;
|
||||
QString m_commandResult;
|
||||
|
||||
int m_waitForStartTimeout;
|
||||
int m_waitForFinishTimeout;
|
||||
bool m_verbose;
|
||||
int m_exitCode;
|
||||
QString m_workingDirectory;
|
||||
|
||||
QScopedPointer<QProcess> m_p;
|
||||
|
||||
QStringList m_args;
|
||||
|
||||
public:
|
||||
Command(QString command,
|
||||
QStringList args,
|
||||
QString workingDirectory,
|
||||
bool verbose = true,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
|
||||
void resetCommandResult() { m_commandResult.clear(); }
|
||||
QString getCommandResult(bool reset = false);
|
||||
QString const &command() const { return m_command; }
|
||||
QString const &commandResult() const { return m_commandResult; }
|
||||
QStringList const &args() const { return m_args; }
|
||||
|
||||
bool exec();
|
||||
int exitCode() const { return m_exitCode; }
|
||||
|
||||
private slots:
|
||||
virtual void readyReadStandardOutput();
|
||||
virtual void readyReadStandardError();
|
||||
};
|
||||
|
||||
#endif // COMMAND_H_INCLUDED
|
@@ -23,6 +23,7 @@ class CommandLineParser : public QCommandLineParser {
|
||||
QString m_alwaysDownloadDC;
|
||||
QString m_readDCVersion{"false"};
|
||||
QString m_dcDir{"etc/dc/"};
|
||||
QString m_debug{"false"};
|
||||
qint64 m_ppid;
|
||||
|
||||
QCommandLineOption m_repositoryUrlOption;
|
||||
@@ -43,6 +44,7 @@ class CommandLineParser : public QCommandLineParser {
|
||||
QCommandLineOption m_dcDirectoryOption;
|
||||
QCommandLineOption m_readDCVersionOption;
|
||||
QCommandLineOption m_setPPid;
|
||||
QCommandLineOption m_debugOption;
|
||||
|
||||
QCommandLineParser m_parser;
|
||||
|
||||
@@ -56,6 +58,9 @@ public:
|
||||
QCommandLineParser &parser() { return m_parser; }
|
||||
QCommandLineParser const &parser() const { return m_parser; }
|
||||
void process(const QCoreApplication &app) { m_parser.process(app); }
|
||||
bool isSet(QCommandLineOption const &o) { return m_parser.isSet(o); }
|
||||
bool isSet(QString const& s) {return m_parser.isSet(s); }
|
||||
bool addOption(QCommandLineOption const &o) { return m_parser.addOption(o); }
|
||||
QString const &iniFileName() const { return m_iniFileName; }
|
||||
void readSettings();
|
||||
QString repositoryUrl();
|
||||
@@ -74,5 +79,6 @@ public:
|
||||
bool alwaysDownloadDC();
|
||||
bool readDCVersion();
|
||||
QString dcDir();
|
||||
bool debug();
|
||||
};
|
||||
#endif // COMMAND_LINE_PARSER_H_INCLUDED
|
69
common/include/log_line_entry.h
Normal file
69
common/include/log_line_entry.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef LOG_LINE_ENTRY_H_INCLUDED
|
||||
#define LOG_LINE_ENTRY_H_INCLUDED
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
struct LogLineEntry {
|
||||
char receiver; // 1 receiver can be: ISMAS
|
||||
char reason[5]; // 6 SW_UP
|
||||
char timestamp[19]; // 25 ISO-format: 1900-xx-xxT00:00:00
|
||||
char eventId; // 26
|
||||
char event[5]; // 31
|
||||
/*
|
||||
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 laeuft, Resultcodes entsprechend laufender Schritt
|
||||
// #define _ISMAS_RESET_WAIT "ISMAS" // reset WAIT-button to "WAIT"
|
||||
// #define _ISMAS_TEST_TRIGGER "U0099" // check the WAIT-button
|
||||
char eventState; // 32
|
||||
char percent; // 33 percent in progressbar of update-tool
|
||||
char resultCode; // 34
|
||||
char step[40]; // 74 step executed
|
||||
char stepResult[40];// 114 result for step
|
||||
char version[13]; // 127
|
||||
char dummy; // 128
|
||||
};
|
||||
|
||||
inline static LogLineEntry initLogLineEntry(
|
||||
char const receiver,
|
||||
char const timestamp[19],
|
||||
char const event[5],
|
||||
char const eventState,
|
||||
char const percent,
|
||||
char const resultCode,
|
||||
char const step[40],
|
||||
char const stepResult[40],
|
||||
char const eventId = 0,
|
||||
char const reason[5] = "SW_UP",
|
||||
char const version[14] = "") {
|
||||
LogLineEntry e;
|
||||
memset(&e, 0, sizeof(e));
|
||||
|
||||
e.receiver = receiver;
|
||||
std::memcpy(e.reason, reason, std::min(sizeof(e.reason), strlen(reason)));
|
||||
std::memcpy(e.timestamp, timestamp, std::min(sizeof(e.timestamp), strlen(timestamp)));
|
||||
e.eventId = eventId;
|
||||
std::memcpy(e.event, event, std::min(sizeof(e.event), strlen(event)));
|
||||
e.eventState = eventState;
|
||||
e.percent = percent;
|
||||
e.resultCode = resultCode;
|
||||
std::memcpy(e.step, step, std::min(sizeof(e.step), strlen(step)));
|
||||
std::memcpy(e.stepResult, stepResult, std::min(sizeof(e.stepResult), strlen(stepResult)));
|
||||
std::memcpy(e.version, version, std::min(sizeof(e.version), strlen(version)));
|
||||
e.dummy = '\0';
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
#endif // LOG_LINE_ENTRY_H_INCLUDED
|
16
common/include/utils.h
Normal file
16
common/include/utils.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef UTILS_INTERNAL_H_INCLUDED
|
||||
#define UTILS_INTERNAL_H_INCLUDED
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace internal {
|
||||
int read1stLineOfFile(QString fileName);
|
||||
QString customerRepoRoot();
|
||||
QString customerRepoDir();
|
||||
QString customerRepoDirName();
|
||||
QString repositoryUrl();
|
||||
QString branchName();
|
||||
bool customerRepoExists();
|
||||
}
|
||||
|
||||
#endif // UTILS_INTERNAL_H_INCLUDED
|
91
common/include/utils_internal.h
Normal file
91
common/include/utils_internal.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#ifndef UTILS_INTERNAL_H_INCLUDED
|
||||
#define UTILS_INTERNAL_H_INCLUDED
|
||||
|
||||
#include <QString>
|
||||
#include <QSettings>
|
||||
#include <memory>
|
||||
|
||||
namespace internal {
|
||||
|
||||
static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
|
||||
static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
|
||||
static constexpr const char *UPDATE_INITIAL{"initial update"};
|
||||
static constexpr const char *UPDATE_REQUESTED{"requested"};
|
||||
|
||||
static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"};
|
||||
static constexpr const int NO_CUSTOMER_REPOSITORY_CODE{-8};
|
||||
static constexpr const char *NO_ETC_CUSTOMER_REPOSITORY{"no etc/ in customer repository"};
|
||||
static constexpr const int NO_ETC_CUSTOMER_REPOSITORY_CODE{-9};
|
||||
static constexpr const char *NO_OPT_CUSTOMER_REPOSITORY{"no opt/ in customer repository"};
|
||||
static constexpr const int NO_OPT_CUSTOMER_REPOSITORY_CODE{-10};
|
||||
|
||||
static constexpr const char *ISMAS_CONNECTED{"connected"};
|
||||
static constexpr const char *ISMAS_DISCONNECTED{"disconnected"};
|
||||
static constexpr const char *ISMAS_DISCONNECTING{"disconnecting"};
|
||||
static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
|
||||
static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
|
||||
|
||||
static constexpr const char *BROKER_CONNECTED{"connected"};
|
||||
static constexpr const char *BROKER_DISCONNECTED{"disconnected"};
|
||||
static constexpr const char *BROKER_DISCONNECTING{"disconnecting"};
|
||||
static constexpr const char *BROKER_NOT_CONNECTED{"not connected"};
|
||||
static constexpr const char *BROKER_CONNECTION_IN_PROGRESS{"connecting"};
|
||||
|
||||
static constexpr const int GIT_CHECKOUT_ERROR_CODE{-2};
|
||||
static constexpr const int GIT_PULL_ERROR_CODE{-4};
|
||||
static constexpr const int GIT_NOT_NECESSARY_CODE{1};
|
||||
static constexpr const int GIT_UPDATED_CODE{2};
|
||||
static constexpr const int GIT_CLONED_CODE{3};
|
||||
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY{"no repository update necessary"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_NOT_NECESSARY{"not necessary"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"};
|
||||
static constexpr const char *GIT_CUSTOMER_REPO_CLONED{"repository cloned"};
|
||||
static constexpr const char *GIT_UPDATED{"updated"};
|
||||
|
||||
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
|
||||
static constexpr const char *EXEC_OPKG_COMMANDS_FAIL{"FAIL"};
|
||||
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_SUCCESS{"success"};
|
||||
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_FAIL{"FAIL"};
|
||||
|
||||
static constexpr const char *UPDATE_DC_JSON_FILES_SUCCESS{"success"};
|
||||
|
||||
static constexpr const char *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
|
||||
|
||||
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};
|
||||
|
||||
static constexpr const char *DEFAULT_INI_DIR{"/etc/tools/atbupdate/"};
|
||||
static constexpr const char *DEFAULT_INSTALL_DIR{"/opt/app/tools/atbupdate/"};
|
||||
|
||||
int read1stLineOfFile(QString fileName);
|
||||
QString customerRepoRoot();
|
||||
QString customerRepoDir();
|
||||
QString customerRepoDcDir();
|
||||
QString customerRepoDirName();
|
||||
QString repositoryUrl();
|
||||
QString branchName();
|
||||
bool customerRepoExists();
|
||||
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName = "");
|
||||
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory, QString const &rootDir = "");
|
||||
}
|
||||
|
||||
#endif // UTILS_INTERNAL_H_INCLUDED
|
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
|
148
common/ismas/ISMASData.h
Normal file
148
common/ismas/ISMASData.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
enum RESULT_CODE {
|
||||
E_SUCCESS=0,
|
||||
// if between 00:00 - 04:00 Wait-button state not WAIT, then we assume
|
||||
// that's an automatic nightly (not-necessary) update
|
||||
E_NO_UPDATE_NECESSARY=1,
|
||||
// if APISM reports the ISMAS is not available (15x, 6s delay each)
|
||||
E_ISMAS_NO_CONNECTION_ERROR=2,
|
||||
// if not within 00:00-04:00 and WAIT-button was not in state WAIT
|
||||
E_ISMAS_TRIGGER_ERROR=3,
|
||||
// cloning git repo. not possible
|
||||
E_GIT_CLONE_ERROR=4,
|
||||
// pulling from remote git server not possible
|
||||
E_GIT_PULL_ERROR=5,
|
||||
// fetching from remote git server not possible
|
||||
E_GIT_FETCH_ERROR=6,
|
||||
// merging fetched data not possible
|
||||
E_GIT_MERGE_ERROR=7,
|
||||
// check sanity of local customer-repository failed
|
||||
E_GIT_CHECK_REPOSITORY_ERROR=8,
|
||||
// switch/checkout of branch (i.e. zone) on error
|
||||
E_GIT_SWITCH_BRANCH_ERROR=9,
|
||||
// fetch/pull of new branch failed. the new branch was not available
|
||||
// when installing via SD-card followed by intial clone during the
|
||||
// update process.
|
||||
E_GIT_FETCH_NEW_BRANCH_ERROR=10,
|
||||
// error computing git-blob hash-value
|
||||
E_GIT_HASH_ERROR=11,
|
||||
// update for general json files failed.
|
||||
E_JSON_FILES_UPDATE_ERROR=12,
|
||||
// error downloading config-json-files to device controller
|
||||
E_JSON_FILES_DOWNLOAD_ERROR=13,
|
||||
// error downloading device-controller
|
||||
E_DC_DOWNLOAD_ERROR=14,
|
||||
// error rsyncing json/ini-files to local filesystem
|
||||
E_RSYN_ERROR=15,
|
||||
// HASH_VALUE_ERROR=14,
|
||||
// HW_COMPATIBILITY_ERROR=15,
|
||||
E_OPKG_COMMANDS_ERROR=16,
|
||||
// CLEANUP_ERROR=18,
|
||||
E_UPDATE_IN_ERROR_STATE=99
|
||||
};
|
||||
|
||||
//
|
||||
// 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
|
128
common/src/command.cpp
Normal file
128
common/src/command.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
#include <QDateTime>
|
||||
|
||||
Command::Command(QString command, QStringList args, QString workingDirectory,
|
||||
bool verbose, int start_timeout, int finish_timeout)
|
||||
: m_command(command.trimmed())
|
||||
, m_commandResult("")
|
||||
, m_waitForStartTimeout(start_timeout)
|
||||
, m_waitForFinishTimeout(finish_timeout)
|
||||
, m_verbose(verbose)
|
||||
, m_exitCode(-1)
|
||||
, m_workingDirectory(workingDirectory)
|
||||
, m_args(args) {
|
||||
m_p.reset(new QProcess(this));
|
||||
if (m_p) {
|
||||
m_p->setWorkingDirectory(workingDirectory);
|
||||
m_p->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
connect(m_p.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
|
||||
connect(m_p.get(), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
|
||||
}
|
||||
}
|
||||
|
||||
void Command::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardOutput();
|
||||
if (m_verbose) {
|
||||
// qCritical().noquote() << s;
|
||||
m_commandResult += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Command::readyReadStandardError() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
if (p) {
|
||||
QString s = p->readAllStandardError();
|
||||
// qCritical().noquote() << s;
|
||||
m_commandResult += s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString Command::getCommandResult(bool reset) {
|
||||
if (reset == false) {
|
||||
return m_commandResult;
|
||||
}
|
||||
|
||||
QString commandResult = m_commandResult;
|
||||
m_commandResult.clear();
|
||||
|
||||
return commandResult;
|
||||
}
|
||||
|
||||
bool Command::exec() {
|
||||
|
||||
if (!m_args.isEmpty()) {
|
||||
m_p->start(m_command, m_args);
|
||||
} else {
|
||||
m_p->start(m_command);
|
||||
}
|
||||
|
||||
qint64 const start = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
|
||||
bool started = false;
|
||||
if ((started = m_p->waitForStarted(m_waitForStartTimeout)) == true) {
|
||||
// qCritical() << "PROCESS" << m_command << "STARTED IN" << m_p->workingDirectory();
|
||||
if (m_p->state() == QProcess::ProcessState::Running) {
|
||||
// qDebug() << "PROCESS" << m_command << "RUNNING IN" << p->workingDirectory();
|
||||
// wait forever for git/opkg-commands to finish
|
||||
int wait = m_waitForFinishTimeout;
|
||||
if (m_command.trimmed().startsWith("git", Qt::CaseInsensitive) ||
|
||||
m_command.trimmed().startsWith("opkg", Qt::CaseInsensitive)) {
|
||||
wait = -1;
|
||||
}
|
||||
bool const no_timeout = m_p->waitForFinished(wait);
|
||||
if (no_timeout) {
|
||||
// qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory();
|
||||
if (m_p->exitStatus() == QProcess::NormalExit) {
|
||||
if ((m_exitCode = m_p->exitCode()) == 0) {
|
||||
qCritical().noquote() << m_p->readAllStandardOutput();
|
||||
//qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
//qDebug() << "EXECUTED" << m_command
|
||||
// << QString("(runtime %1ms)").arg(end-start)
|
||||
// << "with code" << m_exitCode
|
||||
// << "IN" << m_p->workingDirectory();
|
||||
return true;
|
||||
} else {
|
||||
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
qCritical() << "EXECUTED" << m_command
|
||||
<< QString("(runtime %1ms)").arg(end-start)
|
||||
<< "with code" << m_exitCode
|
||||
<< "IN" << m_p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
qCritical() << "PROCESS" << m_command << "CRASHED with code"
|
||||
<< m_p->exitCode()
|
||||
<< QString("(after %1ms)").arg(end-start)
|
||||
<< "IN" << m_p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
qCritical() << "PROCESS" << m_command
|
||||
<< "DID NOT FINISH WITH" << wait
|
||||
<< "MS IN" << m_p->workingDirectory()
|
||||
<< QString("(runtime %1ms)").arg(end-start);
|
||||
}
|
||||
} else {
|
||||
qCritical() << "WRONG PROCESS STATE" << m_p->state()
|
||||
<< "IN" << m_p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
qCritical() << "PROCESS" << m_command << "TIMEOUT AT START"
|
||||
<< QString("(runtime %1ms)").arg(end-start)
|
||||
<< "IN" << m_p->workingDirectory() << m_waitForStartTimeout;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#include <QFile>
|
||||
|
||||
CommandLineParser::CommandLineParser()
|
||||
: m_repositoryUrl("https://git.mimbach49.de/GerhardHoffmann")
|
||||
: m_repositoryUrl("gitea@ptu-config.atb-comm.de:ATB")
|
||||
, m_plugInDir("/usr/lib/")
|
||||
, m_plugInName("libCAslave.so")
|
||||
, m_workingDir("/opt/app/tools/atbupdate/")
|
||||
@@ -100,7 +100,12 @@ CommandLineParser::CommandLineParser()
|
||||
QCommandLineOption(
|
||||
QStringList() << "P" << "set-ppid",
|
||||
QCoreApplication::translate("main", "Set pid of parent process."),
|
||||
QCoreApplication::translate("main", "Set pid of parent process."))) {
|
||||
QCoreApplication::translate("main", "Set pid of parent process.")))
|
||||
, m_debugOption(
|
||||
QCommandLineOption(
|
||||
QStringList() << "debug" << "debug",
|
||||
QCoreApplication::translate("main", "Set debug flag."),
|
||||
QCoreApplication::translate("main", "Set debug flag."))) {
|
||||
|
||||
configure();
|
||||
}
|
||||
@@ -110,7 +115,7 @@ void CommandLineParser::configure() {
|
||||
m_parser.addHelpOption();
|
||||
m_parser.addVersionOption();
|
||||
|
||||
m_repositoryUrlOption.setDefaultValue("https://git.mimbach49.de/GerhardHoffmann");
|
||||
m_repositoryUrlOption.setDefaultValue("https://ptu-config.atb-comm.de/ATB/");
|
||||
m_parser.addOption(m_repositoryUrlOption);
|
||||
|
||||
m_iniFileDirectoryOption.setDefaultValue(QCoreApplication::applicationDirPath());
|
||||
@@ -163,6 +168,9 @@ void CommandLineParser::configure() {
|
||||
|
||||
m_setPPid.setDefaultValue("-1");
|
||||
m_parser.addOption(m_setPPid);
|
||||
|
||||
m_debugOption.setDefaultValue("false");
|
||||
m_parser.addOption(m_debugOption);
|
||||
}
|
||||
|
||||
void CommandLineParser::readSettings() {
|
||||
@@ -180,7 +188,7 @@ void CommandLineParser::readSettings() {
|
||||
for (QString const &key: keys) {
|
||||
QVariant v = settings.value(key);
|
||||
|
||||
//qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
|
||||
// qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
|
||||
// << key << " -> " << v.toString();
|
||||
|
||||
if (key.contains("repository-url")) {
|
||||
@@ -227,6 +235,9 @@ void CommandLineParser::readSettings() {
|
||||
} else
|
||||
if (key.contains("read-dc-version")) {
|
||||
m_readDCVersion = (v.toBool() ? "true" : "false");
|
||||
} else
|
||||
if (key.contains("debug")) {
|
||||
m_debug = (v.toBool() ? "true" : "false");
|
||||
} else {
|
||||
qCritical() << __PRETTY_FUNCTION__
|
||||
<< key << " -> (UNKNOWN) " << v.toString();
|
||||
@@ -288,6 +299,13 @@ bool CommandLineParser::readDCVersion() {
|
||||
return m_readDCVersion == "false" ? false : true;
|
||||
}
|
||||
|
||||
bool CommandLineParser::debug() {
|
||||
if (m_parser.isSet(m_debugOption)) {
|
||||
m_debug = m_parser.value(m_debugOption);
|
||||
}
|
||||
return m_debug == "false" ? false : true;
|
||||
}
|
||||
|
||||
QString CommandLineParser::workingDir() {
|
||||
if (m_parser.isSet(m_workingDirectoryOption)) {
|
||||
m_workingDir = m_parser.value(m_workingDirectoryOption);
|
55
common/src/utils.cpp
Normal file
55
common/src/utils.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
|
||||
namespace internal {
|
||||
|
||||
int read1stLineOfFile(QString fileName) {
|
||||
QFile f(fileName);
|
||||
if (f.exists()) {
|
||||
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&f);
|
||||
in.setCodec("UTF-8");
|
||||
while(!in.atEnd()) {
|
||||
return in.readLine().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString customerRepoRoot() {
|
||||
return "/opt/app/tools/atbupdate/";
|
||||
}
|
||||
|
||||
QString customerRepoDirName() {
|
||||
int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
|
||||
return (customerNr != -1) ? QString("customer_%1").arg(customerNr) : "";
|
||||
}
|
||||
|
||||
QString customerRepoDir() {
|
||||
QString const &n = customerRepoDirName();
|
||||
QString const &r = customerRepoRoot();
|
||||
return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : "";
|
||||
}
|
||||
|
||||
bool customerRepoExists() {
|
||||
QString const repoDir{customerRepoDir()};
|
||||
return !repoDir.isEmpty() ? QDir(repoDir).exists() : false;
|
||||
}
|
||||
|
||||
QString repositoryUrl() {
|
||||
return "gitea@ptu-config.atb-comm.de:ATB/";
|
||||
}
|
||||
|
||||
QString branchName() {
|
||||
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
|
||||
if (zoneNr != -1) {
|
||||
return QString("zg1/zone%1").arg(zoneNr);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace internal
|
191
common/src/utils_internal.cpp
Normal file
191
common/src/utils_internal.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "utils_internal.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
#include <QCryptographicHash>
|
||||
#include <QFileInfoList>
|
||||
|
||||
namespace internal {
|
||||
|
||||
int read1stLineOfFile(QString fileName) {
|
||||
QFile f(fileName);
|
||||
if (f.exists()) {
|
||||
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&f);
|
||||
in.setCodec("UTF-8");
|
||||
while(!in.atEnd()) {
|
||||
return in.readLine().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString customerRepoRoot() {
|
||||
return "/opt/app/tools/atbupdate/";
|
||||
}
|
||||
|
||||
QString customerRepoDirName() {
|
||||
int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
|
||||
return (customerNr != -1) ? QString("customer_%1").arg(customerNr) : "";
|
||||
}
|
||||
|
||||
QString customerRepoDir() {
|
||||
QString const &n = customerRepoDirName();
|
||||
QString const &r = customerRepoRoot();
|
||||
return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : "";
|
||||
}
|
||||
|
||||
QString customerRepoDcDir() {
|
||||
QString const &r = customerRepoDir();
|
||||
return QDir::cleanPath(r + QDir::separator() + "etc/dc/");
|
||||
}
|
||||
|
||||
bool customerRepoExists() {
|
||||
QString const repoDir{customerRepoDir()};
|
||||
return !repoDir.isEmpty() ? QDir(repoDir).exists() : false;
|
||||
}
|
||||
|
||||
QString repositoryUrl() {
|
||||
return "gitea@ptu-config.atb-comm.de:ATB/";
|
||||
}
|
||||
|
||||
QString branchName() {
|
||||
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
|
||||
if (zoneNr != -1) {
|
||||
return QString("zg1/zone%1").arg(zoneNr);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
|
||||
std::unique_ptr<QSettings> settings;
|
||||
|
||||
//QString const fileName{settings->applicationName() + ".ini"};
|
||||
QString const fileName{"ATBUpdateTool.ini"};
|
||||
QDir d;
|
||||
|
||||
if (!optionalDirName.isEmpty()) {
|
||||
d = QDir{optionalDirName};
|
||||
if (d.exists()) { // try to find ini-file under optionalDirname
|
||||
QFileInfo fi{QDir::cleanPath(optionalDirName + QDir::separator() + fileName)};
|
||||
if (fi.exists()) {
|
||||
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
|
||||
return settings;
|
||||
} else {
|
||||
qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
|
||||
}
|
||||
} else {
|
||||
qCritical().noquote() << optionalDirName << "not found. Try" << internal::DEFAULT_INSTALL_DIR;
|
||||
}
|
||||
}
|
||||
d = QDir{internal::DEFAULT_INSTALL_DIR};
|
||||
if (d.exists()) { // try to find ini-file under /opt/app/tools/atbupdate
|
||||
QFileInfo fi{d, fileName};
|
||||
if (fi.exists()) {
|
||||
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
|
||||
return settings;
|
||||
} else {
|
||||
qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
|
||||
}
|
||||
} else {
|
||||
qCritical().noquote() << internal::DEFAULT_INSTALL_DIR << "not found.";
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/*! \brief Find dc-binary to install.
|
||||
*
|
||||
* If rootDir is empty, and if dcDirectory is empty as well, use etc/dc in
|
||||
* custome repository (e,.g. /opt/app/tools/atbupdate/customer_337/etc/dc).
|
||||
* If dcDirectory is not empty, then use it.
|
||||
* If rootDir is \b not empty,check if it alreay ends with "/etc/dc/". in this
|
||||
* case, use rootDir as dcDir. Otherwise, if dcDirectory is empty, use rootDir/etc/dc
|
||||
* (e,.g. /opt/app/tools/atbupdate/customer_337/etc/dc). If dcDirectory
|
||||
* is not empty, use roorDir/dcDirectory.
|
||||
* As last resort, try "/etc/dc".
|
||||
*
|
||||
* \param[in] dcDirectory directory of device controller binary. Maybe empty.
|
||||
* \param[in] rootDir root directory for dcDirectory. Might be empty.
|
||||
* \return name of the found candidate, or null if not found.
|
||||
*/
|
||||
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory,
|
||||
QString const &rootDir) {
|
||||
std::unique_ptr<QString> dcCandidate{nullptr};
|
||||
|
||||
QDir dcDir;
|
||||
|
||||
if (rootDir.isEmpty()) {
|
||||
if (dcDirectory.isEmpty()) {
|
||||
dcDir = customerRepoDcDir();
|
||||
} else {
|
||||
dcDir = dcDirectory;
|
||||
}
|
||||
} else {
|
||||
if (!rootDir.endsWith("/etc/dc") && !rootDir.endsWith("/etc/dc/")) {
|
||||
if (dcDirectory.isEmpty()) {
|
||||
dcDir = QDir::cleanPath(rootDir + QDir::separator() + "etc/dc/");
|
||||
} else {
|
||||
dcDir = QDir::cleanPath(rootDir + QDir::separator() + dcDirectory);
|
||||
}
|
||||
} else {
|
||||
dcDir = QDir::cleanPath(rootDir + QDir::separator());
|
||||
}
|
||||
}
|
||||
|
||||
if (dcDir.exists()) {
|
||||
|
||||
qInfo() << "use" << dcDir.absolutePath() << "as directory (containing dc-binary)";
|
||||
|
||||
QFileInfoList fileInfoList =
|
||||
dcDir.entryInfoList(QStringList("*.bin"),
|
||||
QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
|
||||
|
||||
QFileInfo dc2cbin{dcDir.absoluteFilePath("dc2c.bin")};
|
||||
|
||||
if (dc2cbin.exists()) {
|
||||
|
||||
QCryptographicHash md5gen(QCryptographicHash::Md5);
|
||||
QByteArray ba_dc2cbin{};
|
||||
{
|
||||
QFile f{dc2cbin.absoluteFilePath()};
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
md5gen.addData(f.readAll());
|
||||
ba_dc2cbin = md5gen.result();
|
||||
md5gen.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (ba_dc2cbin.size() > 0) {
|
||||
QFileInfoList::const_iterator it;
|
||||
for (it = fileInfoList.cbegin(); it != fileInfoList.cend(); ++it) {
|
||||
if (it->absoluteFilePath() != dc2cbin.absoluteFilePath()) {
|
||||
QFile f{it->absoluteFilePath()};
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
md5gen.addData(f.readAll());
|
||||
if (ba_dc2cbin == md5gen.result()) {
|
||||
dcCandidate.reset(new QString(f.fileName()));
|
||||
break;
|
||||
}
|
||||
md5gen.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << dcDir.absolutePath() << "does not exist";
|
||||
if (dcDir.absolutePath() != QDir("/etc/dc/").absolutePath()) {
|
||||
qInfo() << __func__ << __LINE__ << "Try /etc/dc/";
|
||||
return dcCandidateToInstall("/etc/dc/", "");
|
||||
}
|
||||
}
|
||||
|
||||
return dcCandidate;
|
||||
}
|
||||
|
||||
} // namespace internal
|
19
misc/atbupdatetool.service
Normal file
19
misc/atbupdatetool.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=ATB update tool
|
||||
|
||||
[Service]
|
||||
Environment=XDG_RUNTIME_DIR=/var/run/user/0
|
||||
# get START_DATE of service. Use '-' to ensure that file exists
|
||||
EnvironmentFile=-/tmp/start_date.env
|
||||
# EnvironmentFile=-/tmp/stop_date.env
|
||||
ExecStartPre=/bin/bash -c 'printf "%%s\n" START_DATE=$(date +"%%Y-%%m-%%d%%H:%%M:%%S") > /tmp/start_date.env'
|
||||
|
||||
ExecStart=/opt/app/tools/atbupdate/ATBUpdateTool --platform wayland
|
||||
|
||||
ExecStartPre=dbus-send --system --type=method_call --dest='eu.atb.ptu.systemcontrol' '/systemcontrol' eu.atb.ptu.systemcontrol.startBackgroundTask string:UPDATE_TOOL
|
||||
ExecStopPost=dbus-send --system --type=method_call --dest='eu.atb.ptu.systemcontrol' '/systemcontrol' eu.atb.ptu.systemcontrol.finishedBackgroundTask string:UPDATE_TOOL
|
||||
# execute script to check if update-tool contains errors not sent to ISMAS.
|
||||
# ExecStopPost=/bin/bash -c 'printf "%%s\n" STOP_DATE=$(date +"%%Y-%%m-%%d%%H:%%M:%%S") > /tmp/stop_date.env'
|
||||
ExecStopPost=/bin/bash -c '[ -f /opt/app/tools/atbupdate/on_update_failure.sh ] && /opt/app/tools/atbupdate/on_update_failure.sh ${START_DATE}'
|
||||
|
||||
#StandardOutput=????
|
184
misc/on_update_failure.sh
Executable file
184
misc/on_update_failure.sh
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/bin/bash
|
||||
|
||||
# set -x
|
||||
|
||||
#
|
||||
#############################################################################
|
||||
# Check if the ATBUpdateTool(.service) did not send U0001 (sucess),
|
||||
# U0002 (activated) or U0003 (error) to ISMAS, including the case that the
|
||||
# tool did not crash or was not killed under other circumstances.
|
||||
#
|
||||
# This script will be called in the associated atbupdatetool.service (see
|
||||
# /lib/systemd/system/atbupdatetool.service).
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
readonly OUT_FILE=/tmp/out.txt
|
||||
readonly SCRIPT_NAME=$(basename $0)
|
||||
|
||||
if [ -z "$START_DATE" ]
|
||||
then
|
||||
START_DATE=$(date +"%Y-%m-%d00:00:00")
|
||||
fi
|
||||
|
||||
if [ -z "$STOP_DATE" ]
|
||||
then
|
||||
STOP_DATE=$(date +"%Y-%m-%d%H:%M:%S")
|
||||
fi
|
||||
|
||||
echo "EXIT_CODE=$EXIT_CODE"
|
||||
echo "SERVICE_RESULT=$SERVICE_RESULT"
|
||||
echo "EXIT_STATUS=$EXIT_STATUS"
|
||||
echo "START_DATE=$START_DATE"
|
||||
echo "STOP_DATE=$STOP_DATE"
|
||||
|
||||
|
||||
last_cmd_event () {
|
||||
# output json; look for start of CMD_EVENT; look for }}; extract everything between; finally re-add }}.
|
||||
# could also look for ">>>", but this might change in the future.
|
||||
local json=$(\
|
||||
journalctl -u atbupdatetool --since="$START_DATE" --until="$STOP_DATE" --output=json-pretty |\
|
||||
grep "#M=APISM#C=CMD_EVENT#J=" |\
|
||||
awk '{split($0, a, "#M=APISM#C=CMD_EVENT#J="); print a[2]}' |\
|
||||
awk '{split($0, a, /\}[\s]*\}/); print a[1]}' |\
|
||||
tr -d '\\' |\
|
||||
tail -1)
|
||||
json+="}}"
|
||||
echo "$json"
|
||||
}
|
||||
|
||||
last_percent_value () {
|
||||
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\3/p" | xargs | awk '{print $NF}')
|
||||
}
|
||||
|
||||
last_step () {
|
||||
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[8]}' | awk '{split($0, b, " : "); print b[2]}' | tr -d '"\\')
|
||||
}
|
||||
|
||||
last_step_result () {
|
||||
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[9]}' | awk '{split($0, b, " : "); print b[2]}' | tr -d '"\\')
|
||||
}
|
||||
|
||||
pid_atbupdatetool () {
|
||||
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(ATBUpdateTool\[\)\(\\s*[0-9]\+\)\(\].*$\)/\3/p" | uniq)
|
||||
}
|
||||
|
||||
last_event () {
|
||||
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[4]}' | awk '{split($0, b, ":"); print b[2]}' | tr -d ' ' | tr -d '"\\')
|
||||
}
|
||||
|
||||
sendU0003 () {
|
||||
LAST_CMD_EVENT=$(last_cmd_event)
|
||||
echo "LAST=$LAST_CMD_EVENT"
|
||||
|
||||
local json_detected=0
|
||||
local temp
|
||||
local x
|
||||
|
||||
if [[ ! -z "$LAST_CMD_EVENT" ]]
|
||||
then
|
||||
temp=$(mktemp -p /tmp)
|
||||
echo "$LAST_CMD_EVENT" > "$temp"
|
||||
x=$(jq .EVENT $temp)
|
||||
if [ $? -eq 0 ]; then
|
||||
json_detected=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $json_detected -eq 1 ]
|
||||
then
|
||||
# local pid=$(jq .EVENT_ID $temp)
|
||||
|
||||
# if json has been detected, use "jq".
|
||||
|
||||
x=$(jq .PARAMETER.PERCENT $temp | tr -d '"')
|
||||
[[ -z "$x" ]] && PERCENT=0 || PERCENT=$x
|
||||
|
||||
x=$(jq .PARAMETER.STEP $temp | tr -d '"')
|
||||
[[ -z "$x" ]] && STEP="unknown" || STEP="$x"
|
||||
|
||||
x=$(jq .PARAMETER.STEP_RESULT $temp | tr -d '"')
|
||||
[[ -z "$x" ]] && STEP_RESULT="unknown" || STEP_RESULT="$x"
|
||||
|
||||
x=$(pid_atbupdatetool)
|
||||
[[ -z "$x" ]] && PID=99999 || PID=$x
|
||||
|
||||
x=$(last_event)
|
||||
[[ -z "$x" ]] && EVENT="unknown" || EVENT="$x"
|
||||
|
||||
else
|
||||
# cannot parse valid json. try original journal text file.
|
||||
|
||||
x=$(last_percent_value)
|
||||
[[ -z "$x" ]] && PERCENT=0 || PERCENT=$x
|
||||
|
||||
x=$(last_step)
|
||||
[[ -z "$x" ]] && STEP="unknown" || STEP="$x"
|
||||
|
||||
x=$(last_step_result)
|
||||
[[ -z "$x" ]] && STEP_RESULT="unknown" || STEP_RESULT="$x"
|
||||
|
||||
x=$(pid_atbupdatetool)
|
||||
[[ -z "$x" ]] && PID=99999 || PID=$x
|
||||
|
||||
x=$(last_event)
|
||||
[[ -z "$x" ]] && EVENT="unknown" || EVENT="$x"
|
||||
fi
|
||||
|
||||
echo "PERCENT=$PERCENT"
|
||||
echo "STEP=$STEP"
|
||||
echo "STEP_RESULT=$STEP_RESULT"
|
||||
echo "PID=$PID"
|
||||
echo "EVENT=$EVENT"
|
||||
|
||||
# build json to be sent to ISMAS with "U0003"
|
||||
|
||||
CURRENT_DATE=$(date +"%Y-%m-%d %H:%M:%S.000%z")
|
||||
U0003Msg="{\
|
||||
\"REASON\":\"SW_UP\",\
|
||||
\"TIMESTAMP\":\"$CURRENT_DATE\",\
|
||||
\"EVENT_ID\":\"$PID\",\
|
||||
\"EVENT\":\"U0003\",\
|
||||
\"EVENTSTATE\":1,\
|
||||
\"PARAMETER\": {\
|
||||
\"PERCENT\" : $PERCENT,\
|
||||
\"RESULTCODE\" : 99,\
|
||||
\"STEP\" : \"$1 -> monitored last step: $STEP\",\
|
||||
\"STEP_RESULT\" : \"$1 -> monitored last step result: $STEP_RESULT\",\
|
||||
\"VERSION\" : \"\"\
|
||||
}\
|
||||
}"
|
||||
|
||||
echo -e "U0003Msg=$U0003Msg"
|
||||
|
||||
(echo "#M=APISM#C=CMD_EVENT#J=$U0003Msg"; sleep 5) | nc localhost 7777
|
||||
}
|
||||
|
||||
# save journal for the last run of atbupdatetool in $OUT_FILE
|
||||
echo $(journalctl -u atbupdatetool --since="$START_DATE" --until=$STOP_DATE) > $OUT_FILE
|
||||
|
||||
if [[ "$EXIT_CODE" = "exited" && "$SERVICE_RESULT" = "success" && "$EXIT_STATUS" = "0" ]]
|
||||
then
|
||||
# almost normal run; at least there was no crash.
|
||||
if cat $OUT_FILE | grep -o "U0003" | wc -l; then
|
||||
echo "$SCRIPT_NAME: Failure code U0003 already sent to ISMAS"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if cat $OUT_FILE | grep -o "U0002" | wc -l; then
|
||||
echo "$SCRIPT_NAME: Success code U0002 already sent to ISMAS"
|
||||
exit 0
|
||||
else
|
||||
sendU0003 "$SCRIPT_NAME: Success code U0002 not sent to ISMAS"
|
||||
fi
|
||||
|
||||
if cat $OUT_FILE | grep -o "U0001" | wc -l; then
|
||||
echo "$SCRIPT_NAME: Success code U0001 already sent to ISMAS"
|
||||
exit 0
|
||||
else
|
||||
sendU0003 "$SCRIPT_NAME: Success code U0001 not sent to ISMAS"
|
||||
fi
|
||||
else
|
||||
# something unexpected has happened.
|
||||
sendU0003 "$SCRIPT_NAME: EXIT_CODE=$EXIT_CODE;SERVICE_RESULT=$SERVICE_RESULT;EXIT_STATUS=$EXIT_STATUS"
|
||||
fi
|
Reference in New Issue
Block a user