Compare commits

...

61 Commits

Author SHA1 Message Date
39b5551e90 continued... 2025-02-21 13:39:46 +01:00
05974fd8ee started documentation 2025-02-21 13:10:36 +01:00
2189684cad Minor: use constants in internal:: 2025-02-21 12:43:15 +01:00
f4d785ea9d Minor: use namespace internal:: 2025-02-21 12:42:13 +01:00
5bae9fcdf1 Minor: save result in m_commandResult. 2025-02-21 12:41:26 +01:00
eddf67739a Minor: renamed constants with prefix E_ 2025-02-21 12:39:53 +01:00
cb28bd2a1f Minor: added new constants 2025-02-21 12:39:23 +01:00
618430bcc5 Minor: added aux function 2025-02-21 12:38:54 +01:00
037b91b889 Update customer repository instead of Check... 2025-02-21 12:38:28 +01:00
96e3b606ef Use defined codes and strings. 2025-02-21 12:37:00 +01:00
5d3849dcf3 Update not necessary between 0:00 - 4:00. 2025-02-21 12:33:39 +01:00
8c66e03ea3 start docu 2025-02-21 12:32:51 +01:00
43f60251ef finished(): send messages to ISMAS 2025-02-20 16:02:21 +01:00
226dbbd050 Removed direct call to dcUpdate(). 2025-02-20 16:00:37 +01:00
6cd14d6559 Minor: Use macro for directory of .pro file. 2025-02-20 15:57:35 +01:00
4c8c3ed3c0 Minor: changed executable names used internally 2025-02-20 15:57:05 +01:00
7258976528 Add ismas-client object for update 2025-02-20 15:56:06 +01:00
d7a4d98a29 Add new constant for progress in percent. 2025-02-20 15:54:06 +01:00
c339941585 Minor: removed some comments 2025-02-20 14:35:03 +01:00
744ad52c89 Start ATBUpdateSync 2025-02-18 15:25:03 +01:00
87ce6a7d54 Start ATBUpdateSync 2025-02-18 15:24:43 +01:00
b25b66395f Support for ATBUpdateOpkg 2025-02-18 14:56:13 +01:00
de9182bdc9 Call ATBUpdateOpkg 2025-02-18 14:55:17 +01:00
af83c11f73 Changes for ATBUpdateOpkg 2025-02-18 14:54:41 +01:00
7cdefc9b49 add verbose parameter 2025-02-18 14:53:54 +01:00
dd0d7790e0 Add some more constants 2025-02-18 14:53:07 +01:00
b23314a1f3 add verbose parameter 2025-02-18 14:52:41 +01:00
9f1f41e4b6 add signal declarations for opkg 2025-02-18 14:52:16 +01:00
522f86aaac add helper variable for updating steplabel 2025-02-18 14:51:30 +01:00
13259ba86e add new signals for opkg 2025-02-18 14:50:50 +01:00
63a959315b add files for ATBUpdateOpkg 2025-02-18 14:49:52 +01:00
c05db3b323 Set up ATBUpdateOpkg 2025-02-18 14:49:01 +01:00
bc21ede1a1 set up ATBUpdateOpkg 2025-02-18 14:47:43 +01:00
8db818f6cd checkin for saving current state 2025-02-14 13:20:42 +01:00
ef9cc23093 Start with git-directory 2025-02-07 13:44:02 +01:00
3a259f8a22 First version of ATBUpdateCheck 2025-02-07 13:32:15 +01:00
b270a9f30e Update main-window 2025-02-06 16:26:44 +01:00
238f2498b7 provide (dummies) for receiving responses from binaries 2025-02-06 16:25:50 +01:00
44585f2c59 start ATBUpdateCheck 2025-02-06 16:25:09 +01:00
c98b01d002 fix typo 2025-02-05 16:30:48 +01:00
31aa7c0584 add directory for check binary 2025-02-05 16:28:14 +01:00
f750f76dbb renamed 2025-02-05 16:27:30 +01:00
aa88a040ba list of commands to execute 2025-02-05 16:27:09 +01:00
3358e1a0d4 start to refactor update-procedure 2025-02-05 16:26:16 +01:00
ea1d858f15 add headers/sources 2025-02-05 16:25:47 +01:00
7b4bee524f adding commnds to execute 2025-02-05 16:25:01 +01:00
b6f0615e9c directory for binary calling rsync on repository 2025-02-05 16:24:22 +01:00
fbedaab3fe directory for binary displaying status of ptu 2025-02-05 16:23:44 +01:00
8a482e328c directory for binary calling opkg-commands 2025-02-05 16:23:14 +01:00
f67b4bfa6f save for weekend 2025-01-10 14:43:14 +01:00
f1aad81a0c save for weekend 2025-01-10 14:19:43 +01:00
8f822c5383 save files with comment 2025-01-09 15:22:10 +01:00
7bfb7f5a3b save for christmas 2024-12-20 13:01:34 +01:00
2ec7b61682 Remove any reference to device controller as downloading jsons/dc-firmware
will be done by ATBDownloadDCJsonFiles and ATBDownloadDCFirmware binaries.
2024-12-06 12:30:54 +01:00
75b0b83174 Update::updateBinary():
begin with starting "/opt/app/tools/atbupdate/ATBDownloadDCFirmware".
2024-12-06 11:51:06 +01:00
79e2405738 Minor: remove unused code. 2024-12-06 11:50:25 +01:00
0ebf8b095a getCommandResult():
reset result if necessary (for instance for showing current result
	in GUI.
2024-12-06 11:48:21 +01:00
11524b8389 read dc-verion directly from binary file 2024-11-28 12:53:44 +01:00
6663866743 Mior: remove debugs 2024-11-28 12:52:50 +01:00
12aa9a734a init some vars to defaults 2024-11-28 12:52:14 +01:00
9b6f5db8fe start with downloading dc: parsing command arguments. started to implement the acrual download 2024-11-27 15:54:42 +01:00
86 changed files with 6662 additions and 430 deletions

View File

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

82
Check/Check.pro Normal file
View File

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

378
Check/ismas_client.cpp Normal file
View File

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

51
Check/ismas_client.h Normal file
View File

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

163
Check/main.cpp Normal file
View File

@ -0,0 +1,163 @@
#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 <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();
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 it = o.find("Broker");
if (it != o.constEnd()) {
// value for "Broker"
QString const &v = it->toString();
if (v.contains(internal::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
connectionStatus = internal::ISMAS_CONNECTED;
} else
if (v.contains(internal::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
connectionStatus = internal::ISMAS_NOT_CONNECTED;
} else
if (v.contains(internal::ISMAS_DISCONNECTED, Qt::CaseInsensitive)) {
connectionStatus = internal::ISMAS_NOT_CONNECTED;
} else
if (v.contains(internal::ISMAS_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
connectionStatus = internal::ISMAS_NOT_CONNECTED;
} else
if (v.contains(internal::ISMAS_DISCONNECTING, Qt::CaseInsensitive)) {
connectionStatus = internal::ISMAS_NOT_CONNECTED;
}
break;
}
}
}
}
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::NO_CUSTOMER_REPOSITORY;
} 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;
}

97
Check/message_handler.cpp Executable file
View File

@ -0,0 +1,97 @@
#include "message_handler.h"
#include <QDateTime>
#include <cstring>
#include <QString>
#include <QFileInfo>
#include <QMessageLogContext>
static char const *DBG_NAME[] = { "DBG ", "WARN ", "CRIT ", "FATAL", "INFO " };
static bool installedMsgHandler = false;
static int debugLevel = LOG_NOTICE;
int getDebugLevel() { return debugLevel; }
void setDebugLevel(int newDebugLevel) {
debugLevel = newDebugLevel;
}
bool messageHandlerInstalled() {
return installedMsgHandler;
}
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
installedMsgHandler = (handler != 0);
static QtMessageHandler prevHandler = nullptr;
if (handler) {
prevHandler = qInstallMessageHandler(handler);
return prevHandler;
} else {
return qInstallMessageHandler(prevHandler);
}
}
///
/// \brief Print message according to given debug level.
///
/// \note Install this function using qInstallMsgHandler().
///
/// int main(int argc, char **argv) {
/// installMsgHandler(atbDebugOutput);
/// QApplication app(argc, argv);
/// ...
/// return app.exec();
/// }
///
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
Q_UNUSED(context);
QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
switch (debugLevel) {
case LOG_DEBUG: { // debug-level message
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
} break;
case LOG_INFO: { // informational message
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_NOTICE: { // normal, but significant, condition
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_WARNING: { // warning conditions
if (type != QtInfoMsg && type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ERR: { // error conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_CRIT: { // critical conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ALERT: { // action must be taken immediately
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_EMERG: { // system is unusable
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
default: {
//fprintf(stderr, "%s No ErrorLevel defined! %s\n",
// datetime.toStdString().c_str(), msg.toStdString().c_str());
}
}
}
#endif

23
Check/message_handler.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef MESSAGE_HANDLER_H_INCLUDED
#define MESSAGE_HANDLER_H_INCLUDED
#include <QtGlobal>
#ifdef __linux__
#include <syslog.h>
#endif
int getDebugLevel();
void setDebugLevel(int newDebugLevel);
bool messageHandlerInstalled();
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const char *);
void atbDebugOutput(QtMsgType type, const char *msg);
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif
#endif // MESSAGE_HANDLER_H_INCLUDED

View File

@ -52,7 +52,7 @@ int main(int argc, char **argv) {
}
// qputenv("XDG_RUNTIME_DIR", "/var/run/user/0");
openlog("ATB-UPDATE-DC-FIRMWARE", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
openlog("DC", LOG_PERROR | LOG_CONS, LOG_USER);
QApplication a(argc, argv);
QApplication::setApplicationName("ATBDownloadDCFirmware");
@ -73,6 +73,7 @@ int main(int argc, char **argv) {
QString workingDir = parser.workingDir();
QString psaConfigDir = parser.psaConfigDir();
QString psaTariffDir = parser.psaTariffDir();
QString psaDcDir = parser.dcDir();
QString iniFileName = parser.iniFileName();
bool const dryRun = parser.dryRun();
bool const noUpdatePsaHardware = parser.noUpdatePsaHardware();
@ -81,6 +82,7 @@ int main(int argc, char **argv) {
bool const showExtendedVersion = parser.extendedVersion();
bool const alwaysDownloadConfig = parser.alwaysDownloadConfig();
bool const alwaysDownloadDC = parser.alwaysDownloadDC();
bool const readDCVersion = parser.readDCVersion();
QString const rtPath = QCoreApplication::applicationDirPath();
@ -109,27 +111,73 @@ int main(int argc, char **argv) {
qInfo() << "machineNr ................" << machineNr;
qInfo() << "customerNr ..............." << customerNr;
qInfo() << "zoneNr ..................." << zoneNr;
qInfo() << "readDCVersion ............" << readDCVersion;
qInfo() << "dcDir ...................." << psaDcDir;
if (!QDir(plugInDir).exists()) {
qCritical() << plugInDir
<< "does not exists, but has to contain dc-library";
exit(-1);
}
if (showExtendedVersion) {
printf(APP_EXTENDED_VERSION"\n");
return 0;
}
QString const &customerRepo = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
QStringList filesToUpdate;
QString const &customerRepo
= QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
// etc/dc: located under mount-path
std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir);
QFileInfo fi;
if (mountPath.has_value()) {
fi.setFile(mountPath.value(), System::getDCFileOnUsbStick(mountPath.value()));
} else
if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) {
fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value()));
} else {
qInfo() << "using customer repository" << customerRepo;
QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/dc"));
if (dir.exists()) {
fi.setFile(dir, dir.absoluteFilePath("dc2c.bin"));
} else {
qCritical() << "DIRECTORY" << dir << "DOES NOT EXIST";
return -1;
}
}
qInfo() << "downloading dc-firmware .." << fi.absoluteFilePath();
qInfo() << "dc-firmware size (bytes) ." << fi.size();
if (readDCVersion) {
qInfo() << "dc-version ..............." << Update::dcVersion(fi.absoluteFilePath());
}
QThread::currentThread()->setObjectName("main thread");
qInfo() << "Main thread" << QThread::currentThreadId();
// qInfo() << "Main thread" << QThread::currentThreadId();
MainWindow mw;
Update update(customerRepo,
QString::number(customerNr),
branchName,
plugInDir,
plugInName,
workingDir,
psaDcDir);
mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
update.doUpdate(fi.absoluteFilePath());
// MainWindow mw;
// mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
// mw.showFullScreen();
// qCritical() << "SHOW";
// mw.show();
qInfo() << "<DC-UPDATE-FINISH>";
return 0;
// return a.exec();
}

View File

@ -1,4 +1,5 @@
#include "update.h"
#include "process/command.h"
#include <QCoreApplication>
#include <QFile>
@ -21,6 +22,8 @@
#include <QDateTime>
#include <QPluginLoader>
#include <QMap>
#include <QStringList>
#include <QString>
#define UPDATE_OPKG (1)
#define UPDATE_DC (0)
@ -92,6 +95,17 @@ bool Update::unloadDCPlugin() {
return false;
}
QString Update::dcVersion(QString const &dcBinFile) {
QProcess p;
QStringList params;
params << "-c" << QString(R"(strings %1 | grep DC2c.\[0-9\] | uniq)").arg(dcBinFile);
p.start("bash", params);
p.waitForFinished();
return QString(p.readAllStandardOutput()).trimmed().split(QRegularExpression("\\s")).first();
}
class hwapi;
Update::Update(QString customerRepository,
QString customerNrStr,
@ -99,11 +113,14 @@ Update::Update(QString customerRepository,
QString plugInDir,
QString pluginName,
QString workingDir,
QString psaDcDir,
bool dryRun,
QObject *parent,
char const *serialInterface,
char const *baudrate)
: QObject(parent)
: QObject(parent) {
#if 0
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_serialInterface(serialInterface)
, m_baudrate(baudrate)
@ -112,100 +129,356 @@ Update::Update(QString customerRepository,
, m_branchName(branchName)
, m_pluginName(pluginName)
, m_workingDir(workingDir)
, m_psaDcDir(psaDcDir)
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
} else {
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;
// carun stoppen
}
#endif
m_start = QDateTime::currentDateTime();
}
Update::~Update() {
unloadDCPlugin();
}
bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! m_hw == nullptr";
return false;
Update::DownloadResult Update::sendStatus(int ret) const {
switch (ret) { // return values of dc are:
case 0: // 0: no answer by now
return DownloadResult::NOP; // 1: error
case 10: // 10: success
return DownloadResult::OK;
default:;
}
int tries = 20;
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
// must deliver 'true', only then are all data from hwapi valid
if (--tries < 0) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED";
return false;
}
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED (" << tries << ")";
m_hw->dc_autoRequest(true);
QThread::msleep(500);
}
bool res = false;
QList<QString>::const_iterator it;
for (it = filesToWorkOn.cbegin(); it != filesToWorkOn.cend(); ++it) {
QString const &fToWorkOn = usbStickDetected ? QDir::cleanPath(it->trimmed())
: QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed());
if (fToWorkOn.contains("DC2C_print", Qt::CaseInsensitive)
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
res = true;
int i = fToWorkOn.indexOf("DC2C_print", Qt::CaseInsensitive);
int const templateIdx = fToWorkOn.mid(i).midRef(10, 2).toInt();
if ((templateIdx < 1) || (templateIdx > 32)) {
qCritical() << "WRONG TEMPLATE INDEX" << templateIdx;
res = false;
} else {
if ((res = updatePrinterTemplate(templateIdx, fToWorkOn))) {
qCritical() <<
QString("DOWNLOADED PRINTER TEMPLATE %1 WITH INDEX=%2")
.arg(fToWorkOn)
.arg(templateIdx);
}
}
} else if (fToWorkOn.contains("DC2C_cash", Qt::CaseInsensitive)
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
if ((res = updateCashConf(fToWorkOn))) {
qCritical() << QString("DOWNLOADED CASH TEMPLATE %1").arg(fToWorkOn);
}
} else if (fToWorkOn.contains("DC2C_conf", Qt::CaseInsensitive)
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
if ((res = updateConfig(fToWorkOn))) {
qCritical() << QString("DOWNLOADED CONFIG TEMPLATE %1").arg(fToWorkOn);
}
} else if (fToWorkOn.contains("DC2C_device", Qt::CaseInsensitive)
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
if ((res = updateDeviceConf(fToWorkOn))) {
qCritical() << QString("DOWNLOADED DEVICE TEMPLATE %1").arg(fToWorkOn);
}
} else {
qCritical() << "UNKNOWN JSON FILE NAME" << fToWorkOn;
res = false;
}
}
return res;
return DownloadResult::ERROR;
}
Update::DownloadResult
Update::sendNextAddress(int bNum) const {
// sends address only if blockNumber is one of 0, 1024, 2048, 3072, 4096
int noAnswerCount = 0;
int errorCount = 0;
if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
// qDebug() << "addr-block" << bNum << "...";
while (noAnswerCount <= 250) {
// TODO
// m_hw->bl_sendAddress(bNum);
QThread::msleep(100);
// TODO
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK());
DownloadResult const res = DownloadResult::OK;
if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) {
if (++errorCount >= 10) {
qCritical() << "addr-block" << bNum << "...FAILED";
return res;
}
} else { // res == DownloadResult::OK
qInfo() << nextTimePoint().toUtf8().constData() << "addr-block" << bNum << "...done";
return res;
}
} else {
noAnswerCount += 1; // no answer by now
}
}
// wait max. about 3 seconds
return DownloadResult::TIMEOUT;
}
// blockNumber is not one of 0, 1024, 2048, 3072, 4096 -> do nothing
return DownloadResult::NOP;
}
Update::DownloadResult
Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
uint8_t local[66];
int const bAddr = bNum * 64;
int noAnswerCount = 0;
int errorCount = 0;
memcpy(local, binary.constData() + bAddr, 64);
local[64] = local[65] = 0x00;
QString s = nextTimePoint();
s += " sending block ";
s += QString("%1/%2 ...done <DC-PROGRESS>").arg(bNum).arg(m_totalBlocks);
s += QString::number(ceil(((bNum * 100.0) / (double)m_totalBlocks)));
qInfo() << s.toUtf8().constData();
QThread::msleep(200);
return DownloadResult::OK;
// QByteArray b((const char *)(&local[0]), 64);
// qCritical() << "SNDB" << bNum << b.size() << b.toHex();
while (noAnswerCount <= 250) {
// TODO
// m_hw->bl_sendDataBlock(64, local);
// TODO
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK());
DownloadResult const res = DownloadResult::OK;
if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) {
if (++errorCount >= 10) {
qCritical() << "data for block" << bNum << "...FAILED";
return res;
}
} else {
qInfo() << nextTimePoint().toUtf8().constData() << "data for block"
<< QString("%1/%2").arg(bNum).arg(m_totalBlocks) << "done";
return res;
}
} else {
noAnswerCount += 1; // no answer by now
}
}
// wait max. about 3 seconds
return DownloadResult::TIMEOUT;
}
bool Update::startBootloader() const {
QThread::msleep(1000);
qInfo() << nextTimePoint().toUtf8().constData() << "starting bootloader ...done";
return true;
#if 0
int nTry = 5;
while (--nTry >= 0) {
m_hw->bl_startBL();
QThread::msleep(5000);
m_hw->bl_checkBL();
if (m_hw->bl_isUp()) {
qInfo() << "starting bootloader...OK";
QThread::msleep(5000);
return true;
} else {
qCritical() << "bootloader not up (" << nTry << ")";
}
}
qCritical() << "starting bootloader...FAILED";
return false;
#endif
}
bool Update::stopBootloader() const {
QThread::msleep(1000);
qInfo() << nextTimePoint().toUtf8().constData() << "stopping bootloader ...done";
return true;
#if 0
qDebug() << "stopping bootloader...";
int nTry = 5;
while (--nTry >= 0) {
m_hw->bl_stopBL();
QThread::msleep(500);
if (!m_hw->bl_isUp()) {
qInfo() << "stopping bootloader...OK";
return true;
}
}
qCritical() << "stopping bootloader...FAILED";
return false;
#endif
}
bool Update::resetDeviceController() const {
// TODO
// m_hw->bl_rebootDC();
// wait maximally 3 seconds, before starting bootloader
QThread::sleep(1);
qInfo() << nextTimePoint().toUtf8().constData()
<< "resetting device controller ...done";
return true;
}
QByteArray Update::loadBinaryDCFile(QString const &filename) const {
QFile file(filename); // closed in destructor call
if (!file.exists()) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< file.fileName() << "does not exist";
return QByteArray();
}
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "cannot open file" << file.fileName();
return QByteArray();
}
qInfo() << nextTimePoint().toUtf8().constData()
<< "loading dc binary to memory" << Update::dcVersion(filename) << "...done";
return file.readAll();
}
/*
///////////////////////////////////////////////////////////////////////////////
//
// USING THE DC BOOTLOADER
//
///////////////////////////////////////////////////////////////////////////////
1 : bl_reboot() // send to application, want DC2 to reset (in order to
// start the bootloader)
//
// NOTE: this function is NOT reliable !!! Sometimes it
// simply does not work, in which case bl_startBL,
// bl_checkBL and bl_isUp do not work as well.
// Alas, there is no feedback if bl_reboot worked!
//
// NOTE: this function can be called only once per
// minute, because once called again, the controller
// performs some self-checks consuming some time.
//
// NOTE: after a successful bl_reboot(), the device is
// waiting about 4 seconds in the bootloader. To stay in
// the bootloader, we have to send the command
// bl_startBL(), which is kind of a misnomer, as it
// should be bl_doNotLeaveBL().
//
2 : bl_startBL(): // send within 4s after DC power-on, otherwise
// bootloader is left.
//
// NOTE: a running bootloader is a MUST for the download
// process of a device controller firmware as it does
// the actual writing of the memory (the bl_reboot()
// from above erases the available memory).
//
3 : bl_check(): // send command to verify if bl is up
//
// NOTE: this command is kind of a request that we want
// to check if the bootloader is up. The device
// (actually the bootloader) responds with its version.
//
4 : bl_isUp(): // returns true if bl is up and running
//
// NOTE: we know what the bootloader version actually is
// as the bootloader does not change. By comparing the
// string received in the previous step with this known
// version string we know if the bootloader is up.
//
// NOTE FOR ALL PREVIOUS STEPS: execute them in their
// own slots each to be sure to receive any possible
// responds from the device.
//
5 : bl_sendAddress(blockNumber)
// send start address, nr of 64-byte block, start with 0
// will be sent only for following block-numbers:
// 0, 1024, 2048, 3072 and 4096, so basically every
// 64kByte.
// for other addresses nothing happens
6 : bl_wasSendingAddOK()
// return val: 0: no response by now
// 1: error
// 10: OK
7 : bl_sendDataBlock()
// send 64 byte from bin file
8 : bl_sendLastBlock()
// send this command after all data are transferred
9 : bl_wasSendingDataOK()
// return val: 0: no response by now
// 1: error
// 10: OK
10 : bl_stopBL() // leave bl and start (the new) application
//
// NOTE: this function MUST work under all conditions.
// Alas, there is no direct result for this command, so
// the only way of knowing it was successful is to ask
// the device if the bootloader is still running.
// There is no problem to repeat this command until the
// bootloader is really not running anymore.
*/
bool Update::doUpdate(QString const &dcFileName) {
qInfo() << "<DC-VERSION>" << Update::dcVersion(dcFileName);
m_dcFileName = dcFileName;
//QString const &fToWorkOn = usbStickDetected ? QDir::cleanPath(it->trimmed())
//: QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed());
//if (!m_hw) {
// qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
// << "ERROR!!! m_hw == nullptr";
// return false;
//}
QByteArray ba = loadBinaryDCFile(m_dcFileName);
if (ba.size() > 0) {
m_totalBlocks = (((ba.size())%64)==0) ? (ba.size()/64) : (ba.size()/64)+1;
qInfo() << nextTimePoint().toUtf8().constData() << "blocks to send" << m_totalBlocks;
// fill last block of data to be sent with 0xFF
ba = ba.leftJustified(m_totalBlocks*64, (char)(0xFF));
resetDeviceController();
if (startBootloader()) {
int currentBlock = 0;
DownloadResult res = DownloadResult::OK;
qInfo() << nextTimePoint().toUtf8().constData() << "64-byte block" << currentBlock;
while (res != DownloadResult::ERROR && currentBlock < m_totalBlocks) {
if ((res = sendNextAddress(currentBlock)) != DownloadResult::ERROR) {
if ((res = sendNextDataBlock(ba, currentBlock)) != DownloadResult::ERROR) {
// TODO
// m_hw->dcDownloadSetCurrentBlockNumber(currentBlock);
currentBlock += 1;
} else break;
}
}
#if 0
qCritical() << "DownloadThread::run(): last 64-byte block %04d" << currentBlock;
int const rest = ba.size() % 64;
int const offset = ba.size() - rest;
char const *startAddress = ba.constData() + offset;
if (rest > 0) {
// SHOULD NEVER HAPPEN !!!
uint8_t local[66];
memset(local, 0xFF, sizeof(local));
memcpy(local, startAddress, rest);
qCritical() << "DownloadThread::run(): ERROR SEND REMAINING" << rest << "BYTES";
m_hw->bl_sendDataBlock(64, local);
} else {
m_hw->bl_sendLastBlock();
m_hw->dcDownloadSetCurrentBlockNumber(currentBlock);
}
qCritical() << "DownloadThread::run(): last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK());
#endif
}
stopBootloader(); // there is no harm in stopping the bootloader even
// if starting the bootloader failed
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
return true;
}
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>";
return false;
}
#if 0
bool Update::checkJsonVersions(QStringList const& jsonFileNames) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
@ -436,3 +709,4 @@ bool Update::updateCashConf(QString jsFile) {
bool Update::updateDeviceConf(QString jsFile) {
return downloadJson(FileTypeJson::DEVICE, 0, jsFile);
}
#endif

View File

@ -8,6 +8,8 @@
#include <QByteArray>
#include <QProcess>
#include <QPluginLoader>
#include <QDateTime>
#include <cmath>
#include <initializer_list>
@ -30,12 +32,20 @@ class Update : public QObject {
QString m_branchName;
QString m_pluginName;
QString m_workingDir;
QString m_psaDcDir;
QString m_dcFileName;
bool m_maintenanceMode;
bool m_dryRun;
bool m_sys_areDCdataValid;
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'));
}
public:
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
@ -44,13 +54,13 @@ public:
static bool unloadDCPlugin();
static QStringList split(QString line, QChar sep = ',');
explicit Update(QString customerRepository,
QString customerNrStr,
QString branchName,
QString plugInDir,
QString pluginName,
QString workingDir,
QString psaDcDir,
bool dryRun = false,
QObject *parent = nullptr,
char const *serialInterface = SERIAL_PORT,
@ -58,72 +68,22 @@ public:
virtual ~Update() override;
bool doUpdate(QStringList const &jsonFilesToDownload, bool usbStickDetected = false);
bool doUpdate(QString const &dcFileName);
static QString dcVersion(QString const &dcBinFile);
bool updatePrinterTemplate(int templateIdx, QString fname) const;
bool updateConfig(QString jsFileToSendToDC);
bool updateCashConf(QString jsFileToSendToDC);
bool updateDeviceConf(QString jsFileToSendToDC);
private:
DownloadResult sendStatus(int ret) const;
DownloadResult sendNextAddress(int bNum) const;
DownloadResult sendNextDataBlock(QByteArray const &binary, int bNum) const;
bool startBootloader() const;
bool stopBootloader() const;
QByteArray loadBinaryDCFile(QString const &dcFilename) const;
bool resetDeviceController() const;
DownloadResult dcDownloadBinary(QByteArray const &b) const;
bool downloadJson(enum FileTypeJson type, int templateIdx,
QString jsFileToSendToDC) const;
QString getFileVersion(QString const& jsonFileName);
bool checkJsonVersions(QStringList const& jsonFileNames =
QStringList(
QList(
std::initializer_list<QString>{
QString("etc/psa_config/DC2C_conf.json"),
QString("etc/psa_config/DC2C_cash.json"),
QString("etc/psa_config/DC2C_device.json"),
QString("etc/psa_config/DC2C_print01.json"),
QString("etc/psa_config/DC2C_print02.json"),
QString("etc/psa_config/DC2C_print03.json"),
QString("etc/psa_config/DC2C_print04.json"),
QString("etc/psa_config/DC2C_print05.json"),
QString("etc/psa_config/DC2C_print06.json"),
QString("etc/psa_config/DC2C_print07.json"),
QString("etc/psa_config/DC2C_print08.json"),
QString("etc/psa_config/DC2C_print09.json"),
QString("etc/psa_config/DC2C_print10.json"),
QString("etc/psa_config/DC2C_print11.json"),
QString("etc/psa_config/DC2C_print12.json"),
QString("etc/psa_config/DC2C_print13.json"),
QString("etc/psa_config/DC2C_print14.json"),
QString("etc/psa_config/DC2C_print15.json"),
QString("etc/psa_config/DC2C_print16.json"),
QString("etc/psa_config/DC2C_print17.json"),
QString("etc/psa_config/DC2C_print18.json"),
QString("etc/psa_config/DC2C_print19.json"),
QString("etc/psa_config/DC2C_print20.json"),
QString("etc/psa_config/DC2C_print21.json"),
QString("etc/psa_config/DC2C_print22.json"),
QString("etc/psa_config/DC2C_print23.json"),
QString("etc/psa_config/DC2C_print24.json"),
QString("etc/psa_config/DC2C_print25.json"),
QString("etc/psa_config/DC2C_print26.json"),
QString("etc/psa_config/DC2C_print27.json"),
QString("etc/psa_config/DC2C_print28.json"),
QString("etc/psa_config/DC2C_print29.json"),
QString("etc/psa_config/DC2C_print30.json"),
QString("etc/psa_config/DC2C_print31.json"),
QString("etc/psa_config/DC2C_print32.json")})));
QString m_fileToDownload;
uint16_t m_totalBlocks = 0;
/*
bool checkDownloadedJsonVersions(QStringList const& jsonFileNames);
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; }
//QString repositoryPath() { return m_repositoryPath; }
//QString const repositoryPath() const { return m_repositoryPath; }
private:
static QString jsonType(enum FileTypeJson type);
bool openSerial(int br, QString baudrate, QString comPort) const;

View File

@ -79,6 +79,7 @@ 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();
@ -88,29 +89,32 @@ int main(int argc, char **argv) {
QString const branchName = (zoneNr != 0)
? QString("zg1/zone%1").arg(zoneNr) : "master";
qInfo() << "pwd ......................" << rtPath;
qInfo() << "repositoryUrl ............" << repositoryUrl;
qInfo() << "plugInDir ................" << plugInDir;
qInfo() << "plugInName ..............." << plugInName;
qInfo() << "workingDir ..............." << workingDir;
qInfo() << "psaConfigDir ............." << psaConfigDir;
qInfo() << "psaTariffDir ............." << psaTariffDir;
qInfo() << "dryRun ..................." << dryRun;
qInfo() << "noUpdatePsaHardware ......" << noUpdatePsaHardware;
qInfo() << "alwaysDownloadConfig ....." << alwaysDownloadConfig;
qInfo() << "alwaysDownloadDC ........." << alwaysDownloadDC;
qInfo() << "showYoctoVersion ........." << showYoctoVersion;
qInfo() << "showYoctoInstallStatus ..." << showYoctoInstallStatus;
qInfo() << "showExtendedVersion ......" << showExtendedVersion;
qInfo() << "iniFileName .............." << iniFileName;
qInfo() << "extended-version ........." << APP_EXTENDED_VERSION;
qInfo() << "machineNr ................" << machineNr;
qInfo() << "customerNr ..............." << customerNr;
qInfo() << "zoneNr ..................." << zoneNr;
if (Update::ppid() == -1) {
qInfo() << "pwd ......................" << rtPath;
qInfo() << "repositoryUrl ............" << repositoryUrl;
qInfo() << "plugInDir ................" << plugInDir;
qInfo() << "plugInName ..............." << plugInName;
qInfo() << "workingDir ..............." << workingDir;
qInfo() << "psaConfigDir ............." << psaConfigDir;
qInfo() << "psaTariffDir ............." << psaTariffDir;
qInfo() << "dryRun ..................." << dryRun;
qInfo() << "noUpdatePsaHardware ......" << noUpdatePsaHardware;
qInfo() << "alwaysDownloadConfig ....." << alwaysDownloadConfig;
qInfo() << "alwaysDownloadDC ........." << alwaysDownloadDC;
qInfo() << "showYoctoVersion ........." << showYoctoVersion;
qInfo() << "showYoctoInstallStatus ..." << showYoctoInstallStatus;
qInfo() << "showExtendedVersion ......" << showExtendedVersion;
qInfo() << "iniFileName .............." << iniFileName;
qInfo() << "extended-version ........." << APP_EXTENDED_VERSION;
qInfo() << "machineNr ................" << machineNr;
qInfo() << "customerNr ..............." << customerNr;
qInfo() << "zoneNr ..................." << zoneNr;
qInfo() << "parent pid ..............." << Update::ppid();
if (showExtendedVersion) {
printf(APP_EXTENDED_VERSION"\n");
return 0;
if (showExtendedVersion) {
printf(APP_EXTENDED_VERSION"\n");
return 0;
}
}
QString const &customerRepo = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
@ -121,7 +125,10 @@ int main(int argc, char **argv) {
if (mountPath.has_value()) {
filesToUpdate = System::getJsonFilesOnUsbStick(mountPath.value());
} else {
qCritical() << "Using customer repository" << customerRepo;
if (Update::ppid() == -1) {
qCritical() << "Using customer repository" << customerRepo;
}
QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/psa_config"));
if (dir.exists()) {
@ -146,13 +153,16 @@ int main(int argc, char **argv) {
plugInName,
workingDir);
update.doUpdate(filesToUpdate, mountPath.has_value());
update.checkJsonVersions();
update.doUpdate();
// update.doUpdate(filesToUpdate, mountPath.has_value());
// update.checkJsonVersions();
//update.checkJsonVersions(filesToUpdate);
if (mountPath.has_value()) {
System::umountUSBStick();
}
qInfo() << "<JS-UPDATE-FINISH>";
return 0;
}

View File

@ -21,10 +21,13 @@
#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}
@ -104,7 +107,7 @@ Update::Update(QString customerRepository,
char const *serialInterface,
char const *baudrate)
: QObject(parent)
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
// , m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_serialInterface(serialInterface)
, m_baudrate(baudrate)
, m_customerRepository(customerRepository)
@ -115,27 +118,65 @@ Update::Update(QString customerRepository,
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin 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);
}
m_start = QDateTime::currentDateTime();
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_sys_areDCDataValid ..."
<< m_sys_areDCdataValid;
if (Update::ppid() == -1) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin 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;
}
}
}
Update::~Update() {
unloadDCPlugin();
// unloadDCPlugin();
}
bool Update::doUpdate() {
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;
}
bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {

View File

@ -8,6 +8,7 @@
#include <QByteArray>
#include <QProcess>
#include <QPluginLoader>
#include <QDateTime>
#include <initializer_list>
@ -36,6 +37,14 @@ 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};
@ -44,6 +53,8 @@ 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,
@ -59,6 +70,7 @@ 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);

84
Git/Git.pro Normal file
View File

@ -0,0 +1,84 @@
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/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 \
git_command.cpp
HEADERS += \
message_handler.h \
../common/include/utils_internal.h \
../common/include/command.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
}

101
Git/git_command.cpp Normal file
View File

@ -0,0 +1,101 @@
#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) {
QStringList const lst{"fsck"};
return exec(lst, start_timeout, finish_timeout);
}
bool GitCommand::checkout(int start_timeout, int finish_timeout) {
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) {
QStringList const lst{"pull"};
return exec(lst, start_timeout, finish_timeout);
}
bool GitCommand::status(int start_timeout, int finish_timeout) {
QStringList const lst{"status"};
return exec(lst, start_timeout, finish_timeout);
}

30
Git/git_command.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef GIT_COMMAND_H_INCLUDED
#define GIT_COMMAND_H_INCLUDED
#include <QStringList>
#include <QScopedPointer>
class QProcess;
class GitCommand {
static bool initEnv;
QString m_workingDirectory;
bool exec(QStringList const &options, int start_timeout = 100000,
int finish_timeout = 100000);
QString m_commandResult{};
public:
GitCommand();
void resetCommandResult() { m_commandResult.clear(); }
QString const &commandResult() const { return m_commandResult; }
bool status(int start_timeout = 100000, int finish_timeout = 100000);
bool check(int start_timeout = 100000, int finish_timeout = 100000);
bool checkout(int start_timeout = 100000, int finish_timeout = 100000);
bool clone(int start_timeout = 100000, int finish_timeout = 100000);
bool pull(int start_timeout = 100000, int finish_timeout = 100000);
};
#endif // GIT_COMMAND_H_INCLUDED

119
Git/main.cpp Normal file
View File

@ -0,0 +1,119 @@
#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 <QRegularExpression>
#include <optional>
#include "message_handler.h"
#include "utils_internal.h"
#include "git_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-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);
}
QCommandLineParser 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);
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;
}
}
}
//int const machineNr = read1stLineOfFile("/mnt/system_data/machine_nr");
//int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
//int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
return 0;
}

97
Git/message_handler.cpp Executable file
View File

@ -0,0 +1,97 @@
#include "message_handler.h"
#include <QDateTime>
#include <cstring>
#include <QString>
#include <QFileInfo>
#include <QMessageLogContext>
static char const *DBG_NAME[] = { "DBG ", "WARN ", "CRIT ", "FATAL", "INFO " };
static bool installedMsgHandler = false;
static int debugLevel = LOG_NOTICE;
int getDebugLevel() { return debugLevel; }
void setDebugLevel(int newDebugLevel) {
debugLevel = newDebugLevel;
}
bool messageHandlerInstalled() {
return installedMsgHandler;
}
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
installedMsgHandler = (handler != 0);
static QtMessageHandler prevHandler = nullptr;
if (handler) {
prevHandler = qInstallMessageHandler(handler);
return prevHandler;
} else {
return qInstallMessageHandler(prevHandler);
}
}
///
/// \brief Print message according to given debug level.
///
/// \note Install this function using qInstallMsgHandler().
///
/// int main(int argc, char **argv) {
/// installMsgHandler(atbDebugOutput);
/// QApplication app(argc, argv);
/// ...
/// return app.exec();
/// }
///
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
Q_UNUSED(context);
QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
switch (debugLevel) {
case LOG_DEBUG: { // debug-level message
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
} break;
case LOG_INFO: { // informational message
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_NOTICE: { // normal, but significant, condition
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_WARNING: { // warning conditions
if (type != QtInfoMsg && type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ERR: { // error conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_CRIT: { // critical conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ALERT: { // action must be taken immediately
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_EMERG: { // system is unusable
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
default: {
//fprintf(stderr, "%s No ErrorLevel defined! %s\n",
// datetime.toStdString().c_str(), msg.toStdString().c_str());
}
}
}
#endif

23
Git/message_handler.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef MESSAGE_HANDLER_H_INCLUDED
#define MESSAGE_HANDLER_H_INCLUDED
#include <QtGlobal>
#ifdef __linux__
#include <syslog.h>
#endif
int getDebugLevel();
void setDebugLevel(int newDebugLevel);
bool messageHandlerInstalled();
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const char *);
void atbDebugOutput(QtMsgType type, const char *msg);
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif
#endif // MESSAGE_HANDLER_H_INCLUDED

85
Opkg/Opkg.pro Normal file
View File

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

69
Opkg/main.cpp Normal file
View File

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

97
Opkg/message_handler.cpp Executable file
View File

@ -0,0 +1,97 @@
#include "message_handler.h"
#include <QDateTime>
#include <cstring>
#include <QString>
#include <QFileInfo>
#include <QMessageLogContext>
static char const *DBG_NAME[] = { "DBG ", "WARN ", "CRIT ", "FATAL", "INFO " };
static bool installedMsgHandler = false;
static int debugLevel = LOG_NOTICE;
int getDebugLevel() { return debugLevel; }
void setDebugLevel(int newDebugLevel) {
debugLevel = newDebugLevel;
}
bool messageHandlerInstalled() {
return installedMsgHandler;
}
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
installedMsgHandler = (handler != 0);
static QtMessageHandler prevHandler = nullptr;
if (handler) {
prevHandler = qInstallMessageHandler(handler);
return prevHandler;
} else {
return qInstallMessageHandler(prevHandler);
}
}
///
/// \brief Print message according to given debug level.
///
/// \note Install this function using qInstallMsgHandler().
///
/// int main(int argc, char **argv) {
/// installMsgHandler(atbDebugOutput);
/// QApplication app(argc, argv);
/// ...
/// return app.exec();
/// }
///
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
Q_UNUSED(context);
QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
switch (debugLevel) {
case LOG_DEBUG: { // debug-level message
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
} break;
case LOG_INFO: { // informational message
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_NOTICE: { // normal, but significant, condition
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_WARNING: { // warning conditions
if (type != QtInfoMsg && type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ERR: { // error conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_CRIT: { // critical conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ALERT: { // action must be taken immediately
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_EMERG: { // system is unusable
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
default: {
//fprintf(stderr, "%s No ErrorLevel defined! %s\n",
// datetime.toStdString().c_str(), msg.toStdString().c_str());
}
}
}
#endif

23
Opkg/message_handler.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef MESSAGE_HANDLER_H_INCLUDED
#define MESSAGE_HANDLER_H_INCLUDED
#include <QtGlobal>
#ifdef __linux__
#include <syslog.h>
#endif
int getDebugLevel();
void setDebugLevel(int newDebugLevel);
bool messageHandlerInstalled();
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const char *);
void atbDebugOutput(QtMsgType type, const char *msg);
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif
#endif // MESSAGE_HANDLER_H_INCLUDED

176
Opkg/opkg_command.cpp Normal file
View File

@ -0,0 +1,176 @@
#include "opkg_command.h"
#include "command.h"
#include "utils_internal.h"
using namespace internal;
#include <QDir>
#include <QDebug>
#include <QFlags>
#include <QRegularExpression>
OpkgCommand::OpkgCommand(bool noaction, QString const &opkg_commands_filename)
: m_noaction(noaction)
, m_opkg_commands_filename(opkg_commands_filename) {
cleanUpOpkgCache();
execCommandsInternal();
}
bool OpkgCommand::readCommands() {
QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
if (!opkgFile.exists()) {
qCritical() << __func__ << ":" << __LINE__
<< opkgFile.fileName() << "does not exists";
return false;
}
m_commands.clear();
if (opkgFile.open(QIODevice::ReadOnly)) {
QTextStream in(&opkgFile);
while (!in.atEnd()) {
QString line = in.readLine();
// TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
static const QRegularExpression comment("^\\s*[#].*$");
static const QRegularExpression emptyLine("^\\s*$");
if (line.indexOf(emptyLine, 0) == -1 &&
line.indexOf(comment, 0) == -1) {
QString const &commandLine = line.trimmed();
if (!commandLine.isEmpty()) {
m_commands << commandLine;
}
}
}
} else {
qCritical() << __func__ << ":" << __LINE__
<< "error opening" << opkgFile.fileName();
}
return m_commands.size() > 0;
}
bool OpkgCommand::execCommandsInternal() {
if (readCommands()) {
// command lines are located between markers: <OPKG>...<OPKG>
// they are later removed when used by the update-tool.
qCritical().noquote() << "<OPKG>";
QListIterator<QString> it(m_commands);
while (it.hasNext()) {
QString command = it.next();
QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
if (cmdAndOptions.size() > 0) {
QString const &cmd = cmdAndOptions.takeFirst();
if (m_noaction) {
if (cmd.contains("opkg")) {
cmdAndOptions.prepend("--noaction");
} else continue; // only opkg has the --noaction option
}
QStringList const &options = cmdAndOptions;
if (exec(cmd, options)) {
qCritical().noquote() << cmd << options.join(" ") << "ok" << "<OPKG>";
} else {
qCritical().noquote() << cmd << options.join(" ") << "FAIL" << "<OPKG>";
}
}
}
return true;
}
return false;
}
bool OpkgCommand::execCommands() {
if (readCommands()) {
QListIterator<QString> it(m_commands);
while (it.hasNext()) {
QString command = it.next();
QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
if (cmdAndOptions.size() > 0) {
QString const &cmd = cmdAndOptions.takeFirst();
if (m_noaction) {
cmdAndOptions.prepend("--noaction");
}
QStringList const &options = cmdAndOptions;
if (exec(cmd, options)) {
qCritical().noquote() << cmd << options.join(" ");
} else {
qCritical().noquote() << cmd << options.join(" ") << "FAIL";
return false;
}
}
}
return true;
}
return false;
#if 0
QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
if (!opkgFile.exists()) {
qCritical() << __func__ << ":" << __LINE__
<< opkgFile.fileName() << "does not exists";
return false;
}
if (opkgFile.open(QIODevice::ReadOnly)) {
QTextStream in(&opkgFile);
while (!in.atEnd()) {
QString line = in.readLine();
// TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
static const QRegularExpression comment("^\\s*[#].*$");
static const QRegularExpression emptyLine("^\\s*$");
if (line.indexOf(emptyLine, 0) == -1 &&
line.indexOf(comment, 0) == -1) {
QString const &commandLine = line.trimmed();
if (!commandLine.isEmpty()) {
QStringList cmdAndOptions = commandLine.split(u' ', QString::SkipEmptyParts);
if (cmdAndOptions.size() > 0) {
QString const &cmd = cmdAndOptions.takeFirst();
if (m_noaction) {
cmdAndOptions.prepend("--noaction");
}
QStringList const &options = cmdAndOptions;
if (exec(cmd, options)) {
qCritical().noquote() << cmd << options.join(" ") << "ok";
} else {
qCritical().noquote() << cmd << options.join(" ") << "FAIL";
}
} else {
continue;
}
}
}
}
return true;
} else {
qCritical() << __func__ << ":" << __LINE__
<< "error opening" << opkgFile.fileName();
}
return false;
#endif
}
bool OpkgCommand::exec(QString const &cmd, QStringList const &options,
int start_timeout, int finish_timeout) {
bool const verbose = false;
return Command(cmd, options, "/tmp", verbose, start_timeout, finish_timeout).exec();
}
bool OpkgCommand::cleanUpOpkgCache() {
bool removedFiles = true;
QDir dir("/var/cache/opkg/");
if (dir.exists()) {
dir.setNameFilters(QStringList() << ".gz" << ".ipk");
dir.setFilter(QDir::Files);
foreach(QString dirFile, dir.entryList()) {
removedFiles &= dir.remove(dirFile);
}
}
if (removedFiles == false) {
qCritical() << "some errors while cleaning up opkg-cache";
}
return removedFiles;
}

29
Opkg/opkg_command.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef OPKG_COMMND_H_INCLUDED
#define OPKG_COMMND_H_INCLUDED
#include <QStringList>
class OpkgCommand {
QString const m_opkg_commands_dir{"/etc/psa_update/"};
bool m_noaction;
QString m_opkg_commands_filename;
QStringList m_commands;
bool execCommands();
bool execCommandsInternal();
bool cleanUpOpkgCache();
public:
OpkgCommand(bool noaction = false,
QString const &opkg_commands_file_name="opkg_commands");
bool exec(QString const &cmd, QStringList const &options,
int start_timeout = 100000, int finish_timeout = 100000);
QStringList commands() { return m_commands; }
QStringList const &commands() const { return m_commands; }
bool readCommands();
};
#endif // OPKG_COMMND_H_INCLUDED

68
Show/Show.pro Normal file
View File

@ -0,0 +1,68 @@
QT += core
TARGET = show_update
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 += \

14
Show/main.cpp Normal file
View File

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

87
Sync/Sync.pro Normal file
View File

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

36
Sync/main.cpp Normal file
View File

@ -0,0 +1,36 @@
#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);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(nullptr);
//atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(LOG_NOTICE);
}
return 0;
}

97
Sync/message_handler.cpp Executable file
View File

@ -0,0 +1,97 @@
#include "message_handler.h"
#include <QDateTime>
#include <cstring>
#include <QString>
#include <QFileInfo>
#include <QMessageLogContext>
static char const *DBG_NAME[] = { "DBG ", "WARN ", "CRIT ", "FATAL", "INFO " };
static bool installedMsgHandler = false;
static int debugLevel = LOG_NOTICE;
int getDebugLevel() { return debugLevel; }
void setDebugLevel(int newDebugLevel) {
debugLevel = newDebugLevel;
}
bool messageHandlerInstalled() {
return installedMsgHandler;
}
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
installedMsgHandler = (handler != 0);
static QtMessageHandler prevHandler = nullptr;
if (handler) {
prevHandler = qInstallMessageHandler(handler);
return prevHandler;
} else {
return qInstallMessageHandler(prevHandler);
}
}
///
/// \brief Print message according to given debug level.
///
/// \note Install this function using qInstallMsgHandler().
///
/// int main(int argc, char **argv) {
/// installMsgHandler(atbDebugOutput);
/// QApplication app(argc, argv);
/// ...
/// return app.exec();
/// }
///
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
Q_UNUSED(context);
QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
switch (debugLevel) {
case LOG_DEBUG: { // debug-level message
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
} break;
case LOG_INFO: { // informational message
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_NOTICE: { // normal, but significant, condition
if (type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_WARNING: { // warning conditions
if (type != QtInfoMsg && type != QtDebugMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ERR: { // error conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_CRIT: { // critical conditions
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_ALERT: { // action must be taken immediately
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
case LOG_EMERG: { // system is unusable
if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
}
} break;
default: {
//fprintf(stderr, "%s No ErrorLevel defined! %s\n",
// datetime.toStdString().c_str(), msg.toStdString().c_str());
}
}
}
#endif

23
Sync/message_handler.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef MESSAGE_HANDLER_H_INCLUDED
#define MESSAGE_HANDLER_H_INCLUDED
#include <QtGlobal>
#ifdef __linux__
#include <syslog.h>
#endif
int getDebugLevel();
void setDebugLevel(int newDebugLevel);
bool messageHandlerInstalled();
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const char *);
void atbDebugOutput(QtMsgType type, const char *msg);
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif
#endif // MESSAGE_HANDLER_H_INCLUDED

18
Sync/sync_command.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "sync_command.h"
#include "command.h"
#include "utils_internal.h"
using namespace internal;
#include <QDir>
#include <QDebug>
#include <QFlags>
#include <QRegularExpression>
SyncCommand::SyncCommand() {
}
bool SyncCommand::exec(QString const &cmd, QStringList const &options,
int start_timeout, int finish_timeout) {
return false;
}

14
Sync/sync_command.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SYNC_COMMAND_H_INCLUDED
#define SYNC_COMMAND_H_INCLUDED
#include <QStringList>
class SyncCommand {
public:
SyncCommand();
bool exec(QString const &cmd, QStringList const &options,
int start_timeout = 100000, int finish_timeout = 100000);
};
#endif // SYNC_COMMAND_H_INCLUDED

View File

@ -216,7 +216,10 @@ GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += plugins
# INCLUDEPATH += plugins
INCLUDEPATH += plugins \
$${_PRO_FILE_PWD_}/../common/ \
$${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17
# CONFIG -= app_bundle
@ -279,9 +282,24 @@ 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 \
commandline_parser.cpp
commandline_parser.cpp \
work_process_list.cpp \
$${_PRO_FILE_PWD_}/../common/src/utils_internal.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.cpp
HEADERS += \
update.h \
@ -293,9 +311,25 @@ 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 \
commandline_parser.h
commandline_parser.h \
work_process_list.h \
$${_PRO_FILE_PWD_}/../common/include/utils_internal.h \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.h \
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.h \
$${_PRO_FILE_PWD_}/../common/ismas/ISMASData.h \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.h
OTHER_FILES += \
ATBUpdateTool.ini

View File

@ -85,7 +85,23 @@ CommandLineParser::CommandLineParser()
, m_yoctoInstallStatusOption(
QCommandLineOption(
QStringList() << "Y" << "yocto-install",
QCoreApplication::translate("main", "Show yocto install status of ATBUpdateTool."))) {
QCoreApplication::translate("main", "Show yocto install status of ATBUpdateTool.")))
, m_dcDirectoryOption(
QCommandLineOption(
QStringList() << "dc-directory" << "dc-directory",
QCoreApplication::translate("main", "device controller directory."),
QCoreApplication::translate("main", "directory")))
, m_readDCVersionOption(
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."))) {
configure();
}
@ -138,6 +154,15 @@ void CommandLineParser::configure() {
m_yoctoInstallStatusOption.setDefaultValue("false");
m_parser.addOption(m_yoctoInstallStatusOption);
m_dcDirectoryOption.setDefaultValue("etc/dc/");
m_parser.addOption(m_dcDirectoryOption);
m_readDCVersionOption.setDefaultValue("false");
m_parser.addOption(m_readDCVersionOption);
m_setPPid.setDefaultValue("-1");
m_parser.addOption(m_setPPid);
}
void CommandLineParser::readSettings() {
@ -145,8 +170,8 @@ void CommandLineParser::readSettings() {
QString const iniFileName = m_parser.value(m_iniFileNameOption);
m_iniFileName = QDir::cleanPath(iniFileDir + QDir::separator() + iniFileName);
qCritical() << __PRETTY_FUNCTION__ << " iniFileDir" << iniFileDir;
qCritical() << __PRETTY_FUNCTION__ << "iniFileName" << m_iniFileName;
//qCritical() << __PRETTY_FUNCTION__ << " iniFileDir" << iniFileDir;
//qCritical() << __PRETTY_FUNCTION__ << "iniFileName" << m_iniFileName;
if (!m_iniFileName.isEmpty()) {
if (QFile(m_iniFileName).exists()) {
@ -155,8 +180,8 @@ void CommandLineParser::readSettings() {
for (QString const &key: keys) {
QVariant v = settings.value(key);
qCritical() << __PRETTY_FUNCTION__
<< key << " -> " << v.toString();
//qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << key << " -> " << v.toString();
if (key.contains("repository-url")) {
m_repositoryUrl = v.toString();
@ -196,6 +221,12 @@ void CommandLineParser::readSettings() {
} else
if (key.contains("plugin-name")) {
m_plugInName = v.toString();
} else
if (key.contains("dc-directory")) {
m_dcDir = v.toString();
} else
if (key.contains("read-dc-version")) {
m_readDCVersion = (v.toBool() ? "true" : "false");
} else {
qCritical() << __PRETTY_FUNCTION__
<< key << " -> (UNKNOWN) " << v.toString();
@ -243,6 +274,20 @@ QString CommandLineParser::psaTariffDir() {
return m_psaTariffDir;
}
QString CommandLineParser::dcDir() {
if (m_parser.isSet(m_dcDirectoryOption)) {
m_dcDir = m_parser.value(m_dcDirectoryOption);
}
return m_dcDir;
}
bool CommandLineParser::readDCVersion() {
if (m_parser.isSet(m_readDCVersionOption)) {
m_readDCVersion = m_parser.value(m_readDCVersionOption);
}
return m_readDCVersion == "false" ? false : true;
}
QString CommandLineParser::workingDir() {
if (m_parser.isSet(m_workingDirectoryOption)) {
m_workingDir = m_parser.value(m_workingDirectoryOption);
@ -250,6 +295,19 @@ 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);
@ -288,9 +346,9 @@ bool CommandLineParser::extendedVersion() {
bool CommandLineParser::alwaysDownloadConfig() {
if (m_parser.isSet(m_alwaysDownloadConfigOption)) {
m_alwaysDownloadConfig = m_parser.value(m_alwaysDownloadConfigOption);
qCritical() << "m_alwaysDownloadConfigOption IS SET" << m_alwaysDownloadConfig;
// qCritical() << "m_alwaysDownloadConfigOption IS SET" << m_alwaysDownloadConfig;
}
qCritical() << "m_alwaysDownloadConfig" << m_alwaysDownloadConfig;
// qCritical() << "m_alwaysDownloadConfig" << m_alwaysDownloadConfig;
return m_alwaysDownloadConfig == "false" ? false : true;
}

View File

@ -1,4 +1,4 @@
#ifndef COMMAND_LINE_PARSER_H_INCLUDED
#ifndef COMMAND_LINE_PARSER_H_INCLUDED
#define COMMAND_LINE_PARSER_H_INCLUDED
#include <QCoreApplication>
@ -11,8 +11,8 @@ class CommandLineParser : public QCommandLineParser {
QString m_plugInDir;
QString m_plugInName;
QString m_workingDir;
QString m_psaConfigDir;
QString m_psaTariffDir;
QString m_psaConfigDir{"etc/psa_config"};
QString m_psaTariffDir{"etc/psa_tariff"};
QString m_dryRun;
QString m_noUpdatePsaHardware;
QString m_showYoctoVersion;
@ -21,6 +21,9 @@ class CommandLineParser : public QCommandLineParser {
QString m_iniFileName;
QString m_alwaysDownloadConfig;
QString m_alwaysDownloadDC;
QString m_readDCVersion{"false"};
QString m_dcDir{"etc/dc/"};
qint64 m_ppid;
QCommandLineOption m_repositoryUrlOption;
QCommandLineOption m_iniFileDirectoryOption;
@ -37,6 +40,9 @@ class CommandLineParser : public QCommandLineParser {
QCommandLineOption m_extendedVersionOption;
QCommandLineOption m_yoctoVersionOption;
QCommandLineOption m_yoctoInstallStatusOption;
QCommandLineOption m_dcDirectoryOption;
QCommandLineOption m_readDCVersionOption;
QCommandLineOption m_setPPid;
QCommandLineParser m_parser;
@ -59,11 +65,14 @@ public:
QString psaConfigDir();
QString psaTariffDir();
bool dryRun();
qint64 ppid();
bool noUpdatePsaHardware();
bool yoctoVersion();
bool yoctoInstallStatus();
bool extendedVersion();
bool alwaysDownloadConfig();
bool alwaysDownloadDC();
bool readDCVersion();
QString dcDir();
};
#endif // COMMAND_LINE_PARSER_H_INCLUDED

View File

@ -2,6 +2,7 @@
#include "update.h"
#include "worker.h"
#include "utils.h"
#include "process/command.h"
#include <QRegularExpression>
#include <QDebug>

View File

@ -4,8 +4,8 @@
#include <QObject>
#include <QStringList>
#include <optional>
#include <QCoreApplication>
#include "process/command.h"
#include "ismas/ismas_client.h"
class Worker;

View File

@ -31,10 +31,12 @@
#include "worker.h"
#include "mainwindow.h"
#include "utils.h"
// #include "process/command.h"
#include <QThread>
#include <QtWidgets>
#include <QScopedPointer>
#include <QScreen>
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
#include <unistd.h>
@ -86,10 +88,12 @@ int main(int argc, char *argv[]) {
if (v.isEmpty()) {
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
if (QFileInfo(sshKeyFile).exists()) {
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;
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...";
@ -199,5 +203,10 @@ int main(int argc, char *argv[]) {
mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
mw.showFullScreen();
// test
//worker.jsUpdate();
worker.workList().exec();
// worker.summary();
return a.exec();
}

View File

@ -2,8 +2,10 @@
#include "ui_mainwindow.h"
#include "worker.h"
#include "utils.h"
#include "utils_internal.h"
#include "progress_event.h"
#include "update_dc_event.h"
#include "process/update_command.h"
#include <DeviceController/interfaces.h>
#include <QDateTime>
@ -11,6 +13,8 @@
#include <QDebug>
#include <QScrollBar>
#include <QEvent>
#include <QColor>
#include <QColorDialog>
MainWindow::MainWindow(Worker *worker, QWidget *parent)
@ -21,16 +25,16 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
, m_progressRunning(false)
, m_updateStep(UpdateDcEvent::UpdateStep::NONE) {
ui->setupUi(this);
this->setStatusBar(new QStatusBar(this));
QFont f;
f.setStyleHint(QFont::Monospace);
f.setWeight(QFont::Bold);
f.setFamily("Misc Fixed");
f.setPixelSize(12);
f.setPointSize(11);
this->statusBar()->setFont(f);
ui->setupUi(this);
ui->updateProgress->setRange(0, 100);
ui->updateProgress->reset();
@ -38,15 +42,15 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
QString start = QDateTime::currentDateTime().toString(Qt::ISODate);
lst << QString("Start: ") + start.leftJustified(m_width-10);
lst << QString("").leftJustified(m_width-3, '=');
lst << QString("Update tool version: %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3);
lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3);
lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3);
lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3);
lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3);
lst << QString("Update tool version : %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3);
lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3);
lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3);
lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3);
lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3);
lst << QString("").leftJustified(m_width-3, '=');
ui->updateStatus->setText(lst.join('\n'));
ui->updateStatus->setEnabled(true);
ui->updateLabel->setText(lst.join('\n'));
ui->updateLabel->setEnabled(true);
// ui->updateStatus->installEventFilter(this);
m_startTimer = new QTimer(this);
@ -78,11 +82,30 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
}
connect(ui->exit, SIGNAL(clicked()),this,SLOT(onQuit()));
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()));
connect(m_worker, SIGNAL(restartExitTimer()),this,SLOT(onRestartExitTimer()));
connect(m_worker, SIGNAL(appendText(QString,QString)),this,SLOT(onAppendText(QString,QString)));
connect(m_worker, SIGNAL(insertText(QString)),this,SLOT(onInsertText(QString)), Qt::DirectConnection);
connect(m_worker, SIGNAL(showErrorMessage(QString,QString)),this, SLOT(onShowErrorMessage(QString,QString)));
connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString)));
connect(m_worker, SIGNAL(showErrorMessage(QStringList)),this, SLOT(onShowErrorMessage(QStringList)));
@ -91,6 +114,365 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
connect(m_worker, SIGNAL(replaceLast(QStringList,QString)),this, SLOT(onReplaceLast(QStringList,QString)));
}
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);
}
void MainWindow::onSetDcDownloadProgress(int v) {
ui->updateProgress->setValue(v);
}
void MainWindow::onShowTariffUpdate(QString) {
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) {
// ausgabe: connected, not connected, connecting
m_stepLabelChopCount = 0;
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
QString tmp("Check backend connection (ISMAS) ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += QString("%1 <font color='Green'>connected</font><br />").arg(tmp);
} else {
s += QString("%1 <font color='Green'>connected&nbsp;(initial configuration)</font><br />").arg(tmp);
}
} else
if (status.contains(UpdateCommand::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Blue'>NOT CONNECTED</font><br />").arg(tmp);
} else
if (status.contains(UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>connecting</font><br />").arg(tmp);
} else
if (status.contains(UpdateCommand::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += QString( "%1 <font color='Red'>NOT CONNECTED. STOP</font><br />").arg(tmp);
} else {
s += QString( "%1 <font color='Red'>not connected.&nbsp;(initial configuration)</font><br />").arg(tmp);
}
} else {
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
}
m_stepLabelChopCount = -s.length();
s += "Check update request";
m_stepLabelChopCount += s.length();
ui->stepLabel->setText(s);
}
void MainWindow::onShowCustRepoStatus(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp("Update customer repository ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(internal::GIT_CUSTOMER_REPO_UP_TO_DATE, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>%2</font><br />").arg(tmp).arg(internal::GIT_CUSTOMER_REPO_UP_TO_DATE);
} else
if (status.contains(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>%2</font><br />").arg(tmp).arg(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
} else {
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
}
m_stepLabelChopCount = -s.length();
s += "Install SW packets (dry run)";
m_stepLabelChopCount += s.length();
ui->stepLabel->setText(s);
}
void MainWindow::onShowExecOpkgStatus(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
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;
if (cmd.back() != QChar('\n')) {
cmd += "\n";
}
onInsertText(cmd);
}
void MainWindow::onShowExecOpkgOverallResult(QString status, bool noaction) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp = noaction ? "Install SW packets (dry run) " : "Install SW packets ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(internal::EXEC_OPKG_COMMANDS_SUCCESS, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
} else
if (status.contains(internal::EXEC_OPKG_COMMANDS_FAIL, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Red'>%2</font><br />").arg(tmp).arg(internal::EXEC_OPKG_COMMANDS_FAIL);
} else {
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
}
if (noaction) {
m_stepLabelChopCount = -s.length();
s += "Install SW packets";
m_stepLabelChopCount += s.length();
} else {
m_stepLabelChopCount = -s.length();
s += "Install DC configuration";
m_stepLabelChopCount += s.length();
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowDownloadDCJsonFilesStatus(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp = "Install DC configuration ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(UpdateCommand::UPDATE_DC_JSON_FILES_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);
}
m_stepLabelChopCount = -s.length();
s += "Synchronize repository/filesystem";
m_stepLabelChopCount += s.length();
ui->stepLabel->setText(s);
}
void MainWindow::onShowSyncCustRepoStatus(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp = "Synchronize repository/filesystem ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_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);
}
m_stepLabelChopCount = -s.length();
s += "Update DC";
m_stepLabelChopCount += s.length();
ui->stepLabel->setText(s);
}
void MainWindow::onShowUpdateDCFirmware(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp = "Update DC ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(UpdateCommand::UPDATE_DC_FIRMARE_SUCCESS, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
} else {
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowUpdateRequest(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = ui->stepLabel->text();
s.chop(m_stepLabelChopCount);
QString tmp = "Check update request ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::UPDATE_NOT_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += QString( "%1 <font color='Red'>NOT REQUESTED. STOP.</font><br />").arg(tmp);
} else {
s += QString("%1 <font color='Blue'>not requested&nbsp;(initial configuration)</font><br />").arg(tmp);
}
} else
if (status.contains(UpdateCommand::UPDATE_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += QString("%1 <font color='Green'>requested</font><br />").arg(tmp);
} else {
s += QString("%1 <font color='Blue'>requested&nbsp;(initial configuration)</font><br />").arg(tmp);
}
} else
if (status.contains(UpdateCommand::UPDATE_NOT_NECESSARY, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>not necessary</font><br />").arg(tmp);
} else
if (status.contains(UpdateCommand::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Blue'>UNKNOWN (ISMAS not connected)</font><br />").arg(tmp);
} else {
s += QString( "%1 <font color='Red'>UNKNOWN</font><br />").arg(tmp);
}
m_stepLabelChopCount = -s.length();
s += "Update customer repository";
m_stepLabelChopCount += s.length();
ui->stepLabel->setText(s);
}
void MainWindow::onShowISMASChecks(QString) {
// deprecated
QString s = ui->stepLabel->text();
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) {
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);
}
MainWindow::~MainWindow() {
delete m_startTimer;
delete m_exitTimer;
@ -199,6 +581,12 @@ void MainWindow::scrollDownTextEdit() {
ui->updateStatus->ensureCursorVisible();
}
void MainWindow::onInsertText(QString text) {
scrollDownTextEdit();
ui->updateStatus->textCursor().insertText(text);
}
void MainWindow::onAppendText(QString text, QString suffix) {
// Utils::printInfoMsg(QString("ON APPEND CALLED AT ")
// + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));

View File

@ -36,8 +36,11 @@ public:
UpdateDcEvent::UpdateStep updateStep() const { return m_updateStep; }
void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; }
QString targetDcVersion() {return m_targetDcVersion; }
public slots:
void onAppendText(QString, QString suffix = "");
void onInsertText(QString);
void onReplaceLast(QStringList, QString suffix = "");
void onReplaceLast(QString, QString suffix = "");
void onShowErrorMessage(QString, QString);
@ -48,6 +51,21 @@ public slots:
void onRestartExitTimer();
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);
#if EMERGENCY_LEAVE_BL==1
void emergencyLeaveBL();
#endif
@ -62,6 +80,9 @@ private slots:
void onQuit();
private:
int const m_showLineLength = 37;
void scrollDownTextEdit();
void onShowMessage(QString, QString);
@ -74,5 +95,7 @@ private:
//int m_progressValue;
UpdateDcEvent::UpdateStep m_updateStep;
QTimer *m_statusTimer;
QString m_targetDcVersion;
int m_stepLabelChopCount{};
};
#endif // MAINWINDOW_H

View File

@ -12,7 +12,10 @@
</property>
<property name="font">
<font>
<family>Source Code Pro</family>
<family>Misc Fixed</family>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="windowTitle">
@ -29,21 +32,28 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="2">
<widget class="QPushButton" name="exit">
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="stepLabel">
<property name="minimumSize">
<size>
<width>0</width>
<height>18</height>
</size>
</property>
<property name="font">
<font>
<family>Misc Fixed</family>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Exit</string>
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QProgressBar" name="updateProgress">
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="3" colspan="3">
<item row="3" column="0" colspan="3">
<widget class="QTextEdit" name="updateStatus">
<property name="enabled">
<bool>true</bool>
@ -52,9 +62,16 @@
<font>
<family>Misc Fixed</family>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::WinPanel</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
@ -64,6 +81,44 @@
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="2" colspan="3">
<widget class="QLabel" name="updateLabel">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="font">
<font>
<family>Misc Fixed</family>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QProgressBar" name="updateProgress">
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="exit">
<property name="text">
<string>Exit</string>
</property>
</widget>
</item>
</layout>

View File

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

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

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

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

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

View File

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

@ -1,44 +1,145 @@
#include "command.h"
#include "worker.h"
#include <QProcess>
#include <QDebug>
#include <QDir>
#include <QRegularExpression>
#include <QDateTime>
#include <QMutexLocker>
Command::Command(QString const &command, int start_timeout, int finish_timeout)
: m_command(command.trimmed())
, m_commandResult("")
, m_waitForStartTimeout(start_timeout)
, m_waitForFinishTimeout(finish_timeout)
, m_exitCode(-1) {
, m_exitCode(-1)
, m_p(nullptr)
, m_worker(nullptr) {
}
QString Command::getCommandResult() const {
return m_commandResult;
QString Command::getCommandResult(bool reset) const {
QMutexLocker locker(&m_mtx);
if (reset == false) {
return m_commandResult;
}
QString commandResult = m_commandResult;
m_commandResult.clear();
return commandResult;
}
void Command::readyReadStandardOutput() {
QMutexLocker locker(&m_mtx);
QProcess *p = (QProcess *)sender();
m_commandResult += p->readAllStandardOutput();
// qCritical() << m_commandResult;
if (p) {
QString s = p->readAllStandardOutput();
// qCritical() << __func__ << ":" << __LINE__ << s;
if (m_worker) {
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 m_worker->showDcDownload(s);
} else
if ((i = s.indexOf("<DC-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
if ((i = s.indexOf("<DC-UPDATE-FINISH>")) != -1) {
m_worker->summary();
// qApp->exit(0);
} else
if ((i = s.indexOf("<DC-UPDATE-SUCCESS>")) != -1) {
m_worker->summary();
} else
if ((i = s.indexOf("<DC-UPDATE-FAILURE>")) != -1) {
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);
}
}
m_commandResult += s;
}
}
void Command::readyReadStandardError() {
QProcess *p = (QProcess *)sender();
QByteArray buf = p->readAllStandardError();
qCritical() << buf;
if (p) {
QByteArray buf = p->readAllStandardError();
qCritical() << buf;
}
}
// 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
QString d = p->readAllStandardOutput();
if (!d.isEmpty()) {
QMutexLocker locker(&m_mtx);
m_commandResult += d;
}
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
<< "FAILED FOR" << m_command;
return false;
}
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);
} else {
m_p->start(m_command);
}
return m_p->waitForStarted(m_waitForStartTimeout);
}
bool Command::execute(QString workingDirectory, QStringList args) {

View File

@ -1,35 +1,55 @@
#ifndef COMMAND_H_INCLUDED
#define COMMAND_H_INCLUDED
#endif // COMMAND_H_INCLUDED
#include <QObject>
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QProcess>
#include <QMutex>
class Worker;
class Command : public QObject {
Q_OBJECT
protected:
QString m_command;
QString m_commandResult;
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,
int finish_timeout = 100000);
QString getCommandResult() const;
QString getCommandResult(bool reset = false) const;
QString command() const { return m_command; }
bool execute(QString workingDirectory, QStringList args = QStringList());
bool start(QString workingDirectory, QStringList args = QStringList());
int exitCode() const { return m_exitCode; }
private slots:
void readyReadStandardOutput();
void readyReadStandardError();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
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);
};
#endif // COMMAND_H_INCLUDED

View File

@ -0,0 +1,85 @@
#include "process/exec_opkg_command.h"
#include "worker.h"
#include "utils_internal.h"
#include <QStringList>
ExecOpkgCommand::ExecOpkgCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
bool noaction,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, 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

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

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

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

@ -0,0 +1,136 @@
#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};
qCritical() << __func__ << ":" << __LINE__ << m_command
<< "exitCode" << exitCode
<< "exitStatus" << exitStatus;
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("ATBDownloadDCFirmware")) {
ISMAS::EventData e(ISMAS::CONTINUE,
internal::PERCENT_UPDATE_DC,
0,
"ATBDownloadDCFirmware",
"downloaded new dc-firmware. about to reboot...");
m_worker->clientForUpdate().sendCmdEvent(e);
} else
if (m_command.contains("ATBUpdateShowPSAInstalled")) {
// TODO
}
if (m_worker->workList().nextExec()) {
m_worker->workList().exec();
}
} else {
bool execShowStatus = true;
m_worker->workList().exec(execShowStatus);
}
}
}

View File

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

@ -0,0 +1,28 @@
#include "process/update_dc_command.h"
#include "worker.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) {
return UpdateCommand::finished(exitCode, exitStatus);
}
void UpdateDCCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
// TODO
Worker *w = worker();
if (w) {
// static constexpr const char *UPDATE_DC_FIRMARE_SUCCESS"success"};
emit w->showUpdateDCFirmware(UpdateCommand::UPDATE_DC_FIRMARE_SUCCESS);
}
}
}

View File

@ -0,0 +1,18 @@
#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 = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // UPDATE_DC_COMMAND_H_INCLUDED

View File

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

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

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

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

@ -105,7 +105,6 @@ 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)
@ -116,54 +115,6 @@ Update::Update(Worker *worker,
, m_workingDir(workingDir)
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
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;
#if 0
QObject const *obj = m_hw->getAPI();
Q_ASSERT(obj != nullptr);
QDebug critical = qCritical();
critical << "connect() to onReportDCDownloadStatus() ...";
if (!connect(obj,
SIGNAL(hwapi_reportDCDownloadStatus(QString const&)),
this,
SLOT(onReportDCDownloadStatus(QString const &)))) {
critical << "FAILED";
} else critical << "DONE";
critical = qCritical();
critical << "connect() to onReportDCDownloadSuccess() ...";
if (!connect(obj,
SIGNAL(hwapi_reportDCDownloadSuccess(QString const&)), this,
SLOT(onReportDCDownloadSuccess(QString const &)))) {
critical << "FAILED";
} else critical << "DONE";
critical = qCritical();
critical << "connect() to onReportDCDownloadFailure() ...";
if (!connect(obj,
SIGNAL(hwapi_reportDCDownloadFailure(QString const &)), this,
SLOT(onReportDCDownloadFailure(QString const &)))) {
critical << "FAILED";
} else critical << "DONE";
#endif
}
}
Update::~Update() {
@ -181,43 +132,6 @@ 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;
}
/*
///////////////////////////////////////////////////////////////////////////////
@ -302,98 +216,23 @@ bool Update::isSerialOpen() const {
// bootloader is really not running anymore.
*/
bool Update::updateBinary(QString const &fileToSendToDC) {
qInfo() << "UPDATING DEVICE CONTROLLER FIRMWARE BINARY" << fileToSendToDC;
QFile dc("/opt/app/tools/atbupdate/ATBDownloadDCFirmware");
if (dc.exists()) {
qCritical() << "ERROR: dc-binary does not exist" << fileToSendToDC;
return false;
}
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";
@ -512,6 +351,7 @@ bool Update::downloadJson(enum FileTypeJson type,
// QThread::sleep(1); // make sure the auto-request flag is acknowledged
}
#endif
return true;
}
@ -570,6 +410,7 @@ 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
@ -592,15 +433,17 @@ 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()) {
@ -625,10 +468,12 @@ QString Update::getFileVersion(QString const& jsonFileName) {
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
}
#endif
return fileVersion;
}
bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
#if 0
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
@ -703,6 +548,7 @@ bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
}
}
#endif
return false;
}
@ -710,6 +556,7 @@ QMap<QString, QString>
Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
QMap<QString, QString> map;
#if 0
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! m_hw == nullptr";
@ -809,11 +656,13 @@ Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
}
}
#endif
return map;
}
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
#if 0
if (!m_hw) {
Utils::printInfoMsg("CA-PLUGIN NOT LOADED");
return false;
@ -1020,4 +869,7 @@ bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
qDebug() << "SET AUTO-REQUEST=TRUE";
return res;
#endif
return false;
}

View File

@ -22,7 +22,6 @@ class Worker;
class Update : public QObject {
Q_OBJECT
hwinf *m_hw = nullptr;
Worker *m_worker = nullptr;
char const *m_serialInterface;
char const *m_baudrate;
@ -102,12 +101,6 @@ 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,21 +1,191 @@
#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>
#include <QDir>
#include <QDirIterator>
#include <QRegularExpression>
#include <QProcess>
#include <QJsonDocument>
#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/")) {
QProcess p;
QStringList params;
params << "-c" << R"(/usr/bin/ptuPackageVersions -i -o json)";
p.start("bash", params);
p.waitForFinished();
QString r = p.readAllStandardOutput();
// ptuPackageVersions returns a json-array
QJsonArray const &ja = QJsonDocument::fromJson(r.remove(QRegExp("\\n")).toUtf8()).array();
if (!ja.empty()) {
qCritical() << __LINE__;
// transform the array into an object, containing the objects
// of the array (christian needs it this way)
foreach (QJsonValue const &value, ja) {
if (value.isObject()) {
QJsonObject obj = value.toObject();
QStringList keys = obj.keys();
if (!keys.isEmpty()) {
QString const &k = keys.first();
QJsonValue const &v = obj.value(k);
if (v.isObject()) {
obj = v.toObject();
if (obj.keys().contains("Version")) {
QJsonValue const &w = obj.value("Version");
if (w.isString()) {
QString s = w.toString();
QPair<QString, QString> p(k, s);
vec.push_back(p);
}
}
}
}
}
}
} else {
qCritical() << __func__ << ":" << __LINE__
<< "ERROR array return by ptuPackageVersions empty";
}
} else {
qCritical() << __func__ << ":" << __LINE__
<< "ERROR executing ptuPackageVersions";
}
return vec;
}
int Utils::read1stLineOfFile(QString fileName) {
QFile f(fileName);
if (f.exists()) {
@ -109,7 +279,7 @@ QString Utils::getTariffInfo(QString fileName) {
}
QString Utils::zoneName(quint8 i) {
QString Utils::zoneName(quint8 /* i */) {
//static constexpr char const *zName[] = {
// "",
// "purple",

View File

@ -9,7 +9,10 @@
#include <QDateTime>
#include <QDir>
#include <QDebug>
#include <QPair>
#include <QProcess>
class Worker;
namespace Utils {
int read1stLineOfFile(QString fileName);
QString getLocation(QString fileName);
@ -33,6 +36,12 @@ namespace Utils {
QString getParentName();
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

@ -0,0 +1,32 @@
#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 (nextExec()) {
m_workList[m_workListIndex]->start("/opt/app/tools/atbupdate");
m_workListIndex += 1;
return true;
}
} else {
m_workList.back()->start("/opt/app/tools/atbupdate");
m_workListIndex = std::numeric_limits<unsigned>::max();
return true;
}
return false;
}

View File

@ -0,0 +1,36 @@
#ifndef WORK_LIST_H_INCLUDED
#define WORK_LIST_H_INCLUDED
#include <vector>
#include <memory>
class UpdateCommand;
class WorkList {
public:
std::vector<std::unique_ptr<UpdateCommand>> m_workList;
unsigned m_workListIndex{0};
WorkList() = default;
template<typename T>
void push_back(T&& arg) {
m_workList.push_back(std::forward<T>(arg));
}
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) {
//}
unsigned nextExecIndex() const;
bool nextExec() const;
bool exec(bool last=false);
};
#endif // WORK_LIST_H_INCLUDED

View File

@ -20,12 +20,25 @@
#include <QRegularExpression>
#include <QJsonArray>
#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"
#include "utils.h" // deprecated
#include "utils_internal.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]");
@ -176,8 +189,90 @@ Worker::Worker(int customerNr,
, 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_withoutIsmasDirectPort(false) /* useful for testing */ {
// *** check ISMAS connectivity ***
// NOTE: if the customer repository does not exist, then it does not matter
// if there is a connection to ISMAS (via APISM).
// NOTE: the several processes will be started WorkList::exec().
int next = 1;
m_workList.push_back(
std::make_unique<CheckIsmasConnectivityCommand>(
//QString("echo CheckIsmasConnectivityCommand")
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 CheckUpdateActivationCommand")
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 CheckAndFetchCustomerRepositoryCommand")
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 ExecOpkgCommand 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 json files down to device controller ***
m_workList.push_back(
std::make_unique<UpdateJsonCommand>(
QString("echo ATBDownloadDCJsonFiles")
//QString("/opt/app/tools/atbupdate/ATBDownloadDCJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
, this, ++next, false));
// sync json files in repo etc-directory with /etc fs-directory
m_workList.push_back(
std::make_unique<UpdateFileSystemCommand>(
QString("echo ATBUpdateSync")
, this, ++next));
// send device-controller firmware down to device-controller-hardware
m_workList.push_back(
std::make_unique<UpdateDCCommand>(
QString("echo ATBDownloadDCFirmware")
// QString("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")
, this, ++next));
// show/send software-status
m_workList.push_back(
std::make_unique<ShowSoftwareStatusCommand>(
QString("echo ATBUpdateShowPSAInstalled")
, this, -1));
// reboot machine
///////////////////////////////////////////////////////////
m_start = QDateTime::currentDateTime();
m_dcDownloadFirmware->setWorker(this);
m_dcDownloadJsonFiles->setWorker(this);
// TODO: turn object into singleton
instance = this;
@ -284,6 +379,8 @@ void Worker::privateUpdate() {
return;
}
return;
QString func(__PRETTY_FUNCTION__);
GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::STARTED));
@ -1267,6 +1364,7 @@ QString Worker::getPluginVersion(QString const &pluginFileName) const {
QStringList Worker::getDCVersion() const {
QStringList lst = (QStringList() << "N/A" << "N/A");
#if 0
Update const *up = update();
if (up) {
hwinf const *caPlugin = up->hw();
@ -1288,6 +1386,7 @@ QStringList Worker::getDCVersion() const {
}
}
}
#endif
return lst;
}
@ -1500,3 +1599,94 @@ 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();
vec.append(Utils::installedTariffFiles(this, m_customerRepository));
vec.append(Utils::installedJsonFiles(this, m_customerRepository));
int max_first = 0, max_second = 0;
for (int i = 0; i < vec.size(); ++i) {
max_first = std::max(max_first, vec[i].first.length());
max_second = std::max(max_second, vec[i].second.length());
}
max_first += 5;
summary = "UPDATE SUMMARY\n\n";
first = QString("%1").arg("start", max_first, QChar(' '));
tmp = QString("%1").arg(start().toString(Qt::ISODate));
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
first = QString("%1").arg("update tool version", max_first, QChar(' '));
tmp = QString("%1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME);
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
first = QString("%1").arg("machine number", max_first, QChar(' '));
tmp = QString("%1").arg(machineNr());
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
first = QString("%1").arg("customer number", max_first, QChar(' '));
tmp = QString("%1").arg(customerNr());
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
first = QString("%1").arg("zone number", max_first, QChar(' '));
tmp = QString("%1").arg(zoneNr());
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
if (m_mainWindow) {
tmp = m_mainWindow->targetDcVersion();
if (!tmp.isEmpty()) {
first = QString("%1").arg("target device controller", max_first, QChar(' '));
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
}
}
first = QString("%1").arg("apism", max_first, QChar(' '));
tmp = QString("%1").arg(apismVersion());
second = QString("%1").arg(tmp, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
for (int i = 0; i < vec.size(); ++i) {
first = QString("%1").arg(vec[i].first, max_first, QChar(' '));
second = QString("%1").arg(vec[i].second, -max_second, QChar(' '));
line = first + ": " + second;
summary += line + "\n";
}
emit showSummary(summary);
emit enableExit();
}

View File

@ -11,14 +11,17 @@
#include <QMap>
#include <QDebug>
#include <QThread>
#include <QByteArray>
#include <QScopedPointer>
#include <optional>
#include <initializer_list>
#include "update.h"
#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"
@ -135,6 +138,8 @@
#define ISMAS_UPDATE_REQUESTS (10)
#define CHECK_UPDATE_TRIGGER_SET "Check update trigger ..."
class Command;
class Update;
class MainWindow;
class hwinf;
class Worker : public QThread{
@ -189,9 +194,14 @@ class Worker : public QThread{
QStringList m_ismasTriggerStatusMessage;
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;
@ -394,6 +404,9 @@ public:
return m_ismasClient;
}
ApismClientForUpdate &clientForUpdate() { return m_clForUpdate; }
ApismClientForUpdate const &clientForUpdate() const { return m_clForUpdate; }
Worker *GUI(QStringList const &lst = QStringList()) {
m_guiMsg = lst;
return this;
@ -458,8 +471,19 @@ 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; }
signals:
void appendText(QString, QString suffix = "");
void insertText(QString);
void replaceLast(QString, QString);
void replaceLast(QStringList, QString);
void showErrorMessage(QString title, QString description);
@ -470,6 +494,21 @@ signals:
void restartExitTimer();
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 showSummary(QString);
void setDcDownloadProgress(int);
private slots:
bool updateTriggerSet();
@ -480,6 +519,9 @@ private slots:
// bool sendIsmasLastVersionNotification(int progress);
bool saveLogFile();
public slots:
void readyReadStandardOutput();
private:
PSAInstalled getPSAInstalled();
static bool sendLastVersionOnce;
@ -487,6 +529,9 @@ private:
bool computeFilesToDownload();
bool execOpkgCommands();
QDateTime m_start;
QByteArray m_standardOutput;
static const QMap<UPDATE_STEP, const char*> smap;
// CONSOLE()

View File

@ -25,7 +25,9 @@ public:
static bool umountSDCard();
static std::optional<QString> checkForUSBStick(QString const &dirPathUnderMountPath = ".");
static std::optional<QString> checkForSDCard(QString const &dirPathUnderMountPath = ".");
static QString getUSBMountPath(QString const &dirPathUnderMountPath = ".");
static QString getSDMountPath(QString const &dirPathUnderMountPath = ".");
//static QString getUSBDeviceName();
static bool umountUSBStick();
@ -54,7 +56,8 @@ public:
static QString getPTU4MACAddress();
static QStringList getJsonFilesOnUsbStick(QString const &mountPath);
static QString getDCFileOnUsbStick(QString const &mountPath);
static QString getDCFileOnSDCard(QString const &mountPath);
};
#endif // SYSTEM_H

49
common/include/command.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef COMMAND_H_INCLUDED
#define COMMAND_H_INCLUDED
#include <QObject>
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QProcess>
#include <QScopedPointer>
class Command : public QObject {
Q_OBJECT
QString m_command;
QString m_commandResult;
int m_waitForStartTimeout;
int m_waitForFinishTimeout;
bool m_verbose;
int m_exitCode;
QString m_workingDirectory;
QScopedPointer<QProcess> m_p;
QStringList m_args;
public:
Command(QString command,
QStringList args,
QString workingDirectory,
bool verbose = true,
int start_timeout = 100000,
int finish_timeout = 100000);
void resetCommandResult() { m_commandResult.clear(); }
QString getCommandResult(bool reset = false);
QString const &command() const { return m_command; }
QString const &commandResult() const { return m_commandResult; }
QStringList const &args() const { return m_args; }
bool exec();
int exitCode() const { return m_exitCode; }
private slots:
virtual void readyReadStandardOutput();
virtual void readyReadStandardError();
};
#endif // COMMAND_H_INCLUDED

16
common/include/utils.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef UTILS_INTERNAL_H_INCLUDED
#define UTILS_INTERNAL_H_INCLUDED
#include <QString>
namespace internal {
int read1stLineOfFile(QString fileName);
QString customerRepoRoot();
QString customerRepoDir();
QString customerRepoDirName();
QString repositoryUrl();
QString branchName();
bool customerRepoExists();
}
#endif // UTILS_INTERNAL_H_INCLUDED

View File

@ -0,0 +1,69 @@
#ifndef UTILS_INTERNAL_H_INCLUDED
#define UTILS_INTERNAL_H_INCLUDED
#include <QString>
namespace internal {
static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
static constexpr const char *UPDATE_REQUESTED{"requested"};
static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"};
static constexpr const char *ISMAS_CONNECTED{"connected"};
static constexpr const char *ISMAS_DISCONNECTED{"disconnected"};
static constexpr const char *ISMAS_DISCONNECTING{"disconnecting"};
static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
static constexpr const int GIT_CHECKOUT_ERROR_CODE{-2};
static constexpr const int GIT_PULL_ERROR_CODE{-4};
static constexpr const int GIT_NOT_NECESSARY_CODE{1};
static constexpr const int GIT_UPDATED_CODE{2};
static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"};
static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"};
static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
static constexpr const char *GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY{"no repository update necessary"};
static constexpr const char *GIT_CUSTOMER_REPO_NOT_NECESSARY{"not necessary"};
static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"};
static constexpr const char *GIT_UPDATED{"updated"};
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
static constexpr const char *EXEC_OPKG_COMMANDS_FAIL{"FAIL"};
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_SUCCESS{"success"};
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_FAIL{"FAIL"};
static constexpr const char *UPDATE_DC_JSON_FILES_SUCCESS{"success"};
static constexpr const char *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
static constexpr const char *UPDATE_DC_FIRMARE_SUCCESS{"success"};
static constexpr const char *OPKG_MARKER{"<OPKG>"};
static constexpr const char *SYNC_MARKER{"<SYNC>"};
static constexpr const char *DC_MARKER{"<DC>"};
static constexpr const char *GIT_MARKER{"<GIT>"};
static constexpr const char *ISMAS_MARKER{"<ISMAS>"};
static constexpr const int PERCENT_CHECK_ISMAS_CONNECIVITY{10};
static constexpr const int PERCENT_CHECK_UPDATE_REQUEST{20};
static constexpr const int PERCENT_CHECK_CUSTOMER_REPOSITORY{30};
static constexpr const int PERCENT_INSTALL_SW_PACKETS_NOACTION{40};
static constexpr const int PERCENT_INSTALL_SW_PACKETS{50};
static constexpr const int PERCENT_INSTALL_DC_CONFIGURATION{60};
static constexpr const int PERCENT_SYNCHRONIZE_REPO_AND_FILESYS{70};
static constexpr const int PERCENT_UPDATE_DC{80};
static constexpr const int PERCENT_SHOW_FINAL_STATUS{90};
int read1stLineOfFile(QString fileName);
QString customerRepoRoot();
QString customerRepoDir();
QString customerRepoDirName();
QString repositoryUrl();
QString branchName();
bool customerRepoExists();
}
#endif // UTILS_INTERNAL_H_INCLUDED

View File

@ -0,0 +1,336 @@
#include "ApismClient.h"
#include <QDebug>
#include <QByteArray>
#include <QHostAddress>
#include <QString>
#include <QList>
#include <QListIterator>
#include <QScopedPointer>
#include <QProcess>
#include <QRegularExpression>
ApismClient::ApismClient(QObject *parent)
: QObject(parent)
, lastError(0)
, lastErrorDescription("")
, currentRequest(ISMAS::REQUEST::NO_REQUEST)
, retryCounter(0)
, flagValidParameter(false)
{
this->apismTcpSendClient.reset(new ApismTcpClient("127.0.0.1", "7777", ApismTcpClient::ExpectedResponse::STATE, this));
this->apismTcpRequestResponseClient.reset(new ApismTcpClient("127.0.0.1", "7778", ApismTcpClient::ExpectedResponse::JSON, this));
this->apismTcpRequestResponseClient->setResponseTimeout(30000);
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::receivedData,
this, &ApismClient::onReceivedResponse);
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::responseTimeout,
this, &ApismClient::onRequestResponseClientResponseTimeout);
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectTimeout,
this, &ApismClient::onRequestResponseClientConnectTimeout);
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionClosedByRemoteHost,
this, &ApismClient::onRequestResponseClientConnectionClosedByRemoteHost);
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionRefusedError,
this, &ApismClient::restartApism);
connect(apismTcpSendClient.get(), &ApismTcpClient::responseTimeout,
this, &ApismClient::onSendClientResponseTimeout);
connect(apismTcpSendClient.get(), &ApismTcpClient::connectionRefusedError,
this, &ApismClient::restartApism);
// not needed as APISM closes the socket after we send data, so readyRead()
// might not even fire
// connect(&m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
// defined for Qt >= 5.15, we have 5.12
// qRegisterMetaType<QAbstractSocket::SocketError>();
// connect(&m_socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
// this, SLOT(onSocketError(&QAbstractSocket::SocketError)));
// switch of DEBUG:
this->apismTcpSendClient->setDebug(true);
this->apismTcpRequestResponseClient->setDebug(true);
}
ApismClient::~ApismClient() {
}
void ApismClient::restartApism() {
QProcess::startDetached("/bin/systemctl", {"restart", "apism"});
}
void ApismClient::sendSelfTest() {
this->currentRequest = ISMAS::REQUEST::SELF;
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_SELF#J={}");
}
void ApismClient::sendRequestParameter() {
this->currentRequest = ISMAS::REQUEST::PARAMETER;
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_ISMASPARAMETER#J={}");
}
void ApismClient::handleISMASResponseError()
{
switch (this->currentRequest) {
case ISMAS::REQUEST::NO_REQUEST:
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: " << currentRequest;
break;
case ISMAS::REQUEST::PING:
//emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
break;
case ISMAS::REQUEST::SELF:
//emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
break;
case ISMAS::REQUEST::PARAMETER:
//emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
break;
}
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
}
void ApismClient::handleISMASOfflineResponseError()
{
nsApismInterface::RESULT_STATE resultState;
if (this->retryCounter < 50) {
resultState = nsApismInterface::RESULT_STATE::ERROR_RETRY;
this->retryCounter++;
}
else {
resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
this->retryCounter = 0;
}
qCritical() << "ApismClient::handleISMASOfflineResponseError(): currentRequest is " << this->currentRequest;
switch (this->currentRequest) {
case ISMAS::REQUEST::NO_REQUEST:
break;
case ISMAS::REQUEST::PING:
//emit this->sendMininformPingResponse(resultState, QJsonObject());
//break;
case ISMAS::REQUEST::SELF:
emit this->sendReqSelfResponse(resultState, QJsonObject());
break;
case ISMAS::REQUEST::PARAMETER:
emit this->sendReqParameterResponse(resultState, QJsonObject());
break;
}
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
// note: this does not work here, because a new request within this error handling method
// must use a new socket connection!
// This does not work with an allready open socket connection.
/* Communication to APISM must be in the following way:
* 1) establish socket connection
* 2) send your request to this socket
* 3) wait for a possible answer
* 4) receive the answer
* 5) close socket connection
*
* => a request can only be sent to apsim if the socket is closed!
* => apism (socket) is blocked systemwide until socket is closed!
* =>
*/
//this->sendSelfTest();
}
void ApismClient::private_handleErrorResponse(QString errorString)
{
qCritical() << "------------------------------------------------------";
qCritical() << "ApismClient::private_handleErrorResponse(" << errorString << ")";
qCritical() << " this->retryCounter = " << this->retryCounter;
qCritical() << "------------------------------------------------------";
this->handleISMASOfflineResponseError();
}
/*
{\r\n \"REQ_START#53365_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
\r\n \"Response\": {\r\n \"Result\": \"ERR:Ung<6E>ltiger Datums-String: \"\r\n }\r\n}
*/
/*
: ISMAS received: "{\r\n \"REQ_PING#30844_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
"PING": { "IsAviable": "TRUE" }
}"
*/
//void ApismClient::onSendClientResponseTimeout()
//{
//
//}
void ApismClient::private_handleReqSelfResponse(QJsonObject response)
{
bool ismasConnected = response["ISMAS"].toBool();
QString brokerConnectedString = response["Broker"].toString();
qCritical() << "ApismClient::handleReqSelfResponse() " << endl
<< " ismasConnected = " << ismasConnected << endl
<< " brokerConnectedString = " << brokerConnectedString;
/* possible values: "Restart connection"
* "Connected"
* "NOT CONNECTED"
*/
if (brokerConnectedString == "NOT CONNECTED") {
qCritical() << "ApismClient: \"NOT CONNECTED\": restart APISM";
this->restartApism();
}
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
}
/**
* sample parameter response:
{
"REQ_ISMASPARAMETER#4210959_Response": {
"Aknoledge": "OK"
},
"Dev_ID": {
"Device_Type": "2020",
"Custom_ID": 332,
"Device_ID": 99
},
"Fileupload": {
"TRG": ""
},
"Parameter": {
"Location": "An Der Bahn 11",
"Group": "Group1",
"Zone": "Zone1",
"Name": "PSA",
"SecNumber": "0",
"LastAcc": "0",
"GPSLat": "49.6062",
"GPSLon": "12.1244",
"TarifID": "none",
"UserTextID": "1"
"TERMINALID": "",
"TERMINALKEY": ""
},
"Lock": {
"Locked": "0"
}
}
*/
void ApismClient::private_handleParameterResponse(QJsonObject response)
{
// extract location info and store location info in persistent data:
QJsonValue jsonSubVal_Location;
jsonSubVal_Location = response["Location"];
QString locationString = jsonSubVal_Location.toString("no location");
//this->persistentData->setParameter("Location", locationString);
// feature UserText
QJsonValue jsonSubVal_UserText;
jsonSubVal_UserText = response["UserTextID"];
QString userTextIdString = jsonSubVal_UserText.toString("0");
//this->persistentData->setParameter("UserTextID", userTextIdString);
// TERMINALID
//QJsonValue jsonSubVal_TERMINALID;
//jsonSubVal_TERMINALID = response["TERMINALID"];
//QString terminalIdString = jsonSubVal_TERMINALID.toString("");
//QString terminalIdFile = this->m_config->getSystemDataPath() + "TERMINALID";
//QString terminalIdStringOrigin = ATBSystem::readPSAConfigString(terminalIdFile);
//if ( (terminalIdString.size() > 1) &&
// (terminalIdString != terminalIdStringOrigin))
//{
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALID: " << terminalIdString;
// ATBSystem::setPSAConfigString(terminalIdFile, terminalIdString);
//}
// TERMINALKEY
//QJsonValue jsonSubVal_TERMINALKEY;
//jsonSubVal_TERMINALKEY = response["TERMINALKEY"];
//QString terminalKeyString = jsonSubVal_TERMINALKEY.toString("");
//QString terminalJeyFile = this->m_config->getSystemDataPath() + "TERMINALKEY";
//QString terminalKeyStringOrigin = ATBSystem::readPSAConfigString(terminalJeyFile);
//if ( (terminalKeyString.size() > 1) &&
// (terminalKeyString != terminalKeyStringOrigin))
//{
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALKEY: " << terminalKeyString;
//
// ATBSystem::setPSAConfigString(terminalJeyFile, terminalKeyString);
//}
//qCritical() << "ApismClient::handleParameterResponse() " << endl
// << " Location = " << locationString << endl
// << " UserTextID = " << userTextIdString << endl
// << " TERMINALID = " << terminalIdString << endl
// << " TERMINALKEY = " << terminalKeyString;
if (locationString != "no location") {
this->flagValidParameter = true;
emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
}
}
void ApismClient::private_handleFileUploadResponse(QJsonObject response) {
QJsonValue jsonSubVal_TRG{response["TRG"]};
if (jsonSubVal_TRG.isUndefined()) {
return;
}
bool updateRequested = (jsonSubVal_TRG.toString("") == "WAIT");
}
/************************************************************************************************
* operators
*/
QDebug operator<< (QDebug debug, ISMAS::REQUEST request)
{
switch(request) {
case ISMAS::REQUEST::NO_REQUEST:
debug << QString("ISMAS::REQUEST::NO_REQUEST");
break;
case ISMAS::REQUEST::PING:
debug << QString("ISMAS::REQUEST::PING");
break;
case ISMAS::REQUEST::SELF:
debug << QString("ISMAS::REQUEST::SELF");
break;
case ISMAS::REQUEST::PARAMETER:
debug << QString("ISMAS::REQUEST::PARAMETER");
break;
}
return debug;
}
QString& operator<< (QString& str, ISMAS::REQUEST request)
{
switch(request) {
case ISMAS::REQUEST::NO_REQUEST:
str = QString("ISMAS::REQUEST::NO_REQUEST");
break;
case ISMAS::REQUEST::PING:
str = QString("ISMAS::REQUEST::PING");
break;
case ISMAS::REQUEST::SELF:
str = QString("ISMAS::REQUEST::SELF");
break;
case ISMAS::REQUEST::PARAMETER:
str = QString("ISMAS::REQUEST::PARAMETER");
break;
}
return str;
}

View File

@ -0,0 +1,99 @@
#ifndef APISM_CLIENT_H_INCLUDED
#define APISM_CLIENT_H_INCLUDED
#include "ISMASData.h"
#include "ApismTcpClient.h"
#include <QObject>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonParseError>
#include <QJsonValue>
#include <QScopedPointer>
QDebug operator<<(QDebug debug, ISMAS::REQUEST request);
QString& operator<<(QString& str, ISMAS::REQUEST request);
namespace nsApismInterface {
enum class RESULT_STATE : quint8 {
SUCCESS = 1,
ERROR_BACKEND = 2, // error from backand (e.g. backend replies with error)
ERROR_NETWORK = 3, // error from network (e.g. host not available)
ERROR_TIMEOUT = 4, // the operation timed out
ERROR_PROCESS = 5, // internal plugin error (e.g. bug in implementation)
ERROR_RETRY = 6, // retry operation
INFO = 7
};
}
// class ISMAS::EventData;
class ApismClient : public QObject {
Q_OBJECT
public:
explicit ApismClient(QObject *parent = 0);
virtual ~ApismClient() = 0;
quint32 getLastError();
const QString & getLastErrorDescription();
ISMAS::REQUEST getCurrentRequest() const { return currentRequest; }
void setCurrentRequest(ISMAS::REQUEST r) { currentRequest = r; }
void resetRetryCounter() { retryCounter = 0; }
int getRetryCounter() const { return retryCounter; }
int incrRetryCounter() { return ++retryCounter; }
ApismTcpClient *tcpSendClient() { return apismTcpSendClient.get(); }
ApismTcpClient *tcpRequestResponseClient() { return apismTcpRequestResponseClient.get(); }
public slots:
void sendSelfTest();
void sendRequestParameter();
void restartApism();
signals:
void sendReqSelfResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
void sendReqParameterResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
private slots:
virtual void onReceivedResponse(QByteArray response) = 0;
virtual void onSendClientResponseTimeout() = 0;
virtual void onRequestResponseClientResponseTimeout() = 0;
virtual void onRequestResponseClientConnectTimeout() = 0;
virtual void onRequestResponseClientConnectionClosedByRemoteHost() = 0;
private:
QScopedPointer<ApismTcpClient> apismTcpSendClient;
QScopedPointer<ApismTcpClient> apismTcpRequestResponseClient;
quint32 lastError;
QString lastErrorDescription;
ISMAS::REQUEST currentRequest;
// counter, incremented if we get an offline response from ISMAS
// causes a resend of the currentRequest.
int retryCounter;
// true, if ISMAS REQ_ISAMASPARAMETER got a valid response
bool flagValidParameter;
void private_handlePingResponse(QJsonObject response);
void private_handleReqSelfResponse(QJsonObject response);
void private_handleReqPingResponse(QJsonObject response);
void private_handleParameterResponse(QJsonObject response);
void private_handleFileUploadResponse(QJsonObject response);
void private_handleErrorResponse(QString errorString);
public:
void handleISMASResponseError();
void handleISMASOfflineResponseError();
};
#endif // APISM_CLIENT_H_INCLUDED

View File

@ -0,0 +1,216 @@
#include "ApismClientForUpdate.h"
#include <QRegularExpression>
ApismClientForUpdate::ApismClientForUpdate(QObject *parent)
: ApismClient(parent) {
}
ApismClientForUpdate::~ApismClientForUpdate() {
}
void ApismClientForUpdate::sendCmdEvent(ISMAS::EventData eventData) {
// QScopedPointer<ISMAS::EventData> eventData(new ISMAS::EventData());
/*
struct EventData : public QJsonObject {
struct : public QJsonObject {
QJsonValue reason;
QJsonValue timestamp;
QJsonValue eventID;
QJsonValue event;
QJsonValue eventState;
struct : public QJsonObject {
QJsonValue percent;
QJsonValue resultCode;
QJsonValue step;
QJsonValue stepResult;
QJsonValue Version;
} parameter;
} newsToIsmas;
};
"\"REASON\":\"SW_UP\","
"\"TIMESTAMP\":\"%s\","
"\"EVENT_ID\":\"0\","
"\"EVENT\":\"%s\","
"\"EVENTSTATE\":1,"
"\"PARAMETER\": {"
"\"PERCENT\" : %d,"
"\"RESULTCODE\" : %d,"
"\"STEP\" : \"%s\","
"\"STEP_RESULT\" : \"%s\","
"\"VERSION\" : \"%s\""
"}"
"}", ts.toStdStr
*/
//eventData->newsToIsmas.reason = data.newsToIsmas;
eventData.insert("REASON", eventData.newsToIsmas.reason);
eventData.insert("TIMESTAMP", eventData.newsToIsmas.timestamp);
eventData.insert("EVENT_ID", eventData.newsToIsmas.eventID);
eventData.insert("EVENT", eventData.newsToIsmas.event);
eventData.insert("EVENT_STATE", eventData.newsToIsmas.eventState);
QJsonObject parameterJsonObject;
parameterJsonObject.insert("PERCENT", eventData.newsToIsmas.parameter.percent);
parameterJsonObject.insert("RESULTCODE", eventData.newsToIsmas.parameter.resultCode);
parameterJsonObject.insert("STEP", eventData.newsToIsmas.parameter.step);
parameterJsonObject.insert("STEP_RESULT", eventData.newsToIsmas.parameter.stepResult);
parameterJsonObject.insert("VERSION", eventData.newsToIsmas.parameter.version);
eventData.insert("PARAMETER", parameterJsonObject);
qCritical() << __func__ << ":" << __LINE__ << eventData;
QJsonDocument jsonDoc(eventData);
QByteArray data = "#M=APISM#C=CMD_EVENT#J=";
data += jsonDoc.toJson(QJsonDocument::Compact);
qCritical() << __func__ << ":" << __LINE__ << data;
tcpSendClient()->sendData(data);
}
void ApismClientForUpdate::onReceivedResponse(QByteArray response) {
// get the root object
QJsonParseError jsonParseError;
QJsonDocument responseDoc = QJsonDocument::fromJson(response, &jsonParseError);
if (jsonParseError.error != QJsonParseError::NoError) {
qCritical() << "ApismClient::onReceivedResponse() response is no json data:";
qCritical() << " Error: " << jsonParseError.errorString();
// workaround for REQ_SELF and offline
if (this->getCurrentRequest() == ISMAS::REQUEST::SELF) {
if (response.contains("Connecting...")) {
qCritical() << " -> Connecting...";
return;
}
if (response.contains("ISMAS is offline")) {
this->restartApism();
qCritical() << " -> Workaround: restart APISM";
return;
}
}
if (response.contains("ISMAS is offline")) {
this->handleISMASOfflineResponseError();
return;
}
else {
this->handleISMASResponseError();
return;
}
}
QJsonObject rootObject = responseDoc.object();
QStringList rootObjectKeys = rootObject.keys();
// DEBUG
qCritical() << "ApismClient::onReceivedResponse(): objects: " << rootObjectKeys;
// results to:
// ApismClient::onReceivedResponse(): objects: ("REQ_START#60044_Response", "Response")
if(rootObjectKeys.indexOf(QRegularExpression("^CMD_GET_APISMSTATUS.*")) >= 0) {
resetRetryCounter();
//this->private_handleReqSelfResponse(rootObject["CMD_GET_APISMSTATUS_RESPONSE#0"].toObject());
}
else
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_ISMASPARAMETER.*")) >= 0) {
resetRetryCounter();
//this->private_handleParameterResponse(rootObject["Parameter"].toObject());
}
else
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_PING.*")) >= 0) {
resetRetryCounter();
//this->private_handleReqPingResponse(rootObject["PING"].toObject());
}
else
if(rootObjectKeys.indexOf(QRegularExpression("^error")) >= 0) {
// handle error objects
//this->private_handleErrorResponse(rootObject["error"].toString());
}
else {
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: ";
qCritical() << " currentRequestName: " << getCurrentRequest();
qCritical() << " rootObject.keys(): " << rootObjectKeys;
this->handleISMASResponseError();
return;
}
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
}
void ApismClientForUpdate::onSendClientResponseTimeout() {
}
void ApismClientForUpdate::onRequestResponseClientResponseTimeout() {
qCritical() << "ApismClient::onRequestResponseClientResponseTimeout(): currentRequest is " << this->getCurrentRequest();
switch (this->getCurrentRequest()) {
case ISMAS::REQUEST::NO_REQUEST:
break;
case ISMAS::REQUEST::PING:
//emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
break;
case ISMAS::REQUEST::SELF:
//emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
break;
case ISMAS::REQUEST::PARAMETER:
//emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
break;
}
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
}
void ApismClientForUpdate::onRequestResponseClientConnectTimeout() {
qCritical() << "ApismClient::onRequestResponseClientConnectTimeout(): currentRequest is " << this->getCurrentRequest();
nsApismInterface::RESULT_STATE resultState;
resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
switch (this->getCurrentRequest()) {
case ISMAS::REQUEST::NO_REQUEST:
qCritical() << "ApismClient::onRequestResponseClientConnectTimeout() for unknown Request: " << getCurrentRequest();
break;
case ISMAS::REQUEST::PING:
//emit this->sendMininformPingResponse(resultState, QJsonObject());
break;
case ISMAS::REQUEST::SELF:
//emit this->sendReqSelfResponse(resultState, QJsonObject());
break;
case ISMAS::REQUEST::PARAMETER:
//emit this->sendReqParameterResponse(resultState, QJsonObject());
break;
}
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
}
void ApismClientForUpdate::onRequestResponseClientConnectionClosedByRemoteHost() {
nsApismInterface::RESULT_STATE resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
switch (this->getCurrentRequest()) {
case ISMAS::REQUEST::NO_REQUEST:
qCritical() << "ApismClient::onRequestResponseClientConnectionClosedByRemoteHost() for unknown Request: " << getCurrentRequest();
break;
case ISMAS::REQUEST::PING:
//emit this->sendMininformPingResponse(resultState, QJsonObject());
break;
case ISMAS::REQUEST::SELF:
emit this->sendReqSelfResponse(resultState, QJsonObject());
break;
case ISMAS::REQUEST::PARAMETER:
emit this->sendReqParameterResponse(resultState, QJsonObject());
break;
}
this->setCurrentRequest(ISMAS::REQUEST::NO_REQUEST);
}

View File

@ -0,0 +1,24 @@
#ifndef APISM_CLIENT_FOR_UPDATE_H_INCLUDED
#define APISM_CLIENT_FOR_UPDATE_H_INCLUDED
#include "ApismClient.h"
class ApismClientForUpdate : public ApismClient {
public:
explicit ApismClientForUpdate(QObject *parent = 0);
virtual ~ApismClientForUpdate();
public slots:
void sendCmdEvent(ISMAS::EventData);
private slots:
virtual void onReceivedResponse(QByteArray response) override;
virtual void onSendClientResponseTimeout() override;
virtual void onRequestResponseClientResponseTimeout() override;
virtual void onRequestResponseClientConnectTimeout() override;
virtual void onRequestResponseClientConnectionClosedByRemoteHost() override;
};
#endif // APISM_CLIENT_FOR_UPDATE_H_INCLUDED

View File

@ -0,0 +1,564 @@
#include "ApismTcpClient.h"
#include <QHostAddress>
#include <QTimer>
ApismMessage::ApismMessage() : state(MessageState::INVALID) { }
ApismTcpClient::ApismTcpClient(const QString & hostname,
const QString & port,
ExpectedResponse expectedResponse,
QObject *parent)
: QObject(parent)
, hostname(hostname)
, port(port)
, responseTimerTimeoutCounter(0)
, flag_selfClosed(false)
, resendCounter(0)
, connectionRefusedCounter(0)
, expectedResponse(expectedResponse)
, isDebug(false)
{
this->responseTimeoutTimer = new QTimer(this);
this->responseTimeoutTimer->setInterval(10000);
this->responseTimeoutTimer->setSingleShot(true);
connect(this->responseTimeoutTimer, SIGNAL(timeout()), this, SLOT(onResponseTimeoutTimerTimeout()));
this->connectTimeoutTimer = new QTimer(this);
this->connectTimeoutTimer->setInterval(10000);
this->connectTimeoutTimer->setSingleShot(true);
connect(this->connectTimeoutTimer, SIGNAL(timeout()), this, SLOT(onConnectTimeoutTimerTimeout()));
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(onSocketConnected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onSocketBytesWritten(qint64)));
// note: from Qt 5.15 onward a new signal "errorOccurred" will be introduced which could be used whithout this static_cast.
// see e.g. https://stackoverflow.com/questions/35655512/compile-error-when-connecting-qtcpsocketerror-using-the-new-qt5-signal-slot
connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), this, &ApismTcpClient::onSocketErrorOccured);
connect(socket, &QTcpSocket::stateChanged, this, &ApismTcpClient::onSocketStateChanged);
this->currentMessage = ApismMessage();
}
void ApismTcpClient::setResponseTimeout(const quint32 timeout_ms)
{
this->responseTimeoutTimer->setInterval(timeout_ms);
}
void ApismTcpClient::setDebug(bool debug)
{
this->isDebug = debug;
}
void ApismTcpClient::connectToHost()
{
this->connectTimeoutTimer->start();
int portNumber = this->port.toInt();
this->socket->connectToHost(QHostAddress(this->hostname), portNumber);
}
void ApismTcpClient::connectToHost(const QString & hostname, const QString & port)
{
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::connectToHost(" << hostname << ", " << port << ")";
this->connectTimeoutTimer->start();
int portNumber = port.toInt();
socket->connectToHost(hostname, portNumber);
}
void ApismTcpClient::closeConnection()
{
this->flag_selfClosed = true;
socket->close();
}
bool ApismTcpClient::isConnected()
{
bool result = false;
QAbstractSocket::SocketState socketState = socket->state();
switch (socketState) {
case QAbstractSocket::UnconnectedState:
/* FALLTHRU */
case QAbstractSocket::HostLookupState:
/* FALLTHRU */
case QAbstractSocket::ConnectingState:
result = false;
break;
case QAbstractSocket::ConnectedState:
/* FALLTHRU */
case QAbstractSocket::BoundState:
result = true;
break;
case QAbstractSocket::ClosingState:
/* FALLTHRU */
case QAbstractSocket::ListeningState:
result = false;
break;
}
return result;
}
/**
* @brief ApismTcpClient::sendData
* @param message
*
* Enqueue message, and try to send it
*/
void ApismTcpClient::sendData(const QByteArray &message)
{
if (this->isDebug) {
qCritical() << "ApismTcpClient::sendData(" << message << ")";
}
this->sendQueue.enqueue(message);
this->sendData();
}
/**
* @brief ApismTcpClient::sendData
*
* Check connection and try to send message from queue.
*/
void ApismTcpClient::sendData()
{
if (this->sendQueue.size() == 0) {
if (this->isDebug) {
qCritical() << "ApismTcpClient::sendData()" << "no messages in send queue";
}
return;
}
// DEBUG
if (this->isDebug) {
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::sendData() sendQueue.size() = " << this->sendQueue.size();
}
switch (this->currentMessage.state) {
case ApismMessage::MessageState::INVALID:
/* FALLTHROUGH */
case ApismMessage::MessageState::NEW:
/* FALLTHROUGH */
case ApismMessage::MessageState::RESEND:
/* FALLTHROUGH */
case ApismMessage::MessageState::ANSWERED:
// allow send message
if (this->isConnected()) {
this->private_sendData();
}
else {
this->connectToHost();
}
break;
case ApismMessage::MessageState::SENT:
// wait for answer...
if (this->isDebug) {
qCritical() << " ... wait for answer";
}
break;
}
}
/**
* @brief ApismTcpClient::private_sendData
*
* Precondition:
* - queue is not empty,
* - socket state is connected
* - current message is ANSWERED or INVALID
*/
void ApismTcpClient::private_sendData()
{
// take message from queue
this->currentMessage.data = this->sendQueue.dequeue();
this->currentMessage.state = ApismMessage::MessageState::SENT;
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::send: " << QString(this->currentMessage.data);
socket->write(this->currentMessage.data);
socket->flush();
// start timeoutTimer
this->responseTimeoutTimer->start();
}
void ApismTcpClient::onSocketConnected()
{
qCritical() << "ApismTcpClient(" << this->expectedResponse << "): Connected!";
this->connectTimeoutTimer->stop();
this->connectionRefusedCounter = 0;
switch (this->currentMessage.state) {
case ApismMessage::MessageState::INVALID:
/* FALLTHROUGH */
case ApismMessage::MessageState::NEW:
/* FALLTHROUGH */
case ApismMessage::MessageState::RESEND:
/* FALLTHROUGH */
case ApismMessage::MessageState::ANSWERED:
// allow send next message
if (this->sendQueue.size() > 0) {
this->private_sendData();
}
break;
case ApismMessage::MessageState::SENT:
// wait for answer...
break;
}
}
void ApismTcpClient::onSocketDisconnected()
{
qCritical() << "ApismTcpClient(" << this->expectedResponse << "): Disconnected!";
if (!this->flag_selfClosed) {
qCritical() << " -> SocketErrorString: " << socket->errorString();
}
this->flag_selfClosed = false;
if ( (socket->error() == QAbstractSocket::SocketError::RemoteHostClosedError) &&
(this->responseTimeoutTimer->isActive()) )
{
this->responseTimeoutTimer->stop();
qCritical() << " -> still waiting for response ";
switch (this->expectedResponse) {
case ApismTcpClient::ExpectedResponse::STATE:
// try resend:
this->currentMessage.state = ApismMessage::MessageState::RESEND;
// enqeue current message for resend:
this->sendQueue.prepend(this->currentMessage.data);
this->sendData();
break;
case ApismTcpClient::ExpectedResponse::JSON:
this->currentMessage.state = ApismMessage::MessageState::INVALID;
emit this->connectionClosedByRemoteHost();
break;
}
}
}
void ApismTcpClient::onSocketBytesWritten(qint64 bytes)
{
if (this->isDebug) {
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onSocketBytesWritten() -> " << bytes << " bytes written";
}
}
void ApismTcpClient::onSocketReadyRead()
{
QByteArray readData;
// stop timeoutTimer
this->responseTimeoutTimer->stop();
readData = socket->readAll();
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::received: " << QString(readData);
switch (this->expectedResponse) {
case ApismTcpClient::ExpectedResponse::JSON:
this->private_handleJSONResponse(readData);
break;
case ApismTcpClient::ExpectedResponse::STATE:
this->private_handleStateResponse(readData);
break;
}
if (this->sendQueue.size() > 0) {
QTimer::singleShot(1000,
this,
[this]() { this->sendData(); }
);
}
else {
this->flag_selfClosed = true;
this->socket->close();
}
}
/******************************************************************************
* response handler:
*/
void ApismTcpClient::private_handleJSONResponse(QByteArray & responseMessage)
{
emit this->receivedData(responseMessage);
// allow send next message:
this->currentMessage.state = ApismMessage::MessageState::ANSWERED;
this->resendCounter = 0;
}
/* possible answers:
* "RECORD SAVED" --> everything is ok
* "RECORD WRITE ABORTED" --> initiate a (delayed) resend
*
*/
void ApismTcpClient::private_handleStateResponse(QByteArray & responseMessage)
{
QString responseMessageString = QString(responseMessage);
if (responseMessageString.contains("ABORTED")) {
// Try to resend later:
this->currentMessage.state = ApismMessage::MessageState::RESEND;
// enqeue current message for resend:
this->sendQueue.prepend(this->currentMessage.data);
}
else
if (responseMessageString.contains("RECORD SAVED")) {
// allow send next message:
this->currentMessage.state = ApismMessage::MessageState::ANSWERED;
this->resendCounter = 0;
}
}
/******************************************************************************
*/
void ApismTcpClient::onResponseTimeoutTimerTimeout()
{
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onResponseTimeoutTimerTimeout():";
switch (this->currentMessage.state) {
case ApismMessage::MessageState::INVALID:
/* FALLTHROUGH */
case ApismMessage::MessageState::NEW:
/* FALLTHROUGH */
case ApismMessage::MessageState::ANSWERED:
// ignore
qCritical() << " -> ignore timeout";
return;
break;
case ApismMessage::MessageState::RESEND:
qCritical() << " -> timeout (RESEND)";
qCritical() << " -> resendCounter = " << this->resendCounter;
switch (this->expectedResponse) {
case ApismTcpClient::ExpectedResponse::STATE:
// try resend:
this->currentMessage.state = ApismMessage::MessageState::RESEND;
// enqeue current message for resend:
this->sendQueue.prepend(this->currentMessage.data);
this->sendData();
break;
case ApismTcpClient::ExpectedResponse::JSON:
this->currentMessage.state = ApismMessage::MessageState::INVALID;
emit this->responseTimeout();
break;
}
break;
case ApismMessage::MessageState::SENT:
// we still do not have a response:
switch (this->expectedResponse) {
case ApismTcpClient::ExpectedResponse::STATE:
// try resend:
this->currentMessage.state = ApismMessage::MessageState::RESEND;
// enqeue current message for resend:
this->sendQueue.prepend(this->currentMessage.data);
this->sendData();
break;
case ApismTcpClient::ExpectedResponse::JSON:
this->currentMessage.state = ApismMessage::MessageState::INVALID;
emit this->responseTimeout();
break;
}
break;
}
// count resends
this->resendCounter++;
}
void ApismTcpClient::onConnectTimeoutTimerTimeout()
{
if (this->sendQueue.size() == 0) {
return;
}
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onConnectTimeoutTimerTimeout() -> sendQueue.size() = " << this->sendQueue.size();
emit this->connectTimeout();
}
void ApismTcpClient::onSocketStateChanged(QAbstractSocket::SocketState socketState)
{
QString msg;
switch (socketState) {
case QAbstractSocket::UnconnectedState:
msg = "UnconnectedState";
break;
case QAbstractSocket::HostLookupState:
msg = "HostLookupState";
break;
case QAbstractSocket::ConnectingState:
msg = "ConnectingState";
break;
case QAbstractSocket::ConnectedState:
msg = "ConnectedState";
break;
case QAbstractSocket::BoundState:
msg = "BoundState";
break;
case QAbstractSocket::ClosingState:
msg = "ClosingState";
break;
case QAbstractSocket::ListeningState:
msg = "ListeningState";
break;
}
if (this->isDebug) {
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::onSocketStateChanged() to: " << msg;
}
}
void ApismTcpClient::onSocketErrorOccured(QAbstractSocket::SocketError socketError)
{
QString msg;
bool flagReconnect = false;
switch (socketError) {
case QAbstractSocket::ConnectionRefusedError:
msg = "ConnectionRefusedError";
flagReconnect = true;
this->private_handleConnectionRefusedError();
break;
case QAbstractSocket::RemoteHostClosedError:
msg = "RemoteHostClosedError";
break;
case QAbstractSocket::HostNotFoundError:
msg = "HostNotFoundError";
break;
case QAbstractSocket::SocketAccessError:
msg = "SocketAccessError";
break;
case QAbstractSocket::SocketResourceError:
msg = "SocketResourceError";
break;
case QAbstractSocket::SocketTimeoutError:
msg = "SocketTimeoutError";
break;
case QAbstractSocket::DatagramTooLargeError:
msg = "DatagramTooLargeError";
break;
case QAbstractSocket::NetworkError:
msg = "NetworkError";
break;
case QAbstractSocket::AddressInUseError:
msg = "AddressInUseError";
break;
case QAbstractSocket::SocketAddressNotAvailableError:
msg = "SocketAddressNotAvailableError";
break;
case QAbstractSocket::UnsupportedSocketOperationError:
msg = "UnsupportedSocketOperationError";
break;
case QAbstractSocket::ProxyAuthenticationRequiredError:
msg = "ProxyAuthenticationRequiredError";
break;
case QAbstractSocket::SslHandshakeFailedError:
msg = "SslHandshakeFailedError";
break;
case QAbstractSocket::UnfinishedSocketOperationError:
msg = "UnfinishedSocketOperationError";
break;
case QAbstractSocket::ProxyConnectionRefusedError:
msg = "ProxyConnectionRefusedError";
break;
case QAbstractSocket::ProxyConnectionClosedError:
msg = "ProxyConnectionClosedError";
break;
case QAbstractSocket::ProxyConnectionTimeoutError:
msg = "ProxyConnectionTimeoutError";
break;
case QAbstractSocket::ProxyNotFoundError:
msg = "ProxyNotFoundError";
break;
case QAbstractSocket::ProxyProtocolError:
msg = "ProxyProtocolError";
break;
case QAbstractSocket::OperationError:
msg = "OperationError";
break;
case QAbstractSocket::SslInternalError:
msg = "SslInternalError";
break;
case QAbstractSocket::SslInvalidUserDataError:
msg = "SslInvalidUserDataError";
break;
case QAbstractSocket::TemporaryError:
msg = "TemporaryError";
break;
case QAbstractSocket::UnknownSocketError:
msg = "UnknownSocketError";
break;
}
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::ApismTcpClient::onSocketErrorOccured() -> " << msg;
if (flagReconnect) {
// try to reconnect for sending:
if (this->sendQueue.size() > 0) {
QTimer::singleShot(1000,
this,
[this]() { this->connectToHost(); }
);
}
}
}
void ApismTcpClient::private_handleConnectionRefusedError()
{
if (this->connectionRefusedCounter > 5) {
qCritical() << "ApismTcpClient(" << this->expectedResponse << ")::ApismTcpClient::connectionRefusedError()";
this->connectionRefusedCounter = 0;
emit this->connectionRefusedError();
}
else {
this->connectionRefusedCounter++;
}
}
QDebug operator<<(QDebug debug, ApismTcpClient::ExpectedResponse response)
{
switch (response) {
case ApismTcpClient::ExpectedResponse::JSON:
debug << "JSON";
break;
case ApismTcpClient::ExpectedResponse::STATE:
debug << "STATE";
break;
}
return debug;
}

View File

@ -0,0 +1,116 @@
#ifndef APISMTCPCLIENT_H
#define APISMTCPCLIENT_H
#include <QObject>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QByteArray>
#include <QQueue>
class QTimer;
class ApismMessage
{
public:
enum class MessageState {
INVALID,
NEW,
SENT,
ANSWERED,
RESEND
};
MessageState state;
QByteArray data;
ApismMessage();
};
class ApismTcpClient : public QObject
{
Q_OBJECT
public:
enum class ExpectedResponse {
JSON,
STATE
};
explicit ApismTcpClient(const QString & hostname, const QString & port, ExpectedResponse expectedResponse, QObject *parent = nullptr);
bool isConnected();
void connectToHost();
void connectToHost(const QString & hostname, const QString & port);
void setResponseTimeout(const quint32 timeout_ms);
// socket is implicitely closed by APISM
void closeConnection();
void sendData(const QByteArray & message);
void sendData();
void setDebug(bool debug);
private slots:
// socket interface
void onSocketConnected();
void onSocketDisconnected();
void onSocketBytesWritten(qint64 bytes);
void onSocketReadyRead();
void onSocketStateChanged(QAbstractSocket::SocketState socketState);
void onSocketErrorOccured(QAbstractSocket::SocketError socketError);
signals:
void receivedData(QByteArray response);
void responseTimeout();
void connectTimeout();
void connectionClosedByRemoteHost();
void connectionRefusedError();
private:
QTcpSocket *socket;
QQueue<QByteArray> sendQueue;
ApismMessage currentMessage;
QString hostname;
QString port;
QTimer *responseTimeoutTimer;
quint8 responseTimerTimeoutCounter;
QTimer *connectTimeoutTimer;
void private_sendData();
bool flag_selfClosed;
int resendCounter;
int connectionRefusedCounter;
ExpectedResponse expectedResponse;
void private_handleJSONResponse(QByteArray & responseMessage);
void private_handleTextResponse(QByteArray & responseMessage);
void private_handleStateResponse(QByteArray & responseMessage);
void private_handleConnectionRefusedError();
bool isDebug;
public slots:
void onResponseTimeoutTimerTimeout();
void onConnectTimeoutTimerTimeout();
};
QDebug operator<<(QDebug debug, ApismTcpClient::ExpectedResponse response);
#endif // APISMTCPCLIENT_H

148
common/ismas/ISMASData.h Normal file
View File

@ -0,0 +1,148 @@
#ifndef ISMASDATA_H
#define ISMASDATA_H
#include <QJsonObject>
#include <QJsonArray>
#include <QDateTime>
namespace ISMAS {
static QString computeTimeStamp() {
QDateTime const local(QDateTime::currentDateTime());
QDateTime utc(local);
utc.setTimeSpec(Qt::UTC);
int const diff = (int)local.secsTo(utc); // diff between UTC and local time
QTime t(0, 0, 0);
t = t.addSecs((uint)diff);
QString const st(QString("%1%2").arg(diff < 0 ? "-" : "+").arg(t.toString("hh:mm")));
return QString (local.toString(Qt::ISODateWithMs) + st);
}
enum RESULT_CODE {
E_SUCCESS=0,
// if between 00:00 - 04:00 Wait-button state not WAIT, then we assume
// that's an automatic nightly (not-necessary) update
E_NO_UPDATE_NECESSARY=1,
// if APISM reports the ISMAS is not available (15x, 6s delay each)
E_ISMAS_NO_CONNECTION_ERROR=2,
// if not within 00:00-04:00 and WAIT-button was not in state WAIT
E_ISMAS_TRIGGER_ERROR=3,
// cloning git repo. not possible
E_GIT_CLONE_ERROR=4,
// pulling from remote git server not possible
E_GIT_PULL_ERROR=5,
// fetching from remote git server not possible
E_GIT_FETCH_ERROR=6,
// merging fetched data not possible
E_GIT_MERGE_ERROR=7,
// check sanity of local customer-repository failed
E_GIT_CHECK_REPOSITORY_ERROR=8,
// switch/checkout of branch (i.e. zone) on error
E_GIT_SWITCH_BRANCH_ERROR=9,
// fetch/pull of new branch failed. the new branch was not available
// when installing via SD-card followed by intial clone during the
// update process.
E_GIT_FETCH_NEW_BRANCH_ERROR=10,
// error computing git-blob hash-value
E_GIT_HASH_ERROR=11,
// update for general json files failed.
E_JSON_FILES_UPDATE_ERROR=12,
// error downloading config-json-files to device controller
E_JSON_FILES_DOWNLOAD_ERROR=13,
// error downloading device-controller
E_DC_DOWNLOAD_ERROR=14,
// error rsyncing json/ini-files to local filesystem
E_RSYN_ERROR=15,
// HASH_VALUE_ERROR=14,
// HW_COMPATIBILITY_ERROR=15,
E_OPKG_COMMANDS_ERROR=16,
// CLEANUP_ERROR=18,
E_UPDATE_IN_ERROR_STATE=99
};
//
// Note:
// ! After U0002 immer ein CMD_SENDVERSION
// ! Only U0002 and U0003 finish the Update process.
// ! U0001: Update finished but not activated
// ! U0002: Update finished and activated
// ! U0003: Update finished but FAILed.
//
// #define _ISMAS_DONE "U0001" // 100%, Check: Resultcode: 0
// #define _ISMAS_SET_WAIT_OK "U0002" // empty WAIT-button (""), ResultCode: 0
// #define _ISMAS_NO_UPDATE_NECESSARY "M0100" // empty WAIT-button (""), ResultCode: 0
// #define _ISMAS_FAILURE "U0003" // FAIL
// #define _ISMAS_CONTINUE "U0010" // %-values: update running, result codes according running step
// #define _ISMAS_RESET_WAIT "ISMAS" // reset WAIT-button to "WAIT"
// #define _ISMAS_TEST_TRIGGER "U0099" // check the WAIT-button
static constexpr const char *DONE {"U0001"};
static constexpr const char *SET_WAIT_OK {"U0002"};
static constexpr const char *NO_UPDATE_NECESSARY{"M0100"};
static constexpr const char *FAILURE {"U0003"};
static constexpr const char *CONTINUE {"U0010"};
static constexpr const char *RESET_WAIT {"ISMAS"};
static constexpr const char *TEST_TRIGGER {"U0099"};
struct EventData : public QJsonObject {
struct : public QJsonObject {
QJsonValue reason;
QJsonValue timestamp;
QJsonValue eventID;
QJsonValue event;
QJsonValue eventState;
struct : public QJsonObject {
QJsonValue percent;
QJsonValue resultCode;
QJsonValue step;
QJsonValue stepResult;
QJsonValue version;
} parameter;
} newsToIsmas;
explicit EventData(QString const &event,
int percent,
int resultCode,
QString const &step,
QString const &stepResult,
QString const &version = "",
QString const &reason = "SW_UP") {
newsToIsmas.reason = reason;
newsToIsmas.timestamp = computeTimeStamp();
newsToIsmas.eventID = QString{"0"};
newsToIsmas.event = event;
newsToIsmas.eventState = 1;
newsToIsmas.parameter.percent = percent;
newsToIsmas.parameter.resultCode = resultCode;
newsToIsmas.parameter.step = step;
newsToIsmas.parameter.stepResult = stepResult;
newsToIsmas.parameter.version = version;
}
};
struct StateData : public QJsonObject {
QJsonValue Timestamp;
QJsonArray HW_States;
struct : public QJsonObject {
QJsonValue name;
QJsonValue value;
QJsonValue unit;
} machineState; //
};
enum class REQUEST : quint8 {
NO_REQUEST,
PING,
SELF,
PARAMETER
};
}
#endif // ISMASDATA_H

View File

@ -265,6 +265,20 @@ std::optional<QString> System::checkForUSBStick(QString const &dirPathUnderMount
return mountPath.isEmpty() ? std::nullopt : std::optional<QString>(mountPath);
}
std::optional<QString> System::checkForSDCard(QString const &dirPathUnderMountPath) {
#if defined (ARCH_DesktopLinux)
// DEBUG / TEST:
if (QFileInfo(getSDMountPath()).isDir())
return true;
else
return false;
#endif
QString const &mountPath = getSDMountPath(dirPathUnderMountPath);
// qCritical() << "MOUNT-PATH" << mountPath;
return mountPath.isEmpty() ? std::nullopt : std::optional<QString>(mountPath);
}
/**
@ -315,7 +329,7 @@ QString System::getUSBMountPath(QString const &dirPathUnderMountPath) {
mountLine = line.split(' ');
if (mountLine.size() > 3) {
qCritical() << "System::getUSBMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2);
// qCritical() << "System::getUSBMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2);
QDir d(QDir::cleanPath(mountLine.at(2) + QDir::separator() + dirPathUnderMountPath));
if (d.exists()) {
return mountLine.at(2);
@ -332,6 +346,64 @@ QString System::getUSBMountPath(QString const &dirPathUnderMountPath) {
return "";
}
QString System::getSDMountPath(QString const &dirPathUnderMountPath) {
#if defined (ARCH_DesktopLinux)
// DEBUG / TEST:
return QDir::homePath().append("/APconfigTest/USB");
#endif
QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
QStringList mountLine;
qDebug() << "System::getSDMountPath()";
QRegExp devRegExp = QRegExp("dev/mmc*", Qt::CaseSensitive, QRegExp::WildcardUnix);
QRegExp mountRegExp = QRegExp("media/mmc*", Qt::CaseSensitive, QRegExp::WildcardUnix);
QString commandString = "mount";
process.start(commandString);
if (!process.waitForStarted()) {
errorMsg = "System::getSDMountPath(): ERROR: waitForStarted()";
return "";
}
if (!process.waitForFinished(600000)) {
errorMsg = "System::getSDMountPath(): ERROR: " + process.errorString();
qDebug() << errorMsg;
return "";
}
else {
QByteArray bytes = process.readAll();
QStringList lines = QString(bytes).split("\n");
foreach (QString line, lines) {
qDebug() << "System::getSDMountPath() line: " << line;
if (line.contains(devRegExp) && line.contains(mountRegExp)) {
qDebug() << " -> this line is a usb storage device mount" << line;
mountLine = line.split(' ');
if (mountLine.size() > 3) {
// qCritical() << "System::getSDMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2);
QDir d(QDir::cleanPath(mountLine.at(2) + QDir::separator() + dirPathUnderMountPath));
if (d.exists()) {
return mountLine.at(2);
} else {
qCritical() << "directory" << d.absolutePath() << "does not exist";
}
}
}
}
}
qDebug() << "System::getSDMountPath() no mounted usb device found!";
return "";
}
QStringList System::getJsonFilesOnUsbStick(QString const &mountPath) {
QStringList jsonFiles;
@ -354,6 +426,38 @@ QStringList System::getJsonFilesOnUsbStick(QString const &mountPath) {
return jsonFiles;
}
QString System::getDCFileOnUsbStick(QString const &mountPath) {
QString dcFile;
// /media/sda2/etc/dc
QString const &dirPath = QDir::cleanPath(mountPath + QDir::separator() + "etc" + QDir::separator() + "dc");
QDir d(dirPath);
if (d.exists()) {
QFileInfo fi(dirPath + QDir::separator() + "dc2c.bin");
if (fi.exists()) {
dcFile = fi.absoluteFilePath();
}
}
return dcFile;
}
QString System::getDCFileOnSDCard(QString const &mountPath) {
QString dcFile;
// /media/sda2/etc/dc
QString const &dirPath = QDir::cleanPath(mountPath + QDir::separator() + "etc" + QDir::separator() + "dc");
QDir d(dirPath);
if (d.exists()) {
QFileInfo fi(dirPath + QDir::separator() + "dc2c.bin");
if (fi.exists()) {
dcFile = fi.absoluteFilePath();
}
}
return dcFile;
}
/********************************************************************************
* static function to check if a mounted sd-card is writable.
*

128
common/src/command.cpp Normal file
View File

@ -0,0 +1,128 @@
#include "command.h"
#include <QProcess>
#include <QDebug>
#include <QDir>
#include <QRegularExpression>
#include <QDateTime>
Command::Command(QString command, QStringList args, QString workingDirectory,
bool verbose, int start_timeout, int finish_timeout)
: m_command(command.trimmed())
, m_commandResult("")
, m_waitForStartTimeout(start_timeout)
, m_waitForFinishTimeout(finish_timeout)
, m_verbose(verbose)
, m_exitCode(-1)
, m_workingDirectory(workingDirectory)
, m_args(args) {
m_p.reset(new QProcess(this));
if (m_p) {
m_p->setWorkingDirectory(workingDirectory);
m_p->setProcessChannelMode(QProcess::MergedChannels);
connect(m_p.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
connect(m_p.get(), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
}
}
void Command::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
if (m_verbose) {
// qCritical().noquote() << s;
m_commandResult += s;
}
}
}
void Command::readyReadStandardError() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardError();
// qCritical().noquote() << s;
m_commandResult += s;
}
}
QString Command::getCommandResult(bool reset) {
if (reset == false) {
return m_commandResult;
}
QString commandResult = m_commandResult;
m_commandResult.clear();
return commandResult;
}
bool Command::exec() {
if (!m_args.isEmpty()) {
m_p->start(m_command, m_args);
} else {
m_p->start(m_command);
}
qint64 const start = QDateTime::currentDateTime().toMSecsSinceEpoch();
bool started = false;
if ((started = m_p->waitForStarted(m_waitForStartTimeout)) == true) {
// qCritical() << "PROCESS" << m_command << "STARTED IN" << m_p->workingDirectory();
if (m_p->state() == QProcess::ProcessState::Running) {
// qDebug() << "PROCESS" << m_command << "RUNNING IN" << p->workingDirectory();
// wait forever for git/opkg-commands to finish
int wait = m_waitForFinishTimeout;
if (m_command.trimmed().startsWith("git", Qt::CaseInsensitive) ||
m_command.trimmed().startsWith("opkg", Qt::CaseInsensitive)) {
wait = -1;
}
bool const no_timeout = m_p->waitForFinished(wait);
if (no_timeout) {
// qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory();
if (m_p->exitStatus() == QProcess::NormalExit) {
if ((m_exitCode = m_p->exitCode()) == 0) {
qCritical().noquote() << m_p->readAllStandardOutput();
//qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
//qDebug() << "EXECUTED" << m_command
// << QString("(runtime %1ms)").arg(end-start)
// << "with code" << m_exitCode
// << "IN" << m_p->workingDirectory();
return true;
} else {
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
qCritical() << "EXECUTED" << m_command
<< QString("(runtime %1ms)").arg(end-start)
<< "with code" << m_exitCode
<< "IN" << m_p->workingDirectory();
}
} else {
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
qCritical() << "PROCESS" << m_command << "CRASHED with code"
<< m_p->exitCode()
<< QString("(after %1ms)").arg(end-start)
<< "IN" << m_p->workingDirectory();
}
} else {
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
qCritical() << "PROCESS" << m_command
<< "DID NOT FINISH WITH" << wait
<< "MS IN" << m_p->workingDirectory()
<< QString("(runtime %1ms)").arg(end-start);
}
} else {
qCritical() << "WRONG PROCESS STATE" << m_p->state()
<< "IN" << m_p->workingDirectory();
}
} else {
qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch();
qCritical() << "PROCESS" << m_command << "TIMEOUT AT START"
<< QString("(runtime %1ms)").arg(end-start)
<< "IN" << m_p->workingDirectory() << m_waitForStartTimeout;
}
return false;
}

55
common/src/utils.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "utils.h"
#include <QFile>
#include <QDir>
#include <QTextStream>
namespace internal {
int read1stLineOfFile(QString fileName) {
QFile f(fileName);
if (f.exists()) {
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&f);
in.setCodec("UTF-8");
while(!in.atEnd()) {
return in.readLine().toInt();
}
}
}
return -1;
}
QString customerRepoRoot() {
return "/opt/app/tools/atbupdate/";
}
QString customerRepoDirName() {
int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
return (customerNr != -1) ? QString("customer_%1").arg(customerNr) : "";
}
QString customerRepoDir() {
QString const &n = customerRepoDirName();
QString const &r = customerRepoRoot();
return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : "";
}
bool customerRepoExists() {
QString const repoDir{customerRepoDir()};
return !repoDir.isEmpty() ? QDir(repoDir).exists() : false;
}
QString repositoryUrl() {
return "gitea@ptu-config.atb-comm.de:ATB/";
}
QString branchName() {
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
if (zoneNr != -1) {
return QString("zg1/zone%1").arg(zoneNr);
}
return "";
}
} // namespace internal

View File

@ -0,0 +1,55 @@
#include "utils.h"
#include <QFile>
#include <QDir>
#include <QTextStream>
namespace internal {
int read1stLineOfFile(QString fileName) {
QFile f(fileName);
if (f.exists()) {
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&f);
in.setCodec("UTF-8");
while(!in.atEnd()) {
return in.readLine().toInt();
}
}
}
return -1;
}
QString customerRepoRoot() {
return "/opt/app/tools/atbupdate/";
}
QString customerRepoDirName() {
int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
return (customerNr != -1) ? QString("customer_%1").arg(customerNr) : "";
}
QString customerRepoDir() {
QString const &n = customerRepoDirName();
QString const &r = customerRepoRoot();
return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : "";
}
bool customerRepoExists() {
QString const repoDir{customerRepoDir()};
return !repoDir.isEmpty() ? QDir(repoDir).exists() : false;
}
QString repositoryUrl() {
return "gitea@ptu-config.atb-comm.de:ATB/";
}
QString branchName() {
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
if (zoneNr != -1) {
return QString("zg1/zone%1").arg(zoneNr);
}
return "";
}
} // namespace internal

View File

@ -0,0 +1,135 @@
\documentclass[fontsize=11
pt,a4paper,draft]{scrartcl}[2003/01/01]
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp}
\usepackage{blindtext}
\usepackage{mathpazo}
\usepackage{amsmath}
\usepackage{listings}
\usepackage{minted}
\usepackage{setspace}
\usepackage[acronym]{glossaries}
\usepackage{euler}
\usepackage[]{mdframed}
\usepackage{tabularx}
\usepackage{hyperref}
\usepackage{pifont}
\usepackage{float}
\usepackage{multirow}
\usepackage{uml}
\usepackage{tikz,pgfplots}
\usetikzlibrary{math}
\global\mdfdefinestyle{default}{%
linecolor=black,linewidth=1pt,%
innertopmargin=20,innerbottommargin=20
}
\lstset{emph={any-of,all-off},emphstyle=\textbf}
\title{ATB Update Tool(s)}
%\author{Gerhard Hoffmann}
\date{\today\\\normalsize Version 0.1.0}
% \newacronym{pnd}{PND}{\textbf{p}ay \textbf{and} \textbf{d}isplay machine}
% \newacronym{psa}{PSA}{pay and display machine}
\newglossaryentry{ISMAS}{%
name=ISMAS,
description={\textbf{I}ntelligentes \textbf{S}ervice
\textbf{M}anagement und \textbf{A}bbrechnungs\textbf{S}ystem}
}%
\newglossaryentry{ATBUpdateCheck}{%
name=ATBUpdateCheck,
description={Tool for checking ISMAS connectivity and for checking
the customer repository}%
}%
\newglossaryentry{ATBUpdateGit}{%
name=ATBUpdateGit,
description={}
}%
\newglossaryentry{ATBUpdateOpkg}{%
name=ATBUpdateOpkg,
description={}
}%
\newglossaryentry{ATBUpdateSync}{%
name=ATBUpdateSync,
description={}
}%
\newglossaryentry{ATBUpdateShow}{%
name=ATBUpdateShow,
description={}
}%
\newglossaryentry{ATBUpdateDC}{%
name=ATBUpdateDC,
description={}
}%
\newglossaryentry{ATBUpdateDCConfig}{%
name=ATBUpdateDCConfig,
description={}
}%
\makeglossaries
\begin{document}
\maketitle
\tableofcontents
\section*{History}
\begin{table}[htbp]
\centering
\begin{tabularx}{\textwidth}{|>{\hsize=.15\hsize}c|>{\hsize=.25\hsize}X|>{\hsize
=.6\hsize}X|}
\hline
\textbf{Version} & \textbf{Date} & \textbf{Comment} \\
\hline
0.1.0 & \today & \\ \hline
\end{tabularx}
\end{table}
\pagebreak
\section{Introduction}
\section{ATBUpdateCheck}
\gls{ATBUpdateCheck}
\gls{ISMAS}
\section{ATBUpdateGit}
\gls{ATBUpdateGit}
\section{ATBUpdateOpkg}
\gls{ATBUpdateOpkg}
\section{ATBUpdateSync}
\gls{ATBUpdateSync}
\section{ATBUpdateDCConfig}
\gls{ATBUpdateDCConfig}
\section{ATBUpdateDC}
\gls{ATBUpdateDC}
\section{ATBUpdateShow}
\gls{ATBUpdateShow}
\section{Known issues}
\pagebreak
% Print the glossary
\printglossaries
\end{document}