Compare commits
184 Commits
Author | SHA1 | Date | |
---|---|---|---|
4b3a39b0e6 | |||
a44b780d93 | |||
19dfae9b56 | |||
bef0d4fe12 | |||
72a2fc781c | |||
fc264689b1 | |||
fc587456d5 | |||
a2b933ab71 | |||
7d0fdf4d6d | |||
c2ce44c79b | |||
16a9556863 | |||
48896f97ec | |||
4486317cb2 | |||
6b9b88ea19 | |||
99a99d95a1 | |||
d4ddbbee21 | |||
34e5189945 | |||
c44c805238 | |||
196f1a730e | |||
7dc04c4422 | |||
5efac2619b | |||
9b0f741b9b | |||
81c5f8ee7e | |||
29e6a25e72 | |||
5abc057bda | |||
8aeb7ecfea | |||
4bb8e241b6 | |||
4469a23f9c | |||
d1f795e2db | |||
6865056f4b | |||
37bd5c90d3 | |||
fcba120dfa | |||
1d4f50fb9f | |||
a78040a037 | |||
9b175d7789 | |||
2d7f145a25 | |||
4589c4ca76 | |||
a32258a59e | |||
22f25e5251 | |||
258d883a51 | |||
504e242d42 | |||
731cdcbe09 | |||
b4e2d4c54a | |||
42961dea40 | |||
fd2f601f67 | |||
b45af505cd | |||
2dfe80b654 | |||
4b9dcc5e99 | |||
53639b55c9 | |||
3a83efbd3f | |||
c9d6a8d245 | |||
91db59b9f3 | |||
1d81e6b650 | |||
6d57b45d1a | |||
4e7ce2cd70 | |||
47fac31223 | |||
0d353cfbcf | |||
bdcb073bf8 | |||
226553a8ab | |||
d4ee56559b | |||
355b28ba40 | |||
edeff35d7e | |||
09d5de1b0b | |||
145fdab26e | |||
89d1ec5b21 | |||
f38c975dc6 | |||
fba007aa35 | |||
8b6adb3ea7 | |||
30603317c6 | |||
7083f3b4f8 | |||
7ff866525e | |||
2164037123 | |||
2e7d33c4c8 | |||
2a2751f6f3 | |||
2764ef4371 | |||
9783f343e1 | |||
8c6f0dfcc7 | |||
d688ad3d5c | |||
7b3f652b0e | |||
4cc42b2a65 | |||
d783fd7fb6 | |||
e0a0ff54e1 | |||
863d052a21 | |||
61b3d29e31 | |||
cac4f7249e | |||
3223c430be | |||
c09682ea33 | |||
fef1d43d5f | |||
705424727b | |||
b96f0896e3 | |||
a3967c76ac | |||
1197598a3d
|
|||
ec13e97226
|
|||
a8dd9d7e24
|
|||
82751eb1d4 | |||
17a4a69df2 | |||
a03261d04a | |||
7832ef5d8c | |||
9c213d0a97 | |||
18378afdc5 | |||
6dd8a8c6b3 | |||
adfb358e12 | |||
ff418b11a1 | |||
38e79f0354 | |||
103b3f3f9c | |||
ff6a6e0e45 | |||
afbce3b4ea | |||
823e59a582 | |||
01cfbddfb1 | |||
838efd3945 | |||
9a65cb4456 | |||
df0951d671 | |||
60cc752819 | |||
57b4716e2a | |||
15f28e9ffd | |||
a07893ddab | |||
d0eb1d12d8 | |||
cd59a39569 | |||
67c8b2f472 | |||
5158878ce2 | |||
b6971c1db5 | |||
9df46a1c49 | |||
6765b12f0c | |||
3e925756cf | |||
b2798b349e | |||
64dce44fe1 | |||
7e96b65c1b | |||
276d65a9d8 | |||
ba71728979 | |||
e82742a609 | |||
6773a7243a | |||
22c8997f1e | |||
9531a08b4a | |||
c065b57f0c | |||
cef05b7511 | |||
bb35e985ad | |||
981a2ea13a | |||
b14b296011 | |||
1ef9853876 | |||
01d8312aa8 | |||
507586f9dc | |||
12ffa71455 | |||
a84f495d43 | |||
7e4b5006eb | |||
0a28f0d82c | |||
5427844977 | |||
a45e552d90 | |||
be28570d23 | |||
1509e8619c | |||
a8df026a80 | |||
a803907449 | |||
afd31f1b27 | |||
f8fef38009 | |||
cbe1fd387d | |||
1620b73d01 | |||
4ebdcf56a0 | |||
99b9419150 | |||
4307fb96a6 | |||
c35390b6d6 | |||
fff6bd2b49 | |||
631ade1954 | |||
337bdd1bb0 | |||
978cc16304 | |||
bea8242d6f | |||
56daa84a14 | |||
17ddfd0ddd | |||
2ac8c4cfc6 | |||
0559ff64e2 | |||
385a7b7b00 | |||
503b7c64f9 | |||
beec9c2f9d | |||
5263b7de0f | |||
9b4d0494c8 | |||
0f2ee0349f | |||
e700a40875 | |||
1eba5338e4 | |||
f20be9ddcf | |||
7631c05e22 | |||
ad93e536f0 | |||
259da8200e | |||
8d528f0f55 | |||
66d0214720 | |||
86064979b4 | |||
86c996d7ac |
@@ -15,47 +15,103 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
VERSION=1.0.0
|
||||
|
||||
# 1.3.6 : Do not update device-controller/json files, but have the library
|
||||
# (in a later step) do that.
|
||||
# Fixed sending messages to ISMAS.
|
||||
# Always execute contents of opkg_commands-file (even if there are no
|
||||
# changes).
|
||||
# 1.3.7 : Wait forever for git-commands to finish in QProcess executing such
|
||||
# a command.
|
||||
# 1.3.8 : Remove accessing opkg_commands under file-system-path /etc/psa_update.
|
||||
# Activate download of json-configuration files.
|
||||
# 1.3.9 : Fix sendLastVersion: use configured branch and not master branch in
|
||||
# git show origin/master -s --format="c=%h m=%s d=%cI" ==>
|
||||
# git show origin/zg1/zone1 -s --format="c=%h m=%s d=%cI"
|
||||
# Use dynamic values for os-release and apism-version when sending
|
||||
# last version info.
|
||||
# 1.3.10: Fix premature killing opkg-commands: detected timeout of 100s was
|
||||
# too small when updating apism.
|
||||
# Fix display of UPDATE_SUCCESS when opkg_command fails. Detected when
|
||||
# updating apsim failed.
|
||||
# 1.3.11: Integrate version of ATBUpdateTool in SendLastVersion-ISMAS-message.
|
||||
# 1.3.12: Add command parameters for output of yocto-infos about ATBUpdateTool.
|
||||
# Use 'git pull' instead of 'git fetch'.
|
||||
# Use 'git clone --filter=blob:none' instead of 'git clone' to speed
|
||||
# up cloning of customer repository.
|
||||
# 1.3.13: Fix: if the customer repository is corrupted, remove it and re-clone
|
||||
# the repository (without checking the ISMAS-trigger (WAIT-)button.
|
||||
VERSION="1.3.14"
|
||||
# 1.3.14: Add additional check for sanity of customer repository using
|
||||
# "git fsck".
|
||||
# Stream-lined code of update process: massive refactoring.
|
||||
# Added functionality: If WAIT button is not active, then an existing
|
||||
# customer repository will be repaired, or a not existing repository
|
||||
# will be cloned. The process stops then.
|
||||
# However, if the WAIT button is active, the at least the commands in
|
||||
# opkg_commands will be executed. Changed files in the customer
|
||||
# repository will be worked on: tariff-files will be synced with the
|
||||
# local filesystem, json-files will be downloaded to firmware.
|
||||
# The device-controller firmware will be handled in a later version.
|
||||
|
||||
# PLANNED TODOS:
|
||||
# 1: Das Repository wird repariert bwz. neu geklont. Unabhaengig vom WAIT.
|
||||
# 2: Wenn der WAIT-Button aktiv ist, dann wird ein Repository repariert (neu
|
||||
# geklont), aber zusaetzlich werden alle verfuegbaren Dateien als neu
|
||||
# angesehen und die entsprechenden Aktionen durchgefuehrt: tariff-files
|
||||
# spiegeln, json-files laden und dc laden. Also VORSICHT: das repository
|
||||
# muss in diesem fall wirklich in ordnung sein.
|
||||
# 3: Wurde keine Datei geaendert, kein initiales Clone und der WAIT-button
|
||||
# nicht aktiv, so (passiert natuerlich nichts) kann man davon ausgehen,
|
||||
# dass es sich um ein automatisches Update handelt. Dann koennte man im
|
||||
# ISMAS eine entsprechende Meldung anzeigen als Teil von SEND-LAST-VERSION.
|
||||
# Wenn der WAIT-button aktiv ist, dann werden zumindest die opkg-commands
|
||||
# ausgefuehrt.
|
||||
# 4: rsync: immer alle Dateien soiegeln (bis auf opkg-commands)
|
||||
# 5: Falls das Tool mal abstuerzt, dann einen Signal-Handler (fuer TERM)
|
||||
# installieren, sodass zumnidest SEND-LASt-VERSION mit rausgeht.
|
||||
# 6: rsync: explizites Binary, nicht das in busybox enthaltene.
|
||||
|
||||
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
|
||||
|
||||
CONFIG += c++17 console
|
||||
CONFIG += c++17
|
||||
# CONFIG -= app_bundle
|
||||
|
||||
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
|
||||
|
||||
# custom target for 'git subtree'
|
||||
# subtree.target = subtree
|
||||
# subtree.commands = git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||
# subtree.depends =
|
||||
# QMAKE_EXTRA_UNIX_TARGETS += subtree
|
||||
|
||||
# ! exists(DCPlugin) {
|
||||
# $$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||
# } else {
|
||||
# $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||
# }
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
contains( CONFIG, PTU5 ) {
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
|
||||
CONFIG += link_pkgconfig
|
||||
lessThan(QT_MAJOR_VERSION, 5): PKGCONFIG += qextserialport
|
||||
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
QMAKE_CXXFLAGS += -O2 -std=c++17 # for GCC >= 4.7
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
ARCH = PTU5
|
||||
DEFINES+=PTU5
|
||||
}
|
||||
contains( CONFIG, PTU5_YOCTO ) {
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
|
||||
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
PTU5BASEPATH = /opt/devel/ptu5
|
||||
ARCH = PTU5
|
||||
DEFINES+=PTU5
|
||||
@@ -69,7 +125,7 @@ contains( CONFIG, DesktopLinux ) {
|
||||
# QMAKE_CC = ccache $$QMAKE_CC
|
||||
# QMAKE_CXX = ccache $$QMAKE_CXX
|
||||
QMAKE_CXXFLAGS += -std=c++17
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
# QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
|
||||
ARCH = DesktopLinux
|
||||
DEFINES+=DesktopLinux
|
||||
@@ -78,6 +134,7 @@ contains( CONFIG, DesktopLinux ) {
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
progress_event.cpp \
|
||||
update_dc_event.cpp \
|
||||
mainwindow.cpp \
|
||||
utils.cpp \
|
||||
update.cpp \
|
||||
@@ -91,6 +148,7 @@ SOURCES += \
|
||||
HEADERS += \
|
||||
update.h \
|
||||
progress_event.h \
|
||||
update_dc_event.h \
|
||||
utils.h \
|
||||
mainwindow.h \
|
||||
git/git_client.h \
|
||||
@@ -105,18 +163,6 @@ HEADERS += \
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
OTHER_FILES += \
|
||||
/opt/app/tools/atbupdate/update_log.csv \
|
||||
main.cpp.bck \
|
||||
main.cpp.bck2 \
|
||||
main.cpp.bck3
|
||||
|
||||
# https://blog.developer.atlassian.com/the-power-of-git-subtree/?_ga=2-71978451-1385799339-1568044055-1068396449-1567112770
|
||||
# git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||
# git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||
# include(./DCPlugin/DCPlugin.pri)
|
||||
|
||||
|
||||
|
||||
##########################################################################################
|
||||
# for running program on target through QtCreator
|
||||
|
@@ -26,29 +26,93 @@ GitClient::GitClient(QString const &customerNrStr,
|
||||
}
|
||||
|
||||
bool GitClient::gitCloneCustomerRepository() {
|
||||
QString gitCommand("git clone ");
|
||||
/* Blobless clone
|
||||
==============
|
||||
|
||||
When using the --filter=blob:none option, the initial git clone will
|
||||
download all reachable commits and trees, and only download the blobs
|
||||
for commits when you do a git checkout. This includes the first checkout
|
||||
inside the git clone operation.
|
||||
|
||||
The important thing to notice is that we have a copy of every blob at
|
||||
HEAD but the blobs in the history are not present. If your repository
|
||||
has a deep history full of large blobs, then this option can
|
||||
significantly reduce your git clone times. The commit and tree data is
|
||||
still present, so any subsequent git checkout only needs to download
|
||||
the missing blobs. The Git client knows how to batch these requests to
|
||||
ask the server only for the missing blobs.
|
||||
|
||||
Further, when running git fetch in a blobless clone, the server only
|
||||
sends the new commits and trees. The new blobs are downloaded only
|
||||
after a git checkout. Note that git pull runs git fetch and then git
|
||||
merge, so it will download the necessary blobs during the git merge
|
||||
command.
|
||||
|
||||
When using a blobless clone, you will trigger a blob download whenever
|
||||
you need the contents of a file, but you will not need one if you only
|
||||
need the OID (object-id) of a file. This means that git log can detect
|
||||
which commits changed a given path without needing to download extra
|
||||
data.
|
||||
|
||||
This means that blobless clones can perform commands like git
|
||||
merge-base, git log, or even git log -- <path> with the same performance
|
||||
as a full clone.
|
||||
|
||||
Commands like git diff or git blame <path> require the contents of the
|
||||
paths to compute diffs, so these will trigger blob downloads the first
|
||||
time they are run. However, the good news is that after that you will
|
||||
have those blobs in your repository and do not need to download them a
|
||||
second time. Most developers only need to run git blame on a small
|
||||
number of files, so this tradeoff of a slightly slower git blame command
|
||||
is worth the faster clone and fetch times.
|
||||
|
||||
Note: git v2.18 does not support treeless clones: --filter=tree:0.
|
||||
*/
|
||||
|
||||
// Note: for some reason it is necessary to pass "--progress ---v",
|
||||
// otherwise QProcess returns an error of 128 = 0x80 for the command.
|
||||
|
||||
QString gitCommand("git clone --progress -vvv --filter=blob:none ");
|
||||
gitCommand += m_repositoryPath;
|
||||
Command c(gitCommand);
|
||||
|
||||
qInfo() << "IN CURRENT WD" << m_workingDirectory
|
||||
<< "CLONE" << m_repositoryPath << "...";
|
||||
<< "CLONE VIA COMMAND" << gitCommand;
|
||||
|
||||
if (c.execute(m_workingDirectory)) { // execute the command in wd
|
||||
QString const result = c.getCommandResult();
|
||||
if (!result.isEmpty()) {
|
||||
// Cloning into 'customer_281'...\n
|
||||
static QRegularExpression re("(^\\s*Cloning\\s+into\\s+[']\\s*)(.*)(\\s*['].*$)");
|
||||
QRegularExpressionMatch match = re.match(result);
|
||||
if (match.hasMatch()) {
|
||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||
if (match.captured(2).trimmed() == m_customerNr) {
|
||||
qInfo() << "CLONING" << m_repositoryPath << "OK";
|
||||
return true;
|
||||
int customer = -1;
|
||||
int cloning = result.indexOf("Cloning", 0, Qt::CaseInsensitive);
|
||||
if (cloning != -1) {
|
||||
customer = result.indexOf("customer_", cloning, Qt::CaseInsensitive);
|
||||
if (customer != -1) {
|
||||
QString customerNr = result.mid(customer);
|
||||
static constexpr char const ch = '\'';
|
||||
int i = customerNr.indexOf(QChar(ch));
|
||||
if (i != -1) {
|
||||
if ((customerNr = customerNr.mid(0, i)) == m_customerNr) {
|
||||
qInfo() << "CLONING" << m_repositoryPath << "OK";
|
||||
return true;
|
||||
}
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("ERROR CLONE RESULT HAS WRONG CUSTOMER-NR. (%1 != %2) CLONE_RESULT=%3")
|
||||
.arg(customerNr)
|
||||
.arg(m_customerNr)
|
||||
.arg(result));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("ERROR CLONE RESULT HAS WRONG FORMAT. CLONING=%1 CUSTOMER=%2 CLONE_RESULT=%3")
|
||||
.arg(cloning)
|
||||
.arg(customer)
|
||||
.arg(result));
|
||||
return false;
|
||||
}
|
||||
Utils::printCriticalErrorMsg(QString("ERROR CLONE RESULT HAS WRONG FORMAT. CLONE_RESULT=") + result);
|
||||
Utils::printCriticalErrorMsg("ERROR CLONE RESULT IS EMPTY");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -114,6 +178,53 @@ bool GitClient::gitCloneAndCheckoutBranch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList GitClient::gitShowReason(QString branchName) {
|
||||
QStringList lst;
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
// %h: commit (short form)
|
||||
// %s: commit message
|
||||
// %cI: commit date, strict ISO 8601 format
|
||||
// Note: branch with branchName has to exist: format zg1/zone1
|
||||
Command c(QString("git show origin/%1 -s --format=\"c=%h m=%s d=%cI\"").arg(branchName));
|
||||
if (c.execute(m_customerRepository)) {
|
||||
QString const s = c.getCommandResult().trimmed();
|
||||
int const c = s.indexOf("c=");
|
||||
int const m = s.indexOf("m=");
|
||||
int const d = s.indexOf("d=");
|
||||
|
||||
QString msg = IsmasClient::getReasonForLastSendVersion();
|
||||
QString commit{""}, date{""};
|
||||
|
||||
if (c != -1) {
|
||||
int start = c + 2;
|
||||
if (m >= start) {
|
||||
int length = m - start;
|
||||
commit = s.mid(start, length).trimmed();
|
||||
|
||||
start = m + 2;
|
||||
if (d >= start) {
|
||||
length = d - start;
|
||||
msg += " (";
|
||||
msg = s.mid(start, length).trimmed();
|
||||
msg += ")";
|
||||
|
||||
start = d + 2;
|
||||
date = s.mid(start);
|
||||
}
|
||||
}
|
||||
|
||||
if (!commit.isEmpty() && !msg.isEmpty() && !date.isEmpty()) {
|
||||
lst << commit << msg << date;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << "CUSTOMER_REPOSITORY" << m_customerRepository
|
||||
<< "DOES NOT EXIST";
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
/*
|
||||
Zu beachten: wird eine datei neu hinzugefuegt (git add/commit) dann aber gleich
|
||||
wieder geloscht, so wird sie im diff nicht angezeigt.
|
||||
@@ -168,92 +279,88 @@ std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GitClient::gitFsck() {
|
||||
bool r = false;
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
Command c("git fsck");
|
||||
if ((r = c.execute(m_customerRepository)) == false) {
|
||||
QString const &s = c.getCommandResult().trimmed();
|
||||
Utils::printCriticalErrorMsg(QString("GIT FSCK FAILED: %1").arg(s));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
/*
|
||||
Hat sich nichts geaendert, so werden auch keine Commits <>..<> angezeigt
|
||||
*/
|
||||
std::optional<QString> GitClient::gitFetch() {
|
||||
std::optional<QString> GitClient::gitPull() {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
qInfo() << "BRANCH NAME" << m_branchName;
|
||||
|
||||
Command c("git fetch");
|
||||
Command c("git pull");
|
||||
if (c.execute(m_customerRepository)) {
|
||||
QString const s = c.getCommandResult().trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
QStringList lines = Update::split(s, '\n');
|
||||
worker()->CONSOLE(lines) << Worker::UPDATE_STEP::UPDATE_REPOSITORY;
|
||||
if (!lines.empty()) {
|
||||
int zoneNr = Utils::read1stLineOfFile("/mnt/system_data/zone_nr");
|
||||
m_branchName = (zoneNr != 0) ? QString("zg1/zone%1").arg(zoneNr) : "master";
|
||||
// lines can look like this:
|
||||
// From https://git.mimbach49.de/GerhardHoffmann/customer_281
|
||||
// 41ec581..5d25ac3 master -> origin/master
|
||||
// ff10f57..43530a1 zg1/zone1 -> origin/zg1/zone1
|
||||
// 6ed893f..5d9882c zg1/zone2 -> origin/zg1/zone2
|
||||
// 4384d17..77045d8 zg1/zone3 -> origin/zg1/zone3
|
||||
// 89d2812..36a0d74 zg1/zone5 -> origin/zg1/zone5
|
||||
bool found = false;
|
||||
for (int i=0; i < lines.size(); ++i) {
|
||||
if (lines.at(i).contains(m_branchName)) {
|
||||
found = true;
|
||||
// 409f198..6c22726 zg1/zone1 -> origin/zg1/zone1
|
||||
static QRegularExpression re("(^\\s*)([0-9A-Fa-f]+..[0-9A-Fa-f]+)(.*$)");
|
||||
QRegularExpressionMatch match = re.match(lines.at(i));
|
||||
if (match.hasMatch()) {
|
||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||
return match.captured(2);
|
||||
static const QRegularExpression alreadyUpToDate("^\\s*Already\\s+up\\s+to\\s+date.*$");
|
||||
if (std::none_of(lines.cbegin(), lines.cend(),
|
||||
[](QString const &s) { return s.contains(alreadyUpToDate); })) {
|
||||
int zoneNr = Utils::read1stLineOfFile("/mnt/system_data/zone_nr");
|
||||
m_branchName = (zoneNr != 0) ? QString("zg1/zone%1").arg(zoneNr) : "master";
|
||||
// lines can look like this:
|
||||
// From https://git.mimbach49.de/GerhardHoffmann/customer_281
|
||||
// 41ec581..5d25ac3 master -> origin/master
|
||||
// ff10f57..43530a1 zg1/zone1 -> origin/zg1/zone1
|
||||
// 6ed893f..5d9882c zg1/zone2 -> origin/zg1/zone2
|
||||
// 4384d17..77045d8 zg1/zone3 -> origin/zg1/zone3
|
||||
// 89d2812..36a0d74 zg1/zone5 -> origin/zg1/zone5
|
||||
bool found = false;
|
||||
for (int i=0; i < lines.size(); ++i) {
|
||||
if (lines.at(i).contains(m_branchName)) {
|
||||
found = true;
|
||||
// 409f198..6c22726 zg1/zone1 -> origin/zg1/zone1
|
||||
static QRegularExpression re("(^\\s*)([0-9A-Fa-f]+..[0-9A-Fa-f]+)(.*$)");
|
||||
QRegularExpressionMatch match = re.match(lines.at(i));
|
||||
if (match.hasMatch()) {
|
||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||
QString const matchCaptured = match.captured(2);
|
||||
worker()->CONSOLE(QStringList(matchCaptured)) << Worker::UPDATE_STEP::UPDATE_REPOSITORY;
|
||||
return matchCaptured;
|
||||
} else {
|
||||
QStringList lst(QString("(wrong capture count (%1)").arg(re.captureCount()));
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
} else {
|
||||
emit m_worker->showErrorMessage("git fetch",
|
||||
QString("(wrong cap-count (%1)").arg(re.captureCount()));
|
||||
QStringList lst("no regex-match for commits");
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
} else {
|
||||
emit m_worker->showErrorMessage("git fetch",
|
||||
"no regex-match for commits");
|
||||
Utils::printCriticalErrorMsg("NO REGEX MATCH FOR COMMITS");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
emit m_worker->showErrorMessage("git fetch",
|
||||
QString("unkown branch name ") + m_branchName);
|
||||
Utils::printCriticalErrorMsg("UNKNOWN BRANCH NAME " + m_branchName);
|
||||
if (!found) {
|
||||
QStringList lst(QString("unknown branch name ") + m_branchName);
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
} else {
|
||||
return "Already up to date";
|
||||
}
|
||||
} else {
|
||||
emit m_worker->showErrorMessage("git fetch",
|
||||
QString("wrong format for result of 'git fetch' ") + s);
|
||||
Utils::printCriticalErrorMsg(QString("WRONG FORMAT FOR RESULT OF 'GIT FETCH' ") + s);
|
||||
QStringList lst(QString("WRONG FORMAT FOR RESULT OF 'GIT PULL' ") + s);
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
} else {
|
||||
emit m_worker->showErrorMessage("git fetch", "empty result for 'git fetch'");
|
||||
Utils::printCriticalErrorMsg("EMPTY RESULT FOR 'GIT FETCH'");
|
||||
QStringList lst("EMPTY RESULT FOR 'GIT PULL'");
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emit m_worker->showErrorMessage("git fetch", QString("repository ") + m_customerRepository + " does not exist");
|
||||
Utils::printCriticalErrorMsg(QString("REPOSITORY ") + m_customerRepository + " DOES NOT EXIST");
|
||||
QStringList lst(QString("REPOSITORY ") + m_customerRepository + " DOES NOT EXIST");
|
||||
worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GitClient::gitFetchAndDiff() {
|
||||
if (gitFetch()) {
|
||||
QString gitCommand("git diff --compact-summary HEAD..FETCH_HEAD");
|
||||
Command c(gitCommand);
|
||||
return c.execute(m_workingDirectory);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitClient::gitPull() {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
Command c("git pull");
|
||||
if (c.execute(m_customerRepository)) {
|
||||
qInfo() << "PULLED INTO" << m_customerRepository;
|
||||
return true;
|
||||
}
|
||||
Utils::printCriticalErrorMsg(QString("PULL INTO " + m_customerRepository + " FAILED"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<QStringList> GitClient::gitMerge() {
|
||||
Command c("git merge");
|
||||
if (c.execute(m_workingDirectory)) {
|
||||
@@ -289,7 +396,7 @@ QString GitClient::gitBlob(QString fileName) {
|
||||
if (fi.exists()) {
|
||||
QString const gitCommand = QString("git hash-object %1").arg(fileName);
|
||||
Command c(gitCommand);
|
||||
if (c.execute(m_workingDirectory)) {
|
||||
if (c.execute("/tmp")) {
|
||||
return c.getCommandResult().trimmed();
|
||||
}
|
||||
}
|
||||
|
@@ -43,14 +43,18 @@ class GitClient : public QObject {
|
||||
|
||||
bool gitCloneAndCheckoutBranch();
|
||||
|
||||
std::optional<QString> gitFetch();
|
||||
bool gitFetchAndDiff();
|
||||
bool gitPull();
|
||||
Worker *worker() { return m_worker; }
|
||||
Worker const *worker() const { return m_worker; }
|
||||
|
||||
std::optional<QString> gitPull();
|
||||
std::optional<QStringList> gitDiff(QString const &commit);
|
||||
std::optional<QStringList> gitMerge();
|
||||
|
||||
bool gitFsck();
|
||||
|
||||
QString gitLastCommit(QString fileName);
|
||||
QString gitBlob(QString fileName);
|
||||
QStringList gitShowReason(QString branchName);
|
||||
static QString gitBlob(QString fileName);
|
||||
QString gitCommitForBlob(QString blob);
|
||||
bool gitIsFileTracked(QString file2name);
|
||||
};
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
@@ -22,6 +23,15 @@
|
||||
#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
|
||||
@@ -46,6 +56,12 @@ 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"
|
||||
@@ -54,12 +70,19 @@ void IsmasClient::printDebugMessage(int port,
|
||||
<< "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"
|
||||
@@ -68,6 +91,7 @@ void IsmasClient::printInfoMessage(int port,
|
||||
<< "local address ..." << clientIP << "\n"
|
||||
<< "local port ......" << clientPort << "\n"
|
||||
<< message;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IsmasClient::printErrorMessage(int port,
|
||||
@@ -137,7 +161,12 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
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;
|
||||
@@ -151,24 +180,56 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
int loop = 0;
|
||||
int bytesWritten = 0;
|
||||
while (bytesWritten < bytesToWrite) {
|
||||
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
|
||||
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("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,7 +241,7 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
// QString("CANNOT CLOSE WRITING END (") + strerror(errno) + ")");
|
||||
// }
|
||||
|
||||
printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT ") + buf);
|
||||
printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT <<<") + buf + ">>>");
|
||||
|
||||
loop = 0;
|
||||
bzero(buf, sizeof(buf));
|
||||
@@ -188,37 +249,73 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
|
||||
int bytesRead = 0;
|
||||
while (bytesRead < bytesToRead) {
|
||||
errno = 0;
|
||||
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) + ")");
|
||||
::close(sockfd);
|
||||
return std::nullopt;
|
||||
} else
|
||||
if (n < 0) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
if (++loop < 10) {
|
||||
QThread::msleep(500);
|
||||
continue;
|
||||
}
|
||||
printErrorMessage(port, clientIP, clientPort,
|
||||
QString("READ TIMEOUT %1(").arg(loop) + strerror(errno) + ")");
|
||||
::close(sockfd);
|
||||
return std::nullopt;
|
||||
}
|
||||
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);
|
||||
// printInfoMessage(port, clientIP, clientPort, QString("MESSAGE RECEIVED ") + buf);
|
||||
QString response(buf);
|
||||
|
||||
if (int idx = response.indexOf("{\"error\":\"ISMAS is offline\"}")) {
|
||||
@@ -293,16 +390,18 @@ QString IsmasClient::errorBackendNotConnected(QString const &info,
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString IsmasClient::errorGitClone(int percent, QString const &info, QString const &version) {
|
||||
QString IsmasClient::errorGitClone(QString const &info,
|
||||
QString const &version) {
|
||||
return updateNewsToIsmas("U0003",
|
||||
percent,
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::INSTALL_ERROR,
|
||||
"CLONE CUSTOMER REPOSITORY FAILED",
|
||||
info.toStdString().c_str(),
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString IsmasClient::backendConnected(QString const &info, QString const &version) {
|
||||
QString IsmasClient::backendConnected(QString const &info,
|
||||
QString const &version) {
|
||||
return updateNewsToIsmas("U0010",
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::SUCCESS,
|
||||
@@ -311,7 +410,8 @@ QString IsmasClient::backendConnected(QString const &info, QString const &versio
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString IsmasClient::execOpkgCommand(QString const &info, QString const &version) {
|
||||
QString IsmasClient::execOpkgCommand(QString const &info,
|
||||
QString const &version) {
|
||||
return updateNewsToIsmas("U0010",
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::SUCCESS,
|
||||
@@ -320,6 +420,15 @@ QString IsmasClient::execOpkgCommand(QString const &info, QString const &version
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString IsmasClient::rsyncFile(QString const &info, QString const &version) {
|
||||
return updateNewsToIsmas("U0010",
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::SUCCESS,
|
||||
"RSYNC FILE",
|
||||
info.toStdString().c_str(),
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
QString IsmasClient::updateTriggerSet(QString const &info, QString const &version) {
|
||||
return updateNewsToIsmas("U0010",
|
||||
m_progressInPercent,
|
||||
@@ -345,13 +454,11 @@ QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) {
|
||||
static char buf[4096*2];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
QString const ts = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
QString sendVersionHash = "N/A";
|
||||
|
||||
// local data="#M=APISM#C=CMD_SENDVERSION#J=
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"{"
|
||||
"\"VERSION_INFO\" : {"
|
||||
"\"REASON\":\"%s\","
|
||||
"\"CREATED\":\"%s\","
|
||||
"\"HASH\":\"%s\""
|
||||
"},"
|
||||
@@ -361,6 +468,13 @@ QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) {
|
||||
"\"ZONE\" : %d,"
|
||||
"\"INFO\" : \"%s\","
|
||||
"\"BLOB\" : \"%s\","
|
||||
"\"LAST-COMMIT\" : \"%s\","
|
||||
"\"SIZE\" : %d,"
|
||||
"\"LOADED\" : \"%s\""
|
||||
"},"
|
||||
"\"OPKG_COMMANDS\" : {"
|
||||
"\"BLOB\" : \"%s\","
|
||||
"\"LAST-COMMIT\" : \"%s\","
|
||||
"\"SIZE\" : %d,"
|
||||
"\"LOADED\" : \"%s\""
|
||||
"},"
|
||||
@@ -529,10 +643,14 @@ QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) {
|
||||
"}"
|
||||
"},"
|
||||
"\"SOFTWARE\": {"
|
||||
"\"RAUC\" : \"%s\","
|
||||
"\"OPKG\" : \"%s\","
|
||||
"\"APISM\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"ATBQT\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"ATB-UPDATE-TOOL\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"}"
|
||||
"},"
|
||||
"\"PLUGINS\" : {"
|
||||
@@ -559,17 +677,24 @@ QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) {
|
||||
"}"
|
||||
"}"
|
||||
"}",
|
||||
ts.toStdString().c_str(),
|
||||
sendVersionHash.toStdString().c_str(),
|
||||
psa.versionInfo.reason.toStdString().c_str(),
|
||||
psa.versionInfo.created.toStdString().c_str(),
|
||||
psa.versionInfo.lastCommit.toStdString().c_str(),
|
||||
|
||||
psa.tariff.version.toStdString().c_str(),
|
||||
psa.tariff.project.toStdString().c_str(),
|
||||
psa.tariff.zone,
|
||||
psa.tariff.info.toStdString().c_str(),
|
||||
psa.tariff.blob.toStdString().c_str(),
|
||||
psa.tariff.lastCommit.toStdString().c_str(),
|
||||
psa.tariff.size,
|
||||
psa.tariff.loadTime.toStdString().c_str(),
|
||||
|
||||
psa.opkg.blob.toStdString().c_str(),
|
||||
psa.opkg.lastCommit.toStdString().c_str(),
|
||||
psa.opkg.size,
|
||||
psa.opkg.loadTime.toStdString().c_str(),
|
||||
|
||||
psa.cash.blob.toStdString().c_str(),
|
||||
psa.cash.size,
|
||||
psa.conf.blob.toStdString().c_str(),
|
||||
@@ -651,9 +776,9 @@ QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) {
|
||||
psa.dc.gitBlob.toStdString().c_str(),
|
||||
psa.dc.gitLastCommit.toStdString().c_str(),
|
||||
|
||||
psa.sw.raucVersion.toStdString().c_str(),
|
||||
psa.sw.opkgVersion.toStdString().c_str(),
|
||||
psa.sw.apismVersion.toStdString().c_str(),
|
||||
psa.sw.atbQTVersion.toStdString().c_str(),
|
||||
psa.sw.atbUpdateToolVersion.toStdString().c_str(),
|
||||
|
||||
psa.pluginVersion.deviceController.toStdString().c_str(),
|
||||
psa.pluginVersion.ingenicoISelfCC.toStdString().c_str(),
|
||||
@@ -735,7 +860,7 @@ QString IsmasClient::updateOfPSAActivated(QString const &version) { // sent ev
|
||||
}
|
||||
|
||||
QString IsmasClient::updateOfPSASucceeded(QString const &version) {
|
||||
m_progressInPercent = 0;
|
||||
m_progressInPercent = 100;
|
||||
return updateNewsToIsmas("U0001",
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::SUCCESS,
|
||||
@@ -762,14 +887,21 @@ QString IsmasClient::jsonParseFailed(int resultCode, QString reason, QString con
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
std::optional<QString> IsmasClient::finalResult(int resultCode, QString reason, QString const &version) {
|
||||
m_progressInPercent = 0;
|
||||
std::optional<QString> IsmasClient::finalResult(int resultCode,
|
||||
QString reason,
|
||||
QString const &version) {
|
||||
Q_UNUSED(resultCode);
|
||||
Q_UNUSED(reason);
|
||||
Q_UNUSED(version);
|
||||
|
||||
/*
|
||||
m_progressInPercent = 100;
|
||||
if (resultCode == RESULT_CODE::SUCCESS) {
|
||||
return updateNewsToIsmas("U0002",
|
||||
m_progressInPercent,
|
||||
RESULT_CODE::SUCCESS,
|
||||
resultCode,
|
||||
"FINAL-UPDATE-RESULT",
|
||||
"(re-)set WAIT state",
|
||||
reason.toStdString().c_str(),
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
if (resultCode == RESULT_CODE::INSTALL_ERROR) {
|
||||
@@ -780,6 +912,7 @@ std::optional<QString> IsmasClient::finalResult(int resultCode, QString reason,
|
||||
reason.toStdString().c_str(),
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
*/
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -792,3 +925,18 @@ QString IsmasClient::updateOfPSAFailed(int resultCode, QString step,
|
||||
reason.toStdString().c_str(),
|
||||
version.toStdString().c_str());
|
||||
}
|
||||
|
||||
char const *IsmasClient::reason[REASON::ENTRIES] = {
|
||||
"TIME-TRIGGERED", "SERVICE", "DEV-TEST"
|
||||
};
|
||||
|
||||
QString IsmasClient::getReasonForLastSendVersion() {
|
||||
QString const &parentName = Utils::getParentName();
|
||||
if (parentName == "ATBQT") {
|
||||
return reason[REASON::SERVICE];
|
||||
}
|
||||
if (parentName == "systemd") {
|
||||
return reason[REASON::TIME_TRIGGERED];
|
||||
}
|
||||
return reason[REASON::DEV_TEST];
|
||||
}
|
||||
|
@@ -7,6 +7,12 @@
|
||||
#include <optional>
|
||||
|
||||
struct PSAInstalled {
|
||||
struct VersionInfo {
|
||||
QString created;
|
||||
QString reason;
|
||||
QString lastCommit;
|
||||
} versionInfo;
|
||||
|
||||
struct Tariff {
|
||||
QString name;
|
||||
QString version;
|
||||
@@ -24,6 +30,13 @@ struct PSAInstalled {
|
||||
QString cpuSerial;
|
||||
} hw;
|
||||
|
||||
struct Opkg {
|
||||
int size;
|
||||
QString blob;
|
||||
QString lastCommit;
|
||||
QString loadTime;
|
||||
} opkg;
|
||||
|
||||
struct DC {
|
||||
QString versionHW;
|
||||
QString versionSW;
|
||||
@@ -33,9 +46,9 @@ struct PSAInstalled {
|
||||
} dc;
|
||||
|
||||
struct SoftWare {
|
||||
QString raucVersion;
|
||||
QString opkgVersion;
|
||||
QString apismVersion;
|
||||
QString atbQTVersion;
|
||||
QString atbUpdateToolVersion;
|
||||
} sw;
|
||||
|
||||
struct PluginVersion {
|
||||
@@ -73,15 +86,20 @@ struct PSAInstalled {
|
||||
hw.linuxVersion = "N/A";
|
||||
hw.cpuSerial = "N/A";
|
||||
|
||||
opkg.size = -1;
|
||||
opkg.blob = "N/A";
|
||||
opkg.lastCommit = "N/A";
|
||||
opkg.loadTime = "N/A";
|
||||
|
||||
dc.versionHW = "N/A";
|
||||
dc.versionSW = "N/A";
|
||||
dc.gitBlob = "N/A";
|
||||
dc.gitLastCommit = "N/A";
|
||||
dc.size = -1;
|
||||
|
||||
sw.raucVersion = "N/A";
|
||||
sw.opkgVersion = "N/A";
|
||||
sw.apismVersion = "N/A";
|
||||
sw.atbQTVersion = "N/A";
|
||||
sw.atbUpdateToolVersion = "N/A";
|
||||
|
||||
pluginVersion.deviceController = "N/A";
|
||||
pluginVersion.ingenicoISelfCC = "N/A";
|
||||
@@ -123,6 +141,7 @@ public:
|
||||
DIRECT_PORT = 7778
|
||||
};
|
||||
|
||||
|
||||
enum RESULT_CODE {
|
||||
SUCCESS=0,
|
||||
NO_UPDATE_NECESSARY=1,
|
||||
@@ -130,9 +149,20 @@ public:
|
||||
WRONG_PACKAGE=3,
|
||||
INSTALL_ERROR=4};
|
||||
|
||||
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);
|
||||
|
||||
static QString getReasonForLastSendVersion();
|
||||
|
||||
int getProgressInPercent() const {return m_progressInPercent; }
|
||||
void setProgressInPercent(int procent) { m_progressInPercent = procent; }
|
||||
|
||||
@@ -147,12 +177,13 @@ public:
|
||||
QString cloneAndCheckoutCustomerRepository(QString const &info, QString const &version = QString()); // clone and checkout customer repository
|
||||
QString checkoutBranch(QString const &info, QString const &version = QString()); // checkout branch
|
||||
QString errorBackendNotConnected(QString const &info, QString const &version = QString()); // checkout branch
|
||||
QString errorGitClone(int percent, QString const &info, QString const &version = QString());
|
||||
QString errorGitClone(QString const &info, QString const &version = QString());
|
||||
QString backendConnected(QString const &info, QString const &version = QString());
|
||||
QString updateTriggerSet(QString const &info, QString const &version = QString());
|
||||
QString errorUpdateTrigger(QString const &info, QString const &version = QString());
|
||||
QString gitFetch(QString const &info, QString const &version = QString());
|
||||
QString execOpkgCommand(QString const &info, QString const &version = QString());
|
||||
QString rsyncFile(QString const &info, QString const &version = QString());
|
||||
QString errorGitFetch(int resultCode, QString const &info, QString const &version = QString());
|
||||
QString updateOfPSAActivated(QString const &version = QString());
|
||||
// and update accepted
|
||||
|
145
main.cpp
145
main.cpp
@@ -31,6 +31,13 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QtWidgets>
|
||||
#include <QScopedPointer>
|
||||
|
||||
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
@@ -57,6 +64,24 @@ int main(int argc, char *argv[]) {
|
||||
setDebugLevel(LOG_NOTICE);
|
||||
}
|
||||
|
||||
//#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
||||
//#ifdef _POSIX_THREAD_PROCESS_SHARED
|
||||
// errno = 0;
|
||||
// int res = 0;
|
||||
// if ((res = sysconf(_SC_THREAD_PROCESS_SHARED)) < 0) {
|
||||
// if (errno != 0) {
|
||||
// qCritical() << "_POSIX_THREAD_PROCESS_SHARED NOT SUPPORTED"
|
||||
// << strerror(errno);
|
||||
// exit(-1);
|
||||
// }
|
||||
// } else {
|
||||
// if (res == _POSIX_THREAD_PROCESS_SHARED) {
|
||||
// Utils::printInfoMsg("_POSIX_THREAD_PROCESS_SHARED SUPPORTED");
|
||||
// }
|
||||
// }
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Download tool for downloading device controller firmware, printer json-files and executing opkg-commands.");
|
||||
parser.addHelpOption();
|
||||
@@ -65,21 +90,21 @@ int main(int argc, char *argv[]) {
|
||||
QCommandLineOption pluginDirectoryOption(QStringList() << "plugin-directory" << "plugin-directory",
|
||||
QCoreApplication::translate("main", "Where to find dc-plugin."),
|
||||
QCoreApplication::translate("main", "directory"));
|
||||
QString const pluginDefault = "./plugins";
|
||||
QString const pluginDefault = "/usr/lib";
|
||||
pluginDirectoryOption.setDefaultValue(pluginDefault);
|
||||
parser.addOption(pluginDirectoryOption);
|
||||
|
||||
QCommandLineOption pluginNameOption(QStringList() << "plugin-name" << "plugin-name",
|
||||
QCoreApplication::translate("main", "Name of dc-plugin."),
|
||||
QCoreApplication::translate("main", "directory"));
|
||||
QString const pluginNameDefault = "libCAmaster.so";
|
||||
QString const pluginNameDefault = "libCAslave.so";
|
||||
pluginNameOption.setDefaultValue(pluginNameDefault);
|
||||
parser.addOption(pluginNameOption);
|
||||
|
||||
QCommandLineOption workingDirectoryOption(QStringList() << "working-directory" << "working-directory",
|
||||
QCoreApplication::translate("main", "working directory of update-script."),
|
||||
QCoreApplication::translate("main", "directory"));
|
||||
QString const workingDirectoryDefault = ".";
|
||||
QString const workingDirectoryDefault = "/opt/app/tools/atbupdate";
|
||||
workingDirectoryOption.setDefaultValue(workingDirectoryDefault);
|
||||
parser.addOption(workingDirectoryOption);
|
||||
|
||||
@@ -87,47 +112,29 @@ int main(int argc, char *argv[]) {
|
||||
QCoreApplication::translate("main", "Start ATBUpdateTool in dry-run-mode. No actual actions."));
|
||||
parser.addOption(dryRunOption);
|
||||
|
||||
// TODO:
|
||||
// add some additional parameters
|
||||
// --dry-run
|
||||
// -d: only update device-controller firmware
|
||||
// -j: only update json-files
|
||||
// -o: only execute opkg-commnds
|
||||
// -f: force. update_psa shall always perform a 'git pull'
|
||||
QCommandLineOption extendedVersionOption(QStringList() << "V" << "extended-version",
|
||||
QCoreApplication::translate("main", "Show extended version (including last git commit)."));
|
||||
parser.addOption(extendedVersionOption);
|
||||
|
||||
QCommandLineOption yoctoVersionOption(QStringList() << "y" << "yocto-version",
|
||||
QCoreApplication::translate("main", "Show yocto version of ATBUpdateTool."));
|
||||
parser.addOption(yoctoVersionOption);
|
||||
|
||||
QCommandLineOption yoctoInstallStatusOption(QStringList() << "Y" << "yocto-install",
|
||||
QCoreApplication::translate("main", "Show yocto install status of ATBUpdateTool."));
|
||||
parser.addOption(yoctoInstallStatusOption);
|
||||
|
||||
// Process the actual command line arguments given by the user
|
||||
parser.process(a);
|
||||
QString plugInDir = parser.value(pluginDirectoryOption);
|
||||
QString plugInName = parser.value(pluginNameOption);
|
||||
QString workingDir = parser.value(workingDirectoryOption);
|
||||
bool dryRun = parser.isSet(dryRunOption);
|
||||
bool const dryRun = parser.isSet(dryRunOption);
|
||||
bool const showYoctoVersion = parser.isSet(yoctoVersionOption);
|
||||
bool const showYoctoInstallStatus = parser.isSet(yoctoInstallStatusOption);
|
||||
bool const showExtendedVersion = parser.isSet(extendedVersionOption);
|
||||
QString const rtPath = QCoreApplication::applicationDirPath();
|
||||
|
||||
if (plugInDir == pluginDefault) {
|
||||
plugInDir = (rtPath + "/" + pluginDefault);
|
||||
}
|
||||
if (!QDir(plugInDir).exists()) {
|
||||
qCritical() << plugInDir
|
||||
<< "does not exists, but has to contain dc-library";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
qInfo() << "pwd ..............." << rtPath;
|
||||
qInfo() << "plugInDir ........." << plugInDir;
|
||||
qInfo() << "plugInName ........" << plugInName;
|
||||
qInfo() << "workingDir ........" << workingDir;
|
||||
qInfo() << "dryRun ............" << dryRun;
|
||||
|
||||
// before loading the library, delete all possible shared memory segments
|
||||
#if defined Q_OS_LINUX || defined Q_OS_UNIX
|
||||
// system("rm -rf /tmp/qipc*");
|
||||
#else
|
||||
#error "Only tested under UNIX/LINUX"
|
||||
#endif
|
||||
|
||||
hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), plugInName);
|
||||
// hw->dc_autoRequest(false);
|
||||
|
||||
int machineNr = Utils::read1stLineOfFile("/etc/machine_nr");
|
||||
int customerNr = Utils::read1stLineOfFile("/etc/cust_nr");
|
||||
int zoneNr = Utils::read1stLineOfFile("/etc/zone_nr");
|
||||
@@ -137,20 +144,76 @@ int main(int argc, char *argv[]) {
|
||||
QThread::currentThread()->setObjectName("main thread");
|
||||
qInfo() << "Main thread" << QThread::currentThreadId();
|
||||
|
||||
Worker worker(hw,
|
||||
customerNr,
|
||||
if (showExtendedVersion) {
|
||||
printf(APP_EXTENDED_VERSION"\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (showYoctoVersion) {
|
||||
printf("%s\n", Worker::getATBUpdateToolYoctoVersion().toStdString().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (showYoctoInstallStatus) {
|
||||
printf("%s\n", Worker::getATBUpdateToolYoctoInstallationStatus().toStdString().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!QDir(plugInDir).exists()) {
|
||||
qCritical() << plugInDir
|
||||
<< "does not exists, but has to contain dc-library";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
qInfo() << "pwd ......................" << rtPath;
|
||||
qInfo() << "plugInDir ................" << plugInDir;
|
||||
qInfo() << "plugInName ..............." << plugInName;
|
||||
qInfo() << "workingDir ..............." << workingDir;
|
||||
qInfo() << "dryRun ..................." << dryRun;
|
||||
qInfo() << "extended-version ........." << APP_EXTENDED_VERSION;
|
||||
//qInfo() << "yocto-version ............" << Worker::getATBUpdateToolYoctoVersion();
|
||||
//qInfo() << "yocto-install-status ....." << Worker::getATBUpdateToolYoctoInstallationStatus();
|
||||
|
||||
// before loading the library, delete all possible shared memory segments
|
||||
#if defined Q_OS_LINUX || defined Q_OS_UNIX
|
||||
// system("rm -rf /tmp/qipc*");
|
||||
#else
|
||||
#error "Only tested under UNIX/LINUX"
|
||||
#endif
|
||||
|
||||
hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), plugInName);
|
||||
hw->dc_autoRequest(true);
|
||||
// hw->dc_openSerial(5, "115200", "ttymxc2", 1);
|
||||
|
||||
Worker worker(customerNr,
|
||||
machineNr,
|
||||
zoneNr,
|
||||
branchName,
|
||||
plugInName,
|
||||
workingDir,
|
||||
dryRun);
|
||||
|
||||
MainWindow mw(&worker);
|
||||
QString const customerNrStr(
|
||||
QString("customer_") + QString::number(customerNr).rightJustified(3, '0'));
|
||||
|
||||
QScopedPointer<Update> update(
|
||||
new Update(hw,
|
||||
&worker,
|
||||
QDir::cleanPath(workingDir + QDir::separator() + customerNrStr),
|
||||
customerNrStr,
|
||||
branchName,
|
||||
plugInName,
|
||||
workingDir,
|
||||
dryRun,
|
||||
nullptr,
|
||||
SERIAL_PORT,
|
||||
"115200"));
|
||||
|
||||
MainWindow mw(hw, &worker, update.get());
|
||||
worker.setMainWindow(&mw);
|
||||
|
||||
mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
mw.setWindowState(Qt::WindowFullScreen);
|
||||
mw.show();
|
||||
mw.showFullScreen();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
|
397
mainwindow.cpp
397
mainwindow.cpp
@@ -3,18 +3,120 @@
|
||||
#include "worker.h"
|
||||
#include "utils.h"
|
||||
#include "progress_event.h"
|
||||
#include "update_dc_event.h"
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QScrollBar>
|
||||
#include <QEvent>
|
||||
|
||||
MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
|
||||
|
||||
#if EMERGENCY_LEAVE_BL==1
|
||||
static int step = 0;
|
||||
|
||||
void MainWindow::emergencyLeaveBL() {
|
||||
//
|
||||
qCritical() << __func__ << step;
|
||||
switch(step) {
|
||||
case 0:
|
||||
if (m_hw->dc_openSerial(5, "115200", "ttymxc2", 1)) {
|
||||
qCritical() << __func__ << "open ok";
|
||||
step++;
|
||||
QThread::msleep(2000);
|
||||
m_hw->dc_autoRequest(false);
|
||||
emit leaveBL();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
m_hw->bl_rebootDC();
|
||||
QThread::msleep(1000);
|
||||
qCritical() << __func__ << "reboot ok" << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
step++;
|
||||
emit leaveBL();
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
m_hw->bl_startBL();
|
||||
QThread::msleep(1000);
|
||||
qCritical() << __func__ << "start" << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
step++;
|
||||
emit leaveBL();
|
||||
break;
|
||||
case 7:
|
||||
case 9:
|
||||
case 11:
|
||||
case 13:
|
||||
case 15:
|
||||
m_hw->bl_checkBL();
|
||||
qCritical() << __func__ << "check" << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
QThread::msleep(1500);
|
||||
++step;
|
||||
emit leaveBL();
|
||||
break;
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
qCritical() << __func__ << "is Up..." << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
if (m_hw->bl_isUp()) {
|
||||
qCritical() << __func__ << "is Up...OK" << step << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
QThread::msleep(5000);
|
||||
step = 16;
|
||||
} else {
|
||||
qCritical() << __func__ << "is Up...NO" << step << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
}
|
||||
++step;
|
||||
emit leaveBL();
|
||||
break;
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
qCritical() << __func__ << "stop" << QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
m_hw->bl_stopBL();
|
||||
QThread::msleep(1000);
|
||||
//m_hw->dc_closeSerial();
|
||||
++step;
|
||||
emit leaveBL();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MainWindow::MainWindow(hwinf *hw, Worker *worker, Update *update, QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
, m_hw(hw)
|
||||
, m_worker(worker)
|
||||
, m_width(70)
|
||||
, m_progressRunning(false)
|
||||
, m_progressValue(0) {
|
||||
// , m_progressValue(0)
|
||||
, m_update(update)
|
||||
, m_updateStep(UpdateDcEvent::UpdateStep::NONE) {
|
||||
|
||||
#if EMERGENCY_LEAVE_BL==1
|
||||
QTimer *t = new QTimer(this);
|
||||
connect(t, SIGNAL(timeout()), this, SLOT(emergencyLeaveBL()));
|
||||
connect(this, SIGNAL(leaveBL()), this, SLOT(emergencyLeaveBL()), Qt::QueuedConnection);
|
||||
t->setSingleShot(true);
|
||||
t->start(1000);
|
||||
return;
|
||||
#endif
|
||||
|
||||
this->setStatusBar(new QStatusBar(this));
|
||||
QFont f;
|
||||
f.setStyleHint(QFont::Monospace);
|
||||
f.setWeight(QFont::Bold);
|
||||
f.setFamily("Misc Fixed");
|
||||
f.setPixelSize(12);
|
||||
this->statusBar()->setFont(f);
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->updateProgress->setRange(0, 100);
|
||||
@@ -24,13 +126,16 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
QString start = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
lst << QString("Start: ") + start.leftJustified(m_width-10);
|
||||
lst << QString("").leftJustified(m_width-3, '=');
|
||||
lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3);
|
||||
lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3);
|
||||
lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3);
|
||||
lst << QString("Update tool version: %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3);
|
||||
lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3);
|
||||
lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3);
|
||||
lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3);
|
||||
lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3);
|
||||
lst << QString("").leftJustified(m_width-3, '=');
|
||||
|
||||
ui->updateStatus->setText(lst.join('\n'));
|
||||
ui->updateStatus->setEnabled(true);
|
||||
// ui->updateStatus->installEventFilter(this);
|
||||
|
||||
m_startTimer = new QTimer(this);
|
||||
connect(m_startTimer, SIGNAL(timeout()), m_worker, SLOT(update()));
|
||||
@@ -42,17 +147,18 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent)
|
||||
m_exitTimer->setSingleShot(true);
|
||||
m_exitTimer->start(1800 * 1000);
|
||||
|
||||
connect(ui->exit, SIGNAL(clicked()), this, SLOT(onQuit()));
|
||||
connect(m_worker, SIGNAL(disableExit()), this, SLOT(onDisableExit()));
|
||||
connect(m_worker, SIGNAL(enableExit()), this, SLOT(onEnableExit()));
|
||||
connect(m_worker, SIGNAL(stopStartTimer()), this, SLOT(onStopStartTimer()));
|
||||
connect(m_worker, SIGNAL(restartExitTimer()), this, SLOT(onRestartExitTimer()));
|
||||
connect(m_worker, SIGNAL(appendText(QString, QString)), this, SLOT(onAppendText(QString, QString)));
|
||||
connect(m_worker, SIGNAL(showErrorMessage(QString,QString)), this, SLOT(onShowErrorMessage(QString,QString)));
|
||||
connect(m_worker, SIGNAL(replaceLast(QString, QString)), this, SLOT(onReplaceLast(QString,QString)));
|
||||
|
||||
ui->updateStatus->setText(lst.join('\n'));
|
||||
ui->updateStatus->setEnabled(true);
|
||||
connect(ui->exit, SIGNAL(clicked()),this,SLOT(onQuit()));
|
||||
connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit()));
|
||||
connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit()));
|
||||
connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer()));
|
||||
connect(m_worker, SIGNAL(restartExitTimer()),this,SLOT(onRestartExitTimer()));
|
||||
connect(m_worker, SIGNAL(appendText(QString,QString)),this,SLOT(onAppendText(QString,QString)));
|
||||
connect(m_worker, SIGNAL(showErrorMessage(QString,QString)),this, SLOT(onShowErrorMessage(QString,QString)));
|
||||
connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString)));
|
||||
connect(m_worker, SIGNAL(showErrorMessage(QStringList)),this, SLOT(onShowErrorMessage(QStringList)));
|
||||
connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString)));
|
||||
connect(m_worker, SIGNAL(replaceLast(QString,QString)),this,SLOT(onReplaceLast(QString,QString)));
|
||||
connect(m_worker, SIGNAL(replaceLast(QStringList,QString)),this, SLOT(onReplaceLast(QStringList,QString)));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
@@ -74,22 +180,22 @@ void MainWindow::customEvent(QEvent *event) {
|
||||
case START_PROGRESS_LOOP: {
|
||||
m_progressRunning = true;
|
||||
ui->updateProgress->reset();
|
||||
m_progressValue = 10;
|
||||
QApplication::postEvent(this, new ProgressEvent(this, m_progressValue));
|
||||
// m_progressValue = 10;
|
||||
QApplication::postEvent(this, new ProgressEvent(this, 1));
|
||||
} break;
|
||||
case STOP_PROGRESS_LOOP: {
|
||||
m_progressRunning = false;
|
||||
m_progressValue -= 10;
|
||||
m_worker->setProgress(m_progressValue/10);
|
||||
// m_progressValue -= 10;
|
||||
// m_worker->setProgress(m_progressValue/10);
|
||||
} break;
|
||||
default: {
|
||||
if (m_progressRunning) {
|
||||
m_progressValue = progress;
|
||||
ui->updateProgress->setValue(progress/10);
|
||||
QApplication::postEvent(this, new ProgressEvent(this, progress+10));
|
||||
QThread::msleep(500);
|
||||
}
|
||||
}
|
||||
if (m_progressRunning) {
|
||||
// m_progressValue = progress;
|
||||
ui->updateProgress->setValue(progress);
|
||||
// ueberpruefen: hauptfenster schickt sich selber ein event
|
||||
// QApplication::postEvent(this, new ProgressEvent(this, progress));
|
||||
// QThread::msleep(500);
|
||||
}}
|
||||
}
|
||||
} else
|
||||
if (sender == m_worker) {
|
||||
@@ -109,6 +215,86 @@ void MainWindow::customEvent(QEvent *event) {
|
||||
} else {
|
||||
qCritical() << "!!! UNKNOWN SENDER !!!";
|
||||
}
|
||||
} else
|
||||
if (event->type() == UpdateDcEvent::type()) {
|
||||
UpdateDcEvent *pevent = (UpdateDcEvent *)event;
|
||||
UpdateDcEvent::UpdateStep const updateStep = pevent->updateStep();
|
||||
QObject const *sender = pevent->sender();
|
||||
if (sender == m_worker) {
|
||||
QDateTime const &recv = QDateTime::currentDateTime();
|
||||
QDateTime const &send = pevent->sendDateTime();
|
||||
qint64 const delay = recv.toMSecsSinceEpoch() - send.toMSecsSinceEpoch();
|
||||
switch(updateStep) {
|
||||
case UpdateDcEvent::UpdateStep::NONE:
|
||||
break;
|
||||
case UpdateDcEvent::UpdateStep::DC_REBOOT: {
|
||||
m_hw->bl_rebootDC();
|
||||
QString msg = QDateTime::currentDateTime().toString(Qt::ISODateWithMs)
|
||||
+ QString(": reset device controller (delay=%1ms").arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
m_updateStep = UpdateDcEvent::UpdateStep::DC_REBOOT;
|
||||
} break;
|
||||
case UpdateDcEvent::UpdateStep::BL_START: {
|
||||
QString const &msg = recv.toString(Qt::ISODateWithMs)
|
||||
+ QString(": start bootloader (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
m_hw->bl_startBL();
|
||||
if (pevent->count() == BL_START_COUNT) {
|
||||
m_updateStep = UpdateDcEvent::UpdateStep::BL_START;
|
||||
}
|
||||
} break;
|
||||
case UpdateDcEvent::UpdateStep::BL_CHECK: {
|
||||
if (m_updateStep != UpdateDcEvent::UpdateStep::BL_IS_UP) {
|
||||
QString const &msg = recv.toString(Qt::ISODateWithMs)
|
||||
+ QString(": request bootloader version (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
m_hw->bl_checkBL();
|
||||
//m_updateStep = UpdateDcEvent::UpdateStep::BL_CHECK;
|
||||
}
|
||||
} break;
|
||||
case UpdateDcEvent::UpdateStep::BL_IS_UP: {
|
||||
QString msg = recv.toString(Qt::ISODateWithMs)
|
||||
+ QString(": check running bootloader (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
if (m_updateStep != UpdateDcEvent::UpdateStep::BL_IS_UP) {
|
||||
if (m_hw->bl_isUp()) {
|
||||
msg = recv.toString(Qt::ISODateWithMs)
|
||||
+ QString(": bootloader running (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
m_updateStep = UpdateDcEvent::UpdateStep::BL_IS_UP;
|
||||
} else {
|
||||
msg = recv.toString(Qt::ISODateWithMs)
|
||||
+ QString(": bootloader stop requested (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
if (m_updateStep == UpdateDcEvent::UpdateStep::BL_STOP) {
|
||||
msg = QDateTime::currentDateTime().toString(Qt::ISODateWithMs)
|
||||
+ QString(": bootloader down (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
m_updateStep = UpdateDcEvent::UpdateStep::BL_IS_DOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case UpdateDcEvent::UpdateStep::BL_STOP: {
|
||||
QString const &msg = QDateTime::currentDateTime().toString(Qt::ISODateWithMs)
|
||||
+ QString(": stop bootloader (%1, delay=%2ms)").arg(pevent->count()).arg(delay);
|
||||
emit m_worker->showStatusMessage("dc update", msg);
|
||||
Utils::printInfoMsg(msg.toUpper());
|
||||
//if (m_bootLoaderIsUp) {
|
||||
m_hw->bl_stopBL();
|
||||
m_updateStep = UpdateDcEvent::UpdateStep::BL_STOP;
|
||||
//}
|
||||
} break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QThread::yieldCurrentThread();
|
||||
@@ -126,72 +312,169 @@ void MainWindow::onEnableExit() {
|
||||
ui->exit->setEnabled(true);
|
||||
}
|
||||
|
||||
//bool MainWindow::eventFilter(QObject *obj, QEvent *ev) {
|
||||
// if (obj == ui->updateStatus) {
|
||||
// qCritical() << "REc. event for text edit" << ev->type();
|
||||
// }
|
||||
// return QMainWindow::eventFilter(obj, ev);
|
||||
//}
|
||||
|
||||
void MainWindow::onRestartExitTimer() {
|
||||
m_exitTimer->stop();
|
||||
m_exitTimer->start(60 * 1000);
|
||||
|
||||
scrollDownTextEdit();
|
||||
ui->updateStatus->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::onQuit() {
|
||||
m_exitTimer->stop();
|
||||
qCritical() << QString("ON QUIT: EXIT CODE %1").arg(m_worker->returnCode());
|
||||
qApp->exit(m_worker->returnCode());
|
||||
int errorCode = 0;
|
||||
|
||||
qCritical()
|
||||
<< QString("ON QUIT: CURRENT STEP %1")
|
||||
.arg(m_worker->getSmap()[m_worker->currentStep()]);
|
||||
|
||||
// TODO: replace SEND_LAST_VERSION with UPDATE_SUCCEEDED
|
||||
if (m_worker->currentStep() != Worker::UPDATE_STEP::SEND_LAST_VERSION) {
|
||||
errorCode = -1;
|
||||
}
|
||||
qCritical() << QString("ON QUIT: EXIT CODE %1").arg(errorCode);
|
||||
qApp->exit(errorCode);
|
||||
}
|
||||
|
||||
void MainWindow::scrollDownTextEdit() {
|
||||
// Utils::printInfoMsg(QString("SCROLL-DOWN-TEXT_EDIT CALLED AT ")
|
||||
// + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));
|
||||
|
||||
ui->updateStatus->setEnabled(true);
|
||||
|
||||
QTextCursor tmpCursor = ui->updateStatus->textCursor();
|
||||
tmpCursor.movePosition(QTextCursor::End);
|
||||
ui->updateStatus->setTextCursor(tmpCursor);
|
||||
ui->updateStatus->ensureCursorVisible();
|
||||
}
|
||||
|
||||
void MainWindow::onAppendText(QString text, QString suffix) {
|
||||
// Utils::printInfoMsg(QString("ON APPEND CALLED AT ")
|
||||
// + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));
|
||||
|
||||
QString editText = ui->updateStatus->toPlainText();
|
||||
scrollDownTextEdit();
|
||||
|
||||
if (!suffix.isNull() && suffix.size() > 0) {
|
||||
qInfo() << "TEXT" << text << "SUFFIX" << suffix;
|
||||
//qInfo() << "TEXT" << text << "SUFFIX" << suffix;
|
||||
if (suffix == Worker::UPDATE_STEP_SUCCESS || suffix == Worker::UPDATE_STEP_FAIL) {
|
||||
editText += QString("\n").leftJustified(m_width-3, '=');
|
||||
editText += " ";
|
||||
ui->updateStatus->insertPlainText(QString("\n").leftJustified(m_width-3, '=') + " ");
|
||||
// editText += QString("\n").leftJustified(m_width-3, '=');
|
||||
// editText += " ";
|
||||
}
|
||||
editText += (QString("\n") + text).leftJustified(m_width - (2 + suffix.size()) ) + suffix;
|
||||
QString const &add = (QString("\n") + text).leftJustified(m_width - (2 + suffix.size())) + suffix;
|
||||
ui->updateStatus->insertPlainText(add);
|
||||
// editText += add;
|
||||
} else {
|
||||
editText += text.leftJustified(m_width-9);
|
||||
QString const &add = text.leftJustified(m_width-9);
|
||||
ui->updateStatus->insertPlainText(add);
|
||||
//editText += add;
|
||||
}
|
||||
|
||||
Utils::printLineEditInfo(editText.split('\n'));
|
||||
// debug
|
||||
// QString editText = ui->updateStatus->toPlainText();
|
||||
// Utils::printLineEditInfo(editText.split('\n', QString::SplitBehavior::SkipEmptyParts));
|
||||
// ui->updateStatus->setText(editText.trimmed());
|
||||
|
||||
ui->updateStatus->setPlainText(editText.trimmed());
|
||||
ui->updateStatus->setEnabled(true);
|
||||
// scrollDownTextEdit();
|
||||
}
|
||||
|
||||
void MainWindow::onReplaceLast(QStringList newTextLines, QString suffix) {
|
||||
// Utils::printInfoMsg(QString("ON REPLACE LAST (LIST) CALLED AT ")
|
||||
// + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));
|
||||
|
||||
int const s = newTextLines.size();
|
||||
if (s > 0) {
|
||||
QString editText = ui->updateStatus->toPlainText();
|
||||
QStringList lines = editText.split('\n', QString::SplitBehavior::SkipEmptyParts);
|
||||
QString newText;
|
||||
if (lines.size() >= s) {
|
||||
for (int i = 0; i < s; ++i) {
|
||||
lines.removeLast();
|
||||
}
|
||||
if (lines.size() > 0) {
|
||||
newText = lines.join('\n');
|
||||
newText += '\n';
|
||||
}
|
||||
QStringList newLines;
|
||||
for (int i = 0; i < s; ++i) {
|
||||
if (i == 0 && !suffix.isNull() && suffix.size() > 0 && suffix != "\n") {
|
||||
newLines += Utils::rstrip(newTextLines.at(i).leftJustified(m_width-10) + suffix);
|
||||
} else {
|
||||
newLines += Utils::rstrip(newTextLines.at(i).leftJustified(m_width-10));
|
||||
}
|
||||
}
|
||||
lines += newLines;
|
||||
newText += newLines.join(' ');
|
||||
}
|
||||
|
||||
ui->updateStatus->setText(newText);
|
||||
Utils::printLineEditInfo(lines);
|
||||
scrollDownTextEdit();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onReplaceLast(QString text, QString suffix) {
|
||||
qInfo() << "REPL TEXT" << text << "SUFFIX" << suffix;
|
||||
// Utils::printInfoMsg(QString("ON REPLACE LAST (TEXT) CALLED AT ")
|
||||
// + QDateTime::currentDateTime().toString(Qt::ISODateWithMs));
|
||||
|
||||
QString editText = ui->updateStatus->toPlainText();
|
||||
QStringList lines = editText.split('\n');
|
||||
QStringList lines = editText.split('\n', QString::SplitBehavior::SkipEmptyParts);
|
||||
if (lines.size() > 0) {
|
||||
lines.removeLast();
|
||||
if (!suffix.isNull() && suffix.size() > 0 && suffix != "\n") {
|
||||
lines += text.leftJustified(m_width-10) + suffix;
|
||||
QString const add = text.leftJustified(m_width-10) + suffix;
|
||||
if (!add.isEmpty()) {
|
||||
lines += text.leftJustified(m_width-10) + suffix;
|
||||
}
|
||||
} else {
|
||||
lines += text.leftJustified(m_width-10);
|
||||
QString const add = text.leftJustified(m_width-10);
|
||||
if (!add.isEmpty()) {
|
||||
lines += text.leftJustified(m_width-10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Utils::printLineEditInfo(lines);
|
||||
|
||||
ui->updateStatus->setText(lines.join('\n').trimmed());
|
||||
ui->updateStatus->setEnabled(true);
|
||||
scrollDownTextEdit();
|
||||
}
|
||||
|
||||
void MainWindow::onShowMessage(QString title, QString text) {
|
||||
this->statusBar()->clearMessage();
|
||||
this->statusBar()->showMessage( // timeout: 10000
|
||||
QString(title + " " + text).leftJustified(80, ' '), 10000);
|
||||
}
|
||||
|
||||
void MainWindow::onShowErrorMessage(QString title, QString text) {
|
||||
text = text.leftJustified(50, ' ');
|
||||
QMessageBox msgBox(QMessageBox::NoIcon, title,
|
||||
text, QMessageBox::Ok,
|
||||
nullptr, Qt::FramelessWindowHint);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.defaultButton()->setVisible(false);
|
||||
onShowMessage(title, text);
|
||||
}
|
||||
|
||||
QTimer *t = new QTimer(this);
|
||||
connect(t, SIGNAL(timeout()), msgBox.defaultButton(), SLOT(click()));
|
||||
t->setSingleShot(true);
|
||||
t->start(5 * 1000);
|
||||
void MainWindow::onShowStatusMessage(QString title, QString text) {
|
||||
onShowMessage(title, text);
|
||||
}
|
||||
|
||||
if(msgBox.exec() == QMessageBox::Ok) {
|
||||
// do something
|
||||
} else {
|
||||
// do something else
|
||||
void MainWindow::onShowErrorMessage(QStringList lst) {
|
||||
if (lst.size() >= 2) {
|
||||
onShowMessage(lst.at(0), lst.at(1));
|
||||
}
|
||||
if (lst.size() == 1) {
|
||||
onShowMessage(lst.at(0), "");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onShowStatusMessage(QStringList lst) {
|
||||
if (lst.size() >= 2) {
|
||||
onShowMessage(lst.at(0), lst.at(1));
|
||||
}
|
||||
if (lst.size() == 1) {
|
||||
onShowMessage(lst.at(0), "");
|
||||
}
|
||||
}
|
||||
|
44
mainwindow.h
44
mainwindow.h
@@ -3,47 +3,83 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QStatusBar>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "worker.h"
|
||||
#include "update.h"
|
||||
#include "update_dc_event.h"
|
||||
|
||||
#define EMERGENCY_LEAVE_BL 0
|
||||
|
||||
class hwinf;
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void customEvent(QEvent *event) override;
|
||||
// bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
|
||||
public:
|
||||
MainWindow(Worker *worker, QWidget *parent = nullptr);
|
||||
MainWindow(hwinf *hw, Worker *worker, Update *update, QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
static const int START_PROGRESS_LOOP = -1;
|
||||
static const int STOP_PROGRESS_LOOP = -2;
|
||||
static const int BL_START_COUNT = 5;
|
||||
static const int BL_CHECK_COUNT = 5;
|
||||
static const int BL_IS_UP_COUNT = 5;
|
||||
static const int BL_STOP_COUNT = 5;
|
||||
|
||||
int progressValue() const { return m_progressValue; }
|
||||
// int progressValue() const { return m_progressValue; }
|
||||
hwinf *getPlugin() { return m_hw; }
|
||||
hwinf const *getPlugin() const { return m_hw; }
|
||||
Update *getUpdate() { return m_update; }
|
||||
Update const *getUpdate() const { return m_update; }
|
||||
UpdateDcEvent::UpdateStep updateStep() const { return m_updateStep; }
|
||||
void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; }
|
||||
|
||||
public slots:
|
||||
void onAppendText(QString, QString suffix = "");
|
||||
void onReplaceLast(QStringList, QString suffix = "");
|
||||
void onReplaceLast(QString, QString suffix = "");
|
||||
void onShowErrorMessage(QString, QString);
|
||||
void onShowStatusMessage(QString, QString);
|
||||
void onShowErrorMessage(QStringList);
|
||||
void onShowStatusMessage(QStringList);
|
||||
void onStopStartTimer();
|
||||
void onRestartExitTimer();
|
||||
void onEnableExit();
|
||||
void onDisableExit();
|
||||
#if EMERGENCY_LEAVE_BL==1
|
||||
void emergencyLeaveBL();
|
||||
#endif
|
||||
|
||||
signals:
|
||||
|
||||
#if EMERGENCY_LEAVE_BL==1
|
||||
void leaveBL();
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
void onQuit();
|
||||
|
||||
private:
|
||||
void scrollDownTextEdit();
|
||||
void onShowMessage(QString, QString);
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
hwinf *m_hw;
|
||||
Worker *m_worker;
|
||||
int m_width;
|
||||
int const m_width;
|
||||
QTimer *m_startTimer;
|
||||
QTimer *m_exitTimer;
|
||||
bool m_progressRunning;
|
||||
int m_progressValue;
|
||||
//int m_progressValue;
|
||||
Update *m_update;
|
||||
UpdateDcEvent::UpdateStep m_updateStep;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>781</width>
|
||||
<height>461</height>
|
||||
<height>441</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
@@ -55,6 +55,15 @@
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
51
plugins/interfaces.h
Normal file → Executable file
51
plugins/interfaces.h
Normal file → Executable file
@@ -193,7 +193,7 @@ struct T_moduleCondition
|
||||
uint8_t coinChecker; // EMP, OMP or mei-cashflow
|
||||
|
||||
uint8_t coinEscrow;
|
||||
uint8_t mifareReader;
|
||||
uint8_t mifareReader; // 0: unknown 1=OK 200=no response 201=wrong response 202: Reader reports HW-error
|
||||
uint8_t creditTerm;
|
||||
uint8_t coinReject;
|
||||
|
||||
@@ -818,7 +818,7 @@ public:
|
||||
// --------------------------------------------- MIFARE -----------------------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// obsolete
|
||||
virtual uint8_t mif_returnReaderStateAndCardType(uint8_t *buf, uint8_t maxBufferSize) const =0;
|
||||
// retval 0=OK 1=error host buffer too small
|
||||
/* data description, new fast version:
|
||||
@@ -840,13 +840,16 @@ public:
|
||||
virtual bool mif_readerIsOK(void) const =0;
|
||||
|
||||
virtual bool mif_cardAttached(void) const =0;
|
||||
// not working! use mif_cardIsAttached() instead
|
||||
|
||||
virtual uint8_t mif_readResult(void) const =0;
|
||||
// result: 0: unknown or still in progress
|
||||
// 1: card read successful
|
||||
// 2: reading error
|
||||
// not working!
|
||||
|
||||
virtual QString mif_cardUID(void) const =0;
|
||||
// not working
|
||||
|
||||
virtual uint8_t mif_getCardDataDec(uint8_t blkNr, uint8_t *buf, uint8_t maxBufferSize) const =0;
|
||||
|
||||
@@ -1289,7 +1292,7 @@ public:
|
||||
// 1= wrong length 2=wrong start sign 5= wrong crc
|
||||
// 6= slave: master cmd was wrong 7: slave: could not write/read data
|
||||
// 8=timeout, got no response from slave
|
||||
|
||||
// 0,8 work, 1..6 not yet tested. 8 comes immed. and stays 8 until reconnect
|
||||
|
||||
// use for important and extended commands (print several templates, print ticket...)
|
||||
virtual void log_startSupervision(void) const =0;
|
||||
@@ -1299,6 +1302,7 @@ public:
|
||||
// 0: started, in progress
|
||||
// 1: done and OK
|
||||
// 2: done and error
|
||||
// not working properly, always 0
|
||||
|
||||
virtual bool log_getVaultData(uint8_t *data) const =0;
|
||||
// get vault record in linear 8bit buffer with 384 byte
|
||||
@@ -1343,6 +1347,37 @@ public:
|
||||
|
||||
|
||||
|
||||
// new functions from 8.9.23
|
||||
virtual QString mif_getReaderType(void) const =0;
|
||||
// return "SL025" if correct reader is connected
|
||||
|
||||
virtual void mif_getCardSize(uint8_t *cardSize, uint8_t *idLeng) const =0;
|
||||
// cardSize=1k or 4kByte
|
||||
// idLeng =4Byte or 7 byte
|
||||
|
||||
virtual char mif_getAtbCardData(uint8_t *buf, uint8_t maxBuffSiz) const =0;
|
||||
// return complete buffer binary, just for test purpose
|
||||
|
||||
virtual bool mif_isValidAtbCard(void) const =0;
|
||||
|
||||
virtual uint32_t mif_getAtbCardCuNu(void) const =0;
|
||||
|
||||
virtual uint8_t mif_getAtbCardTyp(void) const =0;
|
||||
// return 1=upper door card 1=lower door 3=printer-test 4=coin-test
|
||||
// 0: not a valid atb2020 card
|
||||
|
||||
virtual QString mif_getAtbCardPerso(void) const =0;
|
||||
// e.g. "PNsax001" used for personal number, name shortcode, card number
|
||||
// free to use, can be set in AtbMcw23.exe tool
|
||||
|
||||
virtual void mif_getAtbCardExpire(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute) const =0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
virtual void hwapi_templatePrintFinished_OK(void) const=0;
|
||||
virtual void hwapi_templatePrintFinished_Err(void) const=0;
|
||||
@@ -1413,9 +1448,15 @@ signals:
|
||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.1"
|
||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.2"
|
||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.3"
|
||||
#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.4"
|
||||
|
||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.4"
|
||||
// 8.9.2023 two new functions (end of file) for mifare test
|
||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.5"
|
||||
// 18.9.2023 major improvements for DC data exchange
|
||||
// verification of door and cash box signals
|
||||
// intensive verification of Json-Programming Master-Slave (PTU to DC), 100% ok
|
||||
|
||||
#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.6"
|
||||
// 20.9.2023: speeding up door and cash box signals
|
||||
|
||||
|
||||
Q_DECLARE_INTERFACE(hwinf, HWINF_iid)
|
||||
|
BIN
plugins/libCAmaster.so
Normal file → Executable file
BIN
plugins/libCAmaster.so
Normal file → Executable file
Binary file not shown.
@@ -2,13 +2,15 @@
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
|
||||
Command::Command(QString const &command, int start_timeout, int finish_timeout)
|
||||
: m_command(command.trimmed())
|
||||
, m_commandResult("")
|
||||
, m_waitForStartTimeout(start_timeout)
|
||||
, m_waitForFinishTimeout(finish_timeout) {
|
||||
, m_waitForFinishTimeout(finish_timeout)
|
||||
, m_exitCode(-1) {
|
||||
}
|
||||
|
||||
QString Command::getCommandResult() const {
|
||||
@@ -39,46 +41,71 @@ void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
||||
}
|
||||
|
||||
bool Command::execute(QString workingDirectory, QStringList args) {
|
||||
|
||||
if (!QDir::setCurrent(workingDirectory)) {
|
||||
qCritical() << "SET WORKING_DIRECTORY" << workingDirectory
|
||||
<< "FAILED FOR" << m_command;
|
||||
return false;
|
||||
}
|
||||
|
||||
QScopedPointer<QProcess> p(new QProcess(this));
|
||||
p->setWorkingDirectory(workingDirectory);
|
||||
p->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
connect(&(*p), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
|
||||
connect(&(*p), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
|
||||
|
||||
//qCritical() << "START COMMAND" << m_command << "WITH ARGS" << args
|
||||
// << "IN" << workingDirectory;
|
||||
|
||||
p->setWorkingDirectory(workingDirectory);
|
||||
if (!args.isEmpty()) {
|
||||
qDebug() << "START COMMAND" << m_command << "WITH ARGS" << args
|
||||
<< "IN" << p->workingDirectory();
|
||||
p->start(m_command, args);
|
||||
} else {
|
||||
qDebug() << "START COMMAND" << m_command
|
||||
<< "IN" << p->workingDirectory();
|
||||
p->start(m_command);
|
||||
}
|
||||
|
||||
if (p->waitForStarted(m_waitForStartTimeout)) {
|
||||
//qDebug() << "PROCESS" << m_command << "STARTED";
|
||||
qDebug() << "PROCESS" << m_command << "STARTED IN" << p->workingDirectory();
|
||||
if (p->state() == QProcess::ProcessState::Running) {
|
||||
//qDebug() << "PROCESS" << m_command << "RUNNING";
|
||||
if (p->waitForFinished(m_waitForFinishTimeout)) {
|
||||
//qDebug() << "PROCESS" << m_command << "FINISHED";
|
||||
qDebug() << "PROCESS" << m_command << "RUNNING IN" << p->workingDirectory();
|
||||
// wait forever for git/opkg-commands to finish
|
||||
int wait = m_waitForFinishTimeout;
|
||||
if (m_command.trimmed().startsWith("git", Qt::CaseInsensitive) ||
|
||||
m_command.trimmed().startsWith("opkg", Qt::CaseInsensitive)) {
|
||||
wait = -1;
|
||||
}
|
||||
bool const no_timeout = p->waitForFinished(wait);
|
||||
if (no_timeout) {
|
||||
qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory();
|
||||
if (p->exitStatus() == QProcess::NormalExit) {
|
||||
if (p->exitCode() == 0) {
|
||||
if ((m_exitCode = p->exitCode()) == 0) {
|
||||
qDebug() << "EXECUTED" << m_command
|
||||
<< "with code" << m_exitCode
|
||||
<< "IN" << p->workingDirectory();
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "EXECUTED" << m_command << "with code" << p->exitCode();
|
||||
qCritical() << "EXECUTED" << m_command
|
||||
<< "with code" << m_exitCode
|
||||
<< "IN" << p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "CRASHED with code"
|
||||
<< p->exitCode();
|
||||
<< p->exitCode()
|
||||
<< "IN" << p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "DID NOT FINISH";
|
||||
qCritical() << "PROCESS" << m_command
|
||||
<< "DID NOT FINISH WITH" << wait
|
||||
<< "MS IN" << p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "WRONG PROCESS STATE" << p->state();
|
||||
qCritical() << "WRONG PROCESS STATE" << p->state()
|
||||
<< "IN" << p->workingDirectory();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "TIMEOUT AT START";
|
||||
qCritical() << "PROCESS" << m_command << "TIMEOUT AT START"
|
||||
<< "IN" << p->workingDirectory();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -16,15 +16,17 @@ class Command : public QObject {
|
||||
QString m_commandResult;
|
||||
int m_waitForStartTimeout;
|
||||
int m_waitForFinishTimeout;
|
||||
|
||||
int m_exitCode;
|
||||
public:
|
||||
explicit Command(QString const &command,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
|
||||
QString getCommandResult() const;
|
||||
QString command() const { return m_command; }
|
||||
|
||||
bool execute(QString workingDirectory, QStringList args = QStringList());
|
||||
int exitCode() const { return m_exitCode; }
|
||||
|
||||
private slots:
|
||||
void readyReadStandardOutput();
|
||||
|
521
update.cpp
521
update.cpp
@@ -1,5 +1,8 @@
|
||||
#include "update.h"
|
||||
#include "worker.h"
|
||||
#include "utils.h"
|
||||
#include "update_dc_event.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QApplication>
|
||||
@@ -9,10 +12,11 @@
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegExp>
|
||||
#include <QApplication>
|
||||
|
||||
//#include <iostream>
|
||||
//#include <fstream>
|
||||
//#include <ctime>
|
||||
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
@@ -25,17 +29,15 @@
|
||||
#include <QMap>
|
||||
|
||||
#define UPDATE_OPKG (1)
|
||||
#define UPDATE_DC (1)
|
||||
#define UPDATE_PRINTER_TEMPLATES (1)
|
||||
#define UPDATE_CASH_TEMPLATE (1)
|
||||
#define UPDATE_CONF_TEMPLATE (1)
|
||||
#define UPDATE_DEVICE_TEMPLATE (1)
|
||||
#define UPDATE_DC (0)
|
||||
|
||||
static const QMap<QString, int> baudrateMap = {
|
||||
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
|
||||
{"57600" , 4}, {"115200" , 5}
|
||||
};
|
||||
|
||||
QPluginLoader Update::pluginLoader;
|
||||
|
||||
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
hwinf *hw = nullptr;
|
||||
if (plugInDir.exists()) {
|
||||
@@ -44,7 +46,8 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
QFileInfo info(pluginLibName);
|
||||
if (info.exists()) {
|
||||
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
|
||||
static QPluginLoader pluginLoader(pluginLibName);
|
||||
pluginLoader.setFileName(pluginLibName);
|
||||
// static QPluginLoader pluginLoader(pluginLibName);
|
||||
if (!pluginLoader.load()) {
|
||||
qCritical() << "in directory" << plugInDir.absolutePath();
|
||||
qCritical() << "cannot load plugin" << pluginLoader.fileName();
|
||||
@@ -76,11 +79,27 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
return hw;
|
||||
}
|
||||
|
||||
bool Update::unloadDCPlugin() {
|
||||
if (pluginLoader.unload()) {
|
||||
qCritical() << "unloaded plugin" << pluginLoader.fileName();
|
||||
// Note: will re-instantiate the library !
|
||||
// QObject *rootObject = pluginLoader.instance();
|
||||
// if (rootObject) {
|
||||
// qCritical() << "reloaded plugin: root object again available";
|
||||
// return false;
|
||||
// }
|
||||
// qCritical()unloaded plugin: root object gone";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Update::Update(hwinf *hw,
|
||||
Worker *worker,
|
||||
QString customerRepository,
|
||||
QString customerNrStr,
|
||||
QString branchName,
|
||||
QString pluginName,
|
||||
QString workingDir,
|
||||
bool dryRun,
|
||||
QObject *parent,
|
||||
@@ -94,8 +113,17 @@ Update::Update(hwinf *hw,
|
||||
, m_customerRepository(customerRepository)
|
||||
, m_customerNrStr(customerNrStr)
|
||||
, m_branchName(branchName)
|
||||
, m_pluginName(pluginName)
|
||||
, m_workingDir(workingDir)
|
||||
, m_dryRun(dryRun) {
|
||||
|
||||
qInfo() << "UPDATE: m_serialInterface ..." << m_serialInterface;
|
||||
qInfo() << "UPDATE: m_baudrate ..." << m_baudrate;
|
||||
qInfo() << "UPDATE: m_customerRepository ..." << m_customerRepository;
|
||||
qInfo() << "UPDATE: m_customerNr ..........." << m_customerNrStr;
|
||||
qInfo() << "UPDATE: m_branchName ..........." << m_branchName;
|
||||
qInfo() << "UPDATE: m_pluginName ..........." << m_pluginName;
|
||||
qInfo() << "UPDATE: m_workingDirectory ....." << m_workingDir;
|
||||
}
|
||||
|
||||
Update::~Update() {
|
||||
@@ -221,48 +249,99 @@ Update::DownloadResult Update::dc_downloadBinary(QByteArray const &b) const {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Update::startBootloader() const {
|
||||
qDebug() << "starting bootloader...";
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
bool Update::startBootloader() const { // deprecated
|
||||
return false;
|
||||
#if 0
|
||||
int nStartTry = 5;
|
||||
while (--nStartTry >= 0) {
|
||||
m_hw->bl_startBL();
|
||||
QThread::msleep(5000);
|
||||
m_hw->bl_checkBL();
|
||||
if (m_hw->bl_isUp()) {
|
||||
qInfo() << "starting bootloader...OK";
|
||||
QThread::msleep(5000);
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "bootloader not up (" << nTry << ")";
|
||||
QThread::msleep(500);
|
||||
int nCheckTry = 10;
|
||||
while (--nCheckTry >= 0) {
|
||||
m_hw->bl_checkBL();
|
||||
QThread::msleep(500);
|
||||
if (m_hw->bl_isUp()) {
|
||||
qInfo() << "starting bootloader...OK";
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "bootloader not up ("
|
||||
<< nStartTry << "," << nCheckTry << ")" << QThread::currentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
qCritical() << "starting bootloader...FAILED";
|
||||
qCritical() << "starting bootloader...FAILED" << QThread::currentThread();
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Update::stopBootloader() const {
|
||||
qDebug() << "stopping bootloader...";
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_stopBL();
|
||||
QThread::msleep(500);
|
||||
if (!m_hw->bl_isUp()) {
|
||||
qInfo() << "stopping bootloader...OK";
|
||||
return true;
|
||||
// stop bootloader: this MUST work -> otherwise the PSA has to be restarted
|
||||
// manually
|
||||
emit m_worker->showErrorMessage("dc update", "stopping bootloader...");
|
||||
|
||||
int nTryFinalize = 1; // could do this in an endless loop
|
||||
|
||||
do {
|
||||
// in principle, any value except BL_STOP will do, as we want to detect
|
||||
// change to BL_STOP
|
||||
m_worker->mainWindow()->setUpdateStep(UpdateDcEvent::UpdateStep::BL_CHECK);
|
||||
|
||||
QApplication::postEvent(
|
||||
m_worker->mainWindow(),
|
||||
new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_STOP, nTryFinalize));
|
||||
|
||||
QThread::sleep(1);
|
||||
|
||||
int const cntLimit = 20;
|
||||
int cnt = 0;
|
||||
while (++cnt < cntLimit &&
|
||||
m_worker->mainWindow()->updateStep() != UpdateDcEvent::UpdateStep::BL_STOP) {
|
||||
// wait until bl_stopBL() has been sent
|
||||
QThread::msleep(500);
|
||||
}
|
||||
}
|
||||
qCritical() << "stopping bootloader...FAILED";
|
||||
return false;
|
||||
|
||||
QApplication::postEvent(
|
||||
m_worker->mainWindow(),
|
||||
new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_CHECK, nTryFinalize));
|
||||
QThread::sleep(1);
|
||||
|
||||
QApplication::postEvent(
|
||||
m_worker->mainWindow(),
|
||||
new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_IS_UP, nTryFinalize));
|
||||
QThread::sleep(1);
|
||||
|
||||
cnt = 0;
|
||||
while (++cnt < cntLimit &&
|
||||
m_worker->mainWindow()->updateStep() != UpdateDcEvent::UpdateStep::BL_IS_DOWN) {
|
||||
// wait until done
|
||||
QThread::msleep(200);
|
||||
}
|
||||
|
||||
} while (++nTryFinalize <= MainWindow::BL_STOP_COUNT &&
|
||||
m_worker->mainWindow()->updateStep() != UpdateDcEvent::UpdateStep::BL_IS_DOWN);
|
||||
|
||||
return (m_worker->mainWindow()->updateStep() == UpdateDcEvent::UpdateStep::BL_IS_DOWN);
|
||||
}
|
||||
|
||||
// br is a index into a table, used for historical reasons.
|
||||
bool Update::openSerial(int br, QString baudrate, QString comPort) const {
|
||||
qDebug() << "opening serial" << br << baudrate << comPort << "...";
|
||||
if (m_hw->dc_openSerial(br, baudrate, comPort, 1)) { // 1 for connect
|
||||
qInfo() << "opening serial" << br << baudrate << comPort << "...OK";
|
||||
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;
|
||||
}
|
||||
qCritical() << "opening serial" << br << baudrate << comPort << "...FAILED";
|
||||
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("OPENING SERIAL %1").arg(br)
|
||||
+ " " + baudrate + " " + comPort + "...FAILED");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -275,13 +354,15 @@ bool Update::isSerialOpen() const {
|
||||
return m_hw->dc_isPortOpen();
|
||||
}
|
||||
|
||||
bool Update::resetDeviceController() const {
|
||||
bool Update::resetDeviceController() const { // deprecated
|
||||
return false;
|
||||
#if 0
|
||||
qDebug() << "resetting device controller...";
|
||||
m_hw->bl_rebootDC();
|
||||
// wait maximally 3 seconds, before starting bootloader
|
||||
QThread::sleep(1);
|
||||
qInfo() << "resetting device controller...OK";
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
QByteArray Update::loadBinaryDCFile(QString filename) const {
|
||||
@@ -319,17 +400,61 @@ bool Update::downloadBinaryToDC(QString const &bFile) const {
|
||||
}
|
||||
|
||||
/*
|
||||
Using the DC bootloader:
|
||||
1 : bl_reboot() // send to application, want DC2 to reset (in order to start
|
||||
// the bootloader)
|
||||
2 : bl_startBL(): // send within 4s after DC poewer-on, otherwise bl is left
|
||||
3 : bl_check(): // send command to verify if bl is up
|
||||
4 : bl_isUp(): // returns true if bl is up and running
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// USING THE DC BOOTLOADER
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
1 : bl_reboot() // send to application, want DC2 to reset (in order to
|
||||
// start the bootloader)
|
||||
//
|
||||
// NOTE: this function is NOT reliable !!! Sometimes it
|
||||
// simply does not work, in which case bl_startBL,
|
||||
// bl_checkBL and bl_isUp do not work as well.
|
||||
// Alas, there is no feedback if bl_reboot worked!
|
||||
//
|
||||
// NOTE: this function can be called only once per
|
||||
// minute, because once called again, the controller
|
||||
// performs some self-checks consuming some time.
|
||||
//
|
||||
// NOTE: after a successful bl_reboot(), the device is
|
||||
// waiting about 4 seconds in the bootloader. To stay in
|
||||
// the bootloader, we have to send the command
|
||||
// bl_startBL(), which is kind of a misnomer, as it
|
||||
// should be bl_doNotLeaveBL().
|
||||
//
|
||||
2 : bl_startBL(): // send within 4s after DC power-on, otherwise
|
||||
// bootloader is left.
|
||||
//
|
||||
// NOTE: a running bootloader is a MUST for the download
|
||||
// process of a device controller firmware as it does
|
||||
// the actual writing of the memory (the bl_reboot()
|
||||
// from above erases the available memory).
|
||||
//
|
||||
3 : bl_check(): // send command to verify if bl is up
|
||||
//
|
||||
// NOTE: this command is kind of a request that we want
|
||||
// to check if the bootloader is up. The device
|
||||
// (actually the bootloader) responds with its version.
|
||||
//
|
||||
4 : bl_isUp(): // returns true if bl is up and running
|
||||
//
|
||||
// NOTE: we know what the bootloader version actually is
|
||||
// as the bootloader does not change. By comparing the
|
||||
// string received in the previous step with this known
|
||||
// version string we know if the bootloader is up.
|
||||
//
|
||||
// NOTE FOR ALL PREVIOUS STEPS: execute them in their
|
||||
// own slots each to be sure to receive any possible
|
||||
// responds from the device.
|
||||
//
|
||||
5 : bl_sendAddress(blockNumber)
|
||||
// send start address, nr of 64-byte block, start with 0
|
||||
// will be sent only for following block-numbers:
|
||||
// 0, 1024, 2048, 3072 and 4096, so basically every 64kByte
|
||||
// 0, 1024, 2048, 3072 and 4096, so basically every
|
||||
// 64kByte.
|
||||
// for other addresses nothing happens
|
||||
|
||||
6 : bl_wasSendingAddOK()
|
||||
@@ -349,54 +474,119 @@ bool Update::downloadBinaryToDC(QString const &bFile) const {
|
||||
// 10: OK
|
||||
|
||||
10 : bl_stopBL() // leave bl and start (the new) application
|
||||
//
|
||||
// NOTE: this function MUST work under all conditions.
|
||||
// Alas, there is no direct result for this command, so
|
||||
// the only way of knowing it was successful is to ask
|
||||
// the device if the bootloader is still running.
|
||||
// There is no problem to repeat this command until the
|
||||
// bootloader is really not running anymore.
|
||||
*/
|
||||
bool Update::updateBinary(char const *fileToSendToDC) {
|
||||
qInfo() << "UPDATING DEVICE CONTROLLER BINARY" << fileToSendToDC;
|
||||
qInfo() << "UPDATING DEVICE CONTROLLER FIRMWARE BINARY" << fileToSendToDC;
|
||||
QFile fn(fileToSendToDC);
|
||||
bool r;
|
||||
if ((r = fn.exists()) == true) {
|
||||
QFileInfo fi(fn);
|
||||
qInfo() << " UPDATING BINARY" << fi.fileName() << "(size=" << fi.size() << ")";
|
||||
if ((r = updateDC(fileToSendToDC)) == true) {
|
||||
qCritical() << QString(80, '*');
|
||||
qInfo() << " UPDATING BINARY" << fi.fileName() << "(size=" << fi.size() << ") DONE";
|
||||
qCritical() << QString(80, '*');
|
||||
Utils::printInfoMsg(
|
||||
QString(" UPDATING BINARY ") + fi.fileName()
|
||||
+ QString(" (size=%1").arg(fi.size()) + ") DONE");
|
||||
} else {
|
||||
qCritical() << QString(80, '*');
|
||||
qCritical() << " UPDATING BINARY" << fi.fileName() << "(size=" << fi.size() << ") FAILED";
|
||||
qCritical() << QString(80, '*');
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString(" UPDATING BINARY ") + fi.fileName()
|
||||
+ QString(" (size=%1").arg(fi.size()) + ") FAILED");
|
||||
}
|
||||
} else {
|
||||
qCritical() << QString(80, '*');
|
||||
qCritical() << fileToSendToDC << "does not exist -> NO UPDATE OF DC FIRMWARE";
|
||||
qCritical() << QString(80, '*');
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString(fileToSendToDC) + " DOES NOT EXIST -> NO UPDATE OF DC FIRMWARE");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool Update::updateDC(QString bFile) const {
|
||||
qDebug() << "updating dc...";
|
||||
qDebug() << "updating dc: file to send" << bFile;
|
||||
if (!resetDeviceController()) {
|
||||
return false;
|
||||
qDebug() << "IN UPDATEDC: UPDATING DC: FILE TO SEND" << bFile;
|
||||
|
||||
m_worker->mainWindow()->setUpdateStep(UpdateDcEvent::UpdateStep::NONE);
|
||||
|
||||
QApplication::postEvent( // step 1: reset device controller
|
||||
m_worker->mainWindow(),
|
||||
new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::DC_REBOOT, 1));
|
||||
QThread::sleep(1);
|
||||
|
||||
for (int i=1; i <= MainWindow::BL_START_COUNT; ++i) {
|
||||
QApplication::postEvent( // step 2: start bootloader (5x)
|
||||
m_worker->mainWindow(),
|
||||
new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_START, i));
|
||||
QThread::sleep(1);
|
||||
}
|
||||
if (!startBootloader()) {
|
||||
// even when start seems to fail, stopping the boot loader does not harm
|
||||
stopBootloader();
|
||||
|
||||
int const cntLimit = 100; // wait until its for sure that bl_startBL()
|
||||
int cnt = 0; // has been excuted
|
||||
while (++cnt < cntLimit &&
|
||||
m_worker->mainWindow()->updateStep() != UpdateDcEvent::UpdateStep::BL_START) {
|
||||
// wait until all bl_startBL() are done
|
||||
QThread::msleep(200);
|
||||
}
|
||||
|
||||
if (cnt == cntLimit) {
|
||||
// start events not received ???
|
||||
Utils::printCriticalErrorMsg("BL_START EVENT NOT RECEIVED AFTER 20 SECS");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!downloadBinaryToDC(bFile)) {
|
||||
stopBootloader();
|
||||
qCritical() << "updating dc: " << bFile << "...FAILED";
|
||||
m_worker->mainWindow()->setUpdateStep(UpdateDcEvent::UpdateStep::BL_CHECK);
|
||||
|
||||
for (int i=1; i <= MainWindow::BL_IS_UP_COUNT; ++i) {
|
||||
QApplication::postEvent(m_worker->mainWindow(), new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_CHECK, i));
|
||||
QThread::sleep(1);
|
||||
QApplication::postEvent(m_worker->mainWindow(), new UpdateDcEvent(m_worker, UpdateDcEvent::UpdateStep::BL_IS_UP, i));
|
||||
if (m_worker->mainWindow()->updateStep() == UpdateDcEvent::UpdateStep::BL_IS_UP) {
|
||||
break;
|
||||
}
|
||||
QThread::sleep(1);
|
||||
}
|
||||
|
||||
cnt = 0;
|
||||
while (++cnt < cntLimit &&
|
||||
m_worker->mainWindow()->updateStep() != UpdateDcEvent::UpdateStep::BL_IS_UP) {
|
||||
// wait until all bl_startBL() are done
|
||||
QThread::msleep(200);
|
||||
}
|
||||
|
||||
if (cnt == cntLimit) {
|
||||
// really not up
|
||||
Utils::printCriticalErrorMsg("BL_IS_UP EVENT NOT RECEIVED AFTER 20 SECS");
|
||||
stopBootloader(); // try to stop bootloader whichhas been already started
|
||||
return false;
|
||||
}
|
||||
qInfo() << "updating dc: " << bFile << "...OK";
|
||||
|
||||
stopBootloader();
|
||||
//resetDeviceController();
|
||||
if (m_worker->mainWindow()->updateStep() == UpdateDcEvent::UpdateStep::BL_IS_UP) {
|
||||
// bootloader MUST be running to download device-controller
|
||||
#if 0
|
||||
if (!downloadBinaryToDC(bFile)) {
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("UPDATING DC: ") + bFile + " ...DOWNLOAD FAILED");
|
||||
}
|
||||
#endif
|
||||
|
||||
QThread::sleep(3);
|
||||
} else {
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("UPDATING DC: ") + bFile + " BOOT LOADER NOT RUNNING -> NO DOWNLOAD ("
|
||||
+ QThread::currentThread()->objectName() + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
// do this unconditionally, even if bootloader is not running at all ->
|
||||
// the controller possibly tells us nonsense.
|
||||
if (!stopBootloader()) {
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("UPDATING DC: ") + bFile + " BOOT LOADER STILL RUNNING ("
|
||||
+ QThread::currentThread()->objectName() + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
Utils::printInfoMsg(QString("UPDATING DC: ") + bFile + " ...OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -416,9 +606,12 @@ bool Update::downloadJson(enum FileTypeJson type,
|
||||
int templateIdx,
|
||||
QString jsFileToSendToDC) const {
|
||||
|
||||
qDebug() << "updating json-file:" << jsFileToSendToDC << "...";
|
||||
qDebug() << " template-index:" << templateIdx;
|
||||
qDebug() << " json-type:" << jsonType(type);
|
||||
|
||||
Utils::printInfoMsg(
|
||||
QString("UPDATING JSON-FILE=%1, TEMPLATE-INDEX=%2, JSON-TYPE=%3")
|
||||
.arg(jsFileToSendToDC)
|
||||
.arg(templateIdx)
|
||||
.arg(jsonType(type)));
|
||||
|
||||
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
|
||||
qDebug() << "SET AUTO-REQUEST=TRUE";
|
||||
@@ -429,7 +622,7 @@ bool Update::downloadJson(enum FileTypeJson type,
|
||||
while ((ready = m_hw->sys_ready4sending()) == false) {
|
||||
QThread::msleep(200);
|
||||
if (--nTry <= 0) {
|
||||
qCritical() << "SYS NOT READY FOR SENDING AFTER 5 SECONDS";
|
||||
Utils::printCriticalErrorMsg("SYS NOT READY FOR SENDING AFTER 5 SECONDS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -442,22 +635,27 @@ bool Update::downloadJson(enum FileTypeJson type,
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
if (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())) {
|
||||
QThread::sleep(1);
|
||||
qDebug() << "SENT" << jsFileToSendToDC;
|
||||
ret = true;
|
||||
}
|
||||
} else {
|
||||
qCritical() << "SIZE OF" << jsFileToSendToDC
|
||||
<< "TOO BIG (" << fi.size() << "BYTES)";
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("SIZE OF %1 TOO BIG (%2 BYTES)")
|
||||
.arg(jsFileToSendToDC).arg(fi.size()));
|
||||
}
|
||||
} else {
|
||||
qCritical() << "CANNOT OPEN" << jsFileToSendToDC << "FOR READING";
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString("CAN NOT OPEN ") + jsFileToSendToDC + " FOR READING");
|
||||
}
|
||||
} else {
|
||||
qCritical() << jsFileToSendToDC << "DOES NOT EXIST";
|
||||
Utils::printCriticalErrorMsg(
|
||||
QString(jsFileToSendToDC) + " DOES NOT EXIST");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,100 +716,85 @@ void Update::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
}
|
||||
|
||||
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
|
||||
//
|
||||
// ACHTUNG !!!
|
||||
//
|
||||
return true;
|
||||
QStringList Update::getDcSoftAndHardWareVersion() {
|
||||
m_hw->dc_autoRequest(true);
|
||||
QThread::sleep(1); // make sure the timer-slots are active
|
||||
|
||||
bool serialOpened = false;
|
||||
bool serialOpen = false;
|
||||
|
||||
if (!serialOpen) {
|
||||
if (!isSerialOpen()) { // open serial only if not already open
|
||||
if ((serialOpened = openSerial(baudrateMap.value(m_baudrate), m_baudrate, m_serialInterface)) == false) {
|
||||
qCritical() << "CANNOT OPEN" << m_serialInterface << "(BAUDRATE="
|
||||
<< m_baudrate << ")";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
serialOpen = true;
|
||||
qInfo() << "SERIAL OPEN" << m_serialInterface << "(BAUDRATE=" << m_baudrate << ")";
|
||||
for (int i=0; i < 3; ++i) { // send explicit reuests to get
|
||||
// current SW/HW-versions
|
||||
m_hw->request_DC2_SWversion();
|
||||
m_hw->request_DC2_HWversion();
|
||||
QThread::sleep(1);
|
||||
}
|
||||
|
||||
QString const &hwVersion = m_hw->dc_getHWversion().toLower().trimmed();
|
||||
QString const &swVersion = m_hw->dc_getSWversion().toLower().trimmed();
|
||||
|
||||
m_hw->dc_autoRequest(false);
|
||||
QThread::sleep(1); // make sure the timer-slots are inactive
|
||||
|
||||
if (!hwVersion.isEmpty() && !swVersion.isEmpty()) {
|
||||
return QStringList() << hwVersion << swVersion;
|
||||
}
|
||||
|
||||
return QStringList() << "DC HW-version not available"
|
||||
<< "DC SW-version not available";
|
||||
}
|
||||
|
||||
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
|
||||
// always assume that serial line is open
|
||||
bool res = false;
|
||||
QList<QString>::const_iterator it;
|
||||
for (it = filesToWorkOn.cbegin(); it != filesToWorkOn.cend(); ++it) {
|
||||
m_worker->startProgressLoop();
|
||||
QString fToWorkOn = (*it).trimmed();
|
||||
fToWorkOn = QDir::cleanPath(m_customerRepository + QDir::separator() + fToWorkOn);
|
||||
|
||||
static const QRegularExpression version("^.*dc2c[.][0-9][0-9][.][0-9][0-9][.]bin.*$");
|
||||
QString const &fToWorkOn = QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed());
|
||||
#if UPDATE_DC == 1
|
||||
static const QRegularExpression version("^.*dc2c[.][0-9]{1,2}[.][0-9]{1,2}[.]bin.*$");
|
||||
if (fToWorkOn.contains(version)) {
|
||||
|
||||
qInfo() << QString(80, '*');
|
||||
qInfo() << "DO-UPDATE FILE-TO-WORK-ON" << fToWorkOn;
|
||||
qInfo() << QString(80, '*');
|
||||
|
||||
for (int i=0; i < 3; ++i) { // send explicit reuests to get
|
||||
// current SW/HW-versions
|
||||
m_hw->request_DC2_SWversion();
|
||||
m_hw->request_DC2_HWversion();
|
||||
QThread::sleep(1);
|
||||
}
|
||||
|
||||
QString const hwVersion = m_hw->dc_getHWversion().toLower();
|
||||
QString const fwVersion = m_hw->dc_getSWversion().toLower();
|
||||
|
||||
qInfo() << "current dc-hardware-version" << hwVersion;
|
||||
qInfo() << "current dc-firmware-version" << fwVersion;
|
||||
Utils::printInfoMsg("DO-UPDATE FILE-TO-WORK-ON " + fToWorkOn);
|
||||
|
||||
QFile fn(fToWorkOn);
|
||||
QFileInfo finfo(fn);
|
||||
if (!fn.exists()) { // check for broken link
|
||||
qCritical() << QString(80, '*');
|
||||
qCritical() << "FILE-TO-WORK-ON" << fn << "DOES NOT EXIST";
|
||||
qCritical() << QString(80, '*');
|
||||
Utils::printCriticalErrorMsg("DO-UPDATE FILE-TO-WORK-ON "
|
||||
+ fToWorkOn + " DOES NOT EXIST");
|
||||
res = false;
|
||||
} else {
|
||||
if (false) {
|
||||
//if (fwVersion.startsWith(linkTarget.completeBaseName())) {
|
||||
// qCritical() << "current dc-firmware-version" << fwVersion
|
||||
// << "already installed";
|
||||
// res = false;
|
||||
} else {
|
||||
res = true;
|
||||
bool updateBinaryRes = true;
|
||||
|
||||
qInfo() << "DOWNLOADING" << finfo.completeBaseName() << "TO DC";
|
||||
#if UPDATE_DC == 1
|
||||
m_hw->dc_autoRequest(false);// default: turn auto-request setting off
|
||||
QThread::sleep(1); // wait to be sure that there are no more
|
||||
// commands sent to dc-hardware
|
||||
qInfo() << "SET AUTO-REQUEST=FALSE";
|
||||
qInfo() << "DOWNLOADING" << finfo.completeBaseName() << "TO DC";
|
||||
m_hw->dc_autoRequest(false);// default: turn auto-request setting off
|
||||
QThread::sleep(1); // wait to be sure that there are no more
|
||||
// commands sent to dc-hardware
|
||||
qInfo() << "SET AUTO-REQUEST=FALSE";
|
||||
|
||||
if ((res = updateBinary(fToWorkOn.toStdString().c_str())) == true) {
|
||||
qCritical() << "downloaded binary" << fToWorkOn;
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
|
||||
m_hw->dc_autoRequest(true); // turn auto-request setting on
|
||||
qInfo() << "SET AUTO-REQUEST=TRUE";
|
||||
qInfo() << "WAIT 10 SECS TO RECEIVE RESPONSES...";
|
||||
|
||||
QThread::sleep(10); // wait to be sure that responses
|
||||
// have been received
|
||||
qInfo() << "updated dc-hardware-version" << m_hw->dc_getHWversion();
|
||||
qInfo() << "updated dc-firmware-version" << m_hw->dc_getSWversion();
|
||||
#endif
|
||||
if ((updateBinaryRes = updateBinary(fToWorkOn.toStdString().c_str())) == true) {
|
||||
qCritical() << "downloaded binary" << fToWorkOn;
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
|
||||
m_hw->dc_autoRequest(true); // turn auto-request setting on
|
||||
qInfo() << "SET AUTO-REQUEST=TRUE";
|
||||
|
||||
QStringList const &versions = Update::getDcSoftAndHardWareVersion();
|
||||
if (versions.size() >= 2) {
|
||||
if (updateBinaryRes == true) {
|
||||
qInfo() << "dc-hardware-version (UPDATED)" << versions[0];
|
||||
qInfo() << "dc-firmware-version (UPDATED)" << versions[1];
|
||||
} else {
|
||||
qInfo() << "dc-hardware-version (NOT UPDATED)" << versions[0];
|
||||
qInfo() << "dc-firmware-version (NOT UPDATED)" << versions[1];
|
||||
}
|
||||
}
|
||||
res = updateBinaryRes;
|
||||
}
|
||||
} else if (fToWorkOn.contains("DC2C_print", Qt::CaseInsensitive)
|
||||
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
#endif
|
||||
if (fToWorkOn.contains("DC2C_print", Qt::CaseInsensitive)
|
||||
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
res = true;
|
||||
#if UPDATE_PRINTER_TEMPLATES == 1
|
||||
int i = fToWorkOn.indexOf("DC2C_print", Qt::CaseInsensitive);
|
||||
int const templateIdx = fToWorkOn.mid(i).midRef(10, 2).toInt();
|
||||
if ((templateIdx < 1) || (templateIdx > 32)) {
|
||||
@@ -619,56 +802,52 @@ bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
|
||||
res = false;
|
||||
} else {
|
||||
if ((res = updatePrinterTemplate(templateIdx, fToWorkOn))) {
|
||||
qInfo() << "downloaded printer template"<< fToWorkOn;
|
||||
Utils::printInfoMsg(
|
||||
QString("DOWNLOADED PRINTER TEMPLATE %1 WITH INDEX=%2")
|
||||
.arg(fToWorkOn)
|
||||
.arg(templateIdx));
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (fToWorkOn.contains("DC2C_cash", Qt::CaseInsensitive)
|
||||
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
res = true;
|
||||
#if UPDATE_CASH_TEMPLATE == 1
|
||||
if ((res = updateCashConf(fToWorkOn))) {
|
||||
qInfo() << "downloaded cash template"<< fToWorkOn;
|
||||
Utils::printInfoMsg(QString("DOWNLOADED CASH TEMPLATE %1").arg(fToWorkOn));
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
#endif
|
||||
} else if (fToWorkOn.contains("DC2C_conf", Qt::CaseInsensitive)
|
||||
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
res = true;
|
||||
#if UPDATE_CONF_TEMPLATE == 1
|
||||
if ((res= updateConfig(fToWorkOn))) {
|
||||
qInfo() << "downloaded config template"<< fToWorkOn;
|
||||
Utils::printInfoMsg(QString("DOWNLOADED CONFIG TEMPLATE %1").arg(fToWorkOn));
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
#endif
|
||||
} else if (fToWorkOn.contains("DC2C_device", Qt::CaseInsensitive)
|
||||
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
res = true;
|
||||
#if UPDATE_DEVICE_TEMPLATE == 1
|
||||
if ((res = updateDeviceConf(fToWorkOn))) {
|
||||
qInfo() << "downloaded device template"<< fToWorkOn;
|
||||
Utils::printInfoMsg(QString("DOWNLOADED DEVICE TEMPLATE %1").arg(fToWorkOn));
|
||||
++displayIndex;
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
||||
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
||||
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
||||
Worker::UPDATE_STEP_DONE);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
qCritical() << "UNKNOWN JSON FILE NAME" << fToWorkOn;
|
||||
res = false;
|
||||
}
|
||||
m_worker->stopProgressLoop();
|
||||
m_worker->setProgress(100);
|
||||
// m_worker->stopProgressLoop();
|
||||
// m_worker->setProgress(100);
|
||||
|
||||
if (res == false) {
|
||||
break;
|
||||
|
7
update.h
7
update.h
@@ -7,6 +7,7 @@
|
||||
#include <QDir>
|
||||
#include <QByteArray>
|
||||
#include <QProcess>
|
||||
#include <QPluginLoader>
|
||||
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
@@ -27,15 +28,19 @@ class Update : public QObject {
|
||||
QString m_customerRepository;
|
||||
QString m_customerNrStr;
|
||||
QString m_branchName;
|
||||
QString m_pluginName;
|
||||
QString m_workingDir;
|
||||
bool m_maintenanceMode;
|
||||
bool m_dryRun;
|
||||
|
||||
static QPluginLoader pluginLoader;
|
||||
|
||||
public:
|
||||
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
|
||||
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
|
||||
|
||||
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn);
|
||||
static bool unloadDCPlugin();
|
||||
static QStringList split(QString line, QChar sep = ',');
|
||||
|
||||
|
||||
@@ -44,6 +49,7 @@ public:
|
||||
QString customerRepository,
|
||||
QString customerNrStr,
|
||||
QString branchName,
|
||||
QString pluginName,
|
||||
QString workingDir,
|
||||
bool dryRun = false,
|
||||
QObject *parent = nullptr,
|
||||
@@ -85,6 +91,7 @@ private:
|
||||
bool updateDeviceConf(QString jsFileToSendToDC);
|
||||
bool downloadJson(enum FileTypeJson type, int templateIdx,
|
||||
QString jsFileToSendToDC) const;
|
||||
QStringList getDcSoftAndHardWareVersion();
|
||||
|
||||
private slots:
|
||||
void readyReadStandardOutput();
|
||||
|
25
update_dc_event.cpp
Normal file
25
update_dc_event.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "update_dc_event.h"
|
||||
|
||||
QEvent::Type UpdateDcEvent::customEventType = QEvent::None;
|
||||
|
||||
UpdateDcEvent::UpdateDcEvent(QObject const *sender,
|
||||
UpdateStep updateStep,
|
||||
int count,
|
||||
QDateTime const &sendDateTime)
|
||||
: QEvent(UpdateDcEvent::type())
|
||||
, m_sender(sender)
|
||||
, m_updateStep(updateStep)
|
||||
, m_count(count)
|
||||
, m_sendDateTime(sendDateTime) {
|
||||
}
|
||||
|
||||
UpdateDcEvent::~UpdateDcEvent() {
|
||||
}
|
||||
|
||||
QEvent::Type UpdateDcEvent::type() {
|
||||
if (customEventType == QEvent::None) {
|
||||
int generatedType = QEvent::registerEventType();
|
||||
customEventType = static_cast<QEvent::Type>(generatedType);
|
||||
}
|
||||
return customEventType;
|
||||
}
|
40
update_dc_event.h
Normal file
40
update_dc_event.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef UPDATE_DC_EVENT_H_INCLUDED
|
||||
#define UPDATE_DC_EVENT_H_INCLUDED
|
||||
|
||||
#include <QEvent>
|
||||
#include <QDateTime>
|
||||
|
||||
class UpdateDcEvent : public QEvent {
|
||||
public:
|
||||
enum UpdateStep { NONE, DC_REBOOT, BL_START, BL_CHECK, BL_CHECK_AFTER_STOP, BL_IS_UP, BL_IS_DOWN, BL_STOP};
|
||||
|
||||
private:
|
||||
QObject const *m_sender;
|
||||
UpdateStep m_updateStep;
|
||||
int m_count;
|
||||
QDateTime m_sendDateTime;
|
||||
|
||||
public:
|
||||
explicit UpdateDcEvent(QObject const *sender, UpdateStep updateStep,
|
||||
int count,
|
||||
QDateTime const &sendDateTime = QDateTime::currentDateTime());
|
||||
virtual ~UpdateDcEvent();
|
||||
static QEvent::Type type();
|
||||
|
||||
QObject const *sender() { return m_sender; }
|
||||
QObject const *sender() const { return m_sender; }
|
||||
|
||||
void setUpdateStep(UpdateStep updateStep) { m_updateStep = updateStep; }
|
||||
UpdateStep updateStep() { return m_updateStep; }
|
||||
UpdateStep updateStep() const { return m_updateStep; }
|
||||
int count() const { return m_count; }
|
||||
void setCount(int count) { m_count = count; }
|
||||
QDateTime &sendDateTime() { return m_sendDateTime; }
|
||||
QDateTime const &sendDateTime() const { return m_sendDateTime; }
|
||||
|
||||
private:
|
||||
static QEvent::Type customEventType;
|
||||
};
|
||||
|
||||
|
||||
#endif // PROGRESS_EVENT_H_INCLUDED
|
219
utils.cpp
219
utils.cpp
@@ -1,9 +1,20 @@
|
||||
#include "utils.h"
|
||||
#include "message_handler.h"
|
||||
#include "git/git_client.h"
|
||||
|
||||
|
||||
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
int Utils::read1stLineOfFile(QString fileName) {
|
||||
QFile f(fileName);
|
||||
@@ -35,17 +46,70 @@ QString Utils::zoneName(quint8 i) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
void Utils::printCriticalErrorMsg(QString const &errorMsg) {
|
||||
qCritical() << QString(80, '!');
|
||||
void Utils::printCriticalErrorMsg(QString const &errorMsg, bool upper, bool lower) {
|
||||
if (upper) qCritical() << QString(80, 'E');
|
||||
|
||||
qCritical() << errorMsg;
|
||||
qCritical() << QString(80, '!');
|
||||
|
||||
if (lower) qCritical() << QString(80, 'E');
|
||||
}
|
||||
|
||||
void Utils::printInfoMsg(QString const &infoMsg) {
|
||||
qCritical() << QString(80, '=');
|
||||
qCritical() << infoMsg;
|
||||
qCritical() << QString(80, '=');
|
||||
void Utils::printCriticalErrorMsg(QStringList const &errorMsg) {
|
||||
qCritical() << QString(80, 'E');
|
||||
for (int i = 0; i < errorMsg.size(); ++i) {
|
||||
qCritical() << errorMsg.at(i);
|
||||
}
|
||||
qCritical() << QString(80, 'E');
|
||||
}
|
||||
|
||||
void Utils::printUpdateStatusMsg(QDebug &debug, QStringList const &updateMsg) {
|
||||
debug << QString(80, 'U');
|
||||
for (int i = 0; i < updateMsg.size(); ++i) {
|
||||
debug << updateMsg.at(i);
|
||||
}
|
||||
debug << QString(80, 'U');
|
||||
}
|
||||
|
||||
void Utils::printUpdateStatusMsg(QStringList const &updateMsg) {
|
||||
qCritical() << QString(80, 'U');
|
||||
for (int i = 0; i < updateMsg.size(); ++i) {
|
||||
qCritical() << updateMsg.at(i);
|
||||
}
|
||||
qCritical() << QString(80, 'U');
|
||||
}
|
||||
|
||||
void Utils::printUpdateStatusMsg(QString const &updateMsg, bool upper, bool lower) {
|
||||
if (upper) qCritical() << QString(80, 'U');
|
||||
|
||||
qCritical() << updateMsg;
|
||||
|
||||
if (lower) qCritical() << QString(80, 'U');
|
||||
}
|
||||
|
||||
void Utils::printUpdateStatusMsg(QDebug &debug, QString const &updateMsg,
|
||||
bool upper, bool lower) {
|
||||
if (upper) debug << QString(80, 'U');
|
||||
|
||||
debug << updateMsg;
|
||||
|
||||
if (lower) debug << QString(80, 'U');
|
||||
|
||||
}
|
||||
|
||||
void Utils::printInfoMsg(QString const &infoMsg, bool upper, bool lower) {
|
||||
if (upper) qCritical() << QString(80, 'I');
|
||||
|
||||
qCritical() << infoMsg;
|
||||
|
||||
if (lower) qCritical() << QString(80, 'I');
|
||||
}
|
||||
|
||||
void Utils::printInfoMsg(QStringList const &infoMsg) {
|
||||
qCritical() << QString(80, 'I');
|
||||
for (int i = 0; i < infoMsg.size(); ++i) {
|
||||
qCritical() << infoMsg.at(i);
|
||||
}
|
||||
qCritical() << QString(80, 'I');
|
||||
}
|
||||
|
||||
void Utils::printLineEditInfo(QStringList const &lines) {
|
||||
@@ -77,3 +141,144 @@ QString Utils::getTariffLoadTime(QString fileName) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
QString Utils::rstrip(QString const &str) {
|
||||
int n = str.size() - 1;
|
||||
for (; n >= 0; --n) {
|
||||
if (!str.at(n).isSpace()) {
|
||||
return str.left(n + 1);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Utils::sameFilesInDirs(QDir const &dir1, QDir const &dir2,
|
||||
QStringList const &nameFilters) {
|
||||
if (!dir1.exists()) {
|
||||
printCriticalErrorMsg(dir1.dirName() + " DOES NOT EXIST");
|
||||
return false;
|
||||
}
|
||||
if (!dir2.exists()) {
|
||||
printCriticalErrorMsg(dir2.dirName() + " DOES NOT EXIST");
|
||||
return false;
|
||||
}
|
||||
if (dir1.absolutePath() == dir2.absolutePath()) {
|
||||
printCriticalErrorMsg(dir1.dirName() + " AND "+ dir2.dirName() + " HAVE SAME PATH");
|
||||
return false;
|
||||
}
|
||||
|
||||
// files, sorted by name
|
||||
QFileInfoList const &lst1 = dir1.entryInfoList(nameFilters, QDir::Files, QDir::Name);
|
||||
QFileInfoList const &lst2 = dir2.entryInfoList(nameFilters, QDir::Files, QDir::Name);
|
||||
|
||||
QStringList fileNameLst1{};
|
||||
QStringList fileNameLst2{};
|
||||
QListIterator<QFileInfo> i1(lst1);
|
||||
while (i1.hasNext()) {
|
||||
fileNameLst1 << i1.next().fileName();
|
||||
}
|
||||
QListIterator<QFileInfo> i2(lst2);
|
||||
while (i2.hasNext()) {
|
||||
fileNameLst2 << i2.next().fileName();
|
||||
}
|
||||
|
||||
if (fileNameLst1.isEmpty()) {
|
||||
qCritical() << "DIR1" << dir1.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
|
||||
return false;
|
||||
}
|
||||
if (fileNameLst2.isEmpty()) {
|
||||
qCritical() << "DIR1" << dir2.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
|
||||
return false;
|
||||
}
|
||||
if (fileNameLst1 != fileNameLst2) {
|
||||
printCriticalErrorMsg(dir1.dirName() + " AND " + dir2.dirName()
|
||||
+ " DIFFER: [" + fileNameLst1.join(',') + "],["
|
||||
+ fileNameLst2.join(',') + "]");
|
||||
return false;
|
||||
} else {
|
||||
printInfoMsg(dir1.dirName() + " AND " + dir2.dirName()
|
||||
+ " ARE EQUAL: [" + fileNameLst1.join(',') + "]");
|
||||
}
|
||||
|
||||
QStringList gitBlobLst1{};
|
||||
QStringList gitBlobLst2{};
|
||||
QListIterator<QFileInfo> i3(lst1);
|
||||
while (i3.hasNext()) {
|
||||
gitBlobLst1 << GitClient::gitBlob(i3.next().fileName());
|
||||
}
|
||||
QListIterator<QFileInfo> i4(lst2);
|
||||
while (i4.hasNext()) {
|
||||
gitBlobLst2 << GitClient::gitBlob(i4.next().fileName());
|
||||
}
|
||||
|
||||
if (gitBlobLst1.isEmpty()) {
|
||||
qCritical() << "DIR1" << dir1.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
|
||||
return false;
|
||||
}
|
||||
if (gitBlobLst2.isEmpty()) {
|
||||
qCritical() << "DIR1" << dir2.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gitBlobLst1 != gitBlobLst2) {
|
||||
printCriticalErrorMsg(dir1.dirName() + " AND " + dir2.dirName()
|
||||
+ " DIFFER: [" + gitBlobLst1.join(',') + "],["
|
||||
+ gitBlobLst2.join(',') + "]");
|
||||
return false;
|
||||
} else {
|
||||
printInfoMsg(dir1.dirName() + " AND " + dir2.dirName()
|
||||
+ " CONTAIN SAME GIT-BLOBS FOR FILES: [" + fileNameLst1.join(',') + "]");
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString Utils::getParentName() { // get name of parent process
|
||||
QString ppid = QString("/proc/%1/status").arg(getppid());
|
||||
std::ifstream f(ppid.toStdString().c_str());
|
||||
if (f.is_open()) {
|
||||
std::string next;
|
||||
while (std::getline(f, next)) {
|
||||
QString line = QString(next.c_str()).simplified();
|
||||
if (line.startsWith("Name")) {
|
||||
int const idx = line.indexOf(QChar(':'));
|
||||
if (idx != -1) {
|
||||
return line.mid(idx+1).trimmed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Utils::isATBQTRunning() {
|
||||
QDirIterator it("/proc",
|
||||
QStringList() << "status",
|
||||
QDir::Files,
|
||||
QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString const &nextStatusFile = it.next();
|
||||
static const QRegularExpression re("^/proc/[0-9]{1,}/status");
|
||||
QRegularExpressionMatch match = re.match(nextStatusFile);
|
||||
if (match.hasMatch()) {
|
||||
std::ifstream f(nextStatusFile.toStdString().c_str());
|
||||
if (f.is_open()) {
|
||||
std::string next;
|
||||
while (std::getline(f, next)) {
|
||||
QString line = QString(next.c_str()).simplified();
|
||||
if (line.startsWith("Name")) {
|
||||
int const idx = line.indexOf(QChar(':'));
|
||||
if (idx != -1) {
|
||||
QString const binary = line.mid(idx+1).trimmed();
|
||||
if (binary == "ATBQT") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
19
utils.h
19
utils.h
@@ -7,14 +7,29 @@
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
namespace Utils {
|
||||
int read1stLineOfFile(QString fileName);
|
||||
QString zoneName(quint8 i);
|
||||
void printCriticalErrorMsg(QString const &errorMsg);
|
||||
void printInfoMsg(QString const &infoMsg);
|
||||
void printCriticalErrorMsg(QString const &errorMsg, bool upper=false, bool lower=false);
|
||||
void printCriticalErrorMsg(QStringList const &errorMsg);
|
||||
void printInfoMsg(QString const &infoMsg, bool upper=false, bool lower=false);
|
||||
void printInfoMsg(QStringList const &infoMsg);
|
||||
void printUpdateStatusMsg(QDebug &debug, QStringList const &updateMsg);
|
||||
void printUpdateStatusMsg(QStringList const &updateMsg);
|
||||
void printUpdateStatusMsg(QString const &updateMsg, bool upper=false, bool lower=false);
|
||||
void printUpdateStatusMsg(QDebug &debug, QString const &updateMsg, bool upper=false, bool lower=false);
|
||||
void printLineEditInfo(QStringList const &lines);
|
||||
QString getTariffLoadTime(QString fileName);
|
||||
QString rstrip(QString const &str);
|
||||
bool sameFilesInDirs(QDir const &dir1, QDir const &dir2,
|
||||
QStringList const &nameFilters = {"*.json"});
|
||||
|
||||
|
||||
QString getParentName();
|
||||
bool isATBQTRunning();
|
||||
}
|
||||
|
||||
#endif // UTILS_H_INCLUDED
|
||||
|
1720
worker.cpp
1720
worker.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user