Compare commits

..

54 Commits

Author SHA1 Message Date
843ac23770 Build: remove lib dependency on Yocto build 2026-02-10 10:16:20 +01:00
c3b2db7797 Set version 1.5.99 2026-02-10 10:10:34 +01:00
51640b70e9 Merge branch '281/Szeged_without_LibDC' into 281/Szeged 2026-02-10 09:55:35 +01:00
be84c96953 Fix: remove test code 2026-02-10 09:53:58 +01:00
24bf190c90 281/Szeged: Skip updating json files ...
... because this is not supported in currently installed DC-FW version
and DC-lib version.
2026-02-09 15:57:22 +01:00
b656b5eab6 281/Szeged: compile only main program ATBUpdateTool
... because current installed DC-FW version or current installed DClib
in Szeged do not support updating DC-json-files and DC-FW.
2026-02-09 15:55:01 +01:00
6681e61f59 Szeged is still using libCAmaster 2026-02-09 15:21:45 +01:00
7ec6ab00b1 Use interfaces.h from version 1.3.5 2026-02-09 15:19:42 +01:00
057e4603ce ATBUpdateDC: use ATBUpdateTool.ini 2026-02-05 16:19:33 +01:00
7b0e17c478 common/utils_internal: use state from df4e384d9d 2026-02-05 15:14:09 +01:00
e7f78fe976 Fix: merge-conflict from 'save for christmas' ...
518bd87033 2024-12-20 13:01:34
2026-02-05 15:10:18 +01:00
2ac87e93e4 UpdateDC: use common/command 2026-02-05 13:59:41 +01:00
47e7e1e796 Add common/command 2026-02-05 13:59:13 +01:00
553782a2ea Add common/include/utils_internal.h 2026-02-05 13:22:05 +01:00
f2af48eee3 after dc-download, check if device-controller reboots successfully 2026-02-05 12:41:39 +01:00
a30f8334f1 Replace TEST_DC_DOWNLOAD with m_debug. 2026-02-05 12:37:34 +01:00
ea1abc68da Replace TEST_DC_DOWNLOAD with m_debug. 2026-02-05 12:37:19 +01:00
9c40321857 Minor: init. m_debug to false. 2026-02-05 12:36:39 +01:00
0c6b219d31 read ATBUpdateDCsettings in *.ini file 2026-02-05 12:36:13 +01:00
de9304f867 Add define for TEST_DC_DOWNLOAD and add corresponding code
to test the download without actual dc-controller on the PTU.
2026-02-05 12:29:44 +01:00
47ac11fb9a "after dc_download restart autorequest or else E255" 2026-02-05 12:29:40 +01:00
379ca35db2 "shortened time to sendnextblock." 2026-02-05 12:29:34 +01:00
fc41883e6a "increased BL_start Timer (500 -> 1000) " 2026-02-05 12:29:12 +01:00
ff5d0a891c startBootloader():
set wait time to 1000ms.
    set try counter to 10.
    a message to ask for general bl installation (in hardware)
2026-02-05 12:05:29 +01:00
4d91d1e5bb turn dc-download on 2026-02-05 12:04:14 +01:00
bef618a778 testing... 2026-02-05 12:02:52 +01:00
d8112800d5 cleaning up source. rename doUndate() to run(). 2026-02-05 11:46:57 +01:00
98996af2b2 read ini-file and determine device controller to install 2026-02-05 11:46:50 +01:00
eb3f05ff19 preparing dc-update 2026-02-05 11:46:07 +01:00
5b621298c4 take over some code from mainwindow 2026-02-05 11:45:00 +01:00
579997b318 to be removed 2026-02-05 11:44:45 +01:00
6a32c75754 use qcoreapplication -> no window or widgets 2026-02-05 11:44:34 +01:00
724be1568d remove main-window (not needed) 2026-02-05 11:44:08 +01:00
d85eabf3e6 save files with comment (was 8f822c5) 2026-02-05 11:05:22 +01:00
d2d0eb40aa Revert "Remove any reference to device controller as downloading jsons/dc-firmware"
This reverts commit 6b0a784fc8.
2026-02-05 10:26:56 +01:00
518bd87033 save for christmas 2026-02-05 09:18:41 +01:00
6b0a784fc8 Remove any reference to device controller as downloading jsons/dc-firmware
will be done by ATBDownloadDCJsonFiles and ATBDownloadDCFirmware binaries.
2026-02-05 08:42:42 +01:00
093d77ddd1 Update::updateBinary():
begin with starting "/opt/app/tools/atbupdate/ATBDownloadDCFirmware".
2026-02-05 08:38:49 +01:00
ec57f9ba20 Minor: remove unused code. 2026-02-05 08:37:42 +01:00
96828f6e25 getCommandResult():
reset result if necessary (for instance for showing current result
	in GUI.
2026-02-05 08:37:20 +01:00
e1e2008aa6 read dc-verion directly from binary file 2026-02-05 08:36:17 +01:00
e82b92b95b Mior: remove debugs 2026-02-05 08:34:59 +01:00
808f01e1af init some vars to defaults 2026-02-05 08:34:29 +01:00
cf85965946 start with downloading dc: parsing command arguments. started to implement the acrual download 2026-02-05 08:33:58 +01:00
e1e6d1613a Merge branch 'removed-apsim-restart' 2026-02-04 10:13:15 +01:00
5a2ced4a96 set version to 1.5.9 2025-06-16 13:39:03 +02:00
3b3456196f removed restart of apism in case ISMAS is unreachable 2025-06-16 13:34:51 +02:00
c63fa92ff7 script to be started if update-tool finished unexpectedly 2025-05-20 14:19:57 +02:00
42624409ba set version to 1.5.8 2025-05-16 08:42:50 +02:00
c49ff5045b set version to 1.5.7 2025-05-16 08:40:13 +02:00
358fd80c47 Use applicationPid() of update-tool as event-id. (used by christian) 2025-05-14 10:44:09 +02:00
8a2d710cf8 Use pid of update-tool as event-id. (used by christian) 2025-05-14 10:42:27 +02:00
1ea1cdc3e6 set version to 1.5.7 after merge of pu/portrait 2025-02-19 12:08:17 +01:00
348fb15508 Ui: support portrait mode 2025-02-19 11:39:08 +01:00
89 changed files with 1940 additions and 10280 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
tags
*.tags
*.user
documentation/

View File

@@ -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/"
@@ -9,7 +9,7 @@ psa-tariff-directory="etc/psa_tariff/"
[PLUGINS]
plugin-name="libCAslave.so"
plugin-name="libCAmaster.so"
[FLAGS]
no-psa-hardware-update=false
@@ -19,21 +19,3 @@ 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]

View File

@@ -1,3 +1,4 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = Check Show DownloadDCFirmware DownloadDCJsonFiles Git Opkg Sync UpdatePTUDevCtrl
#SUBDIRS = DownloadDCFirmware DownloadDCJsonFiles UpdatePTUDevCtrl
SUBDIRS = UpdatePTUDevCtrl

View File

@@ -1,82 +0,0 @@
QT += core
TARGET = ATBUpdateCheck
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/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 \
ismas_client.cpp \
message_handler.cpp \
../common/src/utils_internal.cpp
HEADERS += \
ismas_client.h \
message_handler.h \
../common/include/utils_internal.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
}

View File

@@ -1,378 +0,0 @@
#ifdef __WIN32__
#error "WIN32 NOT SUPPORTED"
#else
#include "ismas_client.h"
#include <cstring>
#include <cstdio>
#include <errno.h>
#include <arpa/inet.h> // inet_addr()
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <strings.h> // bzero()
#include <sys/socket.h>
#include <unistd.h> // read(), write(), close()
#include <fcntl.h>
#include <QThread>
#include <QJsonDocument>
#include <QJsonObject>
#if 0
########################
# Spec vom 27.10.2023:
# U0010 -> %-Werte
# U0001 -> 100%
# U0003 -> "FAIL"
# U0002 -> "" (OK -> WAIT state reset)
# ISMAS -> "WAIT"
########################
#
# $1: EVENT: U0001 update finished: 100%
# U0002 reset TRG
# U0003 error
# U0010 for update process
# $2: PERCENT : "only for ISMAS: 0-100%",
# $3: RESULTCODE : "only for ISMAS",
# 0: Success
# 1: no Update nessesary
# 2: Backup failed
# 3: Package error/ Wrong package
# 4: Install Error
# $4: STEP : "running step (only for us): update_psa...",
# $5: STEP_RESULT : "error and result text",
# $6: VERSION : "opkg and conf info; what will be updated"
#
#endif
#include <QDateTime>
#include <QDebug>
void IsmasClient::printDebugMessage(int port,
QString const &clientIP,
int clientPort,
QString const &message) {
#if 0
Q_UNUSED(port);
Q_UNUSED(clientIP);
Q_UNUSED(clientPort);
Q_UNUSED(message);
#else
qDebug().noquote()
<< "\n"
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
<< "hostname ........" << "127.0.0.1" << "\n"
<< "port ............" << port << "\n"
<< "local address ..." << clientIP << "\n"
<< "local port ......" << clientPort << "\n"
<< message;
#endif
}
void IsmasClient::printInfoMessage(int port,
QString const &clientIP,
int clientPort,
QString const &message) {
#if 0
Q_UNUSED(port);
Q_UNUSED(clientIP);
Q_UNUSED(clientPort);
Q_UNUSED(message);
#else
qInfo().noquote()
<< "\n"
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
<< "hostname ........" << "127.0.0.1" << "\n"
<< "port ............" << port << "\n"
<< "local address ..." << clientIP << "\n"
<< "local port ......" << clientPort << "\n"
<< message;
#endif
}
void IsmasClient::printErrorMessage(int port,
QString const &clientIP,
int clientPort,
QString const &message) {
qCritical().noquote()
<< "\n"
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
<< "hostname ........" << "127.0.0.1" << "\n"
<< "port ............" << port << "\n"
<< "local address ..." << clientIP << "\n"
<< "local port ......" << clientPort << "\n"
<< message;
}
std::optional<QString>
IsmasClient::sendRequestReceiveResponse(int port, QString const &request, bool verbose) {
if (verbose) {
qInfo() << "REQUEST" << request;
}
int sockfd;
int r;
errno = 0;
// socket create and verification
if ((sockfd = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) {
if (verbose) {
qCritical().noquote()
<< "\n"
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
<< "SOCKET CREATION FAILED (" << strerror(errno) << ")";
}
return std::nullopt;
}
struct sockaddr_in servAddr;
bzero(&servAddr, sizeof(servAddr));
// assign IP, PORT
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons(port);
// connect the client socket to server socket
if ((r = ::connect(sockfd, (struct sockaddr *)(&servAddr), sizeof(servAddr))) != 0) {
if (verbose) {
qCritical().noquote()
<< "\n"
<< "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n"
<< "CONNECTION WITH SERVER FAILED (" << strerror(r) << ")";
}
::close(sockfd);
return std::nullopt;
}
struct sockaddr_in clientAddr;
bzero(&clientAddr, sizeof(clientAddr));
socklen_t sockLen = sizeof(clientAddr);
char clientIP[16];
bzero(&clientIP, sizeof(clientIP));
getsockname(sockfd, (struct sockaddr *)(&clientAddr), &sockLen);
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, sizeof(clientIP));
unsigned int clientPort = ntohs(clientAddr.sin_port);
if (verbose) {
printDebugMessage(port, clientIP, clientPort, QString("CONNECTED TO SERVER"));
}
struct timeval tv;
tv.tv_sec = 10; /* 10 secs timeout for read and write */
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
int maxfdp1;
fd_set rset;
fd_set wset;
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
// no reliable, but does not harm, as we use select() as well
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
int flag = 1;
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
static char buf[1024*8];
bzero(buf, sizeof(buf));
int const bytesToWrite = strlen(request.toStdString().c_str());
strncpy(buf, request.toStdString().c_str(), sizeof(buf)-1);
int loop = 0;
int bytesWritten = 0;
while (bytesWritten < bytesToWrite) {
errno = 0;
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
maxfdp1 = sockfd + 1;
tv.tv_sec = 60; /* 60 secs timeout for read and write -> APISM cuts the connection after 30s */
tv.tv_usec = 0;
int const w = select(maxfdp1, NULL, &wset, NULL, &tv);
if (w < 0) { // error
if (errno == EINTR) {
printErrorMessage(port, clientIP, clientPort,
QString("INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")");
continue;
} else {
printErrorMessage(port, clientIP, clientPort,
QString("SELECT-ERROR (WRITE) %1(").arg(loop) + strerror(errno) + ")");
::close(sockfd);
return std::nullopt;
}
} else
if (w == 0) { // timeout
printErrorMessage(port, clientIP, clientPort,
QString("SELECT-TIMEOUT (WRITE) %1(").arg(loop) + strerror(errno) + ")");
if (++loop < 10) {
QThread::msleep(500);
continue;
}
::close(sockfd);
return std::nullopt;
} else
if (w > 0) {
int n = ::sendto(sockfd, buf+bytesWritten, bytesToWrite-bytesWritten, 0, NULL, 0);
if (n >= 0) {
bytesWritten += n;
} else {
if (errno == EWOULDBLOCK) {
if (++loop < 10) {
QThread::msleep(500);
continue;
}
printErrorMessage(port, clientIP, clientPort,
QString("WRITE TIMEOUT %1(").arg(loop) + strerror(errno) + ")");
::close(sockfd);
return std::nullopt;
} else
if (errno == EINTR) {
printErrorMessage(port, clientIP, clientPort,
QString("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")");
continue;
}
}
}
}
// DO NOT USE SHUTDOWN! APISM CAN NOT COPE WITH IT
// errno = 0;
// if (shutdown(sockfd, SHUT_WR) < 0) {
// printErrorMessage(port, clientIP, clientPort,
// QString("CANNOT CLOSE WRITING END (") + strerror(errno) + ")");
// }
if (verbose) {
printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT <<<") + buf + ">>>");
}
loop = 0;
bzero(buf, sizeof(buf));
int bytesToRead = sizeof(buf)-1;
int bytesRead = 0;
while (bytesRead < bytesToRead) {
errno = 0;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
maxfdp1 = sockfd + 1;
tv.tv_sec = 60; /* 60 secs timeout for read and write */
tv.tv_usec = 0;
QString const selectStart = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
int const r = select(maxfdp1, &rset, NULL, NULL, &tv);
if (r < 0) { // error
if (errno == EINTR) {
printErrorMessage(port, clientIP, clientPort,
QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")");
continue;
} else {
printErrorMessage(port, clientIP, clientPort,
QString("SELECT-ERROR (READ) %1(").arg(loop) + strerror(errno) + ")");
::close(sockfd);
return std::nullopt;
}
} else
if (r == 0) { // timeout
printErrorMessage(port, clientIP, clientPort,
QString("SELECT-TIMEOUT (READ) %1(").arg(loop) + strerror(errno) + ")");
if (++loop < 10) {
QThread::msleep(500);
continue;
}
::close(sockfd);
return std::nullopt;
} else
if (r > 0) {
if (FD_ISSET(sockfd, &rset)) {
int n = ::recvfrom(sockfd, buf+bytesRead, bytesToRead-bytesRead,
0, NULL, NULL);
if (n > 0) { //
bytesRead += n;
} else
if (n == 0) {
// The return value will be 0 when the peer has performed an orderly shutdown.
printErrorMessage(port, clientIP, clientPort,
QString("PEER CLOSED CONNECTION (") + strerror(errno) + ") START AT" +
selectStart + " NOW " + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));
::close(sockfd);
return std::nullopt;
} else
if (n < 0) {
if (errno == EWOULDBLOCK) { // check just in case
if (++loop < 10) {
QThread::msleep(500);
continue;
}
printErrorMessage(port, clientIP, clientPort,
QString("READ TIMEOUT %1(").arg(loop) + strerror(errno) + ")");
::close(sockfd);
return std::nullopt;
}
if (errno == EINTR) {
printErrorMessage(port, clientIP, clientPort,
QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")");
continue;
}
}
}
}
// printInfoMessage(port, clientIP, clientPort, QString("MESSAGE RECEIVED ") + buf);
QString response(buf);
if (int idx = response.indexOf("{\"error\":\"ISMAS is offline\"}")) {
response = response.mid(0, idx);
} else
if (response.contains("RECORD")) { // RECORD SAVED or RECORD WRITE ABORTED
if (verbose) {
printInfoMessage(port, clientIP, clientPort, QString("IGNORED '") + response + "' RESPONSE");
}
::close(sockfd);
return std::nullopt;
}
QJsonParseError parseError;
QJsonDocument document(QJsonDocument::fromJson(response.toUtf8(), &parseError));
if (parseError.error == QJsonParseError::NoError) {
if (document.isObject()) { // done: received valid APISM response
if (verbose) {
printInfoMessage(port, clientIP, clientPort,
QString("VALID APISM RESPONSE .. \n") + response);
}
::close(sockfd);
return response;
} else {
printInfoMessage(port, clientIP, clientPort,
QString("CORRUPTED RESPONSE ") + response);
::close(sockfd);
return std::nullopt;
}
} else {
if (!response.contains("RECORD")) {
// maybe APISM does not send valid JSON: "RECORD SAVED" etc.
printDebugMessage(port, clientIP, clientPort,
QString("PARSE ERROR ") + response + " " + parseError.errorString());
}
::close(sockfd);
return std::nullopt;
}
}
return std::nullopt;
}
char const *IsmasClient::reason[REASON::ENTRIES] = {
"TIME-TRIGGERED", "SERVICE", "DEV-TEST"
};
#endif // __WIN32__

View File

@@ -1,51 +0,0 @@
#ifndef ISMAS_CLIENT_H_INCLUDED
#define ISMAS_CLIENT_H_INCLUDED
#include <QObject>
#include <QString>
#include <optional>
class IsmasClient : public QObject {
Q_OBJECT
public:
explicit IsmasClient() = default;
enum APISM {
DB_PORT = 7777,
DIRECT_PORT = 7778
};
enum RESULT_CODE {
SUCCESS=0,
// if between 00:00 - 04:00 Wait-button state not WAIT, then we assume
// that's an automatic nightly (not-necessary) update
NO_UPDATE_NECESSARY=1,
// if APISM reports the ISMAS is not available (15x, 6s delay each)
ISMAS_NO_CONNECTION_ERROR=2,
// if not within 00:00-04:00 and WAIT-button was not in state WAIT
ISMAS_TRIGGER_ERROR=3,
};
enum REASON {
TIME_TRIGGERED = 0,
SERVICE,
DEV_TEST,
ENTRIES
};
static char const *reason[REASON::ENTRIES];
static std::optional<QString>
sendRequestReceiveResponse(int port, QString const &request, bool verbose=false);
private:
static void printDebugMessage(int port, QString const &clientIP, int clientPort,
QString const &message);
static void printInfoMessage(int port, QString const &clientIP, int clientPort,
QString const &message);
static void printErrorMessage(int port, QString const &clientIP, int clientPort,
QString const &message);
};
#endif // ISMAS_CLIENT_H_INCLUDED

View File

@@ -1,180 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#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");
if (value.isEmpty() || value != "C") {
qputenv("LC_ALL", "C");
}
openlog("ATB-UPDATE_CHECK", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
QCoreApplication a(argc, argv);
QCoreApplication::setApplicationName("ATBUpdateCheck");
QCoreApplication::setApplicationVersion(APP_VERSION);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(nullptr);
//atbInstallMessageHandler(atbDebugOutput);
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);
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 &current = 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 exitCode;
}

View File

@@ -1,97 +0,0 @@
#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

View File

@@ -1,23 +0,0 @@
#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

View File

@@ -2,6 +2,9 @@ QT += core serialport
TARGET = ATBUpdateDC
include(../common.pri)
VERSION="0.1.0"
win32 {
BUILD_DATE=$$system("date /t")
@@ -77,7 +80,7 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \
main.cpp \
../common/src/message_handler.cpp \
../common/src/commandline_parser.cpp \
../UpdatePTUDevCtrl/commandline_parser.cpp \
update.cpp \
../common/src/System.cpp \
../common/src/utils_internal.cpp \
@@ -86,7 +89,7 @@ SOURCES += \
HEADERS += \
../common/include/message_handler.h \
../common/include/commandline_parser.h \
../UpdatePTUDevCtrl/commandline_parser.h \
update.h \
../common/include/System.h \
../common/include/utils_internal.h \

View File

@@ -67,11 +67,11 @@ int main(int argc, char **argv) {
//return 0;
/*
CommandLineParser parser;
parser.process(a);
parser.readSettings();
/*
QString repositoryUrl = parser.repositoryUrl();
QString plugInDir = parser.plugInDir();
QString plugInName = parser.plugInName();
@@ -80,7 +80,6 @@ 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();
@@ -134,75 +133,50 @@ 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;
QString const &psaDcDir = internal::customerRepoDcDir();
QString const &psaRepoRootDir = internal::customerRepoRoot();
QString const &psaRepoDir = internal::customerRepoDir();
QString const &branchName = internal::branchName();
bool debug = false;
bool noaction = true;
QString workingDir;
QString libDir;
QString libca;
std::unique_ptr<QSettings> settings = internal::readSettings();
if (settings) {
settings->beginGroup("ATBUpdateDC");
debug = settings->value("debug", false).toBool();
settings->beginGroup("DIRECTORIES");
workingDir = settings->value("workingdir", "/tmp").toString();
libca = settings->value("libca", "/usr/lib/libCAslave.so").toString();
libDir = settings->value("plugin-directory", "/usr/lib/").toString();
settings->endGroup();
} else {
qCritical() << "count not read ATBUpdateTool.ini";
return -1;
}
QString dcDir = parser.dcDir();
if (!dcDir.isEmpty()) {
psaDcDir = dcDir;
}
debug = parser.debug();
settings->beginGroup("FLAGS");
debug = settings->value("debug", false).toBool();
settings->endGroup();
if (debug) {
qInfo() << " using dc directory: " << psaDcDir;
qInfo() << "using psa repo root directory: " << psaRepoRootDir;
qInfo() << " using customer repository: " << psaRepoDir;
qInfo() << " using branch: " << branchName;
settings->beginGroup("PLUGINS");
libca = libDir + settings->value("plugin-name", "libCAslave.so").toString();
settings->endGroup();
}
// etc/dc: located under mount-path
std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir);
QFileInfo fi;
if (mountPath.has_value()) {
// usbDetected = true;
// mountPath/etc/dc must exists !
// cannot override with commandline parameter --dc-directory
if (debug) {
qInfo() << "using mount path (USB): " << mountPath.value();
}
fi.setFile(mountPath.value(), System::getDCFileOnUsbStick(mountPath.value()));
} else
if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) {
// sdCardDetected = true;
// mountPath/etc/dc must exists !
// cannot override with commandline parameter --dc-directory
if (debug) {
qInfo() << "using mount path (SD): " << mountPath.value();
}
fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value()));
} else {
rootDir = "";
mountPath = QDir::cleanPath(psaRepoRootDir + QDir::separator() + psaDcDir);
if (debug) {
qInfo() << "using as dc-directory" << mountPath.value();
}
}
if (debug) {
qInfo() << "using as mount path: " << mountPath.value();
qInfo() << "using customer repository" << psaRepoDir;
}
std::unique_ptr<QString> c = internal::dcCandidateToInstall(rootDir, mountPath.value());
std::unique_ptr<QString> c = internal::dcCandidateToInstall("/etc/dc/");
if (c) {
fi.setFile(*c);
if (fi.exists() == false) {
@@ -211,6 +185,7 @@ int main(int argc, char **argv) {
}
qInfo() << "dc2c.bin canditate" << fi.absoluteFilePath();
}
}
if (debug) {
qInfo() << "downloading dc-firmware" << fi.absoluteFilePath();
@@ -218,9 +193,6 @@ int main(int argc, char **argv) {
qInfo() << "dc-version" << Update::dcVersion(fi.absoluteFilePath());
}
// only for testing
// return 0;
Update u(fi.absoluteFilePath(), libca, debug, noaction);
u.run();

View File

@@ -1,5 +1,5 @@
#include "update.h"
#include "process/command.h"
#include "command.h"
#include <QCoreApplication>
#include <QFile>

View File

@@ -1,7 +1,9 @@
QT += core
QT += serialport network
TARGET = ATBUpdateJsonFiles
include(../common.pri)
TARGET = ATBDownloadDCJsonFiles
VERSION="0.1.0"
win32 {
@@ -79,13 +81,13 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \
main.cpp \
../UpdatePTUDevCtrl/message_handler.cpp \
../common/src/commandline_parser.cpp \
../UpdatePTUDevCtrl/commandline_parser.cpp \
update.cpp \
../common/src/System.cpp
HEADERS += \
../UpdatePTUDevCtrl/message_handler.h \
../common/include/commandline_parser.h \
../UpdatePTUDevCtrl/commandline_parser.h \
update.h \
../common/include/System.h

View File

@@ -79,7 +79,6 @@ int main(int argc, char **argv) {
bool const showExtendedVersion = parser.extendedVersion();
bool const alwaysDownloadConfig = parser.alwaysDownloadConfig();
bool const alwaysDownloadDC = parser.alwaysDownloadDC();
Update::setPPid(parser.ppid());
QString const rtPath = QCoreApplication::applicationDirPath();
@@ -89,7 +88,6 @@ int main(int argc, char **argv) {
QString const branchName = (zoneNr != 0)
? QString("zg1/zone%1").arg(zoneNr) : "master";
if (Update::ppid() == -1) {
qInfo() << "pwd ......................" << rtPath;
qInfo() << "repositoryUrl ............" << repositoryUrl;
qInfo() << "plugInDir ................" << plugInDir;
@@ -109,13 +107,11 @@ int main(int argc, char **argv) {
qInfo() << "machineNr ................" << machineNr;
qInfo() << "customerNr ..............." << customerNr;
qInfo() << "zoneNr ..................." << zoneNr;
qInfo() << "parent pid ..............." << Update::ppid();
if (showExtendedVersion) {
printf(APP_EXTENDED_VERSION"\n");
return 0;
}
}
QString const &customerRepo = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
QStringList filesToUpdate;
@@ -125,10 +121,7 @@ int main(int argc, char **argv) {
if (mountPath.has_value()) {
filesToUpdate = System::getJsonFilesOnUsbStick(mountPath.value());
} else {
if (Update::ppid() == -1) {
qCritical() << "Using customer repository" << customerRepo;
}
QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/psa_config"));
if (dir.exists()) {
@@ -144,7 +137,7 @@ int main(int argc, char **argv) {
}
}
qCritical() << __LINE__ << "JSON FILES TO UPDATE" << filesToUpdate;
// qCritical() << "JSON FILES TO UPDATE" << filesToUpdate;
Update update(customerRepo,
QString::number(customerNr),
@@ -153,18 +146,13 @@ int main(int argc, char **argv) {
plugInName,
workingDir);
if (!filesToUpdate.empty()) {
update.doUpdate(filesToUpdate, mountPath.has_value());
}
// update.checkJsonVersions();
update.checkJsonVersions();
//update.checkJsonVersions(filesToUpdate);
if (mountPath.has_value()) {
System::umountUSBStick();
}
qInfo() << "<JS-UPDATE-FINISH>";
return 0;
}

View File

@@ -21,13 +21,10 @@
#include <QDateTime>
#include <QPluginLoader>
#include <QMap>
#include <cmath>
#define UPDATE_OPKG (1)
#define UPDATE_DC (0)
qint64 Update::c_ppid = -1;
static const QMap<QString, int> baudrateMap = {
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
{"57600" , 4}, {"115200" , 5}
@@ -118,9 +115,6 @@ Update::Update(QString customerRepository,
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
m_start = QDateTime::currentDateTime();
if (Update::ppid() == -1) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
} else {
@@ -138,49 +132,12 @@ Update::Update(QString customerRepository,
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_sys_areDCDataValid ..."
<< m_sys_areDCdataValid;
}
}
}
Update::~Update() {
// unloadDCPlugin();
unloadDCPlugin();
}
#if 0
bool Update::doUpdate() { // test function
int numberOfFiles = 3;
QString s = nextTimePoint();
s += " sending ";
s += QString("%1 ...done <JS-PROGRESS>").arg("DC2C_cash.json");
s += QString::number(ceil(((1 * 100.0) / (double)numberOfFiles)));
qInfo() << s.toUtf8().constData();
QThread::msleep(2000);
s = nextTimePoint();
s += " sending ";
s += QString("%1 ...done <JS-PROGRESS>").arg("DC2C_device.json");
s += QString::number(ceil(((2 * 100.0) / (double)numberOfFiles)));
qInfo() << s.toUtf8().constData();
QThread::msleep(2000);
s = nextTimePoint();
s += " sending ";
s += QString("%1 ...done <JS-PROGRESS>").arg("DC2C_print01.json");
s += QString::number(ceil(((3 * 100.0) / (double)numberOfFiles)));
qInfo() << s.toUtf8().constData();
QThread::msleep(2000);
return true;
}
#endif
bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {
if (!m_hw) {

View File

@@ -8,7 +8,6 @@
#include <QByteArray>
#include <QProcess>
#include <QPluginLoader>
#include <QDateTime>
#include <initializer_list>
@@ -37,14 +36,6 @@ class Update : public QObject {
static QPluginLoader pluginLoader;
QDateTime m_start;
QString nextTimePoint() const {
float const secs = m_start.msecsTo(QDateTime::currentDateTime()) / 1000.0;
return QStringLiteral("+%1s").arg(secs, 7, 'f', 2, QChar('0'));
}
static qint64 c_ppid;
public:
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
@@ -53,8 +44,6 @@ public:
static bool unloadDCPlugin();
static QStringList split(QString line, QChar sep = ',');
static qint64 ppid() { return c_ppid; }
static void setPPid(qint64 ppid) { c_ppid = ppid; }
explicit Update(QString customerRepository,
QString customerNrStr,
@@ -70,7 +59,6 @@ public:
virtual ~Update() override;
bool doUpdate(QStringList const &jsonFilesToDownload, bool usbStickDetected = false);
bool doUpdate();
bool updatePrinterTemplate(int templateIdx, QString fname) const;
bool updateConfig(QString jsFileToSendToDC);

2970
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -1,87 +0,0 @@
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
}

View File

@@ -1,105 +0,0 @@
#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);
}

View File

@@ -1,30 +0,0 @@
#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

View File

@@ -1,170 +0,0 @@
#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;
}

View File

@@ -1,97 +0,0 @@
#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

View File

@@ -1,23 +0,0 @@
#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

View File

@@ -1,85 +0,0 @@
QT += core
TARGET = ATBUpdateOpkg
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_}/../UpdatePTUDevCtrl \
$${_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 \
opkg_command.cpp
HEADERS += \
message_handler.h \
../common/include/utils_internal.h \
../common/include/command.h \
opkg_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
}

View File

@@ -1,69 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#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;
}

View File

@@ -1,97 +0,0 @@
#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

View File

@@ -1,23 +0,0 @@
#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

View File

@@ -1,176 +0,0 @@
#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;
}

View File

@@ -1,29 +0,0 @@
#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

View File

@@ -1,68 +0,0 @@
QT += core
TARGET = ATBUpdateShow
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/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
# HEADERS += \

View File

@@ -1,14 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
int main(int argc, char **argv) {
return 0;
}

View File

@@ -1,87 +0,0 @@
QT += core
TARGET = ATBUpdateSync
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_}/../UpdatePTUDevCtrl \
$${_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 \
sync_command.cpp
HEADERS += \
message_handler.h \
../common/include/utils_internal.h \
../common/include/command.h \
sync_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
}

View File

@@ -1,94 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include "message_handler.h"
#include "utils_internal.h"
#include "sync_command.h"
int main(int argc, char **argv) {
QByteArray const value = qgetenv("LC_ALL");
if (value.isEmpty() || value != "C") {
qputenv("LC_ALL", "C");
}
openlog("ATB-UPDATE-SYNC", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
QCoreApplication a(argc, argv);
QCoreApplication::setApplicationName("ATBUpdateSync");
QCoreApplication::setApplicationVersion(APP_VERSION);
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;
}

View File

@@ -1,97 +0,0 @@
#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

View File

@@ -1,23 +0,0 @@
#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

View File

@@ -1,21 +0,0 @@
#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();
}

View File

@@ -1,14 +0,0 @@
#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

View File

@@ -1,6 +1,8 @@
QT += core gui
QT += widgets serialport network
include(../common.pri)
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ATBUpdateTool
@@ -147,8 +149,13 @@ 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.
# 2.0.0 : Rewrite of UpdateTool.
VERSION="2.0.0"
# 1.5.7 : Add support for dynamic portrait / landscape.
# 1.5.8 : Use EVENT_ID=<pid of update-tool> for CMD_EVENT.
# 1.5.9 : Removed restart of Apism if ISMAS unreachable.
# 1.5.99 : Special version for 281/Szeged: remove all DC-library dependencies, as
# DC-firmware in Szeged does not support uploading json-files or uploading
# DC-firmware binaries.
VERSION="1.5.99"
# 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
@@ -217,10 +224,7 @@ GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
# INCLUDEPATH += plugins
INCLUDEPATH += plugins \
$${_PRO_FILE_PWD_}/../common/ \
$${_PRO_FILE_PWD_}/../common/include
INCLUDEPATH += plugins
CONFIG += c++17
# CONFIG -= app_bundle
@@ -257,9 +261,6 @@ contains( CONFIG, PTU5_YOCTO ) {
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5
DEFINES+=PTU5
LIBS += -lCAslave
LIBS += -lCAmaster
}
contains( CONFIG, DesktopLinux ) {
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
@@ -283,24 +284,9 @@ SOURCES += \
git/git_client.cpp \
ismas/ismas_client.cpp \
process/command.cpp \
process/update_command.cpp \
process/update_json_command.cpp \
process/update_filesystem_command.cpp \
process/update_dc_command.cpp \
process/check_ismas_connectivity_command.cpp \
process/check_update_activation_command.cpp \
process/check_and_fetch_customer_repository_command.cpp \
process/exec_opkg_command.cpp \
process/show_software_status_command.cpp \
message_handler.cpp \
worker.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
commandline_parser.cpp
HEADERS += \
update.h \
@@ -312,26 +298,9 @@ HEADERS += \
apism/ismas_data.h \
ismas/ismas_client.h \
process/command.h \
process/update_command.h \
process/update_json_command.h \
process/update_filesystem_command.h \
process/update_dc_command.h \
process/check_ismas_connectivity_command.h \
process/check_update_activation_command.h \
process/check_and_fetch_customer_repository_command.h \
process/exec_opkg_command.h \
process/show_software_status_command.h \
message_handler.h \
worker.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
commandline_parser.h
OTHER_FILES += \
ATBUpdateTool.ini

View File

@@ -6,7 +6,7 @@
#include <QFile>
CommandLineParser::CommandLineParser()
: m_repositoryUrl("gitea@ptu-config.atb-comm.de:ATB")
: m_repositoryUrl("https://git.mimbach49.de/GerhardHoffmann")
, m_plugInDir("/usr/lib/")
, m_plugInName("libCAslave.so")
, m_workingDir("/opt/app/tools/atbupdate/")
@@ -95,18 +95,7 @@ CommandLineParser::CommandLineParser()
QCommandLineOption(
QStringList() << "D" << "read-dc-version",
QCoreApplication::translate("main", "Show version of device controller."),
QCoreApplication::translate("main", "Show version of device controller.")))
, m_setPPid(
QCommandLineOption(
QStringList() << "P" << "set-ppid",
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."))) {
QCoreApplication::translate("main", "Show version of device controller."))) {
configure();
}
@@ -115,7 +104,7 @@ void CommandLineParser::configure() {
m_parser.addHelpOption();
m_parser.addVersionOption();
m_repositoryUrlOption.setDefaultValue("https://ptu-config.atb-comm.de/ATB/");
m_repositoryUrlOption.setDefaultValue("https://git.mimbach49.de/GerhardHoffmann");
m_parser.addOption(m_repositoryUrlOption);
m_iniFileDirectoryOption.setDefaultValue(QCoreApplication::applicationDirPath());
@@ -165,12 +154,6 @@ void CommandLineParser::configure() {
m_readDCVersionOption.setDefaultValue("false");
m_parser.addOption(m_readDCVersionOption);
m_setPPid.setDefaultValue("-1");
m_parser.addOption(m_setPPid);
m_debugOption.setDefaultValue("false");
m_parser.addOption(m_debugOption);
}
void CommandLineParser::readSettings() {
@@ -188,7 +171,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")) {
@@ -235,9 +218,6 @@ 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();
@@ -299,13 +279,6 @@ 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);
@@ -313,19 +286,6 @@ QString CommandLineParser::workingDir() {
return m_workingDir;
}
qint64 CommandLineParser::ppid() {
m_ppid = -1;
if (m_parser.isSet(m_setPPid)) {
QString p = m_parser.value(m_setPPid);
bool ok;
qint64 q = p.toLongLong(&ok);
if (ok) {
m_ppid = q;
}
}
return m_ppid;
}
bool CommandLineParser::dryRun() {
if (m_parser.isSet(m_dryRunOption)) {
m_dryRun = m_parser.value(m_dryRunOption);

View File

@@ -23,8 +23,6 @@ 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;
QCommandLineOption m_iniFileDirectoryOption;
@@ -43,8 +41,6 @@ class CommandLineParser : public QCommandLineParser {
QCommandLineOption m_yoctoInstallStatusOption;
QCommandLineOption m_dcDirectoryOption;
QCommandLineOption m_readDCVersionOption;
QCommandLineOption m_setPPid;
QCommandLineOption m_debugOption;
QCommandLineParser m_parser;
@@ -58,9 +54,6 @@ 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();
@@ -70,7 +63,6 @@ public:
QString psaConfigDir();
QString psaTariffDir();
bool dryRun();
qint64 ppid();
bool noUpdatePsaHardware();
bool yoctoVersion();
bool yoctoInstallStatus();
@@ -79,6 +71,5 @@ public:
bool alwaysDownloadDC();
bool readDCVersion();
QString dcDir();
bool debug();
};
#endif // COMMAND_LINE_PARSER_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,6 @@
#include <QThread>
#include <QtWidgets>
#include <QScopedPointer>
#include <QScreen>
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
#include <unistd.h>
@@ -49,36 +48,6 @@
#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");
@@ -118,13 +87,11 @@ int main(int argc, char *argv[]) {
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;
@@ -234,8 +201,7 @@ int main(int argc, char *argv[]) {
mw.showFullScreen();
// test
//worker.jsUpdate();
worker.workList().exec();
worker.dcUpdate();
// worker.summary();
return a.exec();

View File

@@ -2,11 +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"
#include <DeviceController/interfaces.h>
#include <QDateTime>
@@ -17,88 +14,20 @@
#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)
#include <QScreen>
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(60)
, m_width(70)
, m_progressRunning(false)
, m_updateStep(UpdateDcEvent::UpdateStep::NONE)
, m_updateLog("/opt/app/tools/atbupdate/update.log") { // TODO: in ini-file eintragen
, m_updateStep(UpdateDcEvent::UpdateStep::NONE) {
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 += "&nbsp;";
}
m_updateSteps[i] = tmp;
text += m_updateSteps[i];
}
ui->stepLabel->setTextFormat(Qt::RichText);
ui->stepLabel->setText(text);
checkOrientation();
this->setStatusBar(new QStatusBar(this));
QFont f;
@@ -118,7 +47,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 ").arg(m_worker->zoneNr()).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("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3);
lst << QString("").leftJustified(m_width-3, '=');
@@ -154,30 +83,10 @@ 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)));
connect(m_worker, SIGNAL(showJsonDownload(QString)),this,SLOT(onShowJsonDownload(QString)));
connect(m_worker, SIGNAL(showTariffUpdate(QString)),this,SLOT(onShowTariffUpdate(QString)));
// deprecated
connect(m_worker, SIGNAL(showISMASChecks(QString)),this,SLOT(onShowISMASChecks(QString)));
connect(m_worker, SIGNAL(showISMASConnectivity(QString)),this,SLOT(onShowISMASConnectivity(QString)));
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)));
connect(m_worker, SIGNAL(setDcDownloadProgress(int)),this,SLOT(onSetDcDownloadProgress(int)));
connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit()));
connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer()));
@@ -192,98 +101,14 @@ 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");
ui->updateLabel->setText(s);
ui->updateLabel->hide();
ui->stepLabel->hide();
ui->updateProgress->hide();
s += text;
ui->updateStatus->setText(s);
@@ -293,356 +118,10 @@ void MainWindow::onSetDcDownloadProgress(int v) {
ui->updateProgress->setValue(v);
}
void MainWindow::onShowTariffUpdate(QString) {
return;
ui->exit->setEnabled(false);
QString s = ui->stepLabel->text();
QString tmp("Install tariff files ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
ui->stepLabel->setText(s);
}
void MainWindow::onShowISMASConnectivity(QString status) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString stepResult;
QString s = m_updateSteps[CHECK_BACKEND_CONNECTION].trimmed();
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Green'>connected</font>";
stepResult = "ISMAS connected";
} else {
s += " <font color='Green'>connected&nbsp;(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 += " <font color='Green'>connecting</font>";
stepResult = "connecting ISMAS";
} else
if (status.contains(UpdateCommand::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Red'>NOT CONNECTED. STOP</font>";
stepResult = "ISMAS not connected";
} else {
s += " <font color='Red'>not connected.&nbsp;(initial configuration)</font>";
stepResult = "ISMAS not connected (initial configuration)";
}
} else {
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;
QString s = m_updateSteps[UPDATE_CUSTOMER_REPOSITORY].trimmed();
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 += " <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();
QString tmp = "execute opkg commands ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(UpdateCommand::EXEC_OPKG_COMMANDS_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);
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowExecOpkgCommand(QString cmd) {
qCritical() << __func__ << ":" << __LINE__ << "cmd" << cmd;
return;
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 += " <font color='Green'>success</font>";
} else {
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;
QString s = m_updateSteps[SYNCHRONIZE_REPOSITORY].trimmed();
if (status.contains(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else {
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;
QString s = m_updateSteps[UPDATE_DC].trimmed();
if (status.contains(internal::UPDATE_DC_FIRMARE_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
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);
}
void MainWindow::onShowUpdateRequest(QString status) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
//ui->updateProgress->setValue(CHECK_UPDATE_REQUEST_PERCENT_START);
QString s = m_updateSteps[CHECK_UPDATE_REQUEST].trimmed();
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::UPDATE_NOT_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Red'>NOT REQUESTED. STOP.</font>";
} else {
s += " <font color='Blue'>not requested&nbsp;(initial configuration)</font>";
}
} else
if (status.contains(internal::UPDATE_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Green'>requested</font>";
} else {
s += " <font color='Blue'>requested&nbsp;(initial configuration)</font>";
}
} else
if (status.contains(internal::UPDATE_INITIAL, Qt::CaseInsensitive)) {
s += " <font color='Green'>requested&nbsp;(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 += " <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();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
tmp = "Check update activation ";
len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
ui->stepLabel->setText(s);
}
void MainWindow::onShowJsonDownload(QString) {
ui->exit->setEnabled(false);
QString s = ui->stepLabel->text();
QString tmp("Send json files to dc-hardware ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
ui->stepLabel->setText(s);
}
void MainWindow::onShowDcDownload(QString version) {
return;
m_targetDcVersion = version;
ui->exit->setEnabled(false);
// test
// onShowISMASChecks("");
onShowISMASConnectivity("connected");
onShowUpdateRequest("activated");
onShowTariffUpdate("");
onShowJsonDownload("");
QString s = ui->stepLabel->text();
QString tmp("Send dc-firmware to dc-hardware ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='#33FF50'>[OK ]</font> (%2)").arg(tmp).arg(version);
ui->stepLabel->setText(s);
ui->stepLabel->setText(QString("Device controller update. Target version: %1").arg(version).leftJustified(m_width-3));
}
MainWindow::~MainWindow() {
@@ -652,6 +131,56 @@ MainWindow::~MainWindow() {
delete ui;
}
// ----------------------------- Ui::LAYOUT setting -------------------------------------
void MainWindow::checkOrientation()
{
QScreen *screen = QGuiApplication::primaryScreen();
Qt::ScreenOrientation orientation = screen->orientation();
switch (orientation) {
case Qt::PrimaryOrientation:
this->setLandscapeLayout();
break;
case Qt::LandscapeOrientation:
this->setLandscapeLayout();
break;
case Qt::PortraitOrientation:
this->setPortraitLayout();
break;
case Qt::InvertedLandscapeOrientation:
this->setLandscapeLayout();
break;
case Qt::InvertedPortraitOrientation:
this->setPortraitLayout();
break;
}
this->currentOrientation = orientation;
}
void MainWindow::setPortraitLayout()
{
// Adjust layout for portrait mode (480x800)
this->setFixedSize(480, 800);
ui->centralwidget->setFixedSize(480, 800);
}
void MainWindow::setLandscapeLayout()
{
// Adjust layout for landscape mode (800x480)
this->setFixedSize(800, 480);
ui->centralwidget->setFixedSize(800, 480);
}
void MainWindow::customEvent(QEvent *event) {
if (event->type() == ProgressEvent::type()) {
ProgressEvent *pevent = (ProgressEvent *)event;

View File

@@ -4,9 +4,6 @@
#include <QMainWindow>
#include <QTimer>
#include <QStatusBar>
#include <QVector>
#include <QString>
#include <QProgressBar>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
@@ -40,7 +37,6 @@ public:
void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; }
QString targetDcVersion() {return m_targetDcVersion; }
QProgressBar *progressBar();
public slots:
void onAppendText(QString, QString suffix = "");
@@ -56,22 +52,8 @@ public slots:
void onEnableExit();
void onDisableExit();
void onShowDcDownload(QString);
void onShowJsonDownload(QString);
void onShowTariffUpdate(QString);
void onShowISMASChecks(QString);
void onShowISMASConnectivity(QString);
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
@@ -86,13 +68,16 @@ private slots:
void onQuit();
private:
int const m_showLineLength = 37;
void scrollDownTextEdit();
void onShowMessage(QString, QString);
Ui::MainWindow *ui;
void checkOrientation();
void setPortraitLayout();
void setLandscapeLayout();
Qt::ScreenOrientation currentOrientation;
Worker *m_worker;
int const m_width;
QTimer *m_startTimer;
@@ -102,10 +87,5 @@ private:
UpdateDcEvent::UpdateStep m_updateStep;
QTimer *m_statusTimer;
QString m_targetDcVersion;
int m_stepLabelChopCount{};
QVector<QString> m_updateSteps{};
QFile m_updateLog;
};
#endif // MAINWINDOW_H

View File

@@ -10,6 +10,12 @@
<height>480</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>480</height>
</size>
</property>
<property name="font">
<font>
<family>Misc Fixed</family>
@@ -51,9 +57,6 @@
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">

View File

@@ -1,63 +0,0 @@
#include "process/check_and_fetch_customer_repository_command.h"
#include "worker.h"
#include "utils_internal.h"
CheckAndFetchCustomerRepositoryCommand::CheckAndFetchCustomerRepositoryCommand(
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) {
Worker *w = worker();
if (w) {
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);
// }
//}
}

View File

@@ -1,19 +0,0 @@
#ifndef CHECK_AND_FETCH_CUSTOMER_REPOSITORY_COMMAND_H_INCLUDED
#define CHECK_AND_FETCH_CUSTOMER_REPOSITORY_COMMAND_H_INCLUDED
#include "update_command.h"
class CheckAndFetchCustomerRepositoryCommand : public UpdateCommand {
public:
explicit CheckAndFetchCustomerRepositoryCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
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

View File

@@ -1,38 +0,0 @@
#include "process/check_ismas_connectivity_command.h"
#include "worker.h"
#include <QDebug>
CheckIsmasConnectivityCommand::CheckIsmasConnectivityCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int 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) {
Worker *w = worker();
if (w) {
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);
}
}
}
}

View File

@@ -1,18 +0,0 @@
#ifndef CHECK_ISMAS_CONNECTIVITY_COMMAND_H_INCLUDED
#define CHECK_ISMAS_CONNECTIVITY_COMMAND_H_INCLUDED
#include "update_command.h"
class CheckIsmasConnectivityCommand : public UpdateCommand {
public:
explicit CheckIsmasConnectivityCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // CHECK_ISMAS_CONNECTIVITY_COMMAND_H_INCLUDED

View File

@@ -1,43 +0,0 @@
#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, 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) {
Worker *w = worker();
if (w) {
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);
}
}
}
}

View File

@@ -1,18 +0,0 @@
#ifndef CHECK_UPDATE_ACTIVATION_COMMAND_H_INCLUDED
#define CHECK_UPDATE_ACTIVATION_COMMAND_H_INCLUDED
#include "update_command.h"
class CheckUpdateActivationCommand : public UpdateCommand {
public:
explicit CheckUpdateActivationCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // CHECK_UPDATE_ACTIVATION_COMMAND_H_INCLUDED

View File

@@ -37,9 +37,6 @@ void Command::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
// qCritical() << __func__ << ":" << __LINE__ << s;
if (m_worker) {
int i = -1;
if ((i = s.indexOf("<DC-VERSION>")) != -1) {
@@ -50,35 +47,26 @@ 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) {
if ((i = s.indexOf("<PROGRESS>")) != -1) {
bool ok;
int v = s.mid(i+13).trimmed().toInt(&ok);
int v = s.mid(i+10).trimmed().toInt(&ok);
if (ok) {
emit m_worker->setDcDownloadProgress(v);
emit m_worker->insertText(s.mid(0,i) + "\n");
}
} else
if ((i = s.indexOf("<DC-UPDATE-FINISH>")) != -1) {
emit m_worker->summary();
m_worker->summary();
// qApp->exit(0);
} else
if ((i = s.indexOf("<DC-UPDATE-SUCCESS>")) != -1) {
// TODO
emit m_worker->summary();
m_worker->summary();
} else
if ((i = s.indexOf("<DC-UPDATE-FAILURE>")) != -1) {
emit m_worker->summary();
m_worker->summary();
//qApp->exit(-1);
} else
if ((i = s.indexOf("<JS-PROGRESS>")) != -1) {
bool ok;
int v = s.mid(i+13).trimmed().toInt(&ok);
if (ok) {
emit m_worker->setDcDownloadProgress(v);
emit m_worker->insertText(s.mid(0,i) + "\n");
}
} else {
emit m_worker->insertText(s);
}
@@ -95,7 +83,6 @@ void Command::readyReadStandardError() {
}
}
// TODO: nach UpdateCommands ziehen
void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
QProcess *p = (QProcess *)sender();
// read all remaining data sent to the process, just in case
@@ -106,14 +93,8 @@ void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
}
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
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();
//}
}
// TODO: nach UpdateCommand ziehen
bool Command::start(QString workingDirectory, QStringList args) {
if (!QDir::setCurrent(workingDirectory)) {
qCritical() << "SET WORKING_DIRECTORY" << workingDirectory
@@ -123,16 +104,12 @@ bool Command::start(QString workingDirectory, QStringList args) {
if (m_p != nullptr) {
delete m_p;
}
qCritical() << "COMMAND" << m_command << workingDirectory << args;
m_p = new QProcess(this);
m_p->setWorkingDirectory(workingDirectory);
m_p->setProcessChannelMode(QProcess::MergedChannels);
connect(m_p, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
connect(m_p, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
connect(m_p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
if (!args.isEmpty()) {
m_p->start(m_command, args);

View File

@@ -1,5 +1,6 @@
#ifndef COMMAND_H_INCLUDED
#define COMMAND_H_INCLUDED
#endif // COMMAND_H_INCLUDED
#include <QObject>
#include <QCoreApplication>
@@ -12,24 +13,14 @@ class Worker;
class Command : public QObject {
Q_OBJECT
protected:
QString m_command;
mutable QString m_commandResult;
private:
int m_waitForStartTimeout;
int m_waitForFinishTimeout;
int m_exitCode;
protected:
mutable QMutex m_mtx;
private:
QProcess *m_p;
protected:
Worker *m_worker;
public:
explicit Command(QString const &command,
int start_timeout = 100000,
@@ -43,13 +34,9 @@ public:
int exitCode() const { return m_exitCode; }
void setWorker(Worker *worker) {m_worker = worker; }
Worker const *worker() const { return m_worker; }
Worker *worker() { return m_worker; }
protected slots:
virtual void readyReadStandardOutput();
virtual void readyReadStandardError();
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus);
private slots:
void readyReadStandardOutput();
void readyReadStandardError();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
};
#endif // COMMAND_H_INCLUDED

View File

@@ -1,85 +0,0 @@
#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, 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) {
Worker *w = worker();
if (w) {
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);
}
}
}
}
}
}
}

View File

@@ -1,24 +0,0 @@
#ifndef EXEC_OPKG_COMMAND_H_INCLUDED
#define EXEC_OPKG_COMMAND_H_INCLUDED
#include "update_command.h"
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);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // EXEC_OPKG_COMMAND_H_INCLUDED

View File

@@ -1,29 +0,0 @@
#include "process/show_software_status_command.h"
#include "worker.h"
ShowSoftwareStatusCommand::ShowSoftwareStatusCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int 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() {
//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);
// }
//}
}

View File

@@ -1,17 +0,0 @@
#ifndef SHOW_SOFTWARE_STATUS_COMMAND_H_INCLUDED
#define SHOW_SOFTWARE_STATUS_COMMAND_H_INCLUDED
#include "update_command.h"
class ShowSoftwareStatusCommand : public UpdateCommand {
public:
explicit ShowSoftwareStatusCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // SHOW_SOFTWARE_STATUS_COMMAND_H_INCLUDED

View File

@@ -1,141 +0,0 @@
#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)
, m_nextCommandIndex(nextCommandIndex) {
setWorker(worker);
}
bool UpdateCommand::stopUpdateOnFailure() {
return true;
}
void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
QProcess *p = qobject_cast<QProcess *>(sender());
if (p) {
// read all remaining data sent to the process, just in case
QString s = p->readAllStandardOutput().trimmed();
if (!s.isEmpty()) {
m_commandResult += s;
}
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
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_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");
}
}

View File

@@ -1,38 +0,0 @@
#ifndef UPDATE_COMMAND_H_INCLUDED
#define UPDATE_COMMAND_H_INCLUDED
#include "process/command.h"
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"};
static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
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"};
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();
public slots:
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // UPDATE_COMMAND_H_INCLUDED

View File

@@ -1,65 +0,0 @@
#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, 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) {
Worker *w = worker();
if (w) {
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;
}
}
}

View File

@@ -1,18 +0,0 @@
#ifndef UPDATE_DC_COMMAND_H_INCLUDED
#define UPDATE_DC_COMMAND_H_INCLUDED
#include "update_command.h"
class UpdateDCCommand : public UpdateCommand {
public:
explicit UpdateDCCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
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

View File

@@ -1,28 +0,0 @@
#include "process/update_filesystem_command.h"
#include "worker.h"
UpdateFileSystemCommand::UpdateFileSystemCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int 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() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
// TODO
Worker *w = worker();
if (w) {
// static constexpr const char *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
emit w->showSyncCustRepoStatus(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_SUCCESS);
}
}
}

View File

@@ -1,18 +0,0 @@
#ifndef UPDATE_FS_COMMAND_H_INCLUDED
#define UPDATE_FS_COMMAND_H_INCLUDED
#include "update_command.h"
class UpdateFileSystemCommand : public UpdateCommand {
public:
explicit UpdateFileSystemCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // UPDATE_FS_COMMAND_H_INCLUDED

View File

@@ -1,29 +0,0 @@
#include "process/update_json_command.h"
#include "worker.h"
#include <QDebug>
UpdateJsonCommand::UpdateJsonCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int 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() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
// qCritical() << __func__ << ":" << __LINE__ << s;
// static constexpr const char *UPDATE_DC_JSON_FILES_SUCCESS{"success"};
emit m_worker->showDownloadDCJsonFilesStatus(UpdateCommand::UPDATE_DC_JSON_FILES_SUCCESS);
}
}

View File

@@ -1,18 +0,0 @@
#ifndef UPDATE_JSON_COMMAND_H_INCLUDED
#define UPDATE_JSON_COMMAND_H_INCLUDED
#include "process/update_command.h"
class UpdateJsonCommand : public UpdateCommand {
public:
explicit UpdateJsonCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // UPDATE_JSON_HANDLER_H_INCLUDED

View File

@@ -40,6 +40,7 @@ QPluginLoader Update::pluginLoader;
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
hwinf *hw = nullptr;
#if 0
if (plugInDir.exists()) {
QString pluginLibName(fname);
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
@@ -74,6 +75,7 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
qCritical() << "plugins directory" << plugInDir.absolutePath()
<< "does not exist";
}
#endif
return hw;
}
@@ -105,6 +107,7 @@ Update::Update(Worker *worker,
char const *serialInterface,
char const *baudrate)
: QObject(parent)
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_worker(worker)
, m_serialInterface(serialInterface)
, m_baudrate(baudrate)
@@ -115,6 +118,26 @@ Update::Update(Worker *worker,
, m_workingDir(workingDir)
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
#if 0
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin not loaded";
} else {
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() << "ERROR!!! DC DATA NOT VALID -> CA-MASTER-PLUGIN NOT CONNECTED";
break;
}
m_hw->dc_autoRequest(true);
QThread::msleep(500);
}
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_sys_areDCDataValid ..."
<< m_sys_areDCdataValid;
}
#endif
}
Update::~Update() {
@@ -132,6 +155,43 @@ void Update::onReportDCDownloadFailure(QString const &errorMsg) {
qCritical() << "msg" << errorMsg;
}
// br is a index into a table, used for historical reasons.
bool Update::openSerial(int br, QString baudrate, QString comPort) const {
if (m_hw) {
qDebug() << "opening serial" << br << baudrate << comPort << "...";
if (m_hw->dc_openSerial(br, baudrate, comPort, 1) == true) { // 1 for connect
Utils::printInfoMsg(
QString("OPENING SERIAL %1").arg(br)
+ " " + baudrate + " " + comPort + "...OK");
// m_hw->dc_autoRequest(true);
// m_hw->dc_autoRequest(false);
// QThread::sleep(1);
Utils::printInfoMsg(QString("IS PORT OPEN %1").arg(m_hw->dc_isPortOpen()));
return true;
}
Utils::printCriticalErrorMsg(
QString("OPENING SERIAL %1").arg(br)
+ " " + baudrate + " " + comPort + "...FAILED");
}
return false;
}
void Update::closeSerial() const {
qInfo() << "CLOSED SERIAL" << m_baudrate << m_serialInterface;
if (m_hw) {
m_hw->dc_closeSerial();
}
}
bool Update::isSerialOpen() const {
return m_hw ? m_hw->dc_isPortOpen() : false;
}
/*
///////////////////////////////////////////////////////////////////////////////
@@ -226,13 +286,95 @@ bool Update::updateBinary(QString const &fileToSendToDC) {
qInfo() << "updating dc-binary" << fileToSendToDC << "...";
return false;
#if 0
QFile fn(fileToSendToDC);
if (!fn.exists()) {
// output via CONSOLE() etc
return false;
}
bool bl_isUp = false;
if (m_hw->bl_completeStart()) {
int cnt = 5;
while (--cnt > 0) {
if (m_hw->bl_isUp()) {
bl_isUp = true;
break;
}
}
}
if (!bl_isUp) {
return false;
}
if (!m_hw->bl_storeFirmware(fileToSendToDC)) {
m_hw->bl_stopBL();
return false;
}
uint16_t const nrOfFirmwareBlocks = m_hw->bl_getNrOfFirmwareBlocks();
for (uint16_t blockNr = 0; blockNr <= nrOfFirmwareBlocks; ++blockNr) {
m_hw->bl_blockAutoLoad(blockNr);
int sleepTime = 0;
while (1) {
if (sleepTime > 1500) {
m_hw->bl_stopBL();
return false;
}
int8_t const r = m_hw->bl_blockAutoResponse();
// after every "bl_blockAutoLoad()" call this until response
// retval 0: wait 1: OK, blk was sent 2: OK, transfer complete
// 3: error despite repeating, cancel. probably bin file corrupted
// Max duration: 3x no response from BL = 900ms
switch(r) {
case 1:
/* fall through */
case 2:
sleepTime = 0;
break;
case 0: {
QThread::msleep(100);
sleepTime += 100;
} break;
case 3:
m_hw->bl_stopBL();
return false;
default:
m_hw->bl_stopBL();
return false; // unknown error code
}
}
m_hw->bl_stopBL();
}
return true;
#endif
}
QString Update::jsonType(enum FileTypeJson type) {
switch (type) {
case FileTypeJson::CASH: return "CASH";
case FileTypeJson::CONFIG: return "CONFIG";
case FileTypeJson::PRINTER: return "PRINTER";
case FileTypeJson::SERIAL: return "SERIAL";
case FileTypeJson::DEVICE: return "DEVICE";
case FileTypeJson::TIME: return "TIME";
}
return "N/A";
}
bool Update::downloadJson(enum FileTypeJson type,
int templateIdx,
QString jsFileToSendToDC) const {
#if 0
if (m_hw) {
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
qDebug() << "SET AUTO-REQUEST=TRUE";
@@ -351,7 +493,6 @@ bool Update::downloadJson(enum FileTypeJson type,
// QThread::sleep(1); // make sure the auto-request flag is acknowledged
}
#endif
return true;
}
@@ -410,7 +551,6 @@ void Update::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
}
QStringList Update::getDcSoftAndHardWareVersion() {
#if 0
if (m_hw) {
m_hw->dc_autoRequest(true);
QThread::sleep(1); // make sure the timer-slots are active
@@ -433,17 +573,15 @@ QStringList Update::getDcSoftAndHardWareVersion() {
}
}
#endif
return QStringList() << "DC HW-version not available"
<< "DC SW-version not available";
}
QString Update::getFileVersion(QString const& jsonFileName) {
QString fileVersion("");
#if 0
// "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()) {
@@ -468,11 +606,11 @@ QString Update::getFileVersion(QString const& jsonFileName) {
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
}
#endif
return fileVersion;
}
bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
// note: 2026-02-09: this method is not used!
#if 0
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
@@ -547,7 +685,6 @@ bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
}
}
#endif
return false;
}
@@ -555,7 +692,6 @@ bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
QMap<QString, QString>
Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
QMap<QString, QString> map;
#if 0
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
@@ -662,7 +798,6 @@ Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
#if 0
if (!m_hw) {
Utils::printInfoMsg("CA-PLUGIN NOT LOADED");
return false;
@@ -869,7 +1004,4 @@ bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
qDebug() << "SET AUTO-REQUEST=TRUE";
return res;
#endif
return false;
}

View File

@@ -22,6 +22,7 @@ class Worker;
class Update : public QObject {
Q_OBJECT
hwinf *m_hw = nullptr;
Worker *m_worker = nullptr;
char const *m_serialInterface;
char const *m_baudrate;
@@ -101,6 +102,12 @@ public:
QString("etc/psa_config/DC2C_print31.json"),
QString("etc/psa_config/DC2C_print32.json")})));
hwinf *hw() { return m_hw; }
hwinf const *hw() const { return m_hw; }
//QString customerId() { return m_customerId; }
//QString const customerId() const { return m_customerId; }
QString branchName() { return m_branchName; }
QString const branchName() const { return m_branchName; }

View File

@@ -1,14 +1,12 @@
#include "utils.h"
#include "message_handler.h"
#include "git/git_client.h"
#include "worker.h"
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
#include "unistd.h"
#endif
#include <QObject>
#include <QFile>
#include <QTextStream>
#include <QDebug>
@@ -20,124 +18,12 @@
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonArray>
#include <QStringList>
#include <QDirIterator>
#include <fstream>
QVector<QPair<QString, QString>> Utils::installedJsonFiles(Worker const *worker, QDir const &customerDir) {
QVector<QPair<QString, QString>> vec;
QStringList fileList;
QDirIterator it(QDir::cleanPath(customerDir.absolutePath() + QDir::separator() + "etc/psa_config"));
while (it.hasNext()) {
QFileInfo const fi(it.next());
if (fi.fileName().startsWith("DC2C") && fi.fileName().endsWith(".json")) {
fileList << fi.absoluteFilePath();
}
}
fileList.sort();
QString const &current = QDir::current().absolutePath();
if (!QDir::setCurrent(customerDir.absolutePath())) {
qCritical() << __func__ << ":" << __LINE__ << ": ERROR: can not set"
<< "working directory to" << customerDir.absolutePath();
} else {
for (int i = 0; i < fileList.size(); ++i) {
QProcess p;
// connect(&p, SIGNAL(finished(int,QProcess::ExitStatus)), , SLOT(finished(int,QProcess::ExitStatus)));
QStringList params;
params << "log" << "-n" << "1" << "--pretty=format:%H" << "--" << fileList[i];
//QObject::connect(&p, SIGNAL(readyReadStandardOutput()),
// worker, SLOT(Worker::readyReadStandardOutput()), Qt::DirectConnection);
p.start("git", params);
p.waitForReadyRead();
p.write("exit");
p.waitForFinished();
QString r = p.readAll().left(8);
//QObject::disconnect(&p, SIGNAL(readyReadStandardOutput()), worker, SLOT(Worker::readyReadStandardError()));
qCritical() << QDir::current().absolutePath()
<< "JS git log -n 1 --pretty=format:%H -- " << fileList[i] << r;
vec.push_back(QPair<QString, QString>(QFileInfo(fileList[i]).fileName(), r));
}
if (!QDir::setCurrent(current)) {
qCritical() << __func__ << ":" << __LINE__ << ": ERROR: can not set"
<< "working directory to" << current;
}
}
return vec;
}
QVector<QPair<QString, QString>> Utils::installedTariffFiles(Worker const *worker, QDir const &customerDir) {
QVector<QPair<QString, QString>> vec;
QStringList fileList;
QDirIterator it(QDir::cleanPath(customerDir.absolutePath() + QDir::separator() + "etc/psa_tariff"));
while (it.hasNext()) {
QFileInfo const fi(it.next());
if (fi.fileName().startsWith("tariff") && fi.fileName().endsWith(".json")) {
fileList << fi.absoluteFilePath();
}
}
fileList.sort();
QString const &current = QDir::current().absolutePath();
if (!QDir::setCurrent(customerDir.absolutePath())) {
qCritical() << __func__ << ":" << __LINE__ << ": ERROR: can not set"
<< "working directory to" << customerDir.absolutePath();
} else {
for (int i = 0; i < fileList.size(); ++i) {
QProcess p;
QStringList params;
params << "log" << "-n" << "1" << "--pretty=format:%H" << "--" << fileList[i];
//QObject::connect(&p, SIGNAL(readyReadStandardOutput()),
// worker, SLOT(Worker::readyReadStandardOutput()), Qt::DirectConnection);
p.start("git", params);
p.waitForReadyRead();
p.write("exit");
p.waitForFinished();
QString r = p.readAll().left(8);
// QObject::disconnect(&p, SIGNAL(readyReadStandardOutput()), worker, SLOT(Worker::readyReadStandardError()));
qCritical() << QDir::current().absolutePath()
<< "git log -n 1 --pretty=format:%H -- " << fileList[i] << r;
vec.push_back(QPair<QString, QString>(QFileInfo(fileList[i]).fileName(), r));
}
if (!QDir::setCurrent(current)) {
qCritical() << __func__ << ":" << __LINE__ << ": ERROR: can not set"
<< "working directory to" << current;
}
}
return vec;
}
QVector<QPair<QString, QString>> Utils::installedPackages() {
QVector<QPair<QString, QString>> vec;
if (QFile::exists("/usr/bin/")) {
if (QFile::exists("/usr/bin/ptuPackageVersions")) {
QProcess p;
QStringList params;
params << "-c" << R"(/usr/bin/ptuPackageVersions -i -o json)";
@@ -279,7 +165,7 @@ QString Utils::getTariffInfo(QString fileName) {
}
QString Utils::zoneName(quint8 /* i */) {
QString Utils::zoneName(quint8 i) {
//static constexpr char const *zName[] = {
// "",
// "purple",

View File

@@ -10,9 +10,7 @@
#include <QDir>
#include <QDebug>
#include <QPair>
#include <QProcess>
class Worker;
namespace Utils {
int read1stLineOfFile(QString fileName);
QString getLocation(QString fileName);
@@ -38,10 +36,6 @@ namespace Utils {
bool isATBQTRunning();
QVector<QPair<QString, QString>> installedPackages();
QVector<QPair<QString, QString>> installedJsonFiles(Worker const *worker, QDir const &customerDir);
QVector<QPair<QString, QString>> installedTariffFiles(Worker const *worker, QDir const &customerDir);
void finished(int exitCode, QProcess::ExitStatus exitStatus);
}
#endif // UTILS_H_INCLUDED

View File

@@ -1,37 +0,0 @@
#include "work_process_list.h"
#include "process/update_command.h"
#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();
//}
bool WorkList::nextExec() const {
return m_workListIndex < m_workList.size();
}
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;
}
return false;
}

View File

@@ -1,82 +0,0 @@
#ifndef WORK_LIST_H_INCLUDED
#define WORK_LIST_H_INCLUDED
#include <vector>
#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 {
/**
* @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
// template<typename... Ts>
//typename = typename std::enable_if<std::is_same<typename std::decay<Ts...>::type,
// UpdateCommand>::value>::type>
// WorkList(Ts&&... args)
// : m_workList(std::forward<Ts...>(args...))
// , m_workListIndex(0) {
//}
///**
// * \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

View File

@@ -19,28 +19,14 @@
#include <QScopedPointer>
#include <QRegularExpression>
#include <QJsonArray>
#include <QProgressBar>
#include <memory>
#include "message_handler.h"
#include <DeviceController/interfaces.h>
#include "ismas/ismas_client.h"
#include "progress_event.h"
#include "mainwindow.h"
#include "utils.h" // deprecated
#include "utils_internal.h"
#include "log_line_entry.h"
#include "utils.h"
#include "process/command.h"
#include "process/update_command.h"
#include "process/check_ismas_connectivity_command.h"
#include "process/check_update_activation_command.h"
#include "process/check_and_fetch_customer_repository_command.h"
#include "process/update_json_command.h"
#include "process/update_filesystem_command.h"
#include "process/exec_opkg_command.h"
#include "process/update_dc_command.h"
#include "process/show_software_status_command.h"
QString const Worker::UPDATE_STEP_OK ( " [ ok]");
QString const Worker::UPDATE_STEP_DONE ( " [done]");
@@ -187,118 +173,17 @@ 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_summaryTimer(this)
, m_waitForNewUpdates(this)
, m_filesToUpdate()
, m_updateProcessRunning(true)
, m_mainWindow(nullptr) /* contains plugin */
, m_dcDownloadFirmware(new Command("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true"))
, 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_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
, m_withoutIsmasDirectPort(false) /* useful for testing */ {
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 ATBUpdateCheck --ismas-connected")
QString("/opt/app/tools/atbupdate/ATBUpdateCheck --ismas-connected")
, this, ++next));
// *** 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 ATBUpdateCheck --update-requested")
QString("/opt/app/tools/atbupdate/ATBUpdateCheck --update-requested")
, this, ++next));
// *** 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 ATBUpdateGit")
QString("/opt/app/tools/atbupdate/ATBUpdateGit")
, this, ++next));
// *** 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 ATBUpdateOpkg --noaction")
QString("/opt/app/tools/atbupdate/ATBUpdateOpkg --noaction")
, this, ++next, true));
// *** exec opkg-commands ***
// NOTE: first run the opkg commands with action -> no dry-run
m_workList.push_back(
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 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 ATBUpdateShow")
, this, -1));
// reboot machine
///////////////////////////////////////////////////////////
m_start = QDateTime::currentDateTime();
m_dcDownloadFirmware->setWorker(this);
m_dcDownloadJsonFiles->setWorker(this);
// TODO: turn object into singleton
instance = this;
@@ -327,91 +212,10 @@ 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) {
QProgressBar *progressBar = m_mainWindow->progressBar();
if (progressBar) {
progressBar->setValue(progress);
}
//QApplication::postEvent(m_mainWindow,
// new ProgressEvent(this, progress));
QApplication::postEvent(m_mainWindow,
new ProgressEvent(this, progress));
}
}
@@ -429,6 +233,12 @@ 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()) {
@@ -474,14 +284,13 @@ bool Worker::repairCorruptedRepository() {
return true;
}
#if 0
void Worker::privateUpdate() {
if (!m_mainWindow) {
Utils::printCriticalErrorMsg("m_mainWindow NOT SET");
return;
}
return;
//return;
QString func(__PRETTY_FUNCTION__);
@@ -732,9 +541,10 @@ void Worker::privateUpdate() {
// UPDATE THE PSA USING THE CHANGED FILES
//
////////////////////////////////////////////////////////////////////////////
if ((continueUpdate = downloadFilesToPSAHardware()) == false) {
return;
}
// for 281/Szeged: skip uploading files to DeviceController
//if ((continueUpdate = downloadFilesToPSAHardware()) == false) {
// return;
//}
lst = QStringList(QString("DONE"));
ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_SUCCESS));
@@ -752,7 +562,6 @@ 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
@@ -784,16 +593,6 @@ bool Worker::updateTriggerSet() {
CONSOLE(lst) << UPDATE_STEP::DEBUG;
}
if ((repeat % 8) == 0) {
CONSOLE(QStringList(func) << "RESTART APISM") << UPDATE_STEP::DEBUG;
Command c("systemctl restart apism");
if (c.execute("/tmp")) {
QThread::sleep(20); // give APISM some time to reconnect
QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << "RESTART APISM DONE"));
CONSOLE(lst) << UPDATE_STEP::DEBUG;
}
}
if (std::optional<QString> result
= IsmasClient::sendRequestReceiveResponse(
IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) {
@@ -1703,18 +1502,77 @@ PSAInstalled Worker::getPSAInstalled() {
return psaInstalled;
}
void Worker::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
m_standardOutput = p->readAllStandardOutput();
qCritical() << "ZZZZ" << m_standardOutput;
}
bool Worker::jsUpdate() {
return m_dcDownloadJsonFiles->start("/opt/app/tools/atbupdate");
}
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();
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);
}

View File

@@ -11,18 +11,13 @@
#include <QMap>
#include <QDebug>
#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"
#ifdef PTU5
#define SERIAL_PORT "ttymxc2"
@@ -143,21 +138,7 @@ class Command;
class Update;
class MainWindow;
class hwinf;
/*!
\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 {
class Worker : public QThread{
Q_OBJECT
int const m_customerNr;
@@ -193,7 +174,7 @@ class Worker : public QObject {
QString const m_pluginVersionTcpZvt;
int m_ismasUpdateRequests;
QTimer m_summaryTimer;
QTimer m_waitForNewUpdates;
QStringList m_filesToUpdate;
QStringList m_filesToDownload;
@@ -210,13 +191,9 @@ class Worker : public QObject {
MainWindow *m_mainWindow;
Command *m_dcDownloadFirmware;
Command *m_dcDownloadJsonFiles;
bool m_withoutIsmasDirectPort;
QString m_apismVersion;
WorkList m_workList;
ApismClientForUpdate m_clForUpdate;
bool executeOpkgCommand(QString opkgCommand);
bool cleanUpOpkgCache();
QString getOsVersion() const;
@@ -245,7 +222,6 @@ class Worker : public QObject {
int sendUpdateSucceededAndActivated();
int sendFinalResult();
public:
struct UpdateProcessRunning {
Worker *m_worker;
@@ -406,15 +382,10 @@ 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);
@@ -425,9 +396,6 @@ 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;
@@ -449,29 +417,6 @@ 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,
@@ -497,8 +442,6 @@ 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; }
@@ -517,17 +460,10 @@ public:
Update *update() { return m_update; }
Update const *update() const { return m_update; }
bool jsUpdate();
bool dcUpdate();
void summary();
QDateTime start() { return m_start; }
QByteArray standardOutput() const { return m_standardOutput; }
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);
@@ -542,19 +478,6 @@ signals:
void enableExit();
void disableExit();
void showDcDownload(QString);
void showJsonDownload(QString);
void showTariffUpdate(QString);
void showISMASChecks(QString);
void showISMASConnectivity(QString);
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);
@@ -566,10 +489,6 @@ private slots:
bool syncCustomerRepositoryAndFS();
// bool sendIsmasLastVersionNotification(int progress);
bool saveLogFile();
void onFileChanged(QString const&);
public slots:
void readyReadStandardOutput();
private:
PSAInstalled getPSAInstalled();
@@ -579,10 +498,6 @@ private:
bool execOpkgCommands();
QDateTime m_start;
QByteArray m_standardOutput;
QFileSystemWatcher m_fileWatcher;
QFile m_updateLog;
QFile m_updateLogBackup;
static const QMap<UPDATE_STEP, const char*> smap;
@@ -1684,12 +1599,8 @@ 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");
// 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);

1
common.pri Normal file
View File

@@ -0,0 +1 @@
INCLUDEPATH += $$PWD/common/include

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +0,0 @@
#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

View File

@@ -1,16 +0,0 @@
#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

View File

@@ -51,6 +51,7 @@ namespace internal {
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"};
@@ -85,7 +86,7 @@ namespace internal {
QString branchName();
bool customerRepoExists();
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName = "");
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory, QString const &rootDir = "");
}
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory);
}
#endif // UTILS_INTERNAL_H_INCLUDED
#endif // UTILS_INTERNAL_H_INCLUDED

View File

@@ -1,336 +0,0 @@
#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;
}

View File

@@ -1,99 +0,0 @@
#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

View File

@@ -1,216 +0,0 @@
#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);
}

View File

@@ -1,24 +0,0 @@
#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

View File

@@ -1,564 +0,0 @@
#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;
}

View File

@@ -1,116 +0,0 @@
#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

View File

@@ -1,148 +0,0 @@
#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

View File

@@ -1,55 +0,0 @@
#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

View File

@@ -62,7 +62,7 @@ QString branchName() {
}
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
std::unique_ptr<QSettings> settings;
std::unique_ptr<QSettings> settings{std::make_unique<QSettings>()};
//QString const fileName{settings->applicationName() + ".ini"};
QString const fileName{"ATBUpdateTool.ini"};
@@ -71,17 +71,33 @@ std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
if (!optionalDirName.isEmpty()) {
d = QDir{optionalDirName};
if (d.exists()) { // try to find ini-file under optionalDirname
QFileInfo fi{QDir::cleanPath(optionalDirName + QDir::separator() + fileName)};
QFileInfo fi{d, optionalDirName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
qCritical() << fi.absoluteFilePath() << "not found."
<< "Try" << internal::DEFAULT_INI_DIR;
}
} else {
qCritical().noquote() << optionalDirName << "not found. Try" << internal::DEFAULT_INSTALL_DIR;
qCritical() << optionalDirName << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
}
d = internal::DEFAULT_INI_DIR;
if (d.exists()) { // try to find ini-file under /etc/tools/atbupdate
QFileInfo fi{d, fileName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical() << fi.absoluteFilePath() << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
} else {
qCritical() << internal::DEFAULT_INI_DIR << "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};
@@ -89,64 +105,30 @@ std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
qCritical() << fi.absoluteFilePath() << "not found.";
}
} else {
qCritical().noquote() << internal::DEFAULT_INSTALL_DIR << "not found.";
qCritical() << 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> dcCandidateToInstall(QString const &dcDirectory) {
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());
}
}
qCritical() << __func__ << __LINE__ << dcDirectory;
QDir dcDir{dcDirectory.isEmpty() ? customerRepoDcDir() : dcDirectory};
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);
@@ -177,12 +159,6 @@ std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory,
}
}
}
} 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;

View File

@@ -1,19 +0,0 @@
[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=????