diff --git a/DownloadDCFirmware/DownloadDCFirmware.pro b/DownloadDCFirmware/DownloadDCFirmware.pro index b32522f..088f6d1 100644 --- a/DownloadDCFirmware/DownloadDCFirmware.pro +++ b/DownloadDCFirmware/DownloadDCFirmware.pro @@ -80,7 +80,6 @@ SOURCES += \ mainwindow.cpp \ ../common/src/message_handler.cpp \ ../UpdatePTUDevCtrl/commandline_parser.cpp \ - ../UpdatePTUDevCtrl/process/command.cpp \ update.cpp \ dc_download.cpp \ ../common/src/System.cpp @@ -90,7 +89,6 @@ HEADERS += \ mainwindow.h \ ../common/include/message_handler.h \ ../UpdatePTUDevCtrl/commandline_parser.h \ - ../UpdatePTUDevCtrl/process/command.h \ update.h \ dc_download.h \ ../common/include/System.h diff --git a/DownloadDCFirmware/main.cpp b/DownloadDCFirmware/main.cpp index cd4e0bf..4c508fa 100644 --- a/DownloadDCFirmware/main.cpp +++ b/DownloadDCFirmware/main.cpp @@ -52,7 +52,7 @@ int main(int argc, char **argv) { } // qputenv("XDG_RUNTIME_DIR", "/var/run/user/0"); - openlog("ATB-UPDATE-DC-FIRMWARE", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); + openlog("DC", LOG_PERROR | LOG_CONS, LOG_USER); QApplication a(argc, argv); QApplication::setApplicationName("ATBDownloadDCFirmware"); @@ -73,7 +73,7 @@ int main(int argc, char **argv) { QString workingDir = parser.workingDir(); QString psaConfigDir = parser.psaConfigDir(); QString psaTariffDir = parser.psaTariffDir(); - QString dcDir = parser.dcDir(); + QString psaDcDir = parser.dcDir(); QString iniFileName = parser.iniFileName(); bool const dryRun = parser.dryRun(); bool const noUpdatePsaHardware = parser.noUpdatePsaHardware(); @@ -112,13 +112,12 @@ int main(int argc, char **argv) { qInfo() << "customerNr ..............." << customerNr; qInfo() << "zoneNr ..................." << zoneNr; qInfo() << "readDCVersion ............" << readDCVersion; - qInfo() << "dcDir ...................." << dcDir; + qInfo() << "dcDir ...................." << psaDcDir; - if (readDCVersion) { - qInfo() << "dc-version ..............." << Update::dcVersion( - QDir::cleanPath(rtPath + QDir::separator() - + QString("customer_%1").arg(customerNr) + QDir::separator() - + dcDir + QDir::separator() + "dc2c.bin")); + if (!QDir(plugInDir).exists()) { + qCritical() << plugInDir + << "does not exists, but has to contain dc-library"; + exit(-1); } if (showExtendedVersion) { @@ -126,12 +125,47 @@ int main(int argc, char **argv) { return 0; } + QString const &customerRepo + = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr)); - // QString const &customerRepo = QDir::cleanPath(workingDir + QDir::separator() + QString("customer_%1").arg(customerNr)); - // QStringList filesToUpdate; + // etc/dc: located under mount-path + std::optional mountPath = System::checkForUSBStick(psaDcDir); + QFileInfo fi; + if (mountPath.has_value()) { + fi.setFile(mountPath.value(), System::getDCFileOnUsbStick(mountPath.value())); + } else + if ((mountPath = System::checkForSDCard(psaDcDir)).has_value()) { + fi.setFile(mountPath.value(), System::getDCFileOnSDCard(mountPath.value())); + } else { + qInfo() << "using customer repository" << customerRepo; + + QDir dir(QDir::cleanPath(customerRepo + QDir::separator() + "etc/dc")); + if (dir.exists()) { + fi.setFile(dir, dir.absoluteFilePath("dc2c.bin")); + } else { + qCritical() << "DIRECTORY" << dir << "DOES NOT EXIST"; + return -1; + } + } + + qInfo() << "downloading dc-firmware .." << fi.absoluteFilePath(); + qInfo() << "dc-firmware size (bytes) ." << fi.size(); + if (readDCVersion) { + qInfo() << "dc-version ..............." << Update::dcVersion(fi.absoluteFilePath()); + } QThread::currentThread()->setObjectName("main thread"); - qInfo() << "Main thread" << QThread::currentThreadId(); + // qInfo() << "Main thread" << QThread::currentThreadId(); + + Update update(customerRepo, + QString::number(customerNr), + branchName, + plugInDir, + plugInName, + workingDir, + psaDcDir); + + update.doUpdate(fi.absoluteFilePath()); // MainWindow mw; @@ -142,6 +176,8 @@ int main(int argc, char **argv) { // mw.show(); + qInfo() << ""; + return 0; // return a.exec(); } diff --git a/DownloadDCFirmware/update.cpp b/DownloadDCFirmware/update.cpp index e6ba2df..dafbc1b 100644 --- a/DownloadDCFirmware/update.cpp +++ b/DownloadDCFirmware/update.cpp @@ -96,17 +96,14 @@ bool Update::unloadDCPlugin() { } QString Update::dcVersion(QString const &dcBinFile) { - Command c("bash"); - QStringList param; + QProcess p; + QStringList params; - param << "-c" << QString(R"(strings %1 | grep DC2c.\[0-9\] | uniq)").arg(dcBinFile); + params << "-c" << QString(R"(strings %1 | grep DC2c.\[0-9\] | uniq)").arg(dcBinFile); - if (c.execute("/tmp", param)) { - return c.getCommandResult().trimmed().split(QRegularExpression("\\s")).first(); - // qInfo() << "(" << __func__ << ":" << __LINE__ << ")" << v; - } - - return ""; + p.start("bash", params); + p.waitForFinished(); + return QString(p.readAllStandardOutput()).trimmed().split(QRegularExpression("\\s")).first(); } class hwapi; @@ -116,11 +113,14 @@ Update::Update(QString customerRepository, QString plugInDir, QString pluginName, QString workingDir, + QString psaDcDir, bool dryRun, QObject *parent, char const *serialInterface, char const *baudrate) - : QObject(parent) + : QObject(parent) { +#if 0 + , m_hw(loadDCPlugin(QDir(plugInDir), pluginName)) , m_serialInterface(serialInterface) , m_baudrate(baudrate) @@ -129,6 +129,7 @@ Update::Update(QString customerRepository, , m_branchName(branchName) , m_pluginName(pluginName) , m_workingDir(workingDir) + , m_psaDcDir(psaDcDir) , m_dryRun(dryRun) , m_sys_areDCdataValid(false) { @@ -138,6 +139,8 @@ Update::Update(QString customerRepository, // carun stoppen } +#endif + m_start = QDateTime::currentDateTime(); } Update::~Update() { @@ -163,9 +166,16 @@ Update::sendNextAddress(int bNum) const { if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) { // qDebug() << "addr-block" << bNum << "..."; while (noAnswerCount <= 250) { - m_hw->bl_sendAddress(bNum); + // TODO + // m_hw->bl_sendAddress(bNum); + QThread::msleep(100); - DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK()); + + // TODO + // DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK()); + + DownloadResult const res = DownloadResult::OK; + if (res != DownloadResult::NOP) { if (res == DownloadResult::ERROR) { if (++errorCount >= 10) { @@ -173,7 +183,7 @@ Update::sendNextAddress(int bNum) const { return res; } } else { // res == DownloadResult::OK - qCritical() << "addr-block" << bNum << "...OK"; + qInfo() << nextTimePoint().toUtf8().constData() << "addr-block" << bNum << "...done"; return res; } } else { @@ -197,13 +207,28 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const { memcpy(local, binary.constData() + bAddr, 64); local[64] = local[65] = 0x00; + QString s = nextTimePoint(); + s += " sending block "; + s += QString("%1/%2 ...done ").arg(bNum).arg(m_totalBlocks); + s += QString::number(ceil(((bNum * 100.0) / (double)m_totalBlocks))); + + qInfo() << s.toUtf8().constData(); + + QThread::msleep(200); + return DownloadResult::OK; + // QByteArray b((const char *)(&local[0]), 64); // qCritical() << "SNDB" << bNum << b.size() << b.toHex(); while (noAnswerCount <= 250) { - m_hw->bl_sendDataBlock(64, local); - QThread::msleep(10); - DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK()); + // TODO + // m_hw->bl_sendDataBlock(64, local); + + // TODO + // DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK()); + + DownloadResult const res = DownloadResult::OK; + if (res != DownloadResult::NOP) { if (res == DownloadResult::ERROR) { if (++errorCount >= 10) { @@ -211,7 +236,8 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const { return res; } } else { - qCritical() << "data for block" << bNum << "OK"; + qInfo() << nextTimePoint().toUtf8().constData() << "data for block" + << QString("%1/%2").arg(bNum).arg(m_totalBlocks) << "done"; return res; } } else { @@ -223,7 +249,11 @@ Update::sendNextDataBlock(QByteArray const &binary, int bNum) const { } bool Update::startBootloader() const { - qDebug() << "starting bootloader..."; + QThread::msleep(1000); + qInfo() << nextTimePoint().toUtf8().constData() << "starting bootloader ...done"; + return true; + +#if 0 int nTry = 5; while (--nTry >= 0) { m_hw->bl_startBL(); @@ -239,9 +269,15 @@ bool Update::startBootloader() const { } qCritical() << "starting bootloader...FAILED"; return false; +#endif } bool Update::stopBootloader() const { + QThread::msleep(1000); + qInfo() << nextTimePoint().toUtf8().constData() << "stopping bootloader ...done"; + return true; + +#if 0 qDebug() << "stopping bootloader..."; int nTry = 5; while (--nTry >= 0) { @@ -254,21 +290,24 @@ bool Update::stopBootloader() const { } qCritical() << "stopping bootloader...FAILED"; return false; +#endif } bool Update::resetDeviceController() const { - qDebug() << "resetting device controller..."; - m_hw->bl_rebootDC(); + // TODO + // m_hw->bl_rebootDC(); + // wait maximally 3 seconds, before starting bootloader QThread::sleep(1); - qInfo() << "resetting device controller...OK"; + + qInfo() << nextTimePoint().toUtf8().constData() + << "resetting device controller ...done"; + return true; } QByteArray Update::loadBinaryDCFile(QString const &filename) const { - qCritical() << "(" << __func__ << ":" << __LINE__ << ")" - << "loading dc binary" << filename << "..."; QFile file(filename); // closed in destructor call if (!file.exists()) { @@ -281,8 +320,9 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const { << "cannot open file" << file.fileName(); return QByteArray(); } - qCritical() << "(" << __func__ << ":" << __LINE__ << ")" - << "loading dc binary" << filename << "...OK"; + + qInfo() << nextTimePoint().toUtf8().constData() + << "loading dc binary to memory" << Update::dcVersion(filename) << "...done"; return file.readAll(); } @@ -368,42 +408,46 @@ QByteArray Update::loadBinaryDCFile(QString const &filename) const { // There is no problem to repeat this command until the // bootloader is really not running anymore. */ -bool Update::doUpdate() { +bool Update::doUpdate(QString const &dcFileName) { + qInfo() << "" << Update::dcVersion(dcFileName); + + m_dcFileName = dcFileName; + //QString const &fToWorkOn = usbStickDetected ? QDir::cleanPath(it->trimmed()) //: QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed()); - if (!m_hw) { - qCritical() << "(" << __func__ << ":" << __LINE__ << "):" - << "ERROR!!! m_hw == nullptr"; - return false; - } + //if (!m_hw) { + // qCritical() << "(" << __func__ << ":" << __LINE__ << "):" + // << "ERROR!!! m_hw == nullptr"; + // return false; + //} - QByteArray ba = loadBinaryDCFile(m_hw->dcDownloadFileName()); + QByteArray ba = loadBinaryDCFile(m_dcFileName); if (ba.size() > 0) { - uint16_t const totalBlocks = (((ba.size())%64)==0) ? (ba.size()/64) : (ba.size()/64)+1; - m_hw->dcDownloadSetTotalBlockNumber(totalBlocks); + m_totalBlocks = (((ba.size())%64)==0) ? (ba.size()/64) : (ba.size()/64)+1; + + qInfo() << nextTimePoint().toUtf8().constData() << "blocks to send" << m_totalBlocks; // fill last block of data to be sent with 0xFF - ba = ba.leftJustified(totalBlocks*64, (char)(0xFF)); + ba = ba.leftJustified(m_totalBlocks*64, (char)(0xFF)); resetDeviceController(); if (startBootloader()) { - - qCritical() << "DownloadThread::run(): TOTAL NUMBER OF BYTES TO SEND TO DC" << ba.size(); - qCritical() << "DownloadThread::run(): TOTAL NUMBER OF BLOCKS" << totalBlocks; - int currentBlock = 0; DownloadResult res = DownloadResult::OK; - qCritical() << "64-byte block " << currentBlock; - while (res != DownloadResult::ERROR && currentBlock < totalBlocks) { + qInfo() << nextTimePoint().toUtf8().constData() << "64-byte block" << currentBlock; + + while (res != DownloadResult::ERROR && currentBlock < m_totalBlocks) { if ((res = sendNextAddress(currentBlock)) != DownloadResult::ERROR) { if ((res = sendNextDataBlock(ba, currentBlock)) != DownloadResult::ERROR) { - m_hw->dcDownloadSetCurrentBlockNumber(currentBlock); + // TODO + // m_hw->dcDownloadSetCurrentBlockNumber(currentBlock); currentBlock += 1; - } + } else break; } } +#if 0 qCritical() << "DownloadThread::run(): last 64-byte block %04d" << currentBlock; int const rest = ba.size() % 64; @@ -422,10 +466,15 @@ bool Update::doUpdate() { m_hw->dcDownloadSetCurrentBlockNumber(currentBlock); } qCritical() << "DownloadThread::run(): last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK()); +#endif } stopBootloader(); // there is no harm in stopping the bootloader even + // if starting the bootloader failed + qInfo() << nextTimePoint().toUtf8().constData() << ""; + return true; } + qInfo() << nextTimePoint().toUtf8().constData() << ""; return false; } diff --git a/DownloadDCFirmware/update.h b/DownloadDCFirmware/update.h index e253b59..96ac8a7 100644 --- a/DownloadDCFirmware/update.h +++ b/DownloadDCFirmware/update.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include @@ -30,12 +32,20 @@ class Update : public QObject { QString m_branchName; QString m_pluginName; QString m_workingDir; + QString m_psaDcDir; + QString m_dcFileName; bool m_maintenanceMode; bool m_dryRun; bool m_sys_areDCdataValid; static QPluginLoader pluginLoader; + QDateTime m_start; + QString nextTimePoint() const { + float const secs = m_start.msecsTo(QDateTime::currentDateTime()) / 1000.0; + return QStringLiteral("+%1s").arg(secs, 7, 'f', 2, QChar('0')); + } + public: enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; @@ -44,13 +54,13 @@ public: static bool unloadDCPlugin(); static QStringList split(QString line, QChar sep = ','); - explicit Update(QString customerRepository, QString customerNrStr, QString branchName, QString plugInDir, QString pluginName, QString workingDir, + QString psaDcDir, bool dryRun = false, QObject *parent = nullptr, char const *serialInterface = SERIAL_PORT, @@ -58,7 +68,7 @@ public: virtual ~Update() override; - bool doUpdate(); + bool doUpdate(QString const &dcFileName); static QString dcVersion(QString const &dcBinFile); private: @@ -72,7 +82,7 @@ private: DownloadResult dcDownloadBinary(QByteArray const &b) const; QString m_fileToDownload; - + uint16_t m_totalBlocks = 0; /* private: static QString jsonType(enum FileTypeJson type); diff --git a/UpdatePTUDevCtrl/commandline_parser.cpp b/UpdatePTUDevCtrl/commandline_parser.cpp index 9c99a6e..67613d7 100644 --- a/UpdatePTUDevCtrl/commandline_parser.cpp +++ b/UpdatePTUDevCtrl/commandline_parser.cpp @@ -324,9 +324,9 @@ bool CommandLineParser::extendedVersion() { bool CommandLineParser::alwaysDownloadConfig() { if (m_parser.isSet(m_alwaysDownloadConfigOption)) { m_alwaysDownloadConfig = m_parser.value(m_alwaysDownloadConfigOption); - qCritical() << "m_alwaysDownloadConfigOption IS SET" << m_alwaysDownloadConfig; + // qCritical() << "m_alwaysDownloadConfigOption IS SET" << m_alwaysDownloadConfig; } - qCritical() << "m_alwaysDownloadConfig" << m_alwaysDownloadConfig; + // qCritical() << "m_alwaysDownloadConfig" << m_alwaysDownloadConfig; return m_alwaysDownloadConfig == "false" ? false : true; } diff --git a/UpdatePTUDevCtrl/git/git_client.cpp b/UpdatePTUDevCtrl/git/git_client.cpp index e194ad6..4f433d6 100644 --- a/UpdatePTUDevCtrl/git/git_client.cpp +++ b/UpdatePTUDevCtrl/git/git_client.cpp @@ -2,6 +2,7 @@ #include "update.h" #include "worker.h" #include "utils.h" +#include "process/command.h" #include #include diff --git a/UpdatePTUDevCtrl/git/git_client.h b/UpdatePTUDevCtrl/git/git_client.h index 31e5001..d7000e3 100644 --- a/UpdatePTUDevCtrl/git/git_client.h +++ b/UpdatePTUDevCtrl/git/git_client.h @@ -4,8 +4,8 @@ #include #include #include +#include -#include "process/command.h" #include "ismas/ismas_client.h" class Worker; diff --git a/UpdatePTUDevCtrl/main.cpp b/UpdatePTUDevCtrl/main.cpp index c3e8cba..c8f4770 100644 --- a/UpdatePTUDevCtrl/main.cpp +++ b/UpdatePTUDevCtrl/main.cpp @@ -31,6 +31,7 @@ #include "worker.h" #include "mainwindow.h" #include "utils.h" +// #include "process/command.h" #include #include @@ -199,5 +200,9 @@ int main(int argc, char *argv[]) { mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint); mw.showFullScreen(); + // test + worker.dcUpdate(); + // worker.summary(); + return a.exec(); } diff --git a/UpdatePTUDevCtrl/mainwindow.cpp b/UpdatePTUDevCtrl/mainwindow.cpp index 6a7aa64..1584bc3 100644 --- a/UpdatePTUDevCtrl/mainwindow.cpp +++ b/UpdatePTUDevCtrl/mainwindow.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include MainWindow::MainWindow(Worker *worker, QWidget *parent) @@ -21,16 +23,16 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent) , m_progressRunning(false) , m_updateStep(UpdateDcEvent::UpdateStep::NONE) { + ui->setupUi(this); + this->setStatusBar(new QStatusBar(this)); QFont f; f.setStyleHint(QFont::Monospace); f.setWeight(QFont::Bold); f.setFamily("Misc Fixed"); - f.setPixelSize(12); + f.setPointSize(11); this->statusBar()->setFont(f); - ui->setupUi(this); - ui->updateProgress->setRange(0, 100); ui->updateProgress->reset(); @@ -38,15 +40,15 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent) QString start = QDateTime::currentDateTime().toString(Qt::ISODate); lst << QString("Start: ") + start.leftJustified(m_width-10); lst << QString("").leftJustified(m_width-3, '='); - lst << QString("Update tool version: %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3); - lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3); - lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3); - lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3); - lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3); + lst << QString("Update tool version : %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3); + lst << QString("Machine number : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3); + lst << QString("Customer number : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3); + lst << QString("Zone number : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3); + lst << QString("APISM version : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3); lst << QString("").leftJustified(m_width-3, '='); - ui->updateStatus->setText(lst.join('\n')); - ui->updateStatus->setEnabled(true); + ui->updateLabel->setText(lst.join('\n')); + ui->updateLabel->setEnabled(true); // ui->updateStatus->installEventFilter(this); m_startTimer = new QTimer(this); @@ -78,11 +80,15 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent) } connect(ui->exit, SIGNAL(clicked()),this,SLOT(onQuit())); + connect(m_worker, SIGNAL(showSummary(QString)),this,SLOT(onShowSummary(QString))); connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit())); + connect(m_worker, SIGNAL(showDcDownload(QString)),this,SLOT(onShowDcDownload(QString))); + connect(m_worker, SIGNAL(setDcDownloadProgress(int)),this,SLOT(onSetDcDownloadProgress(int))); connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit())); connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer())); connect(m_worker, SIGNAL(restartExitTimer()),this,SLOT(onRestartExitTimer())); connect(m_worker, SIGNAL(appendText(QString,QString)),this,SLOT(onAppendText(QString,QString))); + connect(m_worker, SIGNAL(insertText(QString)),this,SLOT(onInsertText(QString)), Qt::DirectConnection); connect(m_worker, SIGNAL(showErrorMessage(QString,QString)),this, SLOT(onShowErrorMessage(QString,QString))); connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString))); connect(m_worker, SIGNAL(showErrorMessage(QStringList)),this, SLOT(onShowErrorMessage(QStringList))); @@ -91,6 +97,29 @@ MainWindow::MainWindow(Worker *worker, QWidget *parent) connect(m_worker, SIGNAL(replaceLast(QStringList,QString)),this, SLOT(onReplaceLast(QStringList,QString))); } + +void MainWindow::onShowSummary(QString text) { + // QString s = ui->updateLabel->text(); + QString s("\n"); + + ui->updateLabel->setText(s); + ui->updateLabel->hide(); + ui->stepLabel->hide(); + + s += text; + ui->updateStatus->setText(s); +} + +void MainWindow::onSetDcDownloadProgress(int v) { + ui->updateProgress->setValue(v); +} + +void MainWindow::onShowDcDownload(QString version) { + m_targetDcVersion = version; + ui->exit->setEnabled(false); + ui->stepLabel->setText(QString("Device controller update. Target version: %1").arg(version).leftJustified(m_width-3)); +} + MainWindow::~MainWindow() { delete m_startTimer; delete m_exitTimer; @@ -199,6 +228,12 @@ void MainWindow::scrollDownTextEdit() { ui->updateStatus->ensureCursorVisible(); } + +void MainWindow::onInsertText(QString text) { + scrollDownTextEdit(); + ui->updateStatus->textCursor().insertText(text); +} + void MainWindow::onAppendText(QString text, QString suffix) { // Utils::printInfoMsg(QString("ON APPEND CALLED AT ") // + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); diff --git a/UpdatePTUDevCtrl/mainwindow.h b/UpdatePTUDevCtrl/mainwindow.h index 4cf7b5f..cd11f74 100644 --- a/UpdatePTUDevCtrl/mainwindow.h +++ b/UpdatePTUDevCtrl/mainwindow.h @@ -36,8 +36,11 @@ public: UpdateDcEvent::UpdateStep updateStep() const { return m_updateStep; } void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; } + QString targetDcVersion() {return m_targetDcVersion; } + public slots: void onAppendText(QString, QString suffix = ""); + void onInsertText(QString); void onReplaceLast(QStringList, QString suffix = ""); void onReplaceLast(QString, QString suffix = ""); void onShowErrorMessage(QString, QString); @@ -48,6 +51,9 @@ public slots: void onRestartExitTimer(); void onEnableExit(); void onDisableExit(); + void onShowDcDownload(QString); + void onSetDcDownloadProgress(int); + void onShowSummary(QString); #if EMERGENCY_LEAVE_BL==1 void emergencyLeaveBL(); #endif @@ -74,5 +80,6 @@ private: //int m_progressValue; UpdateDcEvent::UpdateStep m_updateStep; QTimer *m_statusTimer; + QString m_targetDcVersion; }; #endif // MAINWINDOW_H diff --git a/UpdatePTUDevCtrl/mainwindow.ui b/UpdatePTUDevCtrl/mainwindow.ui index 4d081d4..5fb5d94 100644 --- a/UpdatePTUDevCtrl/mainwindow.ui +++ b/UpdatePTUDevCtrl/mainwindow.ui @@ -12,7 +12,10 @@ - Source Code Pro + Misc Fixed + 11 + 75 + true @@ -29,21 +32,28 @@ - - + + + + + 0 + 18 + + + + + Misc Fixed + 11 + 75 + true + + - Exit + - - - - 1 - - - - + true @@ -52,9 +62,16 @@ Misc Fixed 11 + 75 true + + Qt::NoFocus + + + QFrame::WinPanel + Qt::ScrollBarAsNeeded @@ -64,6 +81,44 @@ QAbstractScrollArea::AdjustToContents + + false + + + + + + + + 0 + 100 + + + + + Misc Fixed + 11 + 75 + true + + + + + + + + + + + 1 + + + + + + + Exit + diff --git a/UpdatePTUDevCtrl/process/command.cpp b/UpdatePTUDevCtrl/process/command.cpp index ab8f40d..b0b8747 100644 --- a/UpdatePTUDevCtrl/process/command.cpp +++ b/UpdatePTUDevCtrl/process/command.cpp @@ -1,4 +1,5 @@ #include "command.h" +#include "worker.h" #include #include @@ -7,12 +8,15 @@ #include #include + Command::Command(QString const &command, int start_timeout, int finish_timeout) : m_command(command.trimmed()) , m_commandResult("") , m_waitForStartTimeout(start_timeout) , m_waitForFinishTimeout(finish_timeout) - , m_exitCode(-1) { + , m_exitCode(-1) + , m_p(nullptr) + , m_worker(nullptr) { } QString Command::getCommandResult(bool reset) const { @@ -31,13 +35,52 @@ QString Command::getCommandResult(bool reset) const { void Command::readyReadStandardOutput() { QMutexLocker locker(&m_mtx); QProcess *p = (QProcess *)sender(); - m_commandResult += p->readAllStandardOutput(); + if (p) { + QString s = p->readAllStandardOutput(); + if (m_worker) { + int i = -1; + if ((i = s.indexOf("")) != -1) { + s = s.mid(i+12).trimmed(); + if ((i = s.indexOf("\"")) != -1) { + s = s.mid(i+1); + if ((i = s.indexOf("\"")) != -1) { + s = s.mid(0, i).trimmed(); + } + } + emit m_worker->showDcDownload(s); + } else + if ((i = s.indexOf("")) != -1) { + bool ok; + int v = s.mid(i+10).trimmed().toInt(&ok); + if (ok) { + emit m_worker->setDcDownloadProgress(v); + emit m_worker->insertText(s.mid(0,i) + "\n"); + } + } else + if ((i = s.indexOf("")) != -1) { + m_worker->summary(); + // qApp->exit(0); + } else + if ((i = s.indexOf("")) != -1) { + m_worker->summary(); + } else + if ((i = s.indexOf("")) != -1) { + m_worker->summary(); + //qApp->exit(-1); + } else { + emit m_worker->insertText(s); + } + } + m_commandResult += s; + } } void Command::readyReadStandardError() { QProcess *p = (QProcess *)sender(); - QByteArray buf = p->readAllStandardError(); - qCritical() << buf; + if (p) { + QByteArray buf = p->readAllStandardError(); + qCritical() << buf; + } } void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { @@ -52,6 +95,31 @@ void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError())); } +bool Command::start(QString workingDirectory, QStringList args) { + if (!QDir::setCurrent(workingDirectory)) { + qCritical() << "SET WORKING_DIRECTORY" << workingDirectory + << "FAILED FOR" << m_command; + return false; + } + if (m_p != nullptr) { + delete m_p; + } + m_p = new QProcess(this); + m_p->setWorkingDirectory(workingDirectory); + m_p->setProcessChannelMode(QProcess::MergedChannels); + + connect(m_p, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput())); + connect(m_p, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError())); + + if (!args.isEmpty()) { + m_p->start(m_command, args); + } else { + m_p->start(m_command); + } + + return m_p->waitForStarted(m_waitForStartTimeout); +} + bool Command::execute(QString workingDirectory, QStringList args) { if (!QDir::setCurrent(workingDirectory)) { diff --git a/UpdatePTUDevCtrl/process/command.h b/UpdatePTUDevCtrl/process/command.h index 460f935..71efb22 100644 --- a/UpdatePTUDevCtrl/process/command.h +++ b/UpdatePTUDevCtrl/process/command.h @@ -9,7 +9,7 @@ #include #include - +class Worker; class Command : public QObject { Q_OBJECT @@ -19,6 +19,8 @@ class Command : public QObject { int m_waitForFinishTimeout; int m_exitCode; mutable QMutex m_mtx; + QProcess *m_p; + Worker *m_worker; public: explicit Command(QString const &command, int start_timeout = 100000, @@ -28,8 +30,11 @@ public: QString command() const { return m_command; } bool execute(QString workingDirectory, QStringList args = QStringList()); + bool start(QString workingDirectory, QStringList args = QStringList()); int exitCode() const { return m_exitCode; } + void setWorker(Worker *worker) {m_worker = worker; } + private slots: void readyReadStandardOutput(); void readyReadStandardError(); diff --git a/UpdatePTUDevCtrl/utils.cpp b/UpdatePTUDevCtrl/utils.cpp index 010b838..7b7ec65 100644 --- a/UpdatePTUDevCtrl/utils.cpp +++ b/UpdatePTUDevCtrl/utils.cpp @@ -13,9 +13,65 @@ #include #include #include +#include +#include +#include +#include +#include #include +QVector> Utils::installedPackages() { + QVector> vec; + if (QFile::exists("/usr/bin/ptuPackageVersions")) { + QProcess p; + QStringList params; + params << "-c" << R"(/usr/bin/ptuPackageVersions -i -o json)"; + + p.start("bash", params); + p.waitForFinished(); + + QString r = p.readAllStandardOutput(); + + // ptuPackageVersions returns a json-array + QJsonArray const &ja = QJsonDocument::fromJson(r.remove(QRegExp("\\n")).toUtf8()).array(); + if (!ja.empty()) { + qCritical() << __LINE__; + // transform the array into an object, containing the objects + // of the array (christian needs it this way) + foreach (QJsonValue const &value, ja) { + if (value.isObject()) { + QJsonObject obj = value.toObject(); + QStringList keys = obj.keys(); + if (!keys.isEmpty()) { + QString const &k = keys.first(); + QJsonValue const &v = obj.value(k); + if (v.isObject()) { + obj = v.toObject(); + if (obj.keys().contains("Version")) { + QJsonValue const &w = obj.value("Version"); + if (w.isString()) { + QString s = w.toString(); + QPair p(k, s); + vec.push_back(p); + } + } + } + } + } + } + } else { + qCritical() << __func__ << ":" << __LINE__ + << "ERROR array return by ptuPackageVersions empty"; + } + } else { + qCritical() << __func__ << ":" << __LINE__ + << "ERROR executing ptuPackageVersions"; + } + + return vec; +} + int Utils::read1stLineOfFile(QString fileName) { QFile f(fileName); if (f.exists()) { diff --git a/UpdatePTUDevCtrl/utils.h b/UpdatePTUDevCtrl/utils.h index 8fdd648..a5c93c1 100644 --- a/UpdatePTUDevCtrl/utils.h +++ b/UpdatePTUDevCtrl/utils.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace Utils { int read1stLineOfFile(QString fileName); @@ -33,6 +34,8 @@ namespace Utils { QString getParentName(); bool isATBQTRunning(); + + QVector> installedPackages(); } #endif // UTILS_H_INCLUDED diff --git a/UpdatePTUDevCtrl/worker.cpp b/UpdatePTUDevCtrl/worker.cpp index 603debd..20bbe42 100644 --- a/UpdatePTUDevCtrl/worker.cpp +++ b/UpdatePTUDevCtrl/worker.cpp @@ -26,6 +26,7 @@ #include "progress_event.h" #include "mainwindow.h" #include "utils.h" +#include "process/command.h" QString const Worker::UPDATE_STEP_OK ( " [ ok]"); QString const Worker::UPDATE_STEP_DONE ( " [done]"); @@ -176,9 +177,14 @@ Worker::Worker(int customerNr, , m_filesToUpdate() , m_updateProcessRunning(true) , m_mainWindow(nullptr) /* contains plugin */ + , m_dcDownloadFirmware(new Command("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")) //, m_withoutIsmasDirectPort(true) /* useful for testing */ { , m_withoutIsmasDirectPort(false) /* useful for testing */ { + + m_start = QDateTime::currentDateTime(); + m_dcDownloadFirmware->setWorker(this); + // TODO: turn object into singleton instance = this; m_lastFailedUpdateStep = UPDATE_STEP::NONE; @@ -284,6 +290,8 @@ void Worker::privateUpdate() { return; } + return; + QString func(__PRETTY_FUNCTION__); GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::STARTED)); @@ -1267,6 +1275,7 @@ QString Worker::getPluginVersion(QString const &pluginFileName) const { QStringList Worker::getDCVersion() const { QStringList lst = (QStringList() << "N/A" << "N/A"); +#if 0 Update const *up = update(); if (up) { hwinf const *caPlugin = up->hw(); @@ -1288,6 +1297,7 @@ QStringList Worker::getDCVersion() const { } } } +#endif return lst; } @@ -1500,3 +1510,78 @@ PSAInstalled Worker::getPSAInstalled() { return psaInstalled; } + +bool Worker::dcUpdate() { + return m_dcDownloadFirmware->start("/opt/app/tools/atbupdate"); +} + +void Worker::summary() { + + QString summary, first, second, line, tmp; + QVector> vec = Utils::installedPackages(); + + int max_first = 0, max_second = 0; + for (int i = 0; i < vec.size(); ++i) { + max_first = std::max(max_first, vec[i].first.length()); + max_second = std::max(max_second, vec[i].second.length()); + } + + max_first += 5; + + summary = "UPDATE SUMMARY\n\n"; + + first = QString("%1").arg("start", max_first, QChar(' ')); + tmp = QString("%1").arg(start().toString(Qt::ISODate)); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + first = QString("%1").arg("update tool version", max_first, QChar(' ')); + tmp = QString("%1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + first = QString("%1").arg("machine number", max_first, QChar(' ')); + tmp = QString("%1").arg(machineNr()); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + first = QString("%1").arg("customer number", max_first, QChar(' ')); + tmp = QString("%1").arg(customerNr()); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + first = QString("%1").arg("zone number", max_first, QChar(' ')); + tmp = QString("%1").arg(zoneNr()); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + if (m_mainWindow) { + tmp = m_mainWindow->targetDcVersion(); + if (!tmp.isEmpty()) { + first = QString("%1").arg("target device controller", max_first, QChar(' ')); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + } + } + + first = QString("%1").arg("apism", max_first, QChar(' ')); + tmp = QString("%1").arg(apismVersion()); + second = QString("%1").arg(tmp, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + + for (int i = 0; i < vec.size(); ++i) { + first = QString("%1").arg(vec[i].first, max_first, QChar(' ')); + second = QString("%1").arg(vec[i].second, -max_second, QChar(' ')); + line = first + ": " + second; + summary += line + "\n"; + } + + emit showSummary(summary); +} diff --git a/UpdatePTUDevCtrl/worker.h b/UpdatePTUDevCtrl/worker.h index d30984d..8c54d69 100644 --- a/UpdatePTUDevCtrl/worker.h +++ b/UpdatePTUDevCtrl/worker.h @@ -15,7 +15,6 @@ #include #include -#include "update.h" #include "git/git_client.h" #include "ismas/ismas_client.h" #include "utils.h" @@ -135,6 +134,8 @@ #define ISMAS_UPDATE_REQUESTS (10) #define CHECK_UPDATE_TRIGGER_SET "Check update trigger ..." +class Command; +class Update; class MainWindow; class hwinf; class Worker : public QThread{ @@ -189,6 +190,7 @@ class Worker : public QThread{ QStringList m_ismasTriggerStatusMessage; MainWindow *m_mainWindow; + Command *m_dcDownloadFirmware; bool m_withoutIsmasDirectPort; QString m_apismVersion; @@ -458,8 +460,13 @@ public: Update *update() { return m_update; } Update const *update() const { return m_update; } + bool dcUpdate(); + void summary(); + QDateTime start() { return m_start; } + signals: void appendText(QString, QString suffix = ""); + void insertText(QString); void replaceLast(QString, QString); void replaceLast(QStringList, QString); void showErrorMessage(QString title, QString description); @@ -470,6 +477,9 @@ signals: void restartExitTimer(); void enableExit(); void disableExit(); + void showDcDownload(QString); + void showSummary(QString); + void setDcDownloadProgress(int); private slots: bool updateTriggerSet(); @@ -487,6 +497,8 @@ private: bool computeFilesToDownload(); bool execOpkgCommands(); + QDateTime m_start; + static const QMap smap; // CONSOLE() diff --git a/common/include/System.h b/common/include/System.h index 4c59a04..18c0a45 100644 --- a/common/include/System.h +++ b/common/include/System.h @@ -25,7 +25,9 @@ public: static bool umountSDCard(); static std::optional checkForUSBStick(QString const &dirPathUnderMountPath = "."); + static std::optional checkForSDCard(QString const &dirPathUnderMountPath = "."); static QString getUSBMountPath(QString const &dirPathUnderMountPath = "."); + static QString getSDMountPath(QString const &dirPathUnderMountPath = "."); //static QString getUSBDeviceName(); static bool umountUSBStick(); @@ -54,7 +56,8 @@ public: static QString getPTU4MACAddress(); static QStringList getJsonFilesOnUsbStick(QString const &mountPath); - + static QString getDCFileOnUsbStick(QString const &mountPath); + static QString getDCFileOnSDCard(QString const &mountPath); }; #endif // SYSTEM_H diff --git a/common/src/System.cpp b/common/src/System.cpp index 72358e2..2af9af8 100644 --- a/common/src/System.cpp +++ b/common/src/System.cpp @@ -265,6 +265,20 @@ std::optional System::checkForUSBStick(QString const &dirPathUnderMount return mountPath.isEmpty() ? std::nullopt : std::optional(mountPath); } +std::optional System::checkForSDCard(QString const &dirPathUnderMountPath) { +#if defined (ARCH_DesktopLinux) + // DEBUG / TEST: + if (QFileInfo(getSDMountPath()).isDir()) + return true; + else + return false; +#endif + + QString const &mountPath = getSDMountPath(dirPathUnderMountPath); + // qCritical() << "MOUNT-PATH" << mountPath; + return mountPath.isEmpty() ? std::nullopt : std::optional(mountPath); +} + /** @@ -315,7 +329,7 @@ QString System::getUSBMountPath(QString const &dirPathUnderMountPath) { mountLine = line.split(' '); if (mountLine.size() > 3) { - qCritical() << "System::getUSBMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2); + // qCritical() << "System::getUSBMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2); QDir d(QDir::cleanPath(mountLine.at(2) + QDir::separator() + dirPathUnderMountPath)); if (d.exists()) { return mountLine.at(2); @@ -332,6 +346,64 @@ QString System::getUSBMountPath(QString const &dirPathUnderMountPath) { return ""; } +QString System::getSDMountPath(QString const &dirPathUnderMountPath) { + +#if defined (ARCH_DesktopLinux) + // DEBUG / TEST: + return QDir::homePath().append("/APconfigTest/USB"); +#endif + + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + + QStringList mountLine; + + qDebug() << "System::getSDMountPath()"; + + QRegExp devRegExp = QRegExp("dev/mmc*", Qt::CaseSensitive, QRegExp::WildcardUnix); + QRegExp mountRegExp = QRegExp("media/mmc*", Qt::CaseSensitive, QRegExp::WildcardUnix); + + QString commandString = "mount"; + + process.start(commandString); + if (!process.waitForStarted()) { + errorMsg = "System::getSDMountPath(): ERROR: waitForStarted()"; + return ""; + } + if (!process.waitForFinished(600000)) { + errorMsg = "System::getSDMountPath(): ERROR: " + process.errorString(); + qDebug() << errorMsg; + return ""; + } + else { + QByteArray bytes = process.readAll(); + QStringList lines = QString(bytes).split("\n"); + foreach (QString line, lines) { + qDebug() << "System::getSDMountPath() line: " << line; + + if (line.contains(devRegExp) && line.contains(mountRegExp)) { + + qDebug() << " -> this line is a usb storage device mount" << line; + + mountLine = line.split(' '); + if (mountLine.size() > 3) { + // qCritical() << "System::getSDMountPath(): " << mountLine.at(0) << " is mounted on " << mountLine.at(2); + QDir d(QDir::cleanPath(mountLine.at(2) + QDir::separator() + dirPathUnderMountPath)); + if (d.exists()) { + return mountLine.at(2); + } else { + qCritical() << "directory" << d.absolutePath() << "does not exist"; + } + } + } + } + } + + qDebug() << "System::getSDMountPath() no mounted usb device found!"; + + return ""; +} + QStringList System::getJsonFilesOnUsbStick(QString const &mountPath) { QStringList jsonFiles; @@ -354,6 +426,38 @@ QStringList System::getJsonFilesOnUsbStick(QString const &mountPath) { return jsonFiles; } +QString System::getDCFileOnUsbStick(QString const &mountPath) { + QString dcFile; + + // /media/sda2/etc/dc + QString const &dirPath = QDir::cleanPath(mountPath + QDir::separator() + "etc" + QDir::separator() + "dc"); + QDir d(dirPath); + if (d.exists()) { + QFileInfo fi(dirPath + QDir::separator() + "dc2c.bin"); + if (fi.exists()) { + dcFile = fi.absoluteFilePath(); + } + } + + return dcFile; +} + +QString System::getDCFileOnSDCard(QString const &mountPath) { + QString dcFile; + + // /media/sda2/etc/dc + QString const &dirPath = QDir::cleanPath(mountPath + QDir::separator() + "etc" + QDir::separator() + "dc"); + QDir d(dirPath); + if (d.exists()) { + QFileInfo fi(dirPath + QDir::separator() + "dc2c.bin"); + if (fi.exists()) { + dcFile = fi.absoluteFilePath(); + } + } + + return dcFile; +} + /******************************************************************************** * static function to check if a mounted sd-card is writable. *