Compare commits

..

54 Commits

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

View File

@@ -9,7 +9,7 @@ psa-tariff-directory="etc/psa_tariff/"
[PLUGINS] [PLUGINS]
plugin-name="libCAslave.so" plugin-name="libCAmaster.so"
[FLAGS] [FLAGS]
no-psa-hardware-update=false no-psa-hardware-update=false

View File

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

View File

@@ -1,82 +0,0 @@
QT += core
TARGET = ATBUpdateCheck
VERSION="1.0.0"
win32 {
BUILD_DATE=$$system("date /t")
BUILD_TIME=$$system("time /t")
} else {
BUILD_DATE=$$system("date +%d-%m-%y")
BUILD_TIME=$$system("date +%H:%M:%S")
}
GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += \
plugins \
$${INCLUDEINTERFACES} \
$${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17
DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
DEFINES+=APP_BUILD_DATE=\\\"$$BUILD_DATE\\\"
DEFINES+=APP_BUILD_TIME=\\\"$$BUILD_TIME\\\"
DEFINES+=APP_EXTENDED_VERSION=\\\"$$EXTENDED_VERSION\\\"
# keep comments, as /* fall through */
QMAKE_CXXFLAGS += -C
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS += -Wno-deprecated-copy -O
contains( CONFIG, PTU5 ) {
CONFIG += link_pkgconfig
QMAKE_CXXFLAGS += -O2 -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
INCLUDEPATH += $$PTU5BASEPATH/qt/libs/devicecontroller/include
LIBS += -L$$PTU5BASEPATH/qt/libs/devicecontroller/library
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, PTU5_YOCTO ) {
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, DesktopLinux ) {
# QMAKE_CC = ccache $$QMAKE_CC
# QMAKE_CXX = ccache $$QMAKE_CXX
QMAKE_CXXFLAGS += -std=c++17
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
ARCH = DesktopLinux
DEFINES+=DesktopLinux
}
SOURCES += \
main.cpp \
ismas_client.cpp \
message_handler.cpp \
../common/src/utils_internal.cpp
HEADERS += \
ismas_client.h \
message_handler.h \
../common/include/utils_internal.h
##########################################################################################
# for running program on target through QtCreator
contains( CONFIG, PTU5 ) {
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/app/tools/atbupdate/
!isEmpty(target.path): INSTALLS += target
}

View File

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

View File

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

View File

@@ -1,163 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QRegularExpression>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <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;
}

View File

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

View File

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

View File

@@ -1,7 +1,9 @@
QT += core gui QT += core serialport
QT += widgets serialport network
TARGET = ATBUpdateDC
include(../common.pri)
TARGET = ATBDownloadDCFirmware
VERSION="0.1.0" VERSION="0.1.0"
win32 { win32 {
@@ -77,21 +79,21 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
mainwindow.cpp \
../common/src/message_handler.cpp \ ../common/src/message_handler.cpp \
../UpdatePTUDevCtrl/commandline_parser.cpp \ ../UpdatePTUDevCtrl/commandline_parser.cpp \
update.cpp \ update.cpp \
dc_download.cpp \ ../common/src/System.cpp \
../common/src/System.cpp ../common/src/utils_internal.cpp \
../common/src/command.cpp
HEADERS += \ HEADERS += \
mainwindow.h \
../common/include/message_handler.h \ ../common/include/message_handler.h \
../UpdatePTUDevCtrl/commandline_parser.h \ ../UpdatePTUDevCtrl/commandline_parser.h \
update.h \ update.h \
dc_download.h \ ../common/include/System.h \
../common/include/System.h ../common/include/utils_internal.h \
../common/include/command.h
OTHER_FILES += \ OTHER_FILES += \

View File

@@ -1,7 +1,6 @@
#include <QtGlobal> #include <QtGlobal>
#include <QCoreApplication> #include <QCoreApplication>
#include <QApplication>
#include <QByteArray> #include <QByteArray>
#include <QProcess> #include <QProcess>
@@ -11,12 +10,13 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QThread> #include <QThread>
#include <QRegularExpression>
#include "message_handler.h" #include "message_handler.h"
#include "commandline_parser.h" #include "commandline_parser.h"
#include "utils.h" #include "utils.h"
#include "utils_internal.h"
#include "update.h" #include "update.h"
#include "mainwindow.h"
#include "System.h" #include "System.h"
#include <DeviceController/interfaces.h> #include <DeviceController/interfaces.h>
@@ -54,15 +54,20 @@ int main(int argc, char **argv) {
openlog("DC", LOG_PERROR | LOG_CONS, LOG_USER); openlog("DC", LOG_PERROR | LOG_CONS, LOG_USER);
QApplication a(argc, argv); QCoreApplication a(argc, argv);
QApplication::setApplicationName("ATBDownloadDCFirmware"); QCoreApplication::setOrganizationName("ATB Automatentechnik Baumann GmBH");
QApplication::setApplicationVersion(APP_VERSION); QCoreApplication::setApplicationName("ATBUpdateDC");
QCoreApplication::setApplicationVersion(APP_VERSION);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(atbDebugOutput); atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(LOG_NOTICE); setDebugLevel(LOG_NOTICE);
} }
//return 0;
/*
CommandLineParser parser; CommandLineParser parser;
parser.process(a); parser.process(a);
parser.readSettings(); parser.readSettings();
@@ -127,6 +132,35 @@ int main(int argc, char **argv) {
QString const &customerRepo QString const &customerRepo
= QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr)); = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
*/
QString const &psaDcDir = internal::customerRepoDcDir();
QString const &psaRepoRootDir = internal::customerRepoRoot();
QString const &psaRepoDir = internal::customerRepoDir();
QString const &branchName = internal::branchName();
bool debug = false;
bool noaction = true;
QString workingDir;
QString libDir;
QString libca;
std::unique_ptr<QSettings> settings = internal::readSettings();
if (settings) {
settings->beginGroup("DIRECTORIES");
workingDir = settings->value("workingdir", "/tmp").toString();
libDir = settings->value("plugin-directory", "/usr/lib/").toString();
settings->endGroup();
settings->beginGroup("FLAGS");
debug = settings->value("debug", false).toBool();
settings->endGroup();
settings->beginGroup("PLUGINS");
libca = libDir + settings->value("plugin-name", "libCAslave.so").toString();
settings->endGroup();
}
// etc/dc: located under mount-path // etc/dc: located under mount-path
std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir); std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir);
@@ -137,47 +171,32 @@ int main(int argc, char **argv) {
if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) { if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) {
fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value())); fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value()));
} else { } else {
qInfo() << "using customer repository" << customerRepo;
QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/dc")); if (debug) {
if (dir.exists()) { qInfo() << "using customer repository" << psaRepoDir;
fi.setFile(dir, dir.absoluteFilePath("dc2c.bin")); }
} else {
qCritical() << "DIRECTORY" << dir << "DOES NOT EXIST"; std::unique_ptr<QString> c = internal::dcCandidateToInstall("/etc/dc/");
if (c) {
fi.setFile(*c);
if (fi.exists() == false) {
qCritical() << "dc2c.bin candidate" << *c << "does not exist. STOP.";
return -1; return -1;
} }
qInfo() << "dc2c.bin canditate" << fi.absoluteFilePath();
}
} }
qInfo() << "downloading dc-firmware .." << fi.absoluteFilePath(); if (debug) {
qInfo() << "dc-firmware size (bytes) ." << fi.size(); qInfo() << "downloading dc-firmware" << fi.absoluteFilePath();
if (readDCVersion) { qInfo() << "dc-firmware size (bytes)" << fi.size();
qInfo() << "dc-version ..............." << Update::dcVersion(fi.absoluteFilePath()); qInfo() << "dc-version" << Update::dcVersion(fi.absoluteFilePath());
} }
QThread::currentThread()->setObjectName("main thread"); Update u(fi.absoluteFilePath(), libca, debug, noaction);
// qInfo() << "Main thread" << QThread::currentThreadId(); u.run();
Update update(customerRepo,
QString::number(customerNr),
branchName,
plugInDir,
plugInName,
workingDir,
psaDcDir);
update.doUpdate(fi.absoluteFilePath());
// MainWindow mw;
// mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
// mw.showFullScreen();
// qCritical() << "SHOW";
// mw.show();
qInfo() << "<DC-UPDATE-FINISH>"; qInfo() << "<DC-UPDATE-FINISH>";
return 0; return 0;
// return a.exec();
} }

View File

@@ -1,10 +1,7 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer> #include <QTimer>
#include <QStatusBar>
#include <QWidget>
#include <QSerialPort> #include <QSerialPort>
#include <QSerialPortInfo> #include <QSerialPortInfo>

View File

@@ -1,5 +1,5 @@
#include "update.h" #include "update.h"
#include "process/command.h" #include "command.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QFile> #include <QFile>
@@ -24,10 +24,14 @@
#include <QMap> #include <QMap>
#include <QStringList> #include <QStringList>
#include <QString> #include <QString>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QSettings>
#define UPDATE_OPKG (1) #define UPDATE_OPKG (1)
#define UPDATE_DC (0) #define UPDATE_DC (0)
static const QMap<QString, int> baudrateMap = { static const QMap<QString, int> baudrateMap = {
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3}, {"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
{"57600" , 4}, {"115200" , 5} {"57600" , 4}, {"115200" , 5}
@@ -35,25 +39,19 @@ static const QMap<QString, int> baudrateMap = {
QPluginLoader Update::pluginLoader; QPluginLoader Update::pluginLoader;
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) { hwinf *Update::loadDCPlugin(QString const &libCA /* absolute file path */) {
hwinf *hw = nullptr; hwinf *hw = nullptr;
if (plugInDir.exists()) { QFileInfo libCAInfo(libCA);
QString pluginLibName(fname); if (libCAInfo.exists()) {
pluginLibName = plugInDir.absoluteFilePath(pluginLibName); pluginLoader.setFileName(libCA);
QFileInfo info(pluginLibName);
if (info.exists()) {
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
pluginLoader.setFileName(pluginLibName);
// static QPluginLoader pluginLoader(pluginLibName); // static QPluginLoader pluginLoader(pluginLibName);
if (!pluginLoader.load()) { if (!pluginLoader.load()) {
qCritical() << "in directory" << plugInDir.absolutePath();
qCritical() << "cannot load plugin" << pluginLoader.fileName(); qCritical() << "cannot load plugin" << pluginLoader.fileName();
qCritical() << pluginLoader.errorString(); qCritical() << pluginLoader.errorString();
return nullptr; return nullptr;
} }
qCritical() << "loadDCPlugin() plugin directory:" << plugInDir.absolutePath(); // qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName();
qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName();
if (!pluginLoader.isLoaded()) { if (!pluginLoader.isLoaded()) {
qCritical() << pluginLoader.errorString(); qCritical() << pluginLoader.errorString();
@@ -69,14 +67,10 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
return nullptr; return nullptr;
} }
} else { } else {
qCritical() << pluginLibName << "does not exist"; qCritical() << libCAInfo.absoluteFilePath() << "does not exist";
return nullptr;
}
} else {
qCritical() << "plugins directory" << plugInDir.absolutePath()
<< "does not exist";
return nullptr; return nullptr;
} }
return hw; return hw;
} }
@@ -107,40 +101,12 @@ QString Update::dcVersion(QString const &dcBinFile) {
} }
class hwapi; class hwapi;
Update::Update(QString customerRepository, Update::Update(QString const &dcFileName, QString const &libCA, bool debug, bool noaction)
QString customerNrStr, : m_dcFileName(dcFileName)
QString branchName, , m_hw(loadDCPlugin(libCA))
QString plugInDir, , m_sys_areDCdataValid(false)
QString pluginName, , m_debug(debug)
QString workingDir, , m_noaction(noaction) {
QString psaDcDir,
bool dryRun,
QObject *parent,
char const *serialInterface,
char const *baudrate)
: QObject(parent) {
#if 0
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_serialInterface(serialInterface)
, m_baudrate(baudrate)
, m_customerRepository(customerRepository)
, m_customerNrStr(customerNrStr)
, m_branchName(branchName)
, m_pluginName(pluginName)
, m_workingDir(workingDir)
, m_psaDcDir(psaDcDir)
, m_dryRun(dryRun)
, m_sys_areDCdataValid(false) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
} else {
// carun stoppen
}
#endif
m_start = QDateTime::currentDateTime();
} }
Update::~Update() { Update::~Update() {
@@ -166,15 +132,15 @@ Update::sendNextAddress(int bNum) const {
if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) { if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
// qDebug() << "addr-block" << bNum << "..."; // qDebug() << "addr-block" << bNum << "...";
while (noAnswerCount <= 250) { while (noAnswerCount <= 250) {
// TODO
// m_hw->bl_sendAddress(bNum);
QThread::msleep(100); DownloadResult res = DownloadResult::OK;
if (!m_debug) {
m_hw->bl_sendAddress(bNum);
// TODO QThread::msleep(10); //from 100ms to 20ms
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK()); //###################################################################################
res = sendStatus(m_hw->bl_wasSendingAddOK());
DownloadResult const res = DownloadResult::OK; }
if (res != DownloadResult::NOP) { if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) { if (res == DownloadResult::ERROR) {
@@ -189,7 +155,7 @@ Update::sendNextAddress(int bNum) const {
} else { } else {
noAnswerCount += 1; // no answer by now noAnswerCount += 1; // no answer by now
} }
} } // while
// wait max. about 3 seconds // wait max. about 3 seconds
return DownloadResult::TIMEOUT; return DownloadResult::TIMEOUT;
} }
@@ -214,20 +180,20 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
qInfo() << s.toUtf8().constData(); qInfo() << s.toUtf8().constData();
QThread::msleep(200); QThread::msleep(20); //reduce from 200 to 50 ms
return DownloadResult::OK; //############################################################################
// QByteArray b((const char *)(&local[0]), 64); QByteArray b((const char *)(&local[0]), 64);
// qCritical() << "SNDB" << bNum << b.size() << b.toHex(); qCritical() << "SNDB" << bNum << b.size() << b.toHex();
while (noAnswerCount <= 250) { while (noAnswerCount <= 250) {
// TODO
// m_hw->bl_sendDataBlock(64, local);
// TODO DownloadResult res = DownloadResult::OK;
// DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK());
DownloadResult const res = DownloadResult::OK; if (!m_debug) {
m_hw->bl_sendDataBlock(64, local);
res = sendStatus(m_hw->bl_wasSendingDataOK());
}
if (res != DownloadResult::NOP) { if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) { if (res == DownloadResult::ERROR) {
@@ -249,15 +215,13 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
} }
bool Update::startBootloader() const { bool Update::startBootloader() const {
QThread::msleep(1000); qDebug() << "starting bootloader...";
qInfo() << nextTimePoint().toUtf8().constData() << "starting bootloader ...done";
return true;
#if 0 if (!m_debug) {
int nTry = 5; int nTry = 10;
while (--nTry >= 0) { while (--nTry >= 0) {
m_hw->bl_startBL(); m_hw->bl_startBL();
QThread::msleep(5000); QThread::msleep(1000);
m_hw->bl_checkBL(); m_hw->bl_checkBL();
if (m_hw->bl_isUp()) { if (m_hw->bl_isUp()) {
qInfo() << "starting bootloader...OK"; qInfo() << "starting bootloader...OK";
@@ -265,24 +229,27 @@ bool Update::startBootloader() const {
return true; return true;
} else { } else {
qCritical() << "bootloader not up (" << nTry << ")"; qCritical() << "bootloader not up (" << nTry << ")";
qCritical() << "IS BOOTLOADER INSTALLED ???";
} }
} }
qCritical() << "starting bootloader...FAILED"; qCritical() << "starting bootloader...FAILED";
return false; return false;
#endif } else {
QThread::msleep(1000);
qInfo() << "starting bootloader...OK";
}
return true;
} }
bool Update::stopBootloader() const { bool Update::stopBootloader() const {
QThread::msleep(1000);
qInfo() << nextTimePoint().toUtf8().constData() << "stopping bootloader ...done";
return true;
#if 0
qDebug() << "stopping bootloader..."; qDebug() << "stopping bootloader...";
if (!m_debug) {
int nTry = 5; int nTry = 5;
while (--nTry >= 0) { while (--nTry >= 0) {
m_hw->bl_stopBL(); m_hw->bl_stopBL();
QThread::msleep(500); QThread::msleep(1000);
if (!m_hw->bl_isUp()) { if (!m_hw->bl_isUp()) {
qInfo() << "stopping bootloader...OK"; qInfo() << "stopping bootloader...OK";
return true; return true;
@@ -290,12 +257,21 @@ bool Update::stopBootloader() const {
} }
qCritical() << "stopping bootloader...FAILED"; qCritical() << "stopping bootloader...FAILED";
return false; return false;
#endif
} else {
QThread::msleep(1000);
qInfo() << "stopping bootloader...OK";
}
return true;
} }
bool Update::resetDeviceController() const { bool Update::resetDeviceController() const {
// TODO qInfo() << nextTimePoint().toUtf8().constData() << "resetting device controller";
// m_hw->bl_rebootDC();
if (!m_debug) {
m_hw->bl_rebootDC();
}
// wait maximally 3 seconds, before starting bootloader // wait maximally 3 seconds, before starting bootloader
QThread::sleep(1); QThread::sleep(1);
@@ -313,12 +289,12 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const {
if (!file.exists()) { if (!file.exists()) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< file.fileName() << "does not exist"; << file.fileName() << "does not exist";
return QByteArray(); return QByteArray{};
} }
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "cannot open file" << file.fileName(); << "cannot open file" << file.fileName();
return QByteArray(); return QByteArray{};
} }
qInfo() << nextTimePoint().toUtf8().constData() qInfo() << nextTimePoint().toUtf8().constData()
@@ -408,19 +384,26 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const {
// There is no problem to repeat this command until the // There is no problem to repeat this command until the
// bootloader is really not running anymore. // bootloader is really not running anymore.
*/ */
bool Update::doUpdate(QString const &dcFileName) { int Update::run() {
qInfo() << "<DC-VERSION>" << Update::dcVersion(dcFileName); if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
return -(int)Result::PLUGIN_LOAD_ERROR;
}
m_dcFileName = dcFileName; m_start = QDateTime::currentDateTime();
//QString const &fToWorkOn = usbStickDetected ? QDir::cleanPath(it->trimmed()) if (m_debug) {
//: QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed()); qInfo() << "start dc-update for" << m_dcFileName << "at" << m_start.toString(Qt::ISODate);
qInfo() << "<DC-VERSION>" << Update::dcVersion(m_dcFileName);
}
//if (!m_hw) { if (!m_debug) {
// qCritical() << "(" << __func__ << ":" << __LINE__ << "):" m_hw->dc_autoRequest(false);
// << "ERROR!!! m_hw == nullptr"; }
// return false;
//} qInfo() << "DC auto request OFF";
qCritical() << "start dc-update for" << m_dcFileName << "at" << m_start.toString(Qt::ISODate);
QByteArray ba = loadBinaryDCFile(m_dcFileName); QByteArray ba = loadBinaryDCFile(m_dcFileName);
if (ba.size() > 0) { if (ba.size() > 0) {
@@ -433,15 +416,14 @@ bool Update::doUpdate(QString const &dcFileName) {
resetDeviceController(); resetDeviceController();
if (startBootloader()) { if (startBootloader()) {
int currentBlock = 0; int currentBlock = 0;
DownloadResult res = DownloadResult::OK; DownloadResult res = DownloadResult::OK;
qInfo() << nextTimePoint().toUtf8().constData() << "64-byte block" << currentBlock; qInfo() << nextTimePoint().toUtf8().constData() << "64-byte block" << currentBlock;
while (res != DownloadResult::ERROR && currentBlock < m_totalBlocks) { while (res != DownloadResult::ERROR && currentBlock <= m_totalBlocks) {
if ((res = sendNextAddress(currentBlock)) != DownloadResult::ERROR) { if ((res = sendNextAddress(currentBlock)) != DownloadResult::ERROR) {
if ((res = sendNextDataBlock(ba, currentBlock)) != DownloadResult::ERROR) { if ((res = sendNextDataBlock(ba, currentBlock)) != DownloadResult::ERROR) {
// TODO
// m_hw->dcDownloadSetCurrentBlockNumber(currentBlock);
currentBlock += 1; currentBlock += 1;
} else break; } else break;
} }
@@ -470,243 +452,26 @@ bool Update::doUpdate(QString const &dcFileName) {
} }
stopBootloader(); // there is no harm in stopping the bootloader even stopBootloader(); // there is no harm in stopping the bootloader even
// if starting the bootloader failed // if starting the bootloader failed
// check if update was successful
if (!m_debug) {
m_hw->dc_autoRequest(true); //restart dc_autoRequest after download else E255!
}
for (int i = 0; i < 3; ++i) {
qInfo() << "waiting for device controller restart...(" << i << ")";
QThread::sleep(20);
resetDeviceController();
if (startBootloader()) {
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>"; qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
return true; stopBootloader();
return -(int)Result::SUCCESS;
}
}
} }
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>"; qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>";
//To Do Error handling if Dc doesnt start after download
return false; return false;
} }
#if 0
bool Update::checkJsonVersions(QStringList const& jsonFileNames) {
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! m_hw == nullptr";
return false;
}
int tries = 20;
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
// must deliver 'true', only then are all data from hwapi valid
if (--tries < 0) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED";
return false;
}
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED (" << tries << ")";
m_hw->dc_autoRequest(true);
QThread::msleep(500);
}
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
uint8_t jsonNr = 0;
QString const &fName = jsonFileNames[i];
// send one request for every single version
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
// 6=printer template 1 ..... 36= template 32
if (fName.endsWith("conf.json")) {
jsonNr = 1;
} else
if (fName.endsWith("device.json")) {
jsonNr = 2;
} else
if (fName.endsWith("cash.json")) {
jsonNr = 3;
} else {
QRegularExpressionMatch match;
static const QRegularExpression re("^(.*print)([0-3][0-9])\\.json\\s*$");
int idx = fName.indexOf(re, 0, &match);
if (idx != -1) {
QString captured = match.captured(match.lastCapturedIndex());
bool ok = false;
int n = captured.toInt(&ok);
if (ok) {
// note: use 5 (instead of 4 -> index has been shifted)
jsonNr = n + 5;
}
}
}
if (jsonNr != 0) {
// send one request for every single version
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
// 5=printer template 1 ..... 36= template 32
m_hw->sys_requestJsonVersions(jsonNr);
QThread::msleep(500);
char buf[64];
memset(buf, 0x00, sizeof(buf));
m_hw->sys_getJsonVersions(jsonNr, buf);
buf[16] = '\0'; // the DC only handles 16 bytes
static const QByteArray cb(16, (char)0xff);
QString const installedVersion(QString::fromStdString(buf));
QString const fileVersion = getFileVersion(jsonFileNames[i]);
QFileInfo fi(jsonFileNames[i]);
qCritical() << endl;
qCritical() << " json request nr:" << jsonNr;
if (installedVersion == fileVersion) {
qCritical() << " json file:" << fi.fileName();
qCritical() << " installed version in DC:" << installedVersion;
} else
if (cb == QByteArray(buf) && fileVersion == "") {
qCritical() << "unknown json file (repo and DC):" << fi.fileName();
} else {
qCritical() << " json file:" << fi.fileName();
qCritical() << " installed version in DC:" << installedVersion;
qCritical() << " file version in repository:" << fileVersion;
}
} else {
qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
}
}
return false;
}
QString Update::getFileVersion(QString const& jsonFileName) {
// "version":"15.10.2023 14:55 02.00.06",
static const QRegularExpression re("^.*(\\\"[Vv]ersion\\\":)([\\s\\\"]{0,})([^,\\\"]{0,}).*$");
QString fileVersion("");
QFile inputFile(QDir::cleanPath(m_customerRepository + QDir::separator() + jsonFileName));
if (inputFile.exists()) {
if (inputFile.open(QIODevice::ReadOnly)) {
QTextStream in(&inputFile);
while (!in.atEnd()) {
QString line = in.readLine();
QRegularExpressionMatch match;
int idx = line.indexOf(re, 0, &match);
if (idx != -1) {
int const lastCaptured = match.lastCapturedIndex();
// the dc only sends 16 Byte
fileVersion = match.captured(lastCaptured);
fileVersion.truncate(16);
break;
}
}
inputFile.close();
}
} else {
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
}
return fileVersion;
}
bool Update::downloadJson(enum FileTypeJson type,
int templateIdx,
QString jsFileToSendToDC) const {
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
qDebug() << "SET AUTO-REQUEST=TRUE";
QThread::sleep(1); // make sure the auto-request flag is acknowledged
QStringList lst;
bool ready = false;
int nTry = 25;
while ((ready = m_hw->sys_ready4sending()) == false) {
QThread::msleep(200);
if (--nTry <= 0) {
qCritical() << "SYS NOT READY FOR SENDING AFTER 5 SECONDS";
break;
}
}
bool ret = false;
QString msg;
lst.clear();
if (ready) {
QFile file(jsFileToSendToDC);
QFileInfo fi(jsFileToSendToDC); // max. size of template file is 800 bytes
if (file.exists()) {
if (file.open(QIODevice::ReadOnly)) {
if (fi.size() > 0 && fi.size() <= 800) {
QByteArray ba = file.readAll();
// kindOfFile: 1=config, 2=device, 3=cash, 4=serial, 5=time, 6=printer
// nrOfTemplate=1...32 if kindOfFile==6
// content = content of the Json file, max 800byte ascii signs
if (m_hw->sys_sendJsonFileToDc((uint8_t)(type),
templateIdx,
(uint8_t *)ba.data())) {
/*
* Note: the machine id is contained in DC2C_conf.json.
* The idea was to use this to check if the download of
* the json-file was correct. It did not work, as the
* update of the PSA (to reflect a change in the
* machine id) did not happen immediately.
*
m_hw->dc_autoRequest(true);
QThread::msleep(500);
// testing
m_hw->request_ReadbackMachineID();
QThread::msleep(500);
uint8_t data[64];
memset(data, 0x00, sizeof(data));
uint8_t length = 0;
m_hw->readback_machineIDdata(&length, data);
QThread::msleep(500);
QByteArray ba((const char*)data, length);
qCritical() << length << "MACHINE ID =" << ba.toHex(':');
*/
ret = true;
} else {
qCritical() << QString("ERROR SEND JSON-FILE %1 TO DC").arg(file.fileName());
}
} else {
qCritical() << QString("SIZE OF %1 TOO BIG (%2 BYTES)").arg(jsFileToSendToDC).arg(fi.size());
}
} else {
qCritical() << QString("CAN NOT OPEN ") + jsFileToSendToDC + " FOR READING";
}
} else {
qCritical() << (QString(jsFileToSendToDC) + " DOES NOT EXIST");
}
}
m_hw->dc_autoRequest(false);
qDebug() << "SET AUTO-REQUEST=FALSE";
QThread::sleep(1); // make sure the auto-request flag is acknowledged
return ret;
}
bool Update::updatePrinterTemplate(int templateIdx, QString jsFile) const {
return downloadJson(FileTypeJson::PRINTER, templateIdx, jsFile);
}
bool Update::updateConfig(QString jsFile) {
return downloadJson(FileTypeJson::CONFIG, 0, jsFile);
}
bool Update::updateCashConf(QString jsFile) {
return downloadJson(FileTypeJson::CASH, 0, jsFile);
}
bool Update::updateDeviceConf(QString jsFile) {
return downloadJson(FileTypeJson::DEVICE, 0, jsFile);
}
#endif

View File

@@ -17,26 +17,21 @@
#ifdef PTU5 #ifdef PTU5
#define SERIAL_PORT "ttymxc2" #define SERIAL_PORT "ttymxc2"
#define BAUDRATE 115200
#else #else
#define SERIAL_PORT "ttyUSB0" #define SERIAL_PORT "ttyUSB0"
#define BAUDRATE 115200
#endif #endif
class QSerialPort;
class Update : public QObject { class Update : public QObject {
Q_OBJECT Q_OBJECT
QString m_dcFileName{};
hwinf *m_hw = nullptr; hwinf *m_hw = nullptr;
char const *m_serialInterface; bool m_sys_areDCdataValid{};
char const *m_baudrate; bool m_debug{false};
QString m_customerRepository; bool m_noaction;
QString m_customerNrStr;
QString m_branchName;
QString m_pluginName;
QString m_workingDir;
QString m_psaDcDir;
QString m_dcFileName;
bool m_maintenanceMode;
bool m_dryRun;
bool m_sys_areDCdataValid;
static QPluginLoader pluginLoader; static QPluginLoader pluginLoader;
@@ -48,27 +43,16 @@ class Update : public QObject {
public: public:
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; enum class Result {SUCCESS=0, PLUGIN_LOAD_ERROR};
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn); static hwinf *loadDCPlugin(QString const &libCA = "/usr/lib/libCAslave.so");
static bool unloadDCPlugin(); static bool unloadDCPlugin();
static QStringList split(QString line, QChar sep = ','); static QStringList split(QString line, QChar sep = ',');
explicit Update(QString customerRepository, explicit Update(QString const &dcBinFile, QString const &libCA, bool debug, bool noaction);
QString customerNrStr,
QString branchName,
QString plugInDir,
QString pluginName,
QString workingDir,
QString psaDcDir,
bool dryRun = false,
QObject *parent = nullptr,
char const *serialInterface = SERIAL_PORT,
char const *baudrate = "115200");
virtual ~Update() override; virtual ~Update() override;
bool doUpdate(QString const &dcFileName); int run();
static QString dcVersion(QString const &dcBinFile); static QString dcVersion(QString const &dcBinFile);
private: private:

View File

@@ -1,6 +1,8 @@
QT += core QT += core
QT += serialport network QT += serialport network
include(../common.pri)
TARGET = ATBDownloadDCJsonFiles TARGET = ATBDownloadDCJsonFiles
VERSION="0.1.0" VERSION="0.1.0"

View File

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

View File

@@ -21,13 +21,10 @@
#include <QDateTime> #include <QDateTime>
#include <QPluginLoader> #include <QPluginLoader>
#include <QMap> #include <QMap>
#include <cmath>
#define UPDATE_OPKG (1) #define UPDATE_OPKG (1)
#define UPDATE_DC (0) #define UPDATE_DC (0)
qint64 Update::c_ppid = -1;
static const QMap<QString, int> baudrateMap = { static const QMap<QString, int> baudrateMap = {
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3}, {"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
{"57600" , 4}, {"115200" , 5} {"57600" , 4}, {"115200" , 5}
@@ -107,7 +104,7 @@ Update::Update(QString customerRepository,
char const *serialInterface, char const *serialInterface,
char const *baudrate) char const *baudrate)
: QObject(parent) : QObject(parent)
// , m_hw(loadDCPlugin(QDir(plugInDir), pluginName)) , m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_serialInterface(serialInterface) , m_serialInterface(serialInterface)
, m_baudrate(baudrate) , m_baudrate(baudrate)
, m_customerRepository(customerRepository) , m_customerRepository(customerRepository)
@@ -118,9 +115,6 @@ Update::Update(QString customerRepository,
, m_dryRun(dryRun) , m_dryRun(dryRun)
, m_sys_areDCdataValid(false) { , m_sys_areDCdataValid(false) {
m_start = QDateTime::currentDateTime();
if (Update::ppid() == -1) {
if (!m_hw) { if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???"; qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin loaded ???";
} else { } else {
@@ -139,44 +133,9 @@ Update::Update(QString customerRepository,
<< m_sys_areDCdataValid; << m_sys_areDCdataValid;
} }
} }
}
Update::~Update() { 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) { bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {

View File

@@ -8,7 +8,6 @@
#include <QByteArray> #include <QByteArray>
#include <QProcess> #include <QProcess>
#include <QPluginLoader> #include <QPluginLoader>
#include <QDateTime>
#include <initializer_list> #include <initializer_list>
@@ -37,14 +36,6 @@ class Update : public QObject {
static QPluginLoader pluginLoader; 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: public:
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
@@ -53,8 +44,6 @@ public:
static bool unloadDCPlugin(); static bool unloadDCPlugin();
static QStringList split(QString line, QChar sep = ','); 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, explicit Update(QString customerRepository,
QString customerNrStr, QString customerNrStr,
@@ -70,7 +59,6 @@ public:
virtual ~Update() override; virtual ~Update() override;
bool doUpdate(QStringList const &jsonFilesToDownload, bool usbStickDetected = false); bool doUpdate(QStringList const &jsonFilesToDownload, bool usbStickDetected = false);
bool doUpdate();
bool updatePrinterTemplate(int templateIdx, QString fname) const; bool updatePrinterTemplate(int templateIdx, QString fname) const;
bool updateConfig(QString jsFileToSendToDC); bool updateConfig(QString jsFileToSendToDC);

View File

@@ -1,84 +0,0 @@
QT += core
TARGET = ATBUpdateGit
VERSION="1.0.0"
win32 {
BUILD_DATE=$$system("date /t")
BUILD_TIME=$$system("time /t")
} else {
BUILD_DATE=$$system("date +%d-%m-%y")
BUILD_TIME=$$system("date +%H:%M:%S")
}
GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += \
plugins \
$${INCLUDEINTERFACES} \
$${_PRO_FILE_PWD_}/../common/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
}

View File

@@ -1,101 +0,0 @@
#include "git_command.h"
#include "command.h"
#include "utils_internal.h"
using namespace internal;
#include <QProcess>
#include <QByteArray>
#include <QFileInfo>
#include <QDebug>
#include <QDir>
bool GitCommand::initEnv = false;
static bool initEnv() {
QString gitSSHCommand{""};
QByteArray const v = qgetenv("GIT_SSH_COMMAND");
if (v.isEmpty()) {
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
if (QFileInfo(sshKeyFile).exists()) {
if (qgetenv("GIT_SSH_COMMAND").isNull()) {
gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig";
if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) {
qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting...";
return false;
}
}
} else {
qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting...";
return false;
}
} else {
gitSSHCommand = QString(v.toStdString().c_str());
qCritical() << "WARNING GIT_SSH_COMMAND already set in enviroment:"
<< gitSSHCommand;
if (gitSSHCommand != "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig") {
qCritical() << "ERROR" << gitSSHCommand << "wrong. Exiting...";
return false;
}
}
// qCritical() << __func__ << ":" << __LINE__ << gitSSHCommand;
return true;
}
GitCommand::GitCommand()
: m_workingDirectory(customerRepoDir()) {
// qCritical() << __func__ << ":" << __LINE__ << m_workingDirectory;
if (!GitCommand::initEnv) {
GitCommand::initEnv = ::initEnv();
}
}
bool GitCommand::exec(QStringList const &options, int start_timeout, int finish_timeout) {
bool ret = false;
if (GitCommand::initEnv) {
Command cmd(QString("git"), options, m_workingDirectory,
start_timeout, finish_timeout);
ret = cmd.exec();
//qCritical() << __func__ << ":" << __LINE__ << cmd.command()
// << "," << cmd.args()
// << ", result" << cmd.commandResult();
m_commandResult = cmd.commandResult();
}
return ret;
}
bool GitCommand::check(int start_timeout, int finish_timeout) {
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);
}

View File

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

View File

@@ -1,119 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QRegularExpression>
#include <QFile>
#include <QTextStream>
#include <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;
}

View File

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

View File

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

View File

@@ -1,85 +0,0 @@
QT += core
TARGET = ATBUpdateOpkg
VERSION="1.0.0"
win32 {
BUILD_DATE=$$system("date /t")
BUILD_TIME=$$system("time /t")
} else {
BUILD_DATE=$$system("date +%d-%m-%y")
BUILD_TIME=$$system("date +%H:%M:%S")
}
GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += \
plugins \
$${INCLUDEINTERFACES} \
$${_PRO_FILE_PWD_}/../UpdatePTUDevCtrl \
$${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17
DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
DEFINES+=APP_BUILD_DATE=\\\"$$BUILD_DATE\\\"
DEFINES+=APP_BUILD_TIME=\\\"$$BUILD_TIME\\\"
DEFINES+=APP_EXTENDED_VERSION=\\\"$$EXTENDED_VERSION\\\"
# keep comments, as /* fall through */
QMAKE_CXXFLAGS += -C
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS += -Wno-deprecated-copy -O
contains( CONFIG, PTU5 ) {
CONFIG += link_pkgconfig
QMAKE_CXXFLAGS += -O2 -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
INCLUDEPATH += $$PTU5BASEPATH/qt/libs/devicecontroller/include
LIBS += -L$$PTU5BASEPATH/qt/libs/devicecontroller/library
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, PTU5_YOCTO ) {
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, DesktopLinux ) {
# QMAKE_CC = ccache $$QMAKE_CC
# QMAKE_CXX = ccache $$QMAKE_CXX
QMAKE_CXXFLAGS += -std=c++17
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
ARCH = DesktopLinux
DEFINES+=DesktopLinux
}
SOURCES += \
main.cpp \
message_handler.cpp \
../common/src/utils_internal.cpp \
../common/src/command.cpp \
opkg_command.cpp
HEADERS += \
message_handler.h \
../common/include/utils_internal.h \
../common/include/command.h \
opkg_command.h
##########################################################################################
# for running program on target through QtCreator
contains( CONFIG, PTU5 ) {
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/app/tools/atbupdate/
!isEmpty(target.path): INSTALLS += target
}

View File

@@ -1,69 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include "message_handler.h"
#include "utils_internal.h"
#include "opkg_command.h"
int main(int argc, char **argv) {
QByteArray const value = qgetenv("LC_ALL");
if (value.isEmpty() || value != "C") {
qputenv("LC_ALL", "C");
}
openlog("ATB-UPDATE-OPKG", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
QCoreApplication a(argc, argv);
QCoreApplication::setApplicationName("ATBUpdateOpkg");
QCoreApplication::setApplicationVersion(APP_VERSION);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(nullptr);
//atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(LOG_NOTICE);
}
#if 0
QString s = "<OPKG>\n\naaa<OPKG>bbb<OPKG>ccc<OPKG>\n";
QString m_standardOutput{};
if (!s.isEmpty()) {
m_standardOutput += s.replace(QChar('\n'), "");
qCritical() << m_standardOutput;
int startIndex, endIndex{};
while (((startIndex = m_standardOutput.indexOf("<OPKG>")) == 0) &&
((endIndex = m_standardOutput.indexOf("<OPKG>", 1)) != -1)) {
QString str = m_standardOutput.mid(0, endIndex);
qCritical() << "str" << str << str.mid(6);
m_standardOutput = m_standardOutput.mid(endIndex);
// qCritical() << "m" << m_standardOutput;
}
qCritical() << "m" << m_standardOutput;
}
return 0;
#endif
QCommandLineParser parser;
QCommandLineOption noactionOption("noaction");
QCommandLineOption verboseOption("verbose");
parser.addOption(noactionOption);
parser.addOption(verboseOption);
parser.process(a);
bool noaction = parser.isSet(noactionOption);
OpkgCommand opkgCmd(noaction);
return 0;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,87 +0,0 @@
QT += core
TARGET = ATBUpdateSync
VERSION="1.0.0"
win32 {
BUILD_DATE=$$system("date /t")
BUILD_TIME=$$system("time /t")
} else {
BUILD_DATE=$$system("date +%d-%m-%y")
BUILD_TIME=$$system("date +%H:%M:%S")
}
GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += \
plugins \
$${INCLUDEINTERFACES} \
$${_PRO_FILE_PWD_}/../UpdatePTUDevCtrl \
$${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17
DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
DEFINES+=APP_BUILD_DATE=\\\"$$BUILD_DATE\\\"
DEFINES+=APP_BUILD_TIME=\\\"$$BUILD_TIME\\\"
DEFINES+=APP_EXTENDED_VERSION=\\\"$$EXTENDED_VERSION\\\"
# keep comments, as /* fall through */
QMAKE_CXXFLAGS += -C
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS += -Wno-deprecated-copy -O
contains( CONFIG, PTU5 ) {
CONFIG += link_pkgconfig
QMAKE_CXXFLAGS += -O2 -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
INCLUDEPATH += $$PTU5BASEPATH/qt/libs/devicecontroller/include
LIBS += -L$$PTU5BASEPATH/qt/libs/devicecontroller/library
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, PTU5_YOCTO ) {
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5
DEFINES+=PTU5
}
contains( CONFIG, DesktopLinux ) {
# QMAKE_CC = ccache $$QMAKE_CC
# QMAKE_CXX = ccache $$QMAKE_CXX
QMAKE_CXXFLAGS += -std=c++17
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
ARCH = DesktopLinux
DEFINES+=DesktopLinux
}
SOURCES += \
main.cpp \
message_handler.cpp \
../common/src/utils_internal.cpp \
../common/src/command.cpp \
sync_command.cpp
HEADERS += \
message_handler.h \
../common/include/utils_internal.h \
../common/include/command.h \
sync_command.h
##########################################################################################
# for running program on target through QtCreator
contains( CONFIG, PTU5 ) {
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/app/tools/atbupdate/
!isEmpty(target.path): INSTALLS += target
}

View File

@@ -1,94 +0,0 @@
#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include "message_handler.h"
#include "utils_internal.h"
#include "sync_command.h"
int main(int argc, char **argv) {
QByteArray const value = qgetenv("LC_ALL");
if (value.isEmpty() || value != "C") {
qputenv("LC_ALL", "C");
}
openlog("ATB-UPDATE-SYNC", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
QCoreApplication a(argc, argv);
QCoreApplication::setApplicationName("ATBUpdateSync");
QCoreApplication::setApplicationVersion(APP_VERSION);
QDebug debug = qCritical();
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(nullptr);
//atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(LOG_NOTICE);
}
if (internal::customerRepoExists() == false) {
qCritical().noquote() << internal::NO_CUSTOMER_REPOSITORY;
return internal::NO_CUSTOMER_REPOSITORY_CODE;
}
QString const crd = internal::customerRepoDir();
QString const etcInRepo = QDir::cleanPath(crd + QDir::separator() + "etc/");
QString const optInRepo = QDir::cleanPath(crd + QDir::separator() + "opt/");
if (!QDir(etcInRepo).exists()) {
qCritical().noquote() << internal::NO_ETC_CUSTOMER_REPOSITORY;
return internal::NO_ETC_CUSTOMER_REPOSITORY_CODE;
}
if (!QDir(optInRepo).exists()) {
qCritical().noquote() << internal::NO_OPT_CUSTOMER_REPOSITORY;
return internal::NO_OPT_CUSTOMER_REPOSITORY_CODE;
}
#if 0
error codes for rsync:
https://stackoverflow.com/questions/20737204/comprehensive-list-of-rsync-error-codes
0 Success
1 Syntax or usage error
2 Protocol incompatibility
3 Errors selecting input/output files, dirs
4 Requested action not supported: an attempt was made to manipulate 64-bit
files on a platform that cannot support them; or an option was specified
that is supported by the client and not by the server.
5 Error starting client-server protocol
6 Daemon unable to append to log-file
10 Error in socket I/O
11 Error in file I/O
12 Error in rsync protocol data stream
13 Errors with program diagnostics
14 Error in IPC code
20 Received SIGUSR1 or SIGINT
21 Some error returned by waitpid()
22 Error allocating core memory buffers
23 Partial transfer due to error
24 Partial transfer due to vanished source files
25 The --max-delete limit stopped deletions
30 Timeout in data send/receive
35 Timeout waiting for daemon connection
#endif
QStringList options({"-v", "--recursive", "--progress", "--checksum",
"--exclude=.*", "--include=*.bin", "--include=*.json",
"--include=*.ini"});
int ret = SyncCommand().exec("rsync", options << etcInRepo << "/etc");
if (ret == 0) {
ret = SyncCommand().exec("rsync", options << optInRepo << "/opt");
}
return ret;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,8 @@
QT += core gui QT += core gui
QT += widgets serialport network QT += widgets serialport network
include(../common.pri)
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ATBUpdateTool TARGET = ATBUpdateTool
@@ -147,7 +149,13 @@ DEFINES += QT_DEPRECATED_WARNINGS
# 1.5.5 : Call into binary ptuPackageVersion to get installed package # 1.5.5 : Call into binary ptuPackageVersion to get installed package
# versions. # versions.
# 1.5.6 : Show additional update progress info in status bar. # 1.5.6 : Show additional update progress info in status bar.
VERSION="1.5.6" # 1.5.7 : Add support for dynamic portrait / landscape.
# 1.5.8 : Use EVENT_ID=<pid of update-tool> for CMD_EVENT.
# 1.5.9 : Removed restart of Apism if ISMAS unreachable.
# 1.5.99 : Special version for 281/Szeged: remove all DC-library dependencies, as
# DC-firmware in Szeged does not support uploading json-files or uploading
# DC-firmware binaries.
VERSION="1.5.99"
# PLANNED TODOS: # PLANNED TODOS:
# 1: Das Repository wird repariert bwz. neu geklont. Unabhaengig vom WAIT. # 1: Das Repository wird repariert bwz. neu geklont. Unabhaengig vom WAIT.
# 2: Wenn der WAIT-Button aktiv ist, dann wird ein Repository repariert (neu # 2: Wenn der WAIT-Button aktiv ist, dann wird ein Repository repariert (neu
@@ -216,10 +224,7 @@ GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}" EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
# INCLUDEPATH += plugins INCLUDEPATH += plugins
INCLUDEPATH += plugins \
$${_PRO_FILE_PWD_}/../common/ \
$${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17 CONFIG += c++17
# CONFIG -= app_bundle # CONFIG -= app_bundle
@@ -256,9 +261,6 @@ contains( CONFIG, PTU5_YOCTO ) {
PTU5BASEPATH = /opt/devel/ptu5 PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5 ARCH = PTU5
DEFINES+=PTU5 DEFINES+=PTU5
LIBS += -lCAslave
LIBS += -lCAmaster
} }
contains( CONFIG, DesktopLinux ) { contains( CONFIG, DesktopLinux ) {
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
@@ -282,24 +284,9 @@ SOURCES += \
git/git_client.cpp \ git/git_client.cpp \
ismas/ismas_client.cpp \ ismas/ismas_client.cpp \
process/command.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 \ message_handler.cpp \
worker.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 += \ HEADERS += \
update.h \ update.h \
@@ -311,25 +298,9 @@ HEADERS += \
apism/ismas_data.h \ apism/ismas_data.h \
ismas/ismas_client.h \ ismas/ismas_client.h \
process/command.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 \ message_handler.h \
worker.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 += \ OTHER_FILES += \
ATBUpdateTool.ini ATBUpdateTool.ini

View File

@@ -95,13 +95,7 @@ CommandLineParser::CommandLineParser()
QCommandLineOption( QCommandLineOption(
QStringList() << "D" << "read-dc-version", QStringList() << "D" << "read-dc-version",
QCoreApplication::translate("main", "Show version of device controller."), QCoreApplication::translate("main", "Show version of device controller."),
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(); configure();
} }
@@ -160,9 +154,6 @@ void CommandLineParser::configure() {
m_readDCVersionOption.setDefaultValue("false"); m_readDCVersionOption.setDefaultValue("false");
m_parser.addOption(m_readDCVersionOption); m_parser.addOption(m_readDCVersionOption);
m_setPPid.setDefaultValue("-1");
m_parser.addOption(m_setPPid);
} }
void CommandLineParser::readSettings() { void CommandLineParser::readSettings() {
@@ -295,19 +286,6 @@ QString CommandLineParser::workingDir() {
return m_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() { bool CommandLineParser::dryRun() {
if (m_parser.isSet(m_dryRunOption)) { if (m_parser.isSet(m_dryRunOption)) {
m_dryRun = m_parser.value(m_dryRunOption); m_dryRun = m_parser.value(m_dryRunOption);

View File

@@ -23,7 +23,6 @@ class CommandLineParser : public QCommandLineParser {
QString m_alwaysDownloadDC; QString m_alwaysDownloadDC;
QString m_readDCVersion{"false"}; QString m_readDCVersion{"false"};
QString m_dcDir{"etc/dc/"}; QString m_dcDir{"etc/dc/"};
qint64 m_ppid;
QCommandLineOption m_repositoryUrlOption; QCommandLineOption m_repositoryUrlOption;
QCommandLineOption m_iniFileDirectoryOption; QCommandLineOption m_iniFileDirectoryOption;
@@ -42,7 +41,6 @@ class CommandLineParser : public QCommandLineParser {
QCommandLineOption m_yoctoInstallStatusOption; QCommandLineOption m_yoctoInstallStatusOption;
QCommandLineOption m_dcDirectoryOption; QCommandLineOption m_dcDirectoryOption;
QCommandLineOption m_readDCVersionOption; QCommandLineOption m_readDCVersionOption;
QCommandLineOption m_setPPid;
QCommandLineParser m_parser; QCommandLineParser m_parser;
@@ -65,7 +63,6 @@ public:
QString psaConfigDir(); QString psaConfigDir();
QString psaTariffDir(); QString psaTariffDir();
bool dryRun(); bool dryRun();
qint64 ppid();
bool noUpdatePsaHardware(); bool noUpdatePsaHardware();
bool yoctoVersion(); bool yoctoVersion();
bool yoctoInstallStatus(); bool yoctoInstallStatus();

View File

@@ -21,6 +21,7 @@
#include <QThread> #include <QThread>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QCoreApplication>
#if 0 #if 0
######################## ########################
@@ -380,7 +381,7 @@ QString IsmasClient::updateNewsToIsmas(char const *event,
"{" "{"
"\"REASON\":\"SW_UP\"," "\"REASON\":\"SW_UP\","
"\"TIMESTAMP\":\"%s\"," "\"TIMESTAMP\":\"%s\","
"\"EVENT_ID\":\"0\"," "\"EVENT_ID\":\"%d\","
"\"EVENT\":\"%s\"," "\"EVENT\":\"%s\","
"\"EVENTSTATE\":1," "\"EVENTSTATE\":1,"
"\"PARAMETER\": {" "\"PARAMETER\": {"
@@ -390,7 +391,7 @@ QString IsmasClient::updateNewsToIsmas(char const *event,
"\"STEP_RESULT\" : \"%s\"," "\"STEP_RESULT\" : \"%s\","
"\"VERSION\" : \"%s\"" "\"VERSION\" : \"%s\""
"}" "}"
"}", ts.toStdString().c_str(), event, percent, resultCode, "}", ts.toStdString().c_str(), static_cast<int>(QCoreApplication::applicationPid()), event, percent, resultCode,
step, step_result, version); step, step_result, version);
return buf; return buf;
} }

View File

@@ -36,7 +36,6 @@
#include <QThread> #include <QThread>
#include <QtWidgets> #include <QtWidgets>
#include <QScopedPointer> #include <QScopedPointer>
#include <QScreen>
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX) #if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
#include <unistd.h> #include <unistd.h>
@@ -88,13 +87,11 @@ int main(int argc, char *argv[]) {
if (v.isEmpty()) { if (v.isEmpty()) {
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig"); QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
if (QFileInfo(sshKeyFile).exists()) { if (QFileInfo(sshKeyFile).exists()) {
if (qgetenv("GIT_SSH_COMMAND").isNull()) {
gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig"; gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig";
if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) { if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) {
qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting..."; qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting...";
return -1; return -1;
} }
}
} else { } else {
qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting..."; qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting...";
return -1; return -1;
@@ -204,8 +201,7 @@ int main(int argc, char *argv[]) {
mw.showFullScreen(); mw.showFullScreen();
// test // test
//worker.jsUpdate(); worker.dcUpdate();
worker.workList().exec();
// worker.summary(); // worker.summary();
return a.exec(); return a.exec();

View File

@@ -2,10 +2,8 @@
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "worker.h" #include "worker.h"
#include "utils.h" #include "utils.h"
#include "utils_internal.h"
#include "progress_event.h" #include "progress_event.h"
#include "update_dc_event.h" #include "update_dc_event.h"
#include "process/update_command.h"
#include <DeviceController/interfaces.h> #include <DeviceController/interfaces.h>
#include <QDateTime> #include <QDateTime>
@@ -16,14 +14,8 @@
#include <QColor> #include <QColor>
#include <QColorDialog> #include <QColorDialog>
#define CHECK_BACKEND_CONNECTION 0 #include <QScreen>
#define CHECK_UPDATE_REQUEST 1
#define UPDATE_CUSTOMER_REPOSITORY 2
#define INSTALL_SW_PACKETS_DRY_RUN 3
#define INSTALL_SW_PACKETS 4
#define INSTALL_DC_CONFIGURATION 5
#define SYNCHRONIZE_REPOSITORY 6
#define UPDATE_DC 7
MainWindow::MainWindow(Worker *worker, QWidget *parent) MainWindow::MainWindow(Worker *worker, QWidget *parent)
@@ -35,25 +27,7 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
, m_updateStep(UpdateDcEvent::UpdateStep::NONE) { , m_updateStep(UpdateDcEvent::UpdateStep::NONE) {
ui->setupUi(this); ui->setupUi(this);
checkOrientation();
m_updateSteps.resize(8);
m_updateSteps[CHECK_BACKEND_CONNECTION] = "Check backend connection (ISMAS) ";
m_updateSteps[CHECK_UPDATE_REQUEST] = "Check update request ";
m_updateSteps[UPDATE_CUSTOMER_REPOSITORY] = "Update customer repository ";
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN] = "Install SW packets (dry run) ";
m_updateSteps[INSTALL_SW_PACKETS] = "Install SW packets ";
m_updateSteps[INSTALL_DC_CONFIGURATION] = "Install DC configuration ";
m_updateSteps[SYNCHRONIZE_REPOSITORY] = "Synchronize repository/filesystem ";
m_updateSteps[UPDATE_DC] = "Update DC";
for (int i = 0; i < m_updateSteps.size(); ++i) {
QString &tmp = m_updateSteps[i];
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
ui->stepLabel->setText(tmp + "\n");
}
this->setStatusBar(new QStatusBar(this)); this->setStatusBar(new QStatusBar(this));
QFont f; QFont f;
@@ -113,21 +87,6 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
connect(m_worker, SIGNAL(showSummary(QString)),this,SLOT(onShowSummary(QString))); connect(m_worker, SIGNAL(showSummary(QString)),this,SLOT(onShowSummary(QString)));
connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit())); connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit()));
connect(m_worker, SIGNAL(showDcDownload(QString)),this,SLOT(onShowDcDownload(QString))); 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(setDcDownloadProgress(int)),this,SLOT(onSetDcDownloadProgress(int)));
connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit())); connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit()));
connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer())); connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer()));
@@ -150,7 +109,6 @@ void MainWindow::onShowSummary(QString text) {
ui->updateLabel->setText(s); ui->updateLabel->setText(s);
ui->updateLabel->hide(); ui->updateLabel->hide();
ui->stepLabel->hide(); ui->stepLabel->hide();
ui->updateProgress->hide();
s += text; s += text;
ui->updateStatus->setText(s); ui->updateStatus->setText(s);
@@ -160,308 +118,10 @@ void MainWindow::onSetDcDownloadProgress(int v) {
ui->updateProgress->setValue(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) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[CHECK_BACKEND_CONNECTION].trimmed();
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Green'>connected</font>";
} else {
s += " <font color='Green'>connected&nbsp;(initial configuration)</font>";
}
} else
if (status.contains(UpdateCommand::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
s += " <font color='Blue'>NOT CONNECTED</font>";
} else
if (status.contains(UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>connecting</font>";
} else
if (status.contains(UpdateCommand::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Red'>NOT CONNECTED. STOP</font>";
} else {
s += " <font color='Red'>not connected.&nbsp;(initial configuration)</font>";
}
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
m_updateSteps[CHECK_BACKEND_CONNECTION] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowCustRepoStatus(QString status) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[UPDATE_CUSTOMER_REPOSITORY].trimmed();
if (status.contains(internal::GIT_CUSTOMER_REPO_UP_TO_DATE, Qt::CaseInsensitive)) {
s += QString(" <font color='Green'>%1</font>").arg(internal::GIT_CUSTOMER_REPO_UP_TO_DATE);
} else
if (status.contains(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY, Qt::CaseInsensitive)) {
s += QString(" <font color='Green'>%1</font>").arg(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
m_updateSteps[UPDATE_CUSTOMER_REPOSITORY] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowExecOpkgStatus(QString status) {
qCritical() << __func__ << ":" << __LINE__ << "status" << status;
return;
QString s = ui->stepLabel->text();
QString tmp = "execute opkg commands ";
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
if (status.contains(UpdateCommand::EXEC_OPKG_COMMANDS_SUCCESS, Qt::CaseInsensitive)) {
s += QString("%1 <font color='Green'>success</font><br />").arg(tmp);
} else {
s += QString( "%1 <font color='Red'>UNKNOWN STATUS</font><br />").arg(tmp);
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowExecOpkgCommand(QString cmd) {
qCritical() << __func__ << ":" << __LINE__ << "cmd" << cmd;
return;
if (cmd.back() != QChar('\n')) {
cmd += "\n";
}
onInsertText(cmd);
}
void MainWindow::onShowExecOpkgOverallResult(QString status, bool noaction) {
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = noaction ?
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN].trimmed() :
m_updateSteps[INSTALL_SW_PACKETS].trimmed();
if (status.contains(internal::EXEC_OPKG_COMMANDS_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else
if (status.contains(internal::EXEC_OPKG_COMMANDS_FAIL, Qt::CaseInsensitive)) {
s += QString(" <font color='Red'>%1</font>").arg(internal::EXEC_OPKG_COMMANDS_FAIL);
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
if (noaction) {
m_updateSteps[INSTALL_SW_PACKETS_DRY_RUN] = s;
} else {
m_updateSteps[INSTALL_SW_PACKETS] = s;
}
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowDownloadDCJsonFilesStatus(QString status) {
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[INSTALL_DC_CONFIGURATION].trimmed();
if (status.contains(UpdateCommand::UPDATE_DC_JSON_FILES_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
m_updateSteps[INSTALL_DC_CONFIGURATION] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowSyncCustRepoStatus(QString status) {
//qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[SYNCHRONIZE_REPOSITORY].trimmed();
if (status.contains(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
m_updateSteps[SYNCHRONIZE_REPOSITORY] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowUpdateDCFirmware(QString status) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[UPDATE_DC].trimmed();
if (status.contains(UpdateCommand::UPDATE_DC_FIRMARE_SUCCESS, Qt::CaseInsensitive)) {
s += " <font color='Green'>success</font>";
} else {
s += " <font color='Red'>UNKNOWN STATUS</font>";
}
m_updateSteps[UPDATE_DC] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
if (i != UPDATE_DC) {
s += m_updateSteps[i] + "<br />";
} else {
s += m_updateSteps[i];
}
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowUpdateRequest(QString status) {
// qCritical() << __func__ << ":" << __LINE__ << "status" << status;
QString s = m_updateSteps[CHECK_UPDATE_REQUEST].trimmed();
bool const custRepoExists = internal::customerRepoExists();
if (status.contains(UpdateCommand::UPDATE_NOT_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Red'>NOT REQUESTED. STOP.</font>";
} else {
s += " <font color='Blue'>not requested&nbsp;(initial configuration)</font>";
}
} else
if (status.contains(UpdateCommand::UPDATE_REQUESTED, Qt::CaseInsensitive)) {
if (custRepoExists) {
s += " <font color='Green'>requested</font>";
} else {
s += " <font color='Blue'>requested&nbsp;(initial configuration)</font>";
}
} else
if (status.contains(UpdateCommand::UPDATE_NOT_NECESSARY, Qt::CaseInsensitive)) {
s += " <font color='Green'>not necessary</font>";
} else
if (status.contains(UpdateCommand::NO_CUSTOMER_REPOSITORY, Qt::CaseInsensitive)) {
s += " <font color='Blue'>UNKNOWN (ISMAS not connected)</font>";
} else {
s += " <font color='Red'>UNKNOWN</font>";
}
m_updateSteps[CHECK_UPDATE_REQUEST] = s;
s.clear();
for (int i = 0; i < m_updateSteps.size(); ++i) {
s += m_updateSteps[i] + "<br />";
}
ui->stepLabel->setText(s);
}
void MainWindow::onShowISMASChecks(QString) {
// deprecated
QString s = ui->stepLabel->text();
return;
QString tmp("Check ISMAS connectivity ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
tmp = "Check update activation ";
len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
ui->stepLabel->setText(s);
}
void MainWindow::onShowJsonDownload(QString) {
ui->exit->setEnabled(false);
QString s = ui->stepLabel->text();
QString tmp("Send json files to dc-hardware ");
int len = m_showLineLength - tmp.length();
while (--len > 0) {
tmp += "&nbsp;";
}
s += QString("%1 <font color='Green'>[OK ]</font><br />").arg(tmp);
ui->stepLabel->setText(s);
}
void MainWindow::onShowDcDownload(QString version) { void MainWindow::onShowDcDownload(QString version) {
m_targetDcVersion = version; m_targetDcVersion = version;
ui->exit->setEnabled(false); ui->exit->setEnabled(false);
ui->stepLabel->setText(QString("Device controller update. Target version: %1").arg(version).leftJustified(m_width-3));
// 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() { MainWindow::~MainWindow() {
@@ -471,6 +131,56 @@ MainWindow::~MainWindow() {
delete ui; delete ui;
} }
// ----------------------------- Ui::LAYOUT setting -------------------------------------
void MainWindow::checkOrientation()
{
QScreen *screen = QGuiApplication::primaryScreen();
Qt::ScreenOrientation orientation = screen->orientation();
switch (orientation) {
case Qt::PrimaryOrientation:
this->setLandscapeLayout();
break;
case Qt::LandscapeOrientation:
this->setLandscapeLayout();
break;
case Qt::PortraitOrientation:
this->setPortraitLayout();
break;
case Qt::InvertedLandscapeOrientation:
this->setLandscapeLayout();
break;
case Qt::InvertedPortraitOrientation:
this->setPortraitLayout();
break;
}
this->currentOrientation = orientation;
}
void MainWindow::setPortraitLayout()
{
// Adjust layout for portrait mode (480x800)
this->setFixedSize(480, 800);
ui->centralwidget->setFixedSize(480, 800);
}
void MainWindow::setLandscapeLayout()
{
// Adjust layout for landscape mode (800x480)
this->setFixedSize(800, 480);
ui->centralwidget->setFixedSize(800, 480);
}
void MainWindow::customEvent(QEvent *event) { void MainWindow::customEvent(QEvent *event) {
if (event->type() == ProgressEvent::type()) { if (event->type() == ProgressEvent::type()) {
ProgressEvent *pevent = (ProgressEvent *)event; ProgressEvent *pevent = (ProgressEvent *)event;

View File

@@ -4,8 +4,6 @@
#include <QMainWindow> #include <QMainWindow>
#include <QTimer> #include <QTimer>
#include <QStatusBar> #include <QStatusBar>
#include <QVector>
#include <QString>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; } namespace Ui { class MainWindow; }
@@ -54,18 +52,6 @@ public slots:
void onEnableExit(); void onEnableExit();
void onDisableExit(); void onDisableExit();
void onShowDcDownload(QString); 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 onSetDcDownloadProgress(int);
void onShowSummary(QString); void onShowSummary(QString);
#if EMERGENCY_LEAVE_BL==1 #if EMERGENCY_LEAVE_BL==1
@@ -82,13 +68,16 @@ private slots:
void onQuit(); void onQuit();
private: private:
int const m_showLineLength = 37;
void scrollDownTextEdit(); void scrollDownTextEdit();
void onShowMessage(QString, QString); void onShowMessage(QString, QString);
Ui::MainWindow *ui; Ui::MainWindow *ui;
void checkOrientation();
void setPortraitLayout();
void setLandscapeLayout();
Qt::ScreenOrientation currentOrientation;
Worker *m_worker; Worker *m_worker;
int const m_width; int const m_width;
QTimer *m_startTimer; QTimer *m_startTimer;
@@ -98,9 +87,5 @@ private:
UpdateDcEvent::UpdateStep m_updateStep; UpdateDcEvent::UpdateStep m_updateStep;
QTimer *m_statusTimer; QTimer *m_statusTimer;
QString m_targetDcVersion; QString m_targetDcVersion;
int m_stepLabelChopCount{};
QVector<QString> m_updateSteps{};
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@@ -10,6 +10,12 @@
<height>480</height> <height>480</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>480</width>
<height>480</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<family>Misc Fixed</family> <family>Misc Fixed</family>

View File

@@ -1,60 +0,0 @@
#include "process/check_and_fetch_customer_repository_command.h"
#include "worker.h"
#include "utils_internal.h"
CheckAndFetchCustomerRepositoryCommand::CheckAndFetchCustomerRepositoryCommand(
QString const &command, Worker *worker, int nextCommandIndex,
int start_timeout, int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
}
void CheckAndFetchCustomerRepositoryCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
qCritical() << __func__ << ":" << __LINE__ << command() << exitCode << exitStatus;
Worker *w = worker();
if (w) {
switch (exitCode) {
case internal::GIT_CHECKOUT_ERROR_CODE:
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_CHECKOUT_ERROR);
break;
case internal::GIT_PULL_ERROR_CODE:
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_PULL_ERROR);
break;
case internal::GIT_NOT_NECESSARY_CODE:
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
exitCode = 0;
break;
case internal::GIT_UPDATED_CODE:
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED);
exitCode = 0;
break;
case 0:
emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UP_TO_DATE);
default:;
}
}
return UpdateCommand::finished(exitCode, exitStatus);
}
void CheckAndFetchCustomerRepositoryCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
Worker *w = worker();
if (w) {
QString s = p->readAllStandardOutput().trimmed();
m_commandResult += s;
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY)) {
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_NOT_NECESSARY);
m_commandResult.clear();
} else
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_UPDATED)) {
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED);
}
}
}
// static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
// emit w->showCustRepoStatus(UpdateCommand::GIT_CUSTOMER_REPO_UP_TO_DATE);
// }
//}
}

View File

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

View File

@@ -1,38 +0,0 @@
#include "process/check_ismas_connectivity_command.h"
#include "worker.h"
#include <QDebug>
CheckIsmasConnectivityCommand::CheckIsmasConnectivityCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
}
void CheckIsmasConnectivityCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
return UpdateCommand::finished(exitCode, exitStatus);
}
void CheckIsmasConnectivityCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
Worker *w = worker();
if (w) {
QString s = p->readAllStandardOutput().trimmed();
if (s == UpdateCommand::ISMAS_CONNECTED) {
emit w->showISMASConnectivity(UpdateCommand::ISMAS_CONNECTED);
} else
if (s == UpdateCommand::NO_CUSTOMER_REPOSITORY) {
emit w->showISMASConnectivity(UpdateCommand::NO_CUSTOMER_REPOSITORY);
} else
if (s == UpdateCommand::ISMAS_NOT_CONNECTED) {
emit w->showISMASConnectivity(UpdateCommand::ISMAS_NOT_CONNECTED);
} else
if (s == UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS) {
emit w->showISMASConnectivity(UpdateCommand::ISMAS_CONNECTION_IN_PROGRESS);
}
}
}
}

View File

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

View File

@@ -1,40 +0,0 @@
#include "process/check_update_activation_command.h"
#include "worker.h"
#include "utils_internal.h"
#include <QDebug>
CheckUpdateActivationCommand::CheckUpdateActivationCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
}
void CheckUpdateActivationCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
qCritical() << __func__ << ":" << __LINE__ << command() << exitCode << exitStatus;
return UpdateCommand::finished(exitCode, exitStatus);
}
void CheckUpdateActivationCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
Worker *w = worker();
if (w) {
QString s = p->readAllStandardOutput().trimmed();
if (s == internal::UPDATE_REQUESTED) {
emit w->showUpdateRequest(internal::UPDATE_REQUESTED);
} else
if (s == internal::UPDATE_NOT_NECESSARY) {
emit w->showUpdateRequest(internal::UPDATE_NOT_NECESSARY);
} else
if (s == internal::UPDATE_NOT_REQUESTED) {
emit w->showUpdateRequest(internal::UPDATE_NOT_REQUESTED);
} else
if (s == internal::NO_CUSTOMER_REPOSITORY) {
emit w->showUpdateRequest(internal::NO_CUSTOMER_REPOSITORY);
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,85 +0,0 @@
#include "process/exec_opkg_command.h"
#include "worker.h"
#include "utils_internal.h"
#include <QStringList>
ExecOpkgCommand::ExecOpkgCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
bool noaction,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout)
, m_noaction(noaction)
, m_ok_count{0}
, m_fail_count{0} {
}
void ExecOpkgCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
QProcess *p = (QProcess *)sender();
if (p) {
Worker *w = worker();
if (w) {
if (m_fail_count == 0 && m_ok_count > 0) {
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_SUCCESS, m_noaction);
} else
if (m_ok_count == 0 && m_fail_count > 0) {
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_FAIL, m_noaction);
} else {
// TODO
emit w->showExecOpkgOverallResult(internal::EXEC_OPKG_COMMANDS_SUCCESS, m_noaction);
}
}
}
return UpdateCommand::finished(exitCode, exitStatus);
}
void ExecOpkgCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
Worker *w = worker();
if (w) {
QString s = p->readAllStandardOutput().trimmed();
if (!s.isEmpty()) {
m_standardOutput += s.replace(QChar('\n'), "");
// the command lines in etc/psa_update/opkg_commands are
// separated by "<OPKG>" markers. Note that the file opkg_commands
// itself is *not* changed, of course.
int startIndex, endIndex{};
while (((startIndex = m_standardOutput.indexOf(internal::OPKG_MARKER)) == 0) &&
((endIndex = m_standardOutput.indexOf(internal::OPKG_MARKER, 1)) != -1)) {
QString result = m_standardOutput.mid(0, endIndex).mid(6);
m_standardOutput = m_standardOutput.mid(endIndex);
if (!s.isEmpty()) {
QStringList const lst = result.split(u' ', QString::SkipEmptyParts);
if (lst.size() >= 2) {
if (lst.last() == "ok") {
m_ok_count += 1;
if (lst.contains("noaction")) {
emit w->showExecOpkgCommand(result);
} else {
emit w->showExecOpkgCommand(result);
}
} else {
m_fail_count += 1;
if (lst.contains("noaction")) {
emit w->showExecOpkgCommand(result);
} else {
emit w->showExecOpkgCommand(result);
}
}
} else {
emit w->showExecOpkgCommand(result);
}
}
}
}
}
}
}

View File

@@ -1,24 +0,0 @@
#ifndef EXEC_OPKG_COMMAND_H_INCLUDED
#define EXEC_OPKG_COMMAND_H_INCLUDED
#include "update_command.h"
class ExecOpkgCommand : public UpdateCommand {
bool m_noaction{false};
QString m_standardOutput{};
int m_ok_count{};
int m_fail_count{};
public:
explicit ExecOpkgCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
bool noaction,
int start_timeout = 100000,
int finish_timeout = 100000);
public slots:
virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // EXEC_OPKG_COMMAND_H_INCLUDED

View File

@@ -1,29 +0,0 @@
#include "process/show_software_status_command.h"
#include "worker.h"
ShowSoftwareStatusCommand::ShowSoftwareStatusCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
}
void ShowSoftwareStatusCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
return UpdateCommand::finished(exitCode, exitStatus);
}
void ShowSoftwareStatusCommand::readyReadStandardOutput() {
//QProcess *p = (QProcess *)sender();
//if (p) {
// QString s = p->readAllStandardOutput();
//
// TODO
// Worker *w = worker();
//if (w) {
// static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
// emit w->showExecOpkgStatus(UpdateCommand::EXEC_OPKG_COMMANDS_SUCCESS);
// }
//}
}

View File

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

View File

@@ -1,136 +0,0 @@
#include "update_command.h"
#include "worker.h"
#include "utils_internal.h"
#include <QDebug>
#include <QProcess>
UpdateCommand::UpdateCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int finish_timeout)
: Command(command, start_timeout, finish_timeout)
, m_nextCommandIndex(nextCommandIndex) {
setWorker(worker);
}
bool UpdateCommand::stopUpdateOnFailure() {
return true;
}
void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
QProcess *p = qobject_cast<QProcess *>(sender());
if (p) {
// read all remaining data sent to the process, just in case
QString s = p->readAllStandardOutput().trimmed();
if (!s.isEmpty()) {
m_commandResult += s;
}
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
}
if (!m_worker->workList().empty()) {
//static constexpr const int PERCENT_CHECK_ISMAS_CONNECIVITY{10};
//static constexpr const int PERCENT_CHECK_UPDATE_REQUEST{20};
//static constexpr const int PERCENT_CHECK_CUSTOMER_REPOSITORY{30};
//static constexpr const int PERCENT_INSTALL_SW_PACKETS_NOACTION{40};
//static constexpr const int PERCENT_INSTALL_SW_PACKETS{50};
//static constexpr const int PERCENT_INSTALL_DC_CONFIGURATION{60};
//static constexpr const int PERCENT_SYNCHRONIZE_REPO_AND_FILESYS{70};
//static constexpr const int PERCENT_UPDATE_DC{80};
//static constexpr const int PERCENT_SHOW_FINAL_STATUS{90};
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

@@ -1,38 +0,0 @@
#ifndef UPDATE_COMMAND_H_INCLUDED
#define UPDATE_COMMAND_H_INCLUDED
#include "process/command.h"
class Worker;
class UpdateCommand : public Command {
int m_nextCommandIndex{0};
public:
static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
static constexpr const char *UPDATE_REQUESTED{"requested"};
static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"};
static constexpr const char *ISMAS_CONNECTED{"connected"};
static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
static constexpr const char *GIT_CUSTOMER_REPO_UP_TO_DATE{"up to date"};
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
static constexpr const char *UPDATE_DC_JSON_FILES_SUCCESS{"success"};
static constexpr const char *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
static constexpr const char *UPDATE_DC_FIRMARE_SUCCESS{"success"};
explicit UpdateCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout = 100000,
int finish_timeout = 100000);
int nextCommandIndex() { return m_nextCommandIndex; }
virtual bool stopUpdateOnFailure();
public slots:
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;
};
#endif // UPDATE_COMMAND_H_INCLUDED

View File

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

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

View File

@@ -1,28 +0,0 @@
#include "process/update_filesystem_command.h"
#include "worker.h"
UpdateFileSystemCommand::UpdateFileSystemCommand(QString const &command,
Worker *worker,
int nextCommandIndex,
int start_timeout,
int finish_timeout)
: UpdateCommand(command, worker, nextCommandIndex, start_timeout, finish_timeout) {
}
void UpdateFileSystemCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
return UpdateCommand::finished(exitCode, exitStatus);
}
void UpdateFileSystemCommand::readyReadStandardOutput() {
QProcess *p = (QProcess *)sender();
if (p) {
QString s = p->readAllStandardOutput();
// TODO
Worker *w = worker();
if (w) {
// static constexpr const char *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
emit w->showSyncCustRepoStatus(UpdateCommand::SYNC_CUSTOMER_REPO_FILES_SUCCESS);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -40,6 +40,7 @@ QPluginLoader Update::pluginLoader;
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) { hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
hwinf *hw = nullptr; hwinf *hw = nullptr;
#if 0
if (plugInDir.exists()) { if (plugInDir.exists()) {
QString pluginLibName(fname); QString pluginLibName(fname);
pluginLibName = plugInDir.absoluteFilePath(pluginLibName); pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
@@ -74,6 +75,7 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
qCritical() << "plugins directory" << plugInDir.absolutePath() qCritical() << "plugins directory" << plugInDir.absolutePath()
<< "does not exist"; << "does not exist";
} }
#endif
return hw; return hw;
} }
@@ -105,6 +107,7 @@ Update::Update(Worker *worker,
char const *serialInterface, char const *serialInterface,
char const *baudrate) char const *baudrate)
: QObject(parent) : QObject(parent)
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_worker(worker) , m_worker(worker)
, m_serialInterface(serialInterface) , m_serialInterface(serialInterface)
, m_baudrate(baudrate) , m_baudrate(baudrate)
@@ -115,6 +118,26 @@ Update::Update(Worker *worker,
, m_workingDir(workingDir) , m_workingDir(workingDir)
, m_dryRun(dryRun) , m_dryRun(dryRun)
, m_sys_areDCdataValid(false) { , m_sys_areDCdataValid(false) {
#if 0
if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin not loaded";
} else {
int tries = 20;
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
// must deliver 'true', only then are all data from hwapi valid
if (--tries < 0) {
qCritical() << "ERROR!!! DC DATA NOT VALID -> CA-MASTER-PLUGIN NOT CONNECTED";
break;
}
m_hw->dc_autoRequest(true);
QThread::msleep(500);
}
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_sys_areDCDataValid ..."
<< m_sys_areDCdataValid;
}
#endif
} }
Update::~Update() { Update::~Update() {
@@ -132,6 +155,43 @@ void Update::onReportDCDownloadFailure(QString const &errorMsg) {
qCritical() << "msg" << errorMsg; qCritical() << "msg" << errorMsg;
} }
// br is a index into a table, used for historical reasons.
bool Update::openSerial(int br, QString baudrate, QString comPort) const {
if (m_hw) {
qDebug() << "opening serial" << br << baudrate << comPort << "...";
if (m_hw->dc_openSerial(br, baudrate, comPort, 1) == true) { // 1 for connect
Utils::printInfoMsg(
QString("OPENING SERIAL %1").arg(br)
+ " " + baudrate + " " + comPort + "...OK");
// m_hw->dc_autoRequest(true);
// m_hw->dc_autoRequest(false);
// QThread::sleep(1);
Utils::printInfoMsg(QString("IS PORT OPEN %1").arg(m_hw->dc_isPortOpen()));
return true;
}
Utils::printCriticalErrorMsg(
QString("OPENING SERIAL %1").arg(br)
+ " " + baudrate + " " + comPort + "...FAILED");
}
return false;
}
void Update::closeSerial() const {
qInfo() << "CLOSED SERIAL" << m_baudrate << m_serialInterface;
if (m_hw) {
m_hw->dc_closeSerial();
}
}
bool Update::isSerialOpen() const {
return m_hw ? m_hw->dc_isPortOpen() : false;
}
/* /*
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -226,13 +286,95 @@ bool Update::updateBinary(QString const &fileToSendToDC) {
qInfo() << "updating dc-binary" << fileToSendToDC << "..."; qInfo() << "updating dc-binary" << fileToSendToDC << "...";
return false; 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, bool Update::downloadJson(enum FileTypeJson type,
int templateIdx, int templateIdx,
QString jsFileToSendToDC) const { QString jsFileToSendToDC) const {
#if 0
if (m_hw) { if (m_hw) {
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
qDebug() << "SET AUTO-REQUEST=TRUE"; qDebug() << "SET AUTO-REQUEST=TRUE";
@@ -351,7 +493,6 @@ bool Update::downloadJson(enum FileTypeJson type,
// QThread::sleep(1); // make sure the auto-request flag is acknowledged // QThread::sleep(1); // make sure the auto-request flag is acknowledged
} }
#endif
return true; return true;
} }
@@ -410,7 +551,6 @@ void Update::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
} }
QStringList Update::getDcSoftAndHardWareVersion() { QStringList Update::getDcSoftAndHardWareVersion() {
#if 0
if (m_hw) { if (m_hw) {
m_hw->dc_autoRequest(true); m_hw->dc_autoRequest(true);
QThread::sleep(1); // make sure the timer-slots are active QThread::sleep(1); // make sure the timer-slots are active
@@ -433,17 +573,15 @@ QStringList Update::getDcSoftAndHardWareVersion() {
} }
} }
#endif
return QStringList() << "DC HW-version not available" return QStringList() << "DC HW-version not available"
<< "DC SW-version not available"; << "DC SW-version not available";
} }
QString Update::getFileVersion(QString const& jsonFileName) { QString Update::getFileVersion(QString const& jsonFileName) {
QString fileVersion("");
#if 0
// "version":"15.10.2023 14:55 02.00.06", // "version":"15.10.2023 14:55 02.00.06",
static const QRegularExpression re("^.*(\\\"[Vv]ersion\\\":)([\\s\\\"]{0,})([^,\\\"]{0,}).*$"); static const QRegularExpression re("^.*(\\\"[Vv]ersion\\\":)([\\s\\\"]{0,})([^,\\\"]{0,}).*$");
QString fileVersion("");
QFile inputFile(QDir::cleanPath(m_customerRepository + QDir::separator() + jsonFileName)); QFile inputFile(QDir::cleanPath(m_customerRepository + QDir::separator() + jsonFileName));
if (inputFile.exists()) { if (inputFile.exists()) {
@@ -468,11 +606,11 @@ QString Update::getFileVersion(QString const& jsonFileName) {
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist"; // qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
} }
#endif
return fileVersion; return fileVersion;
} }
bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) { bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
// note: 2026-02-09: this method is not used!
#if 0 #if 0
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) { for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
@@ -547,7 +685,6 @@ bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
qCritical() << "CANNOT FIND JSON-NR FOR" << fName; qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
} }
} }
#endif #endif
return false; return false;
} }
@@ -555,7 +692,6 @@ bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
QMap<QString, QString> QMap<QString, QString>
Update::getInstalledJsonVersions(QStringList const& jsonFileNames) { Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
QMap<QString, QString> map; QMap<QString, QString> map;
#if 0 #if 0
if (!m_hw) { if (!m_hw) {
qCritical() << "(" << __func__ << ":" << __LINE__ << "):" qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
@@ -662,7 +798,6 @@ Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) { bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
#if 0
if (!m_hw) { if (!m_hw) {
Utils::printInfoMsg("CA-PLUGIN NOT LOADED"); Utils::printInfoMsg("CA-PLUGIN NOT LOADED");
return false; return false;
@@ -869,7 +1004,4 @@ bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
qDebug() << "SET AUTO-REQUEST=TRUE"; qDebug() << "SET AUTO-REQUEST=TRUE";
return res; return res;
#endif
return false;
} }

View File

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

View File

@@ -1,14 +1,12 @@
#include "utils.h" #include "utils.h"
#include "message_handler.h" #include "message_handler.h"
#include "git/git_client.h" #include "git/git_client.h"
#include "worker.h"
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX) #if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
#include "unistd.h" #include "unistd.h"
#endif #endif
#include <QObject>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <QDebug> #include <QDebug>
@@ -20,124 +18,12 @@
#include <QJsonValue> #include <QJsonValue>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
#include <QStringList>
#include <QDirIterator>
#include <fstream> #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>> Utils::installedPackages() {
QVector<QPair<QString, QString>> vec; QVector<QPair<QString, QString>> vec;
if (QFile::exists("/usr/bin/")) { if (QFile::exists("/usr/bin/ptuPackageVersions")) {
QProcess p; QProcess p;
QStringList params; QStringList params;
params << "-c" << R"(/usr/bin/ptuPackageVersions -i -o json)"; params << "-c" << R"(/usr/bin/ptuPackageVersions -i -o json)";
@@ -279,7 +165,7 @@ QString Utils::getTariffInfo(QString fileName) {
} }
QString Utils::zoneName(quint8 /* i */) { QString Utils::zoneName(quint8 i) {
//static constexpr char const *zName[] = { //static constexpr char const *zName[] = {
// "", // "",
// "purple", // "purple",

View File

@@ -10,9 +10,7 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QPair> #include <QPair>
#include <QProcess>
class Worker;
namespace Utils { namespace Utils {
int read1stLineOfFile(QString fileName); int read1stLineOfFile(QString fileName);
QString getLocation(QString fileName); QString getLocation(QString fileName);
@@ -38,10 +36,6 @@ namespace Utils {
bool isATBQTRunning(); bool isATBQTRunning();
QVector<QPair<QString, QString>> installedPackages(); 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 #endif // UTILS_H_INCLUDED

View File

@@ -1,32 +0,0 @@
#include "work_process_list.h"
#include "process/update_command.h"
#include <limits>
#include <QDebug>
unsigned WorkList::nextExecIndex() const {
if (m_workList.size() > 0 && m_workListIndex < (m_workList.size() - 1)) {
return m_workListIndex + 1;
}
return std::numeric_limits<unsigned>::max();
}
bool WorkList::nextExec() const {
return m_workListIndex < m_workList.size();
}
bool WorkList::exec(bool last) {
if (last == false) {
if (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

@@ -1,36 +0,0 @@
#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,25 +20,13 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QJsonArray> #include <QJsonArray>
#include <memory>
#include "message_handler.h" #include "message_handler.h"
#include <DeviceController/interfaces.h> #include <DeviceController/interfaces.h>
#include "ismas/ismas_client.h" #include "ismas/ismas_client.h"
#include "progress_event.h" #include "progress_event.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "utils.h" // deprecated #include "utils.h"
#include "utils_internal.h"
#include "process/command.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_OK ( " [ ok]");
QString const Worker::UPDATE_STEP_DONE ( " [done]"); QString const Worker::UPDATE_STEP_DONE ( " [done]");
@@ -190,89 +178,12 @@ Worker::Worker(int customerNr,
, m_updateProcessRunning(true) , m_updateProcessRunning(true)
, m_mainWindow(nullptr) /* contains plugin */ , m_mainWindow(nullptr) /* contains plugin */
, m_dcDownloadFirmware(new Command("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")) , 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(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_start = QDateTime::currentDateTime();
m_dcDownloadFirmware->setWorker(this); m_dcDownloadFirmware->setWorker(this);
m_dcDownloadJsonFiles->setWorker(this);
// TODO: turn object into singleton // TODO: turn object into singleton
instance = this; instance = this;
@@ -379,7 +290,7 @@ void Worker::privateUpdate() {
return; return;
} }
return; //return;
QString func(__PRETTY_FUNCTION__); QString func(__PRETTY_FUNCTION__);
@@ -630,9 +541,10 @@ void Worker::privateUpdate() {
// UPDATE THE PSA USING THE CHANGED FILES // UPDATE THE PSA USING THE CHANGED FILES
// //
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
if ((continueUpdate = downloadFilesToPSAHardware()) == false) { // for 281/Szeged: skip uploading files to DeviceController
return; //if ((continueUpdate = downloadFilesToPSAHardware()) == false) {
} // return;
//}
lst = QStringList(QString("DONE")); lst = QStringList(QString("DONE"));
ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_SUCCESS)); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_SUCCESS));
@@ -681,16 +593,6 @@ bool Worker::updateTriggerSet() {
CONSOLE(lst) << UPDATE_STEP::DEBUG; CONSOLE(lst) << UPDATE_STEP::DEBUG;
} }
if ((repeat % 8) == 0) {
CONSOLE(QStringList(func) << "RESTART APISM") << UPDATE_STEP::DEBUG;
Command c("systemctl restart apism");
if (c.execute("/tmp")) {
QThread::sleep(20); // give APISM some time to reconnect
QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << "RESTART APISM DONE"));
CONSOLE(lst) << UPDATE_STEP::DEBUG;
}
}
if (std::optional<QString> result if (std::optional<QString> result
= IsmasClient::sendRequestReceiveResponse( = IsmasClient::sendRequestReceiveResponse(
IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) { IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) {
@@ -1600,18 +1502,6 @@ PSAInstalled Worker::getPSAInstalled() {
return psaInstalled; 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() { bool Worker::dcUpdate() {
return m_dcDownloadFirmware->start("/opt/app/tools/atbupdate"); return m_dcDownloadFirmware->start("/opt/app/tools/atbupdate");
} }
@@ -1621,9 +1511,6 @@ void Worker::summary() {
QString summary, first, second, line, tmp; QString summary, first, second, line, tmp;
QVector<QPair<QString, QString>> vec = Utils::installedPackages(); 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; int max_first = 0, max_second = 0;
for (int i = 0; i < vec.size(); ++i) { for (int i = 0; i < vec.size(); ++i) {
max_first = std::max(max_first, vec[i].first.length()); max_first = std::max(max_first, vec[i].first.length());
@@ -1688,5 +1575,4 @@ void Worker::summary() {
} }
emit showSummary(summary); emit showSummary(summary);
emit enableExit();
} }

View File

@@ -11,17 +11,13 @@
#include <QMap> #include <QMap>
#include <QDebug> #include <QDebug>
#include <QThread> #include <QThread>
#include <QByteArray>
#include <QScopedPointer>
#include <optional> #include <optional>
#include <initializer_list> #include <initializer_list>
#include "git/git_client.h" #include "git/git_client.h"
#include "ismas/ismas_client.h" #include "ismas/ismas_client.h"
#include "ismas/ApismClientForUpdate.h"
#include "utils.h" #include "utils.h"
#include "work_process_list.h"
#ifdef PTU5 #ifdef PTU5
#define SERIAL_PORT "ttymxc2" #define SERIAL_PORT "ttymxc2"
@@ -195,13 +191,9 @@ class Worker : public QThread{
MainWindow *m_mainWindow; MainWindow *m_mainWindow;
Command *m_dcDownloadFirmware; Command *m_dcDownloadFirmware;
Command *m_dcDownloadJsonFiles;
bool m_withoutIsmasDirectPort; bool m_withoutIsmasDirectPort;
QString m_apismVersion; QString m_apismVersion;
WorkList m_workList;
ApismClientForUpdate m_clForUpdate;
bool executeOpkgCommand(QString opkgCommand); bool executeOpkgCommand(QString opkgCommand);
bool cleanUpOpkgCache(); bool cleanUpOpkgCache();
QString getOsVersion() const; QString getOsVersion() const;
@@ -404,9 +396,6 @@ public:
return m_ismasClient; return m_ismasClient;
} }
ApismClientForUpdate &clientForUpdate() { return m_clForUpdate; }
ApismClientForUpdate const &clientForUpdate() const { return m_clForUpdate; }
Worker *GUI(QStringList const &lst = QStringList()) { Worker *GUI(QStringList const &lst = QStringList()) {
m_guiMsg = lst; m_guiMsg = lst;
return this; return this;
@@ -471,16 +460,10 @@ public:
Update *update() { return m_update; } Update *update() { return m_update; }
Update const *update() const { return m_update; } Update const *update() const { return m_update; }
bool jsUpdate();
bool dcUpdate(); bool dcUpdate();
void summary(); void summary();
QDateTime start() { return m_start; } QDateTime start() { return m_start; }
QByteArray standardOutput() const { return m_standardOutput; }
WorkList const &workList() const { return m_workList; }
WorkList &workList() { return m_workList; }
signals: signals:
void appendText(QString, QString suffix = ""); void appendText(QString, QString suffix = "");
void insertText(QString); void insertText(QString);
@@ -495,18 +478,6 @@ signals:
void enableExit(); void enableExit();
void disableExit(); void disableExit();
void showDcDownload(QString); 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 showSummary(QString);
void setDcDownloadProgress(int); void setDcDownloadProgress(int);
@@ -519,9 +490,6 @@ private slots:
// bool sendIsmasLastVersionNotification(int progress); // bool sendIsmasLastVersionNotification(int progress);
bool saveLogFile(); bool saveLogFile();
public slots:
void readyReadStandardOutput();
private: private:
PSAInstalled getPSAInstalled(); PSAInstalled getPSAInstalled();
static bool sendLastVersionOnce; static bool sendLastVersionOnce;
@@ -530,7 +498,6 @@ private:
bool execOpkgCommands(); bool execOpkgCommands();
QDateTime m_start; QDateTime m_start;
QByteArray m_standardOutput;
static const QMap<UPDATE_STEP, const char*> smap; static const QMap<UPDATE_STEP, const char*> smap;

1
common.pri Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -2,11 +2,14 @@
#define UTILS_INTERNAL_H_INCLUDED #define UTILS_INTERNAL_H_INCLUDED
#include <QString> #include <QString>
#include <QSettings>
#include <memory>
namespace internal { namespace internal {
static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"}; static constexpr const char *UPDATE_NOT_NECESSARY{"not necessary"};
static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"}; static constexpr const char *UPDATE_NOT_REQUESTED{"not requested"};
static constexpr const char *UPDATE_INITIAL{"initial update"};
static constexpr const char *UPDATE_REQUESTED{"requested"}; static constexpr const char *UPDATE_REQUESTED{"requested"};
static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"}; static constexpr const char *NO_CUSTOMER_REPOSITORY{"no customer repository"};
@@ -22,10 +25,17 @@ namespace internal {
static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"}; static constexpr const char *ISMAS_NOT_CONNECTED{"not connected"};
static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"}; static constexpr const char *ISMAS_CONNECTION_IN_PROGRESS{"connecting"};
static constexpr const char *BROKER_CONNECTED{"connected"};
static constexpr const char *BROKER_DISCONNECTED{"disconnected"};
static constexpr const char *BROKER_DISCONNECTING{"disconnecting"};
static constexpr const char *BROKER_NOT_CONNECTED{"not connected"};
static constexpr const char *BROKER_CONNECTION_IN_PROGRESS{"connecting"};
static constexpr const int GIT_CHECKOUT_ERROR_CODE{-2}; static constexpr const int GIT_CHECKOUT_ERROR_CODE{-2};
static constexpr const int GIT_PULL_ERROR_CODE{-4}; static constexpr const int GIT_PULL_ERROR_CODE{-4};
static constexpr const int GIT_NOT_NECESSARY_CODE{1}; static constexpr const int GIT_NOT_NECESSARY_CODE{1};
static constexpr const int GIT_UPDATED_CODE{2}; static constexpr const int GIT_UPDATED_CODE{2};
static constexpr const int GIT_CLONED_CODE{3};
static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"}; static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"};
static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"}; static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"};
@@ -33,6 +43,7 @@ namespace internal {
static constexpr const char *GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY{"no repository update necessary"}; 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_NOT_NECESSARY{"not necessary"};
static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"}; static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"};
static constexpr const char *GIT_CUSTOMER_REPO_CLONED{"repository cloned"};
static constexpr const char *GIT_UPDATED{"updated"}; static constexpr const char *GIT_UPDATED{"updated"};
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"}; static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
@@ -40,6 +51,7 @@ namespace internal {
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_SUCCESS{"success"}; static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_SUCCESS{"success"};
static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_FAIL{"FAIL"}; static constexpr const char *EXEC_OPKG_COMMANDS_NOACTION_FAIL{"FAIL"};
static constexpr const char *UPDATE_DC_JSON_FILES_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 *SYNC_CUSTOMER_REPO_FILES_SUCCESS{"success"};
@@ -62,13 +74,19 @@ namespace internal {
static constexpr const int PERCENT_UPDATE_DC{80}; static constexpr const int PERCENT_UPDATE_DC{80};
static constexpr const int PERCENT_SHOW_FINAL_STATUS{90}; static constexpr const int PERCENT_SHOW_FINAL_STATUS{90};
static constexpr const char *DEFAULT_INI_DIR{"/etc/tools/atbupdate/"};
static constexpr const char *DEFAULT_INSTALL_DIR{"/opt/app/tools/atbupdate/"};
int read1stLineOfFile(QString fileName); int read1stLineOfFile(QString fileName);
QString customerRepoRoot(); QString customerRepoRoot();
QString customerRepoDir(); QString customerRepoDir();
QString customerRepoDcDir();
QString customerRepoDirName(); QString customerRepoDirName();
QString repositoryUrl(); QString repositoryUrl();
QString branchName(); QString branchName();
bool customerRepoExists(); bool customerRepoExists();
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName = "");
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory);
} }
#endif // UTILS_INTERNAL_H_INCLUDED #endif // UTILS_INTERNAL_H_INCLUDED

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,12 @@
#include "utils.h" #include "utils_internal.h"
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QTextStream> #include <QTextStream>
#include <QSettings>
#include <QDebug>
#include <QCryptographicHash>
#include <QFileInfoList>
namespace internal { namespace internal {
@@ -35,6 +39,11 @@ QString customerRepoDir() {
return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : ""; return !n.isEmpty() ? QDir::cleanPath(r + QDir::separator() + n) : "";
} }
QString customerRepoDcDir() {
QString const &r = customerRepoDir();
return QDir::cleanPath(r + QDir::separator() + "etc/dc/");
}
bool customerRepoExists() { bool customerRepoExists() {
QString const repoDir{customerRepoDir()}; QString const repoDir{customerRepoDir()};
return !repoDir.isEmpty() ? QDir(repoDir).exists() : false; return !repoDir.isEmpty() ? QDir(repoDir).exists() : false;
@@ -52,4 +61,107 @@ QString branchName() {
return ""; return "";
} }
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
std::unique_ptr<QSettings> settings{std::make_unique<QSettings>()};
//QString const fileName{settings->applicationName() + ".ini"};
QString const fileName{"ATBUpdateTool.ini"};
QDir d;
if (!optionalDirName.isEmpty()) {
d = QDir{optionalDirName};
if (d.exists()) { // try to find ini-file under optionalDirname
QFileInfo fi{d, optionalDirName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical() << fi.absoluteFilePath() << "not found."
<< "Try" << internal::DEFAULT_INI_DIR;
}
} else {
qCritical() << optionalDirName << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
}
d = internal::DEFAULT_INI_DIR;
if (d.exists()) { // try to find ini-file under /etc/tools/atbupdate
QFileInfo fi{d, fileName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical() << fi.absoluteFilePath() << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
} else {
qCritical() << internal::DEFAULT_INI_DIR << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
d = QDir{internal::DEFAULT_INSTALL_DIR};
if (d.exists()) { // try to find ini-file under /opt/app/tools/atbupdate
QFileInfo fi{d, fileName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical() << fi.absoluteFilePath() << "not found.";
}
} else {
qCritical() << internal::DEFAULT_INSTALL_DIR << "not found.";
}
return settings;
}
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory) {
std::unique_ptr<QString> dcCandidate{nullptr};
qCritical() << __func__ << __LINE__ << dcDirectory;
QDir dcDir{dcDirectory.isEmpty() ? customerRepoDcDir() : dcDirectory};
if (dcDir.exists()) {
QFileInfoList fileInfoList =
dcDir.entryInfoList(QStringList("*.bin"),
QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
QFileInfo dc2cbin{dcDir.absoluteFilePath("dc2c.bin")};
if (dc2cbin.exists()) {
QCryptographicHash md5gen(QCryptographicHash::Md5);
QByteArray ba_dc2cbin{};
{
QFile f{dc2cbin.absoluteFilePath()};
if (f.open(QIODevice::ReadOnly)) {
md5gen.addData(f.readAll());
ba_dc2cbin = md5gen.result();
md5gen.reset();
}
}
if (ba_dc2cbin.size() > 0) {
QFileInfoList::const_iterator it;
for (it = fileInfoList.cbegin(); it != fileInfoList.cend(); ++it) {
if (it->absoluteFilePath() != dc2cbin.absoluteFilePath()) {
QFile f{it->absoluteFilePath()};
if (f.open(QIODevice::ReadOnly)) {
md5gen.addData(f.readAll());
if (ba_dc2cbin == md5gen.result()) {
dcCandidate.reset(new QString(f.fileName()));
break;
}
md5gen.reset();
}
}
}
}
}
}
return dcCandidate;
}
} // namespace internal } // namespace internal

View File

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

184
on_update_failure.sh Executable file
View File

@@ -0,0 +1,184 @@
#!/bin/bash
# set -x
#
#############################################################################
# Check if the ATBUpdateTool(.service) did not send U0001 (sucess),
# U0002 (activated) or U0003 (error) to ISMAS, including the case that the
# tool did not crash or was not killed under other circumstances.
#
# This script will be called in the associated atbupdatetool.service (see
# /lib/systemd/system/atbupdatetool.service).
#
###############################################################################
readonly OUT_FILE=/tmp/out.txt
readonly SCRIPT_NAME=$(basename $0)
if [ -z "$START_DATE" ]
then
START_DATE=$(date +"%Y-%m-%d00:00:00")
fi
if [ -z "$STOP_DATE" ]
then
STOP_DATE=$(date +"%Y-%m-%d%H:%M:%S")
fi
echo "EXIT_CODE=$EXIT_CODE"
echo "SERVICE_RESULT=$SERVICE_RESULT"
echo "EXIT_STATUS=$EXIT_STATUS"
echo "START_DATE=$START_DATE"
echo "STOP_DATE=$STOP_DATE"
last_cmd_event () {
# output json; look for start of CMD_EVENT; look for }}; extract everything between; finally re-add }}.
# could also look for ">>>", but this might change in the future.
local json=$(\
journalctl -u atbupdatetool --since="$START_DATE" --until="$STOP_DATE" --output=json-pretty |\
grep "#M=APISM#C=CMD_EVENT#J=" |\
awk '{split($0, a, "#M=APISM#C=CMD_EVENT#J="); print a[2]}' |\
awk '{split($0, a, /\}[\s]*\}/); print a[1]}' |\
tr -d '\\' |\
tail -1)
json+="}}"
echo "$json"
}
last_percent_value () {
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\3/p" | xargs | awk '{print $NF}')
}
last_step () {
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[8]}' | awk '{split($0, b, " : "); print b[2]}' | tr -d '"\\')
}
last_step_result () {
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[9]}' | awk '{split($0, b, " : "); print b[2]}' | tr -d '"\\')
}
pid_atbupdatetool () {
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(ATBUpdateTool\[\)\(\\s*[0-9]\+\)\(\].*$\)/\3/p" | uniq)
}
last_event () {
echo $(cat $OUT_FILE | sed -n "s/\(^.*\)\(\"PERCENT\"\\s*:\)\(\\s*[0-9]\+\)\(.*$\)/\1\2\3\4/p" | tail -1 | awk '{split($0, a, ","); print a[4]}' | awk '{split($0, b, ":"); print b[2]}' | tr -d ' ' | tr -d '"\\')
}
sendU0003 () {
LAST_CMD_EVENT=$(last_cmd_event)
echo "LAST=$LAST_CMD_EVENT"
local json_detected=0
local temp
local x
if [[ ! -z "$LAST_CMD_EVENT" ]]
then
temp=$(mktemp -p /tmp)
echo "$LAST_CMD_EVENT" > "$temp"
x=$(jq .EVENT $temp)
if [ $? -eq 0 ]; then
json_detected=1
fi
fi
if [ $json_detected -eq 1 ]
then
# local pid=$(jq .EVENT_ID $temp)
# if json has been detected, use "jq".
x=$(jq .PARAMETER.PERCENT $temp | tr -d '"')
[[ -z "$x" ]] && PERCENT=0 || PERCENT=$x
x=$(jq .PARAMETER.STEP $temp | tr -d '"')
[[ -z "$x" ]] && STEP="unknown" || STEP="$x"
x=$(jq .PARAMETER.STEP_RESULT $temp | tr -d '"')
[[ -z "$x" ]] && STEP_RESULT="unknown" || STEP_RESULT="$x"
x=$(pid_atbupdatetool)
[[ -z "$x" ]] && PID=99999 || PID=$x
x=$(last_event)
[[ -z "$x" ]] && EVENT="unknown" || EVENT="$x"
else
# cannot parse valid json. try original journal text file.
x=$(last_percent_value)
[[ -z "$x" ]] && PERCENT=0 || PERCENT=$x
x=$(last_step)
[[ -z "$x" ]] && STEP="unknown" || STEP="$x"
x=$(last_step_result)
[[ -z "$x" ]] && STEP_RESULT="unknown" || STEP_RESULT="$x"
x=$(pid_atbupdatetool)
[[ -z "$x" ]] && PID=99999 || PID=$x
x=$(last_event)
[[ -z "$x" ]] && EVENT="unknown" || EVENT="$x"
fi
echo "PERCENT=$PERCENT"
echo "STEP=$STEP"
echo "STEP_RESULT=$STEP_RESULT"
echo "PID=$PID"
echo "EVENT=$EVENT"
# build json to be sent to ISMAS with "U0003"
CURRENT_DATE=$(date +"%Y-%m-%d %H:%M:%S.000%z")
U0003Msg="{\
\"REASON\":\"SW_UP\",\
\"TIMESTAMP\":\"$CURRENT_DATE\",\
\"EVENT_ID\":\"$PID\",\
\"EVENT\":\"U0003\",\
\"EVENTSTATE\":1,\
\"PARAMETER\": {\
\"PERCENT\" : $PERCENT,\
\"RESULTCODE\" : 99,\
\"STEP\" : \"$1 -> monitored last step: $STEP\",\
\"STEP_RESULT\" : \"$1 -> monitored last step result: $STEP_RESULT\",\
\"VERSION\" : \"\"\
}\
}"
echo -e "U0003Msg=$U0003Msg"
(echo "#M=APISM#C=CMD_EVENT#J=$U0003Msg"; sleep 5) | nc localhost 7777
}
# save journal for the last run of atbupdatetool in $OUT_FILE
echo $(journalctl -u atbupdatetool --since="$START_DATE" --until=$STOP_DATE) > $OUT_FILE
if [[ "$EXIT_CODE" = "exited" && "$SERVICE_RESULT" = "success" && "$EXIT_STATUS" = "0" ]]
then
# almost normal run; at least there was no crash.
if cat $OUT_FILE | grep -o "U0003" | wc -l; then
echo "$SCRIPT_NAME: Failure code U0003 already sent to ISMAS"
exit 0
fi
if cat $OUT_FILE | grep -o "U0002" | wc -l; then
echo "$SCRIPT_NAME: Success code U0002 already sent to ISMAS"
exit 0
else
sendU0003 "$SCRIPT_NAME: Success code U0002 not sent to ISMAS"
fi
if cat $OUT_FILE | grep -o "U0001" | wc -l; then
echo "$SCRIPT_NAME: Success code U0001 already sent to ISMAS"
exit 0
else
sendU0003 "$SCRIPT_NAME: Success code U0001 not sent to ISMAS"
fi
else
# something unexpected has happened.
sendU0003 "$SCRIPT_NAME: EXIT_CODE=$EXIT_CODE;SERVICE_RESULT=$SERVICE_RESULT;EXIT_STATUS=$EXIT_STATUS"
fi