Compare commits

..

47 Commits

Author SHA1 Message Date
0fe9ebef66 Make sure that if everything fails, to check /etc/dc for thedc-binary. 2025-10-02 15:36:09 +02:00
d15593c7aa Add doxygen documentation for dcCanditateDc(). 2025-10-02 15:35:05 +02:00
6f60265c74 Only use DEFAULT_INSTALL_DIR, not DEFAULT_INI_DIR. 2025-10-02 15:34:23 +02:00
1c10d9bc14 Mior: add comment line 2025-10-02 15:32:18 +02:00
0bca22f995 make sure dcDir can be overwritten on commandline. however, not if usb/sd was detected. 2025-10-02 15:31:36 +02:00
67eeade609 add command-line parameter "debug" 2025-10-01 14:36:28 +02:00
559298331b dcCandidateToInstall(): pass mount path as second parameter to prevent code duplication. 2025-09-29 13:06:14 +02:00
4f1efcf5cf Check if USB/SD is mounted and get dc-controller from etc/dc. 2025-09-29 13:04:47 +02:00
3047df8130 fix wrong path for command line parser 2025-09-29 13:01:52 +02:00
c783b7a967 remove run()-methode as not a thread anymore. 2025-09-29 11:27:45 +02:00
e4be41e670 Minor: add doxygen comments 2025-09-18 13:54:30 +02:00
b2ecd1b628 Minor: define structure for doxygen-documentation 2025-09-18 13:53:12 +02:00
fb4da1f208 Add Doxyfile for generating documentation 2025-09-18 13:52:10 +02:00
ec4e327899 ignore documentation directory 2025-09-18 13:50:04 +02:00
8621c1dd17 save prepared tools 2025-09-18 13:49:40 +02:00
0ddfc1d7e3 use as build dir for docu. 2025-09-18 12:02:42 +02:00
e95f034538 service calling on_update_failure.sh 2025-09-18 12:00:44 +02:00
72fbd9089a Minor: add doxygen comment 2025-09-16 13:26:35 +02:00
3bdc117c01 Define worker as usual qobject. Thread functionality not necessary anymore:
remove corresponding run() method, i.e. privateTupdate().
2025-09-16 13:08:33 +02:00
12eafc2878 start to add doxygen-comments 2025-09-16 13:07:27 +02:00
9abe718010 send update ACTIVATED command 3x to ISMAS -> reordering with 100% should be impossible now 2025-09-15 13:24:35 +02:00
3b6f22e93b move commndline_parser to common/ 2025-09-15 13:23:29 +02:00
34cc077937 move commandline_parser to ../common/ 2025-09-15 13:12:57 +02:00
ba1b2263d2 IMPORTANT: Use gitea repository url 2025-08-26 14:37:30 +02:00
1f99618ba5 Add helper functions -> QCommandLineParser reported some warnings 2025-08-26 14:36:39 +02:00
df4e384d9d Minor: define constants for case of clone 2025-08-26 14:34:50 +02:00
ede8a9519f Minor: show file in qtcreator 2025-08-26 14:33:28 +02:00
903977bdd1 set correct working directory for git commands except 'clone' 2025-08-26 14:32:49 +02:00
775e9b7b8a Use custom command line parser.
Checkout branch after cloning.
2025-08-26 14:31:26 +02:00
a8fdd29666 use custom command line parser 2025-08-26 14:23:14 +02:00
70d0ffb38d activate opkg with --noaction 2025-08-25 14:00:56 +02:00
f623b36421 after dc-download, check if device-controller reboots successfully 2025-08-25 13:55:49 +02:00
f415406672 test without ppid -> access etc/ in customer-repo 2025-08-25 13:54:44 +02:00
2c1afa463f download jsons after sync 2025-08-21 13:27:06 +02:00
927b488582 Mior: removed debug output 2025-08-21 13:26:11 +02:00
7712803ad6 Set pid into news to ISMAS (used by Christian to reorder events correctly) 2025-08-21 11:27:22 +02:00
bc88a9b0be Use ATBUpdateTool.ini for all child-processes (ATBUpdateDC etc.) 2025-08-21 11:03:51 +02:00
8b3f0991f7 Minor: add helpers lastFailedUpdateStep() and setLastFailedUpdateStep(). 2025-08-21 10:56:50 +02:00
8123526e11 Minor: add helper size() 2025-08-21 10:56:13 +02:00
57a093e9ae No timeout for running processes. 2025-08-21 10:55:33 +02:00
10536c81a5 Send to UPDATE SUCCEEDED to ISMAS when nothing else to do. 2025-08-21 10:54:18 +02:00
659dc69831 Replace TEST_DC_DOWNLOAD with m_debug. 2025-08-21 10:51:16 +02:00
a47dd60e9e Replace TEST_DC_DOWNLOAD with m_debug. 2025-08-20 11:15:09 +02:00
575a740692 Minor: init. m_debug to false. 2025-08-20 11:12:56 +02:00
e22d78cba8 read ATBUpdateDCsettings in *.ini file 2025-08-20 11:11:02 +02:00
ad8b9f26c0 add sections for child-applications 2025-08-20 11:10:17 +02:00
5b5a4504fa use ca-slave-plugin to download jsonfiles to DC 2025-08-20 10:03:11 +02:00
32 changed files with 4766 additions and 318 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
[REPOSITORY_URL] [REPOSITORY_URL]
repository-url="gitea@ptu-config.atb-comm.de:ATB/" repository-url="gitea@ptu-config.atb-comm.de:ATB"
[DIRECTORIES] [DIRECTORIES]
plugin-directory="/usr/lib/" plugin-directory="/usr/lib/"
@@ -19,3 +19,21 @@ yocto-version=false
yocto-install=false yocto-install=false
always-download-config=true always-download-config=true
always-download-dc=false always-download-dc=false
[ATBUpdateCheck]
[ATBUpdateDC]
debug=true
workingDir=/tmp
libca=/usr/lib/libCAslave.so
[ATBUpdateGit]
[ATBUpdateJsonFiles]
[ATBUpdateOpkg]
[ATBUpdateShow]
[ATBUpdateSync]

View File

@@ -77,7 +77,7 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
../common/src/message_handler.cpp \ ../common/src/message_handler.cpp \
../UpdatePTUDevCtrl/commandline_parser.cpp \ ../common/src/commandline_parser.cpp \
update.cpp \ update.cpp \
../common/src/System.cpp \ ../common/src/System.cpp \
../common/src/utils_internal.cpp \ ../common/src/utils_internal.cpp \
@@ -86,7 +86,7 @@ SOURCES += \
HEADERS += \ HEADERS += \
../common/include/message_handler.h \ ../common/include/message_handler.h \
../UpdatePTUDevCtrl/commandline_parser.h \ ../common/include/commandline_parser.h \
update.h \ update.h \
../common/include/System.h \ ../common/include/System.h \
../common/include/utils_internal.h \ ../common/include/utils_internal.h \

View File

@@ -67,11 +67,11 @@ int main(int argc, char **argv) {
//return 0; //return 0;
/*
CommandLineParser parser; CommandLineParser parser;
parser.process(a); parser.process(a);
parser.readSettings(); parser.readSettings();
/*
QString repositoryUrl = parser.repositoryUrl(); QString repositoryUrl = parser.repositoryUrl();
QString plugInDir = parser.plugInDir(); QString plugInDir = parser.plugInDir();
QString plugInName = parser.plugInName(); QString plugInName = parser.plugInName();
@@ -80,6 +80,7 @@ int main(int argc, char **argv) {
QString psaTariffDir = parser.psaTariffDir(); QString psaTariffDir = parser.psaTariffDir();
QString psaDcDir = parser.dcDir(); QString psaDcDir = parser.dcDir();
QString iniFileName = parser.iniFileName(); QString iniFileName = parser.iniFileName();
bool debug = parser.debug();
bool const dryRun = parser.dryRun(); bool const dryRun = parser.dryRun();
bool const noUpdatePsaHardware = parser.noUpdatePsaHardware(); bool const noUpdatePsaHardware = parser.noUpdatePsaHardware();
bool const showYoctoVersion = parser.yoctoVersion(); bool const showYoctoVersion = parser.yoctoVersion();
@@ -133,11 +134,13 @@ int main(int argc, char **argv) {
QString const &customerRepo QString const &customerRepo
= QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr)); = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr));
*/ */
QString psaDcDir = internal::customerRepoDcDir();
QString const &psaDcDir = internal::customerRepoDcDir(); QString psaRepoRootDir = internal::customerRepoRoot();
QString const &psaRepoRootDir = internal::customerRepoRoot(); QString psaRepoDir = internal::customerRepoDir();
QString const &psaRepoDir = internal::customerRepoDir(); QString branchName = internal::branchName();
QString const &branchName = internal::branchName(); QString rootDir = "/etc/dc/";
// bool usbDetected = false;
// bool sdCardDetected = false;
bool debug = false; bool debug = false;
bool noaction = true; bool noaction = true;
@@ -146,40 +149,67 @@ int main(int argc, char **argv) {
std::unique_ptr<QSettings> settings = internal::readSettings(); std::unique_ptr<QSettings> settings = internal::readSettings();
if (settings) { if (settings) {
settings->beginGroup("COMMON"); settings->beginGroup("ATBUpdateDC");
debug = settings->value("debug", false).toBool(); debug = settings->value("debug", false).toBool();
settings->endGroup(); workingDir = settings->value("workingdir", "/tmp").toString();
settings->beginGroup("RUNTIME");
noaction = settings->value("noaction", true).toBool();
workingDir = settings->value("workingdir", "/tmp").toBool();
libca = settings->value("libca", "/usr/lib/libCAslave.so").toString(); libca = settings->value("libca", "/usr/lib/libCAslave.so").toString();
settings->endGroup(); settings->endGroup();
} else {
qCritical() << "count not read ATBUpdateTool.ini";
return -1;
}
QString dcDir = parser.dcDir();
if (!dcDir.isEmpty()) {
psaDcDir = dcDir;
}
debug = parser.debug();
if (debug) {
qInfo() << " using dc directory: " << psaDcDir;
qInfo() << "using psa repo root directory: " << psaRepoRootDir;
qInfo() << " using customer repository: " << psaRepoDir;
qInfo() << " using branch: " << branchName;
} }
// etc/dc: located under mount-path // etc/dc: located under mount-path
std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir); std::optional<QString> mountPath = System::checkForUSBStick(psaDcDir);
QFileInfo fi; QFileInfo fi;
if (mountPath.has_value()) { if (mountPath.has_value()) {
fi.setFile(mountPath.value(), System::getDCFileOnUsbStick(mountPath.value())); // usbDetected = true;
// mountPath/etc/dc must exists !
// cannot override with commandline parameter --dc-directory
if (debug) {
qInfo() << "using mount path (USB): " << mountPath.value();
}
} else } else
if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) { if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) {
fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value())); // sdCardDetected = true;
} else { // mountPath/etc/dc must exists !
// cannot override with commandline parameter --dc-directory
if (debug) { if (debug) {
qInfo() << "using customer repository" << psaRepoDir; qInfo() << "using mount path (SD): " << mountPath.value();
} }
} else {
rootDir = "";
mountPath = QDir::cleanPath(psaRepoRootDir + QDir::separator() + psaDcDir);
if (debug) {
qInfo() << "using as dc-directory" << mountPath.value();
}
}
std::unique_ptr<QString> c = internal::dcCandidateToInstall("/etc/dc/"); if (debug) {
if (c) { qInfo() << "using as mount path: " << mountPath.value();
fi.setFile(*c); }
if (fi.exists() == false) {
qCritical() << "dc2c.bin candidate" << *c << "does not exist. STOP."; std::unique_ptr<QString> c = internal::dcCandidateToInstall(rootDir, mountPath.value());
return -1; if (c) {
} fi.setFile(*c);
qInfo() << "dc2c.bin canditate" << fi.absoluteFilePath(); if (fi.exists() == false) {
qCritical() << "dc2c.bin candidate" << *c << "does not exist. STOP.";
return -1;
} }
qInfo() << "dc2c.bin canditate" << fi.absoluteFilePath();
} }
if (debug) { if (debug) {
@@ -188,6 +218,9 @@ int main(int argc, char **argv) {
qInfo() << "dc-version" << Update::dcVersion(fi.absoluteFilePath()); qInfo() << "dc-version" << Update::dcVersion(fi.absoluteFilePath());
} }
// only for testing
// return 0;
Update u(fi.absoluteFilePath(), libca, debug, noaction); Update u(fi.absoluteFilePath(), libca, debug, noaction);
u.run(); u.run();

View File

@@ -26,14 +26,12 @@
#include <QString> #include <QString>
#include <QSerialPort> #include <QSerialPort>
#include <QSerialPortInfo> #include <QSerialPortInfo>
#include <QSettings>
#define UPDATE_OPKG (1) #define UPDATE_OPKG (1)
#define UPDATE_DC (0) #define UPDATE_DC (0)
// TODO: dynamisch setzen
#define TEST_DC_DOWNLOAD (0) // 0/1
static const QMap<QString, int> baudrateMap = { static const QMap<QString, int> baudrateMap = {
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3}, {"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
{"57600" , 4}, {"115200" , 5} {"57600" , 4}, {"115200" , 5}
@@ -135,15 +133,15 @@ Update::sendNextAddress(int bNum) const {
// qDebug() << "addr-block" << bNum << "..."; // qDebug() << "addr-block" << bNum << "...";
while (noAnswerCount <= 250) { while (noAnswerCount <= 250) {
#if TEST_DC_DOWNLOAD==0 DownloadResult res = DownloadResult::OK;
m_hw->bl_sendAddress(bNum); if (!m_debug) {
m_hw->bl_sendAddress(bNum);
QThread::msleep(10); //from 100ms to 20ms QThread::msleep(10); //from 100ms to 20ms
//################################################################################### //###################################################################################
DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK()); res = sendStatus(m_hw->bl_wasSendingAddOK());
#else }
DownloadResult const res = DownloadResult::OK;
#endif
if (res != DownloadResult::NOP) { if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) { if (res == DownloadResult::ERROR) {
if (++errorCount >= 10) { if (++errorCount >= 10) {
@@ -157,7 +155,7 @@ Update::sendNextAddress(int bNum) const {
} else { } else {
noAnswerCount += 1; // no answer by now noAnswerCount += 1; // no answer by now
} }
} } // while
// wait max. about 3 seconds // wait max. about 3 seconds
return DownloadResult::TIMEOUT; return DownloadResult::TIMEOUT;
} }
@@ -190,13 +188,12 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
while (noAnswerCount <= 250) { while (noAnswerCount <= 250) {
#if TEST_DC_DOWNLOAD==0 DownloadResult res = DownloadResult::OK;
m_hw->bl_sendDataBlock(64, local);
DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK()); if (!m_debug) {
#else m_hw->bl_sendDataBlock(64, local);
DownloadResult const res = DownloadResult::OK; res = sendStatus(m_hw->bl_wasSendingDataOK());
#endif }
if (res != DownloadResult::NOP) { if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) { if (res == DownloadResult::ERROR) {
@@ -220,60 +217,61 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const {
bool Update::startBootloader() const { bool Update::startBootloader() const {
qDebug() << "starting bootloader..."; qDebug() << "starting bootloader...";
#if TEST_DC_DOWNLOAD==0 if (!m_debug) {
int nTry = 10; int nTry = 10;
while (--nTry >= 0) { while (--nTry >= 0) {
m_hw->bl_startBL(); m_hw->bl_startBL();
QThread::msleep(1000); QThread::msleep(1000);
m_hw->bl_checkBL(); m_hw->bl_checkBL();
if (m_hw->bl_isUp()) { if (m_hw->bl_isUp()) {
qInfo() << "starting bootloader...OK"; qInfo() << "starting bootloader...OK";
QThread::msleep(5000); QThread::msleep(5000);
return true; return true;
} else { } else {
qCritical() << "bootloader not up (" << nTry << ")"; qCritical() << "bootloader not up (" << nTry << ")";
qCritical() << "IS BOOTLOADER INSTALLED ???"; qCritical() << "IS BOOTLOADER INSTALLED ???";
}
} }
qCritical() << "starting bootloader...FAILED";
return false;
} else {
QThread::msleep(1000);
qInfo() << "starting bootloader...OK";
} }
qCritical() << "starting bootloader...FAILED";
#else
QThread::msleep(1000);
qInfo() << "starting bootloader...OK";
return true; return true;
#endif
return false;
} }
bool Update::stopBootloader() const { bool Update::stopBootloader() const {
qDebug() << "stopping bootloader..."; qDebug() << "stopping bootloader...";
#if TEST_DC_DOWNLOAD==0 if (!m_debug) {
int nTry = 5; int nTry = 5;
while (--nTry >= 0) { while (--nTry >= 0) {
m_hw->bl_stopBL(); m_hw->bl_stopBL();
QThread::msleep(1000); QThread::msleep(1000);
if (!m_hw->bl_isUp()) { if (!m_hw->bl_isUp()) {
qInfo() << "stopping bootloader...OK"; qInfo() << "stopping bootloader...OK";
return true; return true;
}
} }
qCritical() << "stopping bootloader...FAILED";
return false;
} else {
QThread::msleep(1000);
qInfo() << "stopping bootloader...OK";
} }
qCritical() << "stopping bootloader...FAILED";
#else // Test code
QThread::msleep(1000);
qInfo() << "stopping bootloader...OK";
return true; return true;
#endif
return false;
} }
bool Update::resetDeviceController() const { bool Update::resetDeviceController() const {
qInfo() << nextTimePoint().toUtf8().constData() << "resetting device controller"; qInfo() << nextTimePoint().toUtf8().constData() << "resetting device controller";
#if TEST_DC_DOWNLOAD==0 if (!m_debug) {
m_hw->bl_rebootDC(); m_hw->bl_rebootDC();
#endif }
// wait maximally 3 seconds, before starting bootloader // wait maximally 3 seconds, before starting bootloader
QThread::sleep(1); QThread::sleep(1);
@@ -399,9 +397,9 @@ int Update::run() {
qInfo() << "<DC-VERSION>" << Update::dcVersion(m_dcFileName); qInfo() << "<DC-VERSION>" << Update::dcVersion(m_dcFileName);
} }
#if TEST_DC_DOWNLOAD==0 if (!m_debug) {
m_hw->dc_autoRequest(false); m_hw->dc_autoRequest(false);
#endif }
qInfo() << "DC auto request OFF"; qInfo() << "DC auto request OFF";
@@ -452,15 +450,25 @@ int Update::run() {
qCritical() << "DownloadThread::run(): last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK()); qCritical() << "DownloadThread::run(): last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK());
#endif #endif
} }
// TODO
stopBootloader(); // there is no harm in stopping the bootloader even stopBootloader(); // there is no harm in stopping the bootloader even
// if starting the bootloader failed // if starting the bootloader failed
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
#if TEST_DC_DOWNLOAD==0 // check if update was successful
m_hw->dc_autoRequest(true); //restart dc_autoRequest after download else E255! if (!m_debug) {
#endif m_hw->dc_autoRequest(true); //restart dc_autoRequest after download else E255!
return -(int)Result::SUCCESS; }
for (int i = 0; i < 3; ++i) {
qInfo() << "waiting for device controller restart...(" << i << ")";
QThread::sleep(20);
resetDeviceController();
if (startBootloader()) {
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-SUCCESS>";
stopBootloader();
return -(int)Result::SUCCESS;
}
}
} }
qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>"; qInfo() << nextTimePoint().toUtf8().constData() << "<DC-UPDATE-FAILURE>";

View File

@@ -30,7 +30,7 @@ class Update : public QObject {
QString m_dcFileName{}; QString m_dcFileName{};
hwinf *m_hw = nullptr; hwinf *m_hw = nullptr;
bool m_sys_areDCdataValid{}; bool m_sys_areDCdataValid{};
bool m_debug; bool m_debug{false};
bool m_noaction; bool m_noaction;
static QPluginLoader pluginLoader; static QPluginLoader pluginLoader;

View File

@@ -79,13 +79,13 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
../UpdatePTUDevCtrl/message_handler.cpp \ ../UpdatePTUDevCtrl/message_handler.cpp \
../UpdatePTUDevCtrl/commandline_parser.cpp \ ../common/src/commandline_parser.cpp \
update.cpp \ update.cpp \
../common/src/System.cpp ../common/src/System.cpp
HEADERS += \ HEADERS += \
../UpdatePTUDevCtrl/message_handler.h \ ../UpdatePTUDevCtrl/message_handler.h \
../UpdatePTUDevCtrl/commandline_parser.h \ ../common/include/commandline_parser.h \
update.h \ update.h \
../common/include/System.h ../common/include/System.h

View File

@@ -144,7 +144,7 @@ int main(int argc, char **argv) {
} }
} }
// qCritical() << "JSON FILES TO UPDATE" << filesToUpdate; qCritical() << __LINE__ << "JSON FILES TO UPDATE" << filesToUpdate;
Update update(customerRepo, Update update(customerRepo,
QString::number(customerNr), QString::number(customerNr),
@@ -153,8 +153,10 @@ int main(int argc, char **argv) {
plugInName, plugInName,
workingDir); workingDir);
update.doUpdate(); if (!filesToUpdate.empty()) {
// update.doUpdate(filesToUpdate, mountPath.has_value()); update.doUpdate(filesToUpdate, mountPath.has_value());
}
// update.checkJsonVersions(); // update.checkJsonVersions();
//update.checkJsonVersions(filesToUpdate); //update.checkJsonVersions(filesToUpdate);

View File

@@ -107,7 +107,7 @@ Update::Update(QString customerRepository,
char const *serialInterface, char const *serialInterface,
char const *baudrate) char const *baudrate)
: QObject(parent) : QObject(parent)
// , m_hw(loadDCPlugin(QDir(plugInDir), pluginName)) , m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
, m_serialInterface(serialInterface) , m_serialInterface(serialInterface)
, m_baudrate(baudrate) , m_baudrate(baudrate)
, m_customerRepository(customerRepository) , m_customerRepository(customerRepository)
@@ -145,7 +145,8 @@ Update::~Update() {
// unloadDCPlugin(); // unloadDCPlugin();
} }
bool Update::doUpdate() { #if 0
bool Update::doUpdate() { // test function
int numberOfFiles = 3; int numberOfFiles = 3;
@@ -178,6 +179,7 @@ bool Update::doUpdate() {
return true; return true;
} }
#endif
bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) { bool Update::doUpdate(QStringList const &filesToWorkOn, bool usbStickDetected) {

2970
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -16,11 +16,12 @@ GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1")
EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}" EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}"
INCLUDEPATH += \ INCLUDEPATH += plugins \
plugins \ $${INCLUDEINTERFACES}/ \
$${INCLUDEINTERFACES} \ $${_PRO_FILE_PWD_}/../common/ \
$${_PRO_FILE_PWD_}/../common/include $${_PRO_FILE_PWD_}/../common/include
CONFIG += c++17 CONFIG += c++17
DEFINES+=APP_VERSION=\\\"$$VERSION\\\" DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
@@ -67,12 +68,14 @@ SOURCES += \
message_handler.cpp \ message_handler.cpp \
../common/src/utils_internal.cpp \ ../common/src/utils_internal.cpp \
../common/src/command.cpp \ ../common/src/command.cpp \
../common/src/commandline_parser.cpp \
git_command.cpp git_command.cpp
HEADERS += \ HEADERS += \
message_handler.h \ message_handler.h \
../common/include/utils_internal.h \ ../common/include/utils_internal.h \
../common/include/command.h \ ../common/include/command.h \
../common/include/commandline_parser.h \
git_command.h git_command.h
########################################################################################## ##########################################################################################

View File

@@ -64,11 +64,13 @@ bool GitCommand::exec(QStringList const &options, int start_timeout, int finish_
} }
bool GitCommand::check(int start_timeout, int finish_timeout) { bool GitCommand::check(int start_timeout, int finish_timeout) {
m_workingDirectory = customerRepoDir();
QStringList const lst{"fsck"}; QStringList const lst{"fsck"};
return exec(lst, start_timeout, finish_timeout); return exec(lst, start_timeout, finish_timeout);
} }
bool GitCommand::checkout(int start_timeout, int finish_timeout) { bool GitCommand::checkout(int start_timeout, int finish_timeout) {
m_workingDirectory = customerRepoDir();
int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr"); int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
if (zoneNr != -1) { if (zoneNr != -1) {
QStringList const lst{"checkout", QString("zg1/zone%1").arg(zoneNr)}; QStringList const lst{"checkout", QString("zg1/zone%1").arg(zoneNr)};
@@ -91,11 +93,13 @@ bool GitCommand::clone(int start_timeout, int finish_timeout) {
} }
bool GitCommand::pull(int start_timeout, int finish_timeout) { bool GitCommand::pull(int start_timeout, int finish_timeout) {
m_workingDirectory = customerRepoDir();
QStringList const lst{"pull"}; QStringList const lst{"pull"};
return exec(lst, start_timeout, finish_timeout); return exec(lst, start_timeout, finish_timeout);
} }
bool GitCommand::status(int start_timeout, int finish_timeout) { bool GitCommand::status(int start_timeout, int finish_timeout) {
m_workingDirectory = customerRepoDir();
QStringList const lst{"status"}; QStringList const lst{"status"};
return exec(lst, start_timeout, finish_timeout); return exec(lst, start_timeout, finish_timeout);
} }

View File

@@ -8,6 +8,7 @@
#include <QSettings> #include <QSettings>
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QDateTime>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@@ -22,6 +23,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "utils_internal.h" #include "utils_internal.h"
#include "git_command.h" #include "git_command.h"
#include "commandline_parser.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
QByteArray const value = qgetenv("LC_ALL"); QByteArray const value = qgetenv("LC_ALL");
@@ -41,7 +43,7 @@ int main(int argc, char **argv) {
setDebugLevel(LOG_NOTICE); setDebugLevel(LOG_NOTICE);
} }
QCommandLineParser parser; CommandLineParser parser;
parser.setApplicationDescription("git-commands for the update-system"); parser.setApplicationDescription("git-commands for the update-system");
QCommandLineOption const checkCustomerRepositoryOption{"check"}; QCommandLineOption const checkCustomerRepositoryOption{"check"};
@@ -56,6 +58,54 @@ int main(int argc, char **argv) {
QCommandLineOption verboseOption{parser.addVersionOption()}; QCommandLineOption verboseOption{parser.addVersionOption()};
parser.process(a); parser.process(a);
parser.readSettings();
#if 0
// note: also used in initEnv().
QString repositoryUrl = parser.repositoryUrl();
if (repositoryUrl.endsWith('/')) {
repositoryUrl.chop(1);
}
if (!repositoryUrl.isEmpty()) {
qInfo() << "customer repository url" << repositoryUrl;
} else {
qCritical() << "ERROR customer repository url empty. git commands might fail.";
}
if (repositoryUrl.contains("ptu-config.atb-comm.de")) {
QString gitSSHCommand("");
QByteArray const v = qgetenv("GIT_SSH_COMMAND");
if (v.isEmpty()) {
QString sshKeyFile("/opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig");
if (QFileInfo(sshKeyFile).exists()) {
if (qgetenv("GIT_SSH_COMMAND").isNull()) {
gitSSHCommand = "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig";
if (!qputenv("GIT_SSH_COMMAND", QByteArray(gitSSHCommand.toStdString().c_str()))) {
qCritical() << "ERROR: GIT_SSH_COMMAND not put into env. Exiting...";
return -1;
}
}
} else {
qCritical() << "ERROR ssh-key-file" << sshKeyFile << "does not exists. Exiting...";
return -1;
}
} else {
gitSSHCommand = QString(v.toStdString().c_str());
qInfo() << "GIT_SSH_COMMAND already set in enviroment:" << gitSSHCommand;
if (gitSSHCommand != "ssh -i /opt/app/tools/atbupdate/.keys/id_ed25519_ptuConfig") {
qCritical() << "ERROR" << gitSSHCommand << "wrong. Exiting...";
return -1;
}
}
if (!gitSSHCommand.isEmpty()) {
qInfo() << "GIT_SSH_COMMAND .........." << gitSSHCommand;
}
}
#endif
if (parser.isSet(verboseOption)) { if (parser.isSet(verboseOption)) {
parser.showVersion(); parser.showVersion();
@@ -108,12 +158,13 @@ int main(int argc, char **argv) {
if (!gitCmd.clone()) { if (!gitCmd.clone()) {
return -3; return -3;
} }
if (!gitCmd.checkout()) {
return -2;
}
qCritical() << internal::GIT_CUSTOMER_REPO_CLONED;
return internal::GIT_CLONED_CODE;
} }
} }
//int const machineNr = read1stLineOfFile("/mnt/system_data/machine_nr");
//int const customerNr = read1stLineOfFile("/mnt/system_data/cust_nr");
//int const zoneNr = read1stLineOfFile("/mnt/system_data/zone_nr");
return 0; return 0;
} }

View File

@@ -294,9 +294,9 @@ SOURCES += \
process/show_software_status_command.cpp \ process/show_software_status_command.cpp \
message_handler.cpp \ message_handler.cpp \
worker.cpp \ worker.cpp \
commandline_parser.cpp \
work_process_list.cpp \ work_process_list.cpp \
$${_PRO_FILE_PWD_}/../common/src/utils_internal.cpp \ $${_PRO_FILE_PWD_}/../common/src/utils_internal.cpp \
$${_PRO_FILE_PWD_}/../common/src/commandline_parser.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.cpp \ $${_PRO_FILE_PWD_}/../common/ismas/ApismClient.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.cpp \ $${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.cpp \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.cpp $${_PRO_FILE_PWD_}/../common/ismas/ApismClientForUpdate.cpp
@@ -323,9 +323,9 @@ HEADERS += \
process/show_software_status_command.h \ process/show_software_status_command.h \
message_handler.h \ message_handler.h \
worker.h \ worker.h \
commandline_parser.h \
work_process_list.h \ work_process_list.h \
$${_PRO_FILE_PWD_}/../common/include/utils_internal.h \ $${_PRO_FILE_PWD_}/../common/include/utils_internal.h \
$${_PRO_FILE_PWD_}/../common/include/commandline_parser.h \
$${_PRO_FILE_PWD_}/../common/include/log_line_entry.h \ $${_PRO_FILE_PWD_}/../common/include/log_line_entry.h \
$${_PRO_FILE_PWD_}/../common/ismas/ApismClient.h \ $${_PRO_FILE_PWD_}/../common/ismas/ApismClient.h \
$${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.h \ $${_PRO_FILE_PWD_}/../common/ismas/ApismTcpClient.h \

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -49,6 +49,36 @@
#define SERIAL_PORT "ttyUSB0" #define SERIAL_PORT "ttyUSB0"
#endif #endif
/**
* @mainpage ATB-Update-Tool Documentation
* \section intro_sec Introduction
* The ATB update tool consistes of several binaries, which are executed in
* order:
* * \ref ATBUpdateTool
* * \ref ATBUpdateCheck
* * \ref ATBUpdateGit
* * \ref ATBUpdateSync
* * \ref ATBUpdateOpkg
* * \ref ATBUpdateDC
* * \ref ATBUpdateJsonFiles
* * \ref ATBUpdateShow
*
* The binaries are started synchonously as child processes of \ref ATBUpdateTool:
* each binary will finish before the next one is started.
* The output for the child process is captured in \ref ATBUpdateTool, and
* optionally shown in the GUI presemted to the user.
*
* - \page ATBUpdateTool
* - \page ATBUpdateCheck
* - \page ATBUpdateGit
* - \page ATBUpdateSync
* - \page ATBUpdateOpkg
* - \page ATBUpdateDC
* Typical call: ./ATBUpdateDC --dc-directory /etc/dc/ --debug true
* - \page ATBUpdateJsonFiles
* - \page ATBUpdateShow
*/
// argv[1]: file to send to dc // argv[1]: file to send to dc
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QByteArray const value = qgetenv("LC_ALL"); QByteArray const value = qgetenv("LC_ALL");

View File

@@ -50,12 +50,11 @@
#define UPDATE_DOWNLOAD_JSON_START (91) #define UPDATE_DOWNLOAD_JSON_START (91)
#define UPDATE_DOWNLOAD_JSON_END (100) #define UPDATE_DOWNLOAD_JSON_END (100)
void MainWindow::onFileChanged(QString const& /*f*/) { void MainWindow::onFileChanged(QString const& /*f*/) {
static int i = 30; static int i = 30;
ui->updateProgress->setValue(++i); ui->updateProgress->setValue(++i);
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate) << "YYYYYYYYYYYYYYYYYY file changed" << i;
// TODO: daten an ISMAS senden // TODO: daten an ISMAS senden
} }

View File

@@ -49,6 +49,9 @@ void CheckAndFetchCustomerRepositoryCommand::readyReadStandardOutput() {
} else } else
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_UPDATED)) { if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_UPDATED)) {
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED); //emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_UPDATED);
} else
if (m_commandResult.contains(internal::GIT_CUSTOMER_REPO_CLONED)) {
//emit w->showCustRepoStatus(internal::GIT_CUSTOMER_REPO_CLONED);
} }
} }
} }

View File

@@ -45,10 +45,6 @@ void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
//static constexpr const int PERCENT_UPDATE_DC{80}; //static constexpr const int PERCENT_UPDATE_DC{80};
//static constexpr const int PERCENT_SHOW_FINAL_STATUS{90}; //static constexpr const int PERCENT_SHOW_FINAL_STATUS{90};
qCritical() << __func__ << ":" << __LINE__ << m_command
<< "exitCode" << exitCode
<< "exitStatus" << exitStatus;
if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit) { if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit) {
if (m_command.contains("ATBUpdateCheck")) { if (m_command.contains("ATBUpdateCheck")) {
@@ -127,10 +123,19 @@ void UpdateCommand::finished(int exitCode, QProcess::ExitStatus exitStatus) {
if (m_worker->workList().nextExec()) { if (m_worker->workList().nextExec()) {
m_worker->workList().exec(); m_worker->workList().exec();
} else {
// testing
qCritical() << __func__ << ":" << __LINE__ << "TEST: SEND UPDATE SUCCEEDED TO ISMAS";
m_worker->setLastFailedUpdateStep(Worker::UPDATE_STEP::NONE);
Worker::UpdateProcessRunning _(m_worker);
} }
} else { } else {
bool execShowStatus = true; bool execShowStatus = true;
m_worker->workList().exec(execShowStatus); m_worker->workList().exec(execShowStatus);
} }
} else {
Q_ASSERT_X(false,
QString("%1:%2").arg(__func__).arg(__LINE__).toUtf8().constData(),
"empty worker list");
} }
} }

View File

@@ -9,7 +9,7 @@ public:
Worker *worker, Worker *worker,
int nextCommandIndex, int nextCommandIndex,
int start_timeout = 100000, int start_timeout = 100000,
int finish_timeout = 100000); int finish_timeout = -1);
public slots: public slots:
virtual void readyReadStandardOutput() override; virtual void readyReadStandardOutput() override;
virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override; virtual void finished(int exitCode, QProcess::ExitStatus exitStatus) override;

View File

@@ -4,12 +4,12 @@
#include <limits> #include <limits>
#include <QDebug> #include <QDebug>
unsigned WorkList::nextExecIndex() const { //unsigned WorkList::nextExecIndex() const {
if (m_workList.size() > 0 && m_workListIndex < (m_workList.size() - 1)) { // if (m_workList.size() > 0 && m_workListIndex < (m_workList.size() - 1)) {
return m_workListIndex + 1; // return m_workListIndex + 1;
} // }
return std::numeric_limits<unsigned>::max(); // return std::numeric_limits<unsigned>::max();
} //}
bool WorkList::nextExec() const { bool WorkList::nextExec() const {
return m_workListIndex < m_workList.size(); return m_workListIndex < m_workList.size();
@@ -17,12 +17,17 @@ bool WorkList::nextExec() const {
bool WorkList::exec(bool last) { bool WorkList::exec(bool last) {
if (last == false) { if (last == false) {
// if not the last entry in the worklist
if (nextExec()) { if (nextExec()) {
// and there is a next entry (a binary) to execute, start the
// binary if the specified working directory.
m_workList[m_workListIndex]->start("/opt/app/tools/atbupdate"); m_workList[m_workListIndex]->start("/opt/app/tools/atbupdate");
// update to point to next entry
m_workListIndex += 1; m_workListIndex += 1;
return true; return true;
} }
} else { } else {
// start the last entry in the worklist
m_workList.back()->start("/opt/app/tools/atbupdate"); m_workList.back()->start("/opt/app/tools/atbupdate");
m_workListIndex = std::numeric_limits<unsigned>::max(); m_workListIndex = std::numeric_limits<unsigned>::max();
return true; return true;

View File

@@ -5,18 +5,42 @@
#include <memory> #include <memory>
class UpdateCommand; class UpdateCommand;
/**
* @brief This class is responsible for calling the several binaries
* \ref ATBUpdateTool consists of.
*
* This class maintains a worklist, which conists of entries of type UpdateCommand.
*
* @see UpdateCommand
*/
class WorkList { class WorkList {
public: /**
* @brief Actual worklist of items to be eecuted.
*/
std::vector<std::unique_ptr<UpdateCommand>> m_workList; std::vector<std::unique_ptr<UpdateCommand>> m_workList;
public:
unsigned m_workListIndex{0}; unsigned m_workListIndex{0};
WorkList() = default; WorkList() = default;
/**
* \brief Put new work item into worklist.
*
* \tparam arg Work item to be added to worklist.
*/
template<typename T> template<typename T>
void push_back(T&& arg) { void push_back(T&& arg) {
m_workList.push_back(std::forward<T>(arg)); m_workList.push_back(std::forward<T>(arg));
} }
/**
* \brief Check if worklist is empty.
*
* \retval true if worklist is empty.
* \retval false otherwise.
*/
bool empty() const { return m_workList.empty(); } bool empty() const { return m_workList.empty(); }
// move constructor: pass in classes derived from UpdateCommand // move constructor: pass in classes derived from UpdateCommand
@@ -28,9 +52,31 @@ public:
// , m_workListIndex(0) { // , m_workListIndex(0) {
//} //}
unsigned nextExecIndex() const; ///**
// * \brief Put new work item into worklist.
// *
// */
//unsigned nextExecIndex() const;
/**
* \brief Put new work item into worklist.
*
*/
bool nextExec() const; bool nextExec() const;
/**
* \brief Put new work item into worklist.
*
* \param last
*/
bool exec(bool last=false); bool exec(bool last=false);
/**
* \brief Get current size of worklist.
*
* \retval Current size of worklist.
*/
unsigned size() { return m_workList.size(); }
}; };
#endif // WORK_LIST_H_INCLUDED #endif // WORK_LIST_H_INCLUDED

View File

@@ -252,8 +252,8 @@ Worker::Worker(int customerNr,
// NOTE: first run the opkg commands with no action -> dry-run // NOTE: first run the opkg commands with no action -> dry-run
m_workList.push_back( m_workList.push_back(
std::make_unique<ExecOpkgCommand>( std::make_unique<ExecOpkgCommand>(
QString("echo ATBUpdateOpkg --noaction") // QString("echo ATBUpdateOpkg --noaction")
// QString("/opt/app/tools/atbupdate/ATBUpdateOpkg --noaction") QString("/opt/app/tools/atbupdate/ATBUpdateOpkg --noaction")
, this, ++next, true)); , this, ++next, true));
// *** exec opkg-commands *** // *** exec opkg-commands ***
@@ -271,20 +271,21 @@ Worker::Worker(int customerNr,
QString("/opt/app/tools/atbupdate/ATBUpdateDC") QString("/opt/app/tools/atbupdate/ATBUpdateDC")
, this, ++next)); , this, ++next));
// *** send json files down to device controller ***
m_workList.push_back(
std::make_unique<UpdateJsonCommand>(
QString("echo ATBUpdateJsonFiles")
//QString("/opt/app/tools/atbupdate/ATBUpdateJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
, this, ++next, false));
// sync json files in repo etc-directory with /etc fs-directory // sync json files in repo etc-directory with /etc fs-directory
m_workList.push_back( m_workList.push_back(
std::make_unique<UpdateFileSystemCommand>( std::make_unique<UpdateFileSystemCommand>(
QString("echo ATBUpdateSync") QString("echo ATBUpdateSync")
, this, ++next)); , this, ++next));
// *** send json files down to device controller ***
m_workList.push_back(
std::make_unique<UpdateJsonCommand>(
//QString("echo ATBUpdateJsonFiles")
//QString("/opt/app/tools/atbupdate/ATBUpdateJsonFiles --set-ppid %1").arg(QCoreApplication::applicationPid())
// use customer repo
QString("/opt/app/tools/atbupdate/ATBUpdateJsonFiles").arg(QCoreApplication::applicationPid())
, this, ++next, false));
// show/send software-status // show/send software-status
m_workList.push_back( m_workList.push_back(
@@ -428,12 +429,6 @@ void Worker::stopProgressLoop() {
displayProgressInMainWindow(MainWindow::STOP_PROGRESS_LOOP); displayProgressInMainWindow(MainWindow::STOP_PROGRESS_LOOP);
} }
static std::once_flag once;
void Worker::run() {
// user should not start the update process several times
std::call_once(once, &Worker::privateUpdate, this);
}
bool Worker::isRepositoryCorrupted() { bool Worker::isRepositoryCorrupted() {
QDir customerRepository(m_customerRepository); QDir customerRepository(m_customerRepository);
if (customerRepository.exists()) { if (customerRepository.exists()) {
@@ -479,6 +474,7 @@ bool Worker::repairCorruptedRepository() {
return true; return true;
} }
#if 0
void Worker::privateUpdate() { void Worker::privateUpdate() {
if (!m_mainWindow) { if (!m_mainWindow) {
Utils::printCriticalErrorMsg("m_mainWindow NOT SET"); Utils::printCriticalErrorMsg("m_mainWindow NOT SET");
@@ -756,6 +752,7 @@ void Worker::privateUpdate() {
// final messages: see destructor of UpdateProcessRunning subclass // final messages: see destructor of UpdateProcessRunning subclass
m_lastFailedUpdateStep = UPDATE_STEP::NONE; m_lastFailedUpdateStep = UPDATE_STEP::NONE;
} }
#endif
bool Worker::updateTriggerSet() { bool Worker::updateTriggerSet() {
// repository is existent and not corrupted. check now if the ISMAS-trigger // repository is existent and not corrupted. check now if the ISMAS-trigger

View File

@@ -143,7 +143,21 @@ class Command;
class Update; class Update;
class MainWindow; class MainWindow;
class hwinf; class hwinf;
class Worker : public QThread{
/*!
\class Worker
\brief The worker class ties together the parts the update tool consists of:
* ATBUpdateTool
* ATBUpdateCheck
* ATBUpdateGit
* ATBUpdateSync
* ATBUpdateOpkg
* ATBUpdateDC
* ATBUpdateJsonFiles
* ATBUpdateShow
*
*/
class Worker : public QObject {
Q_OBJECT Q_OBJECT
int const m_customerNr; int const m_customerNr;
@@ -231,6 +245,7 @@ class Worker : public QThread{
int sendUpdateSucceededAndActivated(); int sendUpdateSucceededAndActivated();
int sendFinalResult(); int sendFinalResult();
public:
struct UpdateProcessRunning { struct UpdateProcessRunning {
Worker *m_worker; Worker *m_worker;
@@ -391,10 +406,15 @@ private:
hwinf *m_hw = nullptr; hwinf *m_hw = nullptr;
UPDATE_STEP m_lastFailedUpdateStep = UPDATE_STEP::NONE; UPDATE_STEP m_lastFailedUpdateStep = UPDATE_STEP::NONE;
protected:
virtual void run();
public: public:
UPDATE_STEP lastFailedUpdateStep() const {
return m_lastFailedUpdateStep;
}
void setLastFailedUpdateStep(UPDATE_STEP step) {
m_lastFailedUpdateStep = step;
}
QDebug CONSOLE(QStringList const &lst = QStringList()) { QDebug CONSOLE(QStringList const &lst = QStringList()) {
m_debugMsg = lst; m_debugMsg = lst;
return QDebug(QtMsgType::QtInfoMsg); return QDebug(QtMsgType::QtInfoMsg);
@@ -429,6 +449,29 @@ public:
static const QString UPDATE_STEP_WRONG; static const QString UPDATE_STEP_WRONG;
static const QString UPDATE_STEP_SUCCESS; static const QString UPDATE_STEP_SUCCESS;
/**
* Create a new Worker object to be used as the controlling instance of the
* update process.
*
* @brief Constructor
* @param customerNr
* @param machineNr
* @param zoneNr
* @param repositoryUrl
* @param branchName
* @param pluginDir
* @param pluginName
* @param workingDir
* @param noUpdatePsaHardware
* @param alwaysDownloadConfig
* @param alwaysDownloadDC
* @param dryRun
* @param parent
* @param serialInterface
* @param baudrate
*
* @todo einige parameter werden wohl ueberfluessig
*/
explicit Worker(int customerNr, // 281 explicit Worker(int customerNr, // 281
int machineNr, int machineNr,
int zoneNr, int zoneNr,
@@ -1641,8 +1684,12 @@ private:
smap[UPDATE_STEP::UPDATE_FINALIZE], smap[UPDATE_STEP::UPDATE_FINALIZE],
instance->m_ismasMsg.join(' ').toStdString().c_str(), instance->m_ismasMsg.join(' ').toStdString().c_str(),
instance->m_versionInfo.size() >= 1 ? instance->m_versionInfo.at(0).toUtf8().constData() : "N/A"); instance->m_versionInfo.size() >= 1 ? instance->m_versionInfo.at(0).toUtf8().constData() : "N/A");
ismasClient.sendRequestReceiveResponse( // send ACTIVATE message 3x -> reorder should be impossible now
IsmasClient::APISM::DB_PORT, ismasUpdateNews); for (int i = 0; i < 3; ++i) {
ismasClient.sendRequestReceiveResponse(
IsmasClient::APISM::DB_PORT, ismasUpdateNews);
QThread::msleep(1000);
}
} break; } break;
case UPDATE_STEP::UPDATE_NOT_NECESSARY: { case UPDATE_STEP::UPDATE_NOT_NECESSARY: {
ismasClient.setProgressInPercent(_UPDATE_NOT_NECESSARY + _UPDATE_NOT_NECESSARY_CORRECTION); ismasClient.setProgressInPercent(_UPDATE_NOT_NECESSARY + _UPDATE_NOT_NECESSARY_CORRECTION);

View File

@@ -23,6 +23,7 @@ class CommandLineParser : public QCommandLineParser {
QString m_alwaysDownloadDC; QString m_alwaysDownloadDC;
QString m_readDCVersion{"false"}; QString m_readDCVersion{"false"};
QString m_dcDir{"etc/dc/"}; QString m_dcDir{"etc/dc/"};
QString m_debug{"false"};
qint64 m_ppid; qint64 m_ppid;
QCommandLineOption m_repositoryUrlOption; QCommandLineOption m_repositoryUrlOption;
@@ -43,6 +44,7 @@ class CommandLineParser : public QCommandLineParser {
QCommandLineOption m_dcDirectoryOption; QCommandLineOption m_dcDirectoryOption;
QCommandLineOption m_readDCVersionOption; QCommandLineOption m_readDCVersionOption;
QCommandLineOption m_setPPid; QCommandLineOption m_setPPid;
QCommandLineOption m_debugOption;
QCommandLineParser m_parser; QCommandLineParser m_parser;
@@ -56,6 +58,9 @@ public:
QCommandLineParser &parser() { return m_parser; } QCommandLineParser &parser() { return m_parser; }
QCommandLineParser const &parser() const { return m_parser; } QCommandLineParser const &parser() const { return m_parser; }
void process(const QCoreApplication &app) { m_parser.process(app); } void process(const QCoreApplication &app) { m_parser.process(app); }
bool isSet(QCommandLineOption const &o) { return m_parser.isSet(o); }
bool isSet(QString const& s) {return m_parser.isSet(s); }
bool addOption(QCommandLineOption const &o) { return m_parser.addOption(o); }
QString const &iniFileName() const { return m_iniFileName; } QString const &iniFileName() const { return m_iniFileName; }
void readSettings(); void readSettings();
QString repositoryUrl(); QString repositoryUrl();
@@ -74,5 +79,6 @@ public:
bool alwaysDownloadDC(); bool alwaysDownloadDC();
bool readDCVersion(); bool readDCVersion();
QString dcDir(); QString dcDir();
bool debug();
}; };
#endif // COMMAND_LINE_PARSER_H_INCLUDED #endif // COMMAND_LINE_PARSER_H_INCLUDED

View File

@@ -35,6 +35,7 @@ namespace internal {
static constexpr const int GIT_PULL_ERROR_CODE{-4}; static constexpr const int GIT_PULL_ERROR_CODE{-4};
static constexpr const int GIT_NOT_NECESSARY_CODE{1}; static constexpr const int GIT_NOT_NECESSARY_CODE{1};
static constexpr const int GIT_UPDATED_CODE{2}; static constexpr const int GIT_UPDATED_CODE{2};
static constexpr const int GIT_CLONED_CODE{3};
static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"}; static constexpr const char *GIT_CUSTOMER_REPO_CHECKOUT_ERROR{"checkout error"};
static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"}; static constexpr const char *GIT_CUSTOMER_REPO_PULL_ERROR{"pull error"};
@@ -42,6 +43,7 @@ namespace internal {
static constexpr const char *GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY{"no repository update necessary"}; static constexpr const char *GIT_CUSTOMER_REPO_NO_UPDATE_NECESSARY{"no repository update necessary"};
static constexpr const char *GIT_CUSTOMER_REPO_NOT_NECESSARY{"not necessary"}; static constexpr const char *GIT_CUSTOMER_REPO_NOT_NECESSARY{"not necessary"};
static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"}; static constexpr const char *GIT_CUSTOMER_REPO_UPDATED{"repository updated"};
static constexpr const char *GIT_CUSTOMER_REPO_CLONED{"repository cloned"};
static constexpr const char *GIT_UPDATED{"updated"}; static constexpr const char *GIT_UPDATED{"updated"};
static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"}; static constexpr const char *EXEC_OPKG_COMMANDS_SUCCESS{"success"};
@@ -83,7 +85,7 @@ namespace internal {
QString branchName(); QString branchName();
bool customerRepoExists(); bool customerRepoExists();
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName = ""); std::unique_ptr<QSettings> readSettings(QString const &optionalDirName = "");
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory = ""); std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory, QString const &rootDir = "");
} }
#endif // UTILS_INTERNAL_H_INCLUDED #endif // UTILS_INTERNAL_H_INCLUDED

View File

@@ -6,7 +6,7 @@
#include <QFile> #include <QFile>
CommandLineParser::CommandLineParser() CommandLineParser::CommandLineParser()
: m_repositoryUrl("https://git.mimbach49.de/GerhardHoffmann") : m_repositoryUrl("gitea@ptu-config.atb-comm.de:ATB")
, m_plugInDir("/usr/lib/") , m_plugInDir("/usr/lib/")
, m_plugInName("libCAslave.so") , m_plugInName("libCAslave.so")
, m_workingDir("/opt/app/tools/atbupdate/") , m_workingDir("/opt/app/tools/atbupdate/")
@@ -100,7 +100,12 @@ CommandLineParser::CommandLineParser()
QCommandLineOption( QCommandLineOption(
QStringList() << "P" << "set-ppid", QStringList() << "P" << "set-ppid",
QCoreApplication::translate("main", "Set pid of parent process."), QCoreApplication::translate("main", "Set pid of parent process."),
QCoreApplication::translate("main", "Set pid of parent process."))) { QCoreApplication::translate("main", "Set pid of parent process.")))
, m_debugOption(
QCommandLineOption(
QStringList() << "debug" << "debug",
QCoreApplication::translate("main", "Set debug flag."),
QCoreApplication::translate("main", "Set debug flag."))) {
configure(); configure();
} }
@@ -110,7 +115,7 @@ void CommandLineParser::configure() {
m_parser.addHelpOption(); m_parser.addHelpOption();
m_parser.addVersionOption(); m_parser.addVersionOption();
m_repositoryUrlOption.setDefaultValue("https://git.mimbach49.de/GerhardHoffmann"); m_repositoryUrlOption.setDefaultValue("https://ptu-config.atb-comm.de/ATB/");
m_parser.addOption(m_repositoryUrlOption); m_parser.addOption(m_repositoryUrlOption);
m_iniFileDirectoryOption.setDefaultValue(QCoreApplication::applicationDirPath()); m_iniFileDirectoryOption.setDefaultValue(QCoreApplication::applicationDirPath());
@@ -163,6 +168,9 @@ void CommandLineParser::configure() {
m_setPPid.setDefaultValue("-1"); m_setPPid.setDefaultValue("-1");
m_parser.addOption(m_setPPid); m_parser.addOption(m_setPPid);
m_debugOption.setDefaultValue("false");
m_parser.addOption(m_debugOption);
} }
void CommandLineParser::readSettings() { void CommandLineParser::readSettings() {
@@ -180,7 +188,7 @@ void CommandLineParser::readSettings() {
for (QString const &key: keys) { for (QString const &key: keys) {
QVariant v = settings.value(key); QVariant v = settings.value(key);
//qCritical() << "(" << __func__ << ":" << __LINE__ << ")" // qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << key << " -> " << v.toString(); // << key << " -> " << v.toString();
if (key.contains("repository-url")) { if (key.contains("repository-url")) {
@@ -227,6 +235,9 @@ void CommandLineParser::readSettings() {
} else } else
if (key.contains("read-dc-version")) { if (key.contains("read-dc-version")) {
m_readDCVersion = (v.toBool() ? "true" : "false"); m_readDCVersion = (v.toBool() ? "true" : "false");
} else
if (key.contains("debug")) {
m_debug = (v.toBool() ? "true" : "false");
} else { } else {
qCritical() << __PRETTY_FUNCTION__ qCritical() << __PRETTY_FUNCTION__
<< key << " -> (UNKNOWN) " << v.toString(); << key << " -> (UNKNOWN) " << v.toString();
@@ -288,6 +299,13 @@ bool CommandLineParser::readDCVersion() {
return m_readDCVersion == "false" ? false : true; return m_readDCVersion == "false" ? false : true;
} }
bool CommandLineParser::debug() {
if (m_parser.isSet(m_debugOption)) {
m_debug = m_parser.value(m_debugOption);
}
return m_debug == "false" ? false : true;
}
QString CommandLineParser::workingDir() { QString CommandLineParser::workingDir() {
if (m_parser.isSet(m_workingDirectoryOption)) { if (m_parser.isSet(m_workingDirectoryOption)) {
m_workingDir = m_parser.value(m_workingDirectoryOption); m_workingDir = m_parser.value(m_workingDirectoryOption);

View File

@@ -62,41 +62,26 @@ QString branchName() {
} }
std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) { std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
std::unique_ptr<QSettings> settings{std::make_unique<QSettings>()}; std::unique_ptr<QSettings> settings;
QString const fileName{settings->applicationName() + ".ini"}; //QString const fileName{settings->applicationName() + ".ini"};
QString const fileName{"ATBUpdateTool.ini"};
QDir d; QDir d;
if (!optionalDirName.isEmpty()) { if (!optionalDirName.isEmpty()) {
d = QDir{optionalDirName}; d = QDir{optionalDirName};
if (d.exists()) { // try to find ini-file under optionalDirname if (d.exists()) { // try to find ini-file under optionalDirname
QFileInfo fi{d, optionalDirName}; QFileInfo fi{QDir::cleanPath(optionalDirName + QDir::separator() + fileName)};
if (fi.exists()) { if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat)); settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings; return settings;
} else { } else {
qCritical() << fi.absoluteFilePath() << "not found." qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
<< "Try" << internal::DEFAULT_INI_DIR;
} }
} else { } else {
qCritical() << optionalDirName << "not found." qCritical().noquote() << optionalDirName << "not found. Try" << internal::DEFAULT_INSTALL_DIR;
<< "Try" << internal::DEFAULT_INSTALL_DIR;
} }
} }
d = internal::DEFAULT_INI_DIR;
if (d.exists()) { // try to find ini-file under /etc/tools/atbupdate
QFileInfo fi{d, fileName};
if (fi.exists()) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings;
} else {
qCritical() << fi.absoluteFilePath() << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
} else {
qCritical() << internal::DEFAULT_INI_DIR << "not found."
<< "Try" << internal::DEFAULT_INSTALL_DIR;
}
d = QDir{internal::DEFAULT_INSTALL_DIR}; d = QDir{internal::DEFAULT_INSTALL_DIR};
if (d.exists()) { // try to find ini-file under /opt/app/tools/atbupdate if (d.exists()) { // try to find ini-file under /opt/app/tools/atbupdate
QFileInfo fi{d, fileName}; QFileInfo fi{d, fileName};
@@ -104,30 +89,64 @@ std::unique_ptr<QSettings> readSettings(QString const &optionalDirName) {
settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat)); settings.reset(new QSettings(fi.absoluteFilePath(), QSettings::IniFormat));
return settings; return settings;
} else { } else {
qCritical() << fi.absoluteFilePath() << "not found."; qCritical().noquote() << "read" << fileName << ":" << fi.absoluteFilePath() << "not found.";
} }
} else { } else {
qCritical() << internal::DEFAULT_INSTALL_DIR << "not found."; qCritical().noquote() << internal::DEFAULT_INSTALL_DIR << "not found.";
} }
return settings; return settings;
} }
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory) { /*! \brief Find dc-binary to install.
*
* If rootDir is empty, and if dcDirectory is empty as well, use etc/dc in
* custome repository (e,.g. /opt/app/tools/atbupdate/customer_337/etc/dc).
* If dcDirectory is not empty, then use it.
* If rootDir is \b not empty,check if it alreay ends with "/etc/dc/". in this
* case, use rootDir as dcDir. Otherwise, if dcDirectory is empty, use rootDir/etc/dc
* (e,.g. /opt/app/tools/atbupdate/customer_337/etc/dc). If dcDirectory
* is not empty, use roorDir/dcDirectory.
* As last resort, try "/etc/dc".
*
* \param[in] dcDirectory directory of device controller binary. Maybe empty.
* \param[in] rootDir root directory for dcDirectory. Might be empty.
* \return name of the found candidate, or null if not found.
*/
std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory,
QString const &rootDir) {
std::unique_ptr<QString> dcCandidate{nullptr}; std::unique_ptr<QString> dcCandidate{nullptr};
qCritical() << __func__ << __LINE__ << dcDirectory; QDir dcDir;
if (rootDir.isEmpty()) {
if (dcDirectory.isEmpty()) {
dcDir = customerRepoDcDir();
} else {
dcDir = dcDirectory;
}
} else {
if (!rootDir.endsWith("/etc/dc") && !rootDir.endsWith("/etc/dc/")) {
if (dcDirectory.isEmpty()) {
dcDir = QDir::cleanPath(rootDir + QDir::separator() + "etc/dc/");
} else {
dcDir = QDir::cleanPath(rootDir + QDir::separator() + dcDirectory);
}
} else {
dcDir = QDir::cleanPath(rootDir + QDir::separator());
}
}
QDir dcDir{dcDirectory.isEmpty() ? customerRepoDcDir() : dcDirectory};
if (dcDir.exists()) { if (dcDir.exists()) {
qInfo() << "use" << dcDir.absolutePath() << "as directory (containing dc-binary)";
QFileInfoList fileInfoList = QFileInfoList fileInfoList =
dcDir.entryInfoList(QStringList("*.bin"), dcDir.entryInfoList(QStringList("*.bin"),
QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks); QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
QFileInfo dc2cbin{dcDir.absoluteFilePath("dc2c.bin")}; QFileInfo dc2cbin{dcDir.absoluteFilePath("dc2c.bin")};
if (dc2cbin.exists()) { if (dc2cbin.exists()) {
QCryptographicHash md5gen(QCryptographicHash::Md5); QCryptographicHash md5gen(QCryptographicHash::Md5);
@@ -158,6 +177,12 @@ std::unique_ptr<QString> dcCandidateToInstall(QString const &dcDirectory) {
} }
} }
} }
} else {
qCritical() << dcDir.absolutePath() << "does not exist";
if (dcDir.absolutePath() != QDir("/etc/dc/").absolutePath()) {
qInfo() << __func__ << __LINE__ << "Try /etc/dc/";
return dcCandidateToInstall("/etc/dc/", "");
}
} }
return dcCandidate; return dcCandidate;

View File

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

View File

@@ -0,0 +1,19 @@
[Unit]
Description=ATB update tool
[Service]
Environment=XDG_RUNTIME_DIR=/var/run/user/0
# get START_DATE of service. Use '-' to ensure that file exists
EnvironmentFile=-/tmp/start_date.env
# EnvironmentFile=-/tmp/stop_date.env
ExecStartPre=/bin/bash -c 'printf "%%s\n" START_DATE=$(date +"%%Y-%%m-%%d%%H:%%M:%%S") > /tmp/start_date.env'
ExecStart=/opt/app/tools/atbupdate/ATBUpdateTool --platform wayland
ExecStartPre=dbus-send --system --type=method_call --dest='eu.atb.ptu.systemcontrol' '/systemcontrol' eu.atb.ptu.systemcontrol.startBackgroundTask string:UPDATE_TOOL
ExecStopPost=dbus-send --system --type=method_call --dest='eu.atb.ptu.systemcontrol' '/systemcontrol' eu.atb.ptu.systemcontrol.finishedBackgroundTask string:UPDATE_TOOL
# execute script to check if update-tool contains errors not sent to ISMAS.
# ExecStopPost=/bin/bash -c 'printf "%%s\n" STOP_DATE=$(date +"%%Y-%%m-%%d%%H:%%M:%%S") > /tmp/stop_date.env'
ExecStopPost=/bin/bash -c '[ -f /opt/app/tools/atbupdate/on_update_failure.sh ] && /opt/app/tools/atbupdate/on_update_failure.sh ${START_DATE}'
#StandardOutput=????

184
misc/on_update_failure.sh Executable file
View File

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