Compare commits

..

No commits in common. "f52dec91244362fabd5df5206412327444c6986c" and "57b82094c8230973789d208d7da1547fe274c473" have entirely different histories.

16 changed files with 1750 additions and 2191 deletions

View File

@ -3,11 +3,9 @@ QT += core
QT += widgets serialport QT += widgets serialport
QT += network QT += network
TARGET = ATBUpdateDC TARGET = up_dev_ctrl
INCLUDEPATH += plugins CONFIG += c++11
CONFIG += c++17
# CONFIG -= app_bundle # CONFIG -= app_bundle
# DEFINES+=LinuxDesktop # DEFINES+=LinuxDesktop
@ -20,11 +18,11 @@ QMAKE_CXXFLAGS += -Wno-deprecated-copy
# subtree.depends = # subtree.depends =
# QMAKE_EXTRA_UNIX_TARGETS += subtree # QMAKE_EXTRA_UNIX_TARGETS += subtree
# ! exists(DCPlugin) { ! exists(DCPlugin) {
# $$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash") $$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
# } else { } else {
# $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash") # $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
# } }
# You can make your code fail to compile if it uses deprecated APIs. # You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line. # In order to do so, uncomment the following line.
@ -54,27 +52,20 @@ contains( CONFIG, DesktopLinux ) {
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
update.cpp \ update.cpp \
message_handler.cpp \ message_handler.cpp
worker.cpp \
worker_thread.cpp
HEADERS += \ HEADERS += \
update.h \ update.h \
message_handler.h \ message_handler.h \
worker.h \ DCPlugin/include/interfaces.h
worker_thread.h \
plugins/interfaces.h
OTHER_FILES += \ OTHER_FILES += \
/opt/app/tools/atbupdate/update_log.csv \ /opt/app/tools/atbupdate/update_log.csv
main.cpp.bck \
main.cpp.bck2 \
main.cpp.bck3
# https://blog.developer.atlassian.com/the-power-of-git-subtree/?_ga=2-71978451-1385799339-1568044055-1068396449-1567112770 # https://blog.developer.atlassian.com/the-power-of-git-subtree/?_ga=2-71978451-1385799339-1568044055-1068396449-1567112770
# git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash # git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
# git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash # git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
# include(./DCPlugin/DCPlugin.pri) include(./DCPlugin/DCPlugin.pri)
# Default rules for deployment. # Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin qnx: target.path = /tmp/$${TARGET}/bin

Binary file not shown.

View File

@ -2,7 +2,6 @@
\usepackage{euler} \usepackage{euler}
\usepackage[english]{babel} \usepackage[english]{babel}
\usepackage{lipsum} \usepackage{lipsum}
\usepackage{multirow}
\usepackage[colorlinks=true, urlcolor=blue, linkcolor=red]{hyperref} \usepackage[colorlinks=true, urlcolor=blue, linkcolor=red]{hyperref}
\newcounter{Chapcounter} \newcounter{Chapcounter}
\newcommand\showmycounter{\addtocounter{Chapcounter}{1}\themycounter} \newcommand\showmycounter{\addtocounter{Chapcounter}{1}\themycounter}
@ -20,58 +19,44 @@
\begin{document} \begin{document}
\maketitle \maketitle
% \chapter{Introduction} \chapter{Introduction}
\section{Motivation} \section{Motivation}
The two main components of a PSA are
The two main components of a PSA are \begin{itemize}
\begin{itemize} \item PTU software.
\item PTU software. \item Device controller (DC) firmware.
\item Device controller (DC) firmware. \end{itemize}
\end{itemize} While the DC firmware is basically the same for each PSA (even for different
customers), the PTU software is highly dependent on customer requirements.\par
While the DC firmware is basically the same for each PSA (even for different Hence, each customer is assigned an own git-repository, which will be loaded
customers), the PTU software is highly dependent on customer requirements.\par ("cloned") on the PSA when configuring the machine for the first time.\par
Hence, each customer is assigned an own git-repository, which will be loaded Two special tools, the {\bf UpdateController} (a \href{https://doc.qt.io/qt-5/}{Qt}
("cloned") on the PSA when configuring the machine for the first time.\par binary [{\bf \nameref{UpdateTool}}]) and the {\bf UpdateScript}
Two special tools, the {\bf UpdateController} (a \href{https://doc.qt.io/qt-5/}{Qt} (a \href{https://www.gnu.org/software/bash/manual/bash.html}{bash}
binary [{\bf \nameref{UpdateTool}}]) and the {\bf UpdateScript} script [{\bf \nameref{UpdateScript}}]), work together to finish a PSA installation.\par
(a \href{https://www.gnu.org/software/bash/manual/bash.html}{bash}
script [{\bf \nameref{UpdateScript}}]), work together to finish a PSA installation.\par
\section{PSA: Initial configuration} \section{PSA: Initial configuration}
For the initial configuration, a PSA loads a customer-specific git-repository,
For the initial configuration, a PSA loads a customer-specific git-repository, which structure is detailed below [{\bf \nameref{repostructure}}].\par
which structure is detailed below [{\bf \nameref{repostructure}}].\par The "git clone" for the repository is done by the UpdateScript [{\bf \nameref{UpdateScript}}].
The "git clone" for the repository is done by the UpdateScript [{\bf \nameref{UpdateScript}}]. It updates the file
It updates the file \begin{center}
\begin{center} \fbox{
\fbox{ /opt/app/tools/atbupdate/update\_log.csv
/opt/app/tools/atbupdate/update\_log.csv }
} \end{center}
\end{center} which will be interpreted by the UpdateController [{\bf \nameref{UpdateTool}}].
which will be interpreted by the UpdateController [{\bf \nameref{UpdateTool}}]. The structure of {\bf update\_log.csv} is detailed below [{\bf \nameref{updatelogcsv}}].\par
The structure of [{\bf \nameref{updatelogcsv}}] is detailed below.\par Each line of {\bf update\_log.csv} represents a command for the UpdateController,
Each line of update\_log.csv represents a command for the UpdateController, which will either download certain files to the DC or execute some
which will either download certain files to the DC or execute some \href{https://openwrt.org/docs/guide-user/additional-software/opkg}{opkg}
\href{https://openwrt.org/docs/guide-user/additional-software/opkg}{opkg} commands [{\bf \nameref{opkg}}].
commands [{\bf \nameref{opkg}}].
\section{PSA: Update} \section{PSA: Update}
The update of a PSA is basically managed by \href{https://git-scm.com/}{git}, a
free and open source distributed version control system. Like many other Version
Control Systems, git has a way to fire off custom scripts when certain important
actions occur, so-called \href{https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks}{hooks}.
The hooks used for a PSA update are called {\bf post-checkout} and {\bf post-merge}.\par
The post-checkout hook is called when checking out some branch of the customer-repository
(for instance when cloning the customer repository for the first time). In contrast,
the post-merge hook is called when a \href{https://www.git-scm.com/docs/git-pull}{git pull}
operation has been issued (more precisely, a \href {https://www.git-scm.com/docs/git-fetch}{git-fetch}
followed by a \href{https://www.git-scm.com/docs/git-merge}{git-merge}).\par
Both hooks update the file [{\bf \nameref{updatelogcsv}}], which is interpreted
by the UpdateController in a second step.
% \chapter{Update-Tool "up\_dev\_ctrl"} \newpage
\chapter{Update-Tool "up\_dev\_ctrl"}
\section{up\_dev\_ctrl} \section{up\_dev\_ctrl}
\label{UpdateTool} \label{UpdateTool}
@ -94,7 +79,7 @@ by the UpdateController in a second step.
\newpage \newpage
% \chapter{Update-Script "update\_psa"} \chapter{Update-Script "update\_psa"}
\section{update\_psa} \section{update\_psa}
\label{UpdateScript} \label{UpdateScript}
@ -113,60 +98,13 @@ by the UpdateController in a second step.
\end{itemize} \end{itemize}
\newpage \newpage
%\chapter{Annex} \chapter{Annex}
\section{Structure of a customer git-repository} \section{Structure of a customer git-repository}
\label{repostructure} \label{repostructure}
\subsection{The post-checkout hook}
TODO: checkout\_history
\subsection{The post-merge hook}
They are both located under the {\bf .githooks}-directory
\section{update\_log.csv} \section{Structure of "update\_log.csv"}
\label{updatelogcsv} \label{updatelogcsv}
\begin{table}[h!]
\begin{center}
\caption{Initial state of update\_log.csv}
\label{tab:initial_state}
\begin{tabular}{llll}
\textbf{Request} & \textbf{Name} & \textbf{Date} & \textbf{Status}\\
\hline
\multicolumn{4}{c}{}\\
DOWNLOAD & /etc/dc/dc2c4.21.bin & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print01.json & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print02.json & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print03.json & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print04.json & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print29.json & 2023-05-01T12:00:00 & N/A\\
DOWNLOAD & /etc/psa\_config/DC2C\_print32.json & 2023-05-01T12:00:00 & N/A\\
EXECUTE & opkg update & 2023-05-01T12:00:00 & N/A\\
\end{tabular}
\end{center}
\end{table}
\begin{table}[h!]
\begin{center}
\caption{State of update\_log.csv after updating}
\label{tab:initial_state}
\begin{tabular}{llll}
\textbf{Request} & \textbf{Name} & \textbf{Date} & \textbf{Status}\\
\hline
\multicolumn{4}{c}{}\\
DONE & /etc/dc/dc2c4.21.bin & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print01.json & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print02.json & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print03.json & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print04.json & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print29.json & 2023-05-01T12:00:00 & N/A\\
DONE & /etc/psa\_config/DC2C\_print32.json & 2023-05-01T12:00:00 & N/A\\
DONE & opkg update & 2023-05-01T12:00:00 & N/A\\
\end{tabular}
\end{center}
\end{table}
\newpage
\section{The package manager "opkg"} \section{The package manager "opkg"}
\label{opkg} \label{opkg}
\section{Known problems}
\end{document} \end{document}

View File

@ -5,7 +5,8 @@
#include <QFileInfo> #include <QFileInfo>
#include "message_handler.h" #include "message_handler.h"
#include "plugins/interfaces.h" #include "interfaces.h"
#include "DCPlugin/include/hwapi.h"
#include <unistd.h> #include <unistd.h>
#include <thread> #include <thread>
@ -16,10 +17,6 @@
#include <QDir> #include <QDir>
#include "update.h" #include "update.h"
#include "worker_thread.h"
#include "worker.h"
#include <thread>
#ifdef PTU5 #ifdef PTU5
#define SERIAL_PORT "ttymxc2" #define SERIAL_PORT "ttymxc2"
@ -27,13 +24,20 @@
#define SERIAL_PORT "ttyUSB0" #define SERIAL_PORT "ttyUSB0"
#endif #endif
static void doWork(QString update_ctrl_file, QString workingDir) { class Work : public QRunnable {
std::this_thread::sleep_for(std::chrono::milliseconds(2000)); QString m_update_ctrl_file;
//Update update(update_ctrl_file, workingDir); QString m_workingDir;
//update.doUpdate(); public:
std::this_thread::sleep_for(std::chrono::milliseconds(2000)); explicit Work(QString update_ctrl_file, QString workingDir)
QCoreApplication::quit(); : m_update_ctrl_file(update_ctrl_file)
} , m_workingDir(workingDir) {
}
void run() {
Update m_update(m_update_ctrl_file, m_workingDir);
// if (m_update.doUpdate()) {
// }
}
};
// 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[]) {
@ -50,29 +54,15 @@ int main(int argc, char *argv[]) {
qputenv("XDG_RUNTIME_DIR", "/run/user/0"); qputenv("XDG_RUNTIME_DIR", "/run/user/0");
} }
QString rtPath = QCoreApplication::applicationDirPath();
QString plugInDir(rtPath +(rtPath.endsWith("/") ? "" : "/") + "plugins");
if (!QDir(plugInDir).exists()) {
qCritical() << plugInDir
<< "does not exists, but has to contain dc-library";
exit(-1);
}
qInfo() << "pwd" << "=" << rtPath;
qInfo() << "plugInDir" << "=" << plugInDir;
hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), "libCAmaster.so");
QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv"; QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
QString const workingDir = (argc == 2) ? argv[1] : "."; QString const workingDir = (argc == 2) ? argv[1] : ".";
Update update(hw, update_ctrl_file, workingDir);
Work work(update_ctrl_file, workingDir);
work.setAutoDelete(false);
QThreadPool *threadPool = QThreadPool::globalInstance();
threadPool->start(&work);
if (!threadPool->waitForDone()) {
return -1;
}
return 0; return 0;
std::thread t(doWork, update_ctrl_file, workingDir);
int ret = a.exec();
t.join();
return ret;
} }

View File

@ -1,81 +0,0 @@
#include <QCoreApplication>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QFileInfo>
#include "message_handler.h"
#include "plugins/interfaces.h"
#include "DCPlugin/include/hwapi.h"
#include <unistd.h>
#include <thread>
#include <memory>
static void updateBinary(std::unique_ptr<hwinf> hw, // update d2dc*.bin
char const *fileToSendToDC,
char const *baudrate,
char const *serialInterface) {
for (int i=0; i < 1;++i) {
hw->dc_updateDC(fileToSendToDC, baudrate, serialInterface);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
QCoreApplication::quit();
}
static void updatePrinterConf(std::unique_ptr<hwinf> hw, // update printer-file
char const *fileToSendToDC,
char const *baudrate,
char const *serialInterface) {
for (int i=0; i < 1;++i) {
hw->dc_updateDC(fileToSendToDC, baudrate, serialInterface);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
QCoreApplication::quit();
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(QtMsgType::QtDebugMsg);
//setDebugLevel(QtMsgType::QtDebugMsg);
}
if (argc > 2) {
qCritical() << "Usage: " << argv[0] << "<file to send to dc>";
return -1;
}
std::unique_ptr<hwinf> hw(new hwapi());
QFileInfo fileInfo(argv[1]);
QString fname(fileInfo.fileName());
int ret = 0;
if (fname.startsWith("dc") && fname.endsWith(".bin")) {
#ifdef PTU5
std::thread t(updateBinary, std::move(hw),
fname.toStdString().c_str(), "115200", "ttymxc2");
#else
std::thread t(updateBinary, std::move(hw),
fname.toStdString().c_str(), "115200", "ttyUSB0");
#endif
ret = a.exec();
t.join();
} else
if (fname.startsWith("DC") && fname.endsWith(".json")) {
#ifdef PTU5
std::thread t(updatePrinterConf, std::move(hw),
fname.toStdString().c_str(), "115200", "ttymxc2");
#else
std::thread t(updatePrinterConf, std::move(hw),
fname.toStdString().c_str(), "115200", "ttyUSB0");
#endif
ret = a.exec();
t.join();
}
return ret;
}

View File

@ -1,54 +0,0 @@
#include <QCoreApplication>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QFileInfo>
#include "message_handler.h"
#include "interfaces.h"
#include "DCPlugin/include/hwapi.h"
#include <unistd.h>
#include <thread>
#include <memory>
#include <QSharedMemory>
#include <QRunnable>
#include <QThreadPool>
#include <QDir>
#include "update.h"
#include "worker_thread.h"
#include "worker.h"
#ifdef PTU5
#define SERIAL_PORT "ttymxc2"
#else
#define SERIAL_PORT "ttyUSB0"
#endif
// argv[1]: file to send to dc
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(QtMsgType::QtDebugMsg);
//setDebugLevel(QtMsgType::QtDebugMsg);
}
QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
if (value.size() == 0) {
qputenv("XDG_RUNTIME_DIR", "/run/user/0");
}
QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
QString const workingDir = (argc == 2) ? argv[1] : ".";
Worker worker(update_ctrl_file, workingDir);
qCritical() << "starting main event loop";
int ret = a.exec();
qCritical() << "stopping main event loop" << ret;
return ret;
}

View File

@ -1,62 +0,0 @@
#include <QCoreApplication>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QFileInfo>
#include "message_handler.h"
#include "plugins/interfaces.h"
#include <unistd.h>
#include <thread>
#include <memory>
#include <QSharedMemory>
#include <QRunnable>
#include <QThreadPool>
#include <QDir>
#include "update.h"
#include "worker_thread.h"
#include "worker.h"
#include <thread>
#ifdef PTU5
#define SERIAL_PORT "ttymxc2"
#else
#define SERIAL_PORT "ttyUSB0"
#endif
static void doWork(QString update_ctrl_file, QString workingDir) {
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
Update update(update_ctrl_file, workingDir);
update.doUpdate();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
QCoreApplication::quit();
}
// argv[1]: file to send to dc
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
atbInstallMessageHandler(atbDebugOutput);
setDebugLevel(QtMsgType::QtDebugMsg);
//setDebugLevel(QtMsgType::QtDebugMsg);
}
QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
if (value.size() == 0) {
qputenv("XDG_RUNTIME_DIR", "/run/user/0");
}
// QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
// QString const workingDir = (argc == 2) ? argv[1] : ".";
// std::thread t(doWork, update_ctrl_file, workingDir);
int ret = a.exec();
// t.join();
return ret;
}

View File

@ -3,7 +3,8 @@
#include <QDateTime> #include <QDateTime>
#include <cstring> #include <cstring>
#define OUTPUT_LEN (512) #define OUTPUT_LEN (20)
static bool installedMsgHandler = false; static bool installedMsgHandler = false;
static QtMsgType debugLevel = QtInfoMsg; static QtMsgType debugLevel = QtInfoMsg;
@ -40,10 +41,49 @@ QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
/// return app.exec(); /// return app.exec();
/// } /// }
/// ///
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
void atbDebugOutput(QtMsgType type, const char *msg) {
switch (type) {
case QtDebugMsg: {
if (debugLevel <= QtDebugMsg) {
fprintf(stderr, "%*.*s Debug: %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
} break;
case QtInfoMsg: {
if (debugLevel <= QtInfoMsg) {
fprintf(stderr, "%*.*s Info: %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
} break;
case QtWarningMsg: {
if (debugLevel <= QtWarningMsg) {
fprintf(stderr, "%*.*s Warning: %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
} break;
case QtCriticalMsg: {
if (debugLevel <= QtCriticalMsg) {
fprintf(stderr, "%*.*s Critical: %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
} break;
case QtFatalMsg: {
if (debugLevel <= QtFatalMsg) {
fprintf(stderr, "%*.*s Fatal: %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
// abort();
} break;
default: {
fprintf(stderr, "%*.*s No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN,
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), msg);
}
}
}
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
static constexpr const char *format = "hh:mm:ss"; static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
// static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
QByteArray localMsg = msg.toLocal8Bit(); QByteArray localMsg = msg.toLocal8Bit();
const char *file = context.file ? context.file : ""; const char *file = context.file ? context.file : "";
const char *function = context.function ? context.function : ""; const char *function = context.function ? context.function : "";
@ -57,65 +97,54 @@ void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
} }
qint64 const currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); qint64 const currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
int const fractional_part = currentMSecsSinceEpoch % 1000; int const fractional_part = currentMSecsSinceEpoch % 1000;
char buf[OUTPUT_LEN]{};
memset(buf, 0x00, sizeof(buf));
QDateTime const datetime = QDateTime::fromMSecsSinceEpoch(currentMSecsSinceEpoch); QDateTime const datetime = QDateTime::fromMSecsSinceEpoch(currentMSecsSinceEpoch);
switch (type) { switch (type) {
case QtDebugMsg: { case QtDebugMsg: {
if (debugLevel == QtDebugMsg) { if (debugLevel <= QtDebugMsg) {
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d DEBG %s\n", // fprintf(stderr, "%*.*s CTX %s (%s:%u) ->\n", OUTPUT_LEN, OUTPUT_LEN,
function, file, context.line, // "", function, file, context.line);
datetime.time().toString(format).toStdString().c_str(), //fprintf(stderr, "%*.*s.%03d DEBG %s\n", OUTPUT_LEN, OUTPUT_LEN,
fractional_part, // datetime.toString(format).toStdString().c_str(), fractional_part,
localMsg.constData()); // localMsg.constData());
fprintf(stderr, "%*.*s.%03d DEBUG %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
datetime.toString(format).toStdString().c_str(), fractional_part,
localMsg.constData(), file, context.line);
} }
} break; } break;
case QtInfoMsg: { case QtInfoMsg: {
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg) { if (debugLevel <= QtInfoMsg) {
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d INFO %s\n", fprintf(stderr, "%*.*s.%03d INFO %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
function, file, context.line, datetime.toString(format).toStdString().c_str(), fractional_part,
datetime.time().toString(format).toStdString().c_str(), localMsg.constData(), file, context.line);
fractional_part,
localMsg.constData());
} }
} break; } break;
case QtWarningMsg: { case QtWarningMsg: {
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg || debugLevel == QtWarningMsg) { if (debugLevel <= QtWarningMsg) {
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d WARN %s\n", fprintf(stderr, "%*.*s.%03d WARN %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
function, file, context.line, datetime.toString(format).toStdString().c_str(), fractional_part,
datetime.time().toString(format).toStdString().c_str(), localMsg.constData(), file, context.line);
fractional_part,
localMsg.constData());
} }
} break; } break;
case QtCriticalMsg: { case QtCriticalMsg: {
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg if (debugLevel <= QtCriticalMsg) {
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg) { fprintf(stderr, "%*.*s.%03d CRIT %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d CRIT %s\n", datetime.toString(format).toStdString().c_str(), fractional_part,
function, file, context.line, localMsg.constData(), file, context.line);
datetime.time().toString(format).toStdString().c_str(),
fractional_part,
localMsg.constData());
} }
} break; } break;
case QtFatalMsg: { case QtFatalMsg: {
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg if (debugLevel <= QtFatalMsg) {
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg fprintf(stderr, "%*.*s.%03d FATAL %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
|| debugLevel == QtFatalMsg) { datetime.toString(format).toStdString().c_str(), fractional_part,
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d FATAL %s\n", localMsg.constData(), file, context.line);
function, file, context.line,
datetime.time().toString(format).toStdString().c_str(),
fractional_part,
localMsg.constData());
} }
} break; } break;
default: { default: {
fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN, fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN,
datetime.time().toString(format).toStdString().c_str(), fractional_part, datetime.toString(format).toStdString().c_str(), fractional_part,
msg.toStdString().c_str()); msg.toStdString().c_str());
} }
} }
fprintf(stderr, "%s\n", buf);
} }
#endif #endif

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -8,82 +8,43 @@
#include <QTextStream> #include <QTextStream>
#include <QRegularExpression> #include <QRegularExpression>
#include "plugins/interfaces.h" #include "interfaces.h"
#include "DCPlugin/include/hwapi.h"
#include <QSharedMemory> #include <QSharedMemory>
#include <QScopedPointer> #include <QScopedPointer>
#include <QProcess> #include <QProcess>
#include <QDir> #include <QDir>
#include <QThread>
#include <QDateTime>
#include <QPluginLoader>
#define COLUMN_REQUEST (0) #define COLUMN_REQUEST (0)
#define COLUMN_NAME (1) #define COLUMN_NAME (1)
#define COLUMN_DATE_TIME (2) #define COLUMN_DATE_TIME (2)
#define COLUMN_RESULT (3) #define COLUMN_RESULT (3)
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) { void ScopedPointerCustomDeleter::cleanup(Update *update) {
hwinf *hw = nullptr; if (update->m_delete) {
if (plugInDir.exists()) { delete update;
QString pluginLibName(fname);
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
QFileInfo info(pluginLibName);
if (info.exists()) {
pluginLibName = plugInDir.absoluteFilePath(pluginLibName);
static QPluginLoader pluginLoader(pluginLibName);
if (!pluginLoader.load()) {
qCritical() << "in directory" << plugInDir.absolutePath();
qCritical() << "cannot load plugin" << pluginLoader.fileName();
qCritical() << pluginLoader.errorString();
exit(-1);
}
if (!pluginLoader.isLoaded()) {
qCritical() << pluginLoader.errorString();
exit(-2);
}
QObject *plugin = pluginLoader.instance();
if (!plugin) {
qCritical() << "cannot start instance";
exit(-3);
}
if (! (hw = qobject_cast<hwinf *>(plugin))) {
qCritical() << "cannot cast plugin" << plugin << "to hwinf";
exit(-4);
}
} else {
qCritical() << pluginLibName << "does not exist";
exit(-5);
}
} else {
qCritical() << "plugins directory" << plugInDir.absolutePath()
<< "does not exist";
exit(-6);
} }
return hw;
} }
Update::Update(hwinf *hw, Update::Update(QString update_ctrl_file,
QString update_ctrl_file,
QString workingDir, QString workingDir,
QObject *parent, QObject *parent,
hwinf *hw,
char const *serialInterface, char const *serialInterface,
char const *baudrate) char const *baudrate)
: QObject(parent) : QObject(parent)
, m_hw(hw) , m_hw(hw != nullptr ? hw : new hwapi())
, m_serialInterface(serialInterface) , m_serialInterface(serialInterface)
, m_baudrate(baudrate) , m_baudrate(baudrate)
, m_update_ctrl_file(update_ctrl_file) , m_update_ctrl_file(update_ctrl_file)
, m_update_ctrl_file_copy(update_ctrl_file + ".copy") , m_update_ctrl_file_copy(update_ctrl_file + ".copy")
, m_workingDir(workingDir) , m_workingDir(workingDir)
, m_init(true) { , m_init(true)
, m_delete(hw == nullptr) {
// qCritical() << "workingDir" << m_workingDir; // qCritical() << "workingDir" << m_workingDir;
// m_hw->dc_autoRequest(false);
return;
execUpdateScript(); execUpdateScript();
if (!m_update_ctrl_file.exists()) { if (!m_update_ctrl_file.exists()) {
@ -106,8 +67,6 @@ Update::Update(hwinf *hw,
m_init = false; m_init = false;
} }
qDebug() << "Opened" << m_update_ctrl_file_copy.fileName(); qDebug() << "Opened" << m_update_ctrl_file_copy.fileName();
//QApplication::processEvents();
} }
Update::~Update() { Update::~Update() {
@ -119,14 +78,6 @@ bool Update::execUpdateScript() {
update_psa += m_workingDir; update_psa += m_workingDir;
qCritical() << "update_psa: " << update_psa; qCritical() << "update_psa: " << update_psa;
//QApplication::processEvents();
//for (int i=0;i<10;++i) {
// QThread::sleep(1);
//QApplication::processEvents();
//}
// debug
return true;
//QStringList const params(QStringList() << "-c" << update_psa); //QStringList const params(QStringList() << "-c" << update_psa);
@ -151,248 +102,19 @@ bool Update::execUpdateScript() {
return false; return false;
} }
Update::DownloadResult Update::sendStatus(int ret) const {
switch (ret) { // return values of dc are:
case 0: // 0: no answer by now
return DownloadResult::NOP; // 1: error
case 10: // 10: success
return DownloadResult::OK;
default:;
}
return DownloadResult::ERROR;
}
Update::DownloadResult Update::sendNextAddress(int bNum) const {
// sends address only if blockNumber is one of 0, 1024, 2048, 3072, 4096
int noAnswerCount = 0;
int errorCount = 0;
if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
qDebug() << "addr-block" << bNum << "...";
while (noAnswerCount <= 250) {
m_hw->bl_sendAddress(bNum);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK());
if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) {
if (++errorCount >= 10) {
qCritical() << "addr-block" << bNum << "...FAILED";
return res;
}
} else { // res == DownloadResult::OK
qInfo() << "addr-block" << bNum << "...OK";
return res;
}
} else {
noAnswerCount += 1; // no answer by now
}
}
// wait max. about 3 seconds
return DownloadResult::TIMEOUT;
}
// blockNumber is not one of 0, 1024, 2048, 3072, 4096 -> do nothing
return DownloadResult::NOP;
}
Update::DownloadResult Update::sendNextDataBlock(QByteArray const &binary,
int bNum) const {
uint8_t local[66];
int const bAddr = bNum * 64;
int noAnswerCount = 0;
int errorCount = 0;
memcpy(local, binary.constData() + bAddr, 64);
local[64] = local[65] = 0x00;
//for (int i=0; i<4; ++i) {
// printf("%04d ", bNum);
// for (int j=0; j < 16; ++j) {
// printf("%02x ", local[i*16 + j]);
// } printf("\n");
//}
while (noAnswerCount <= 250) {
m_hw->bl_sendDataBlock(64, local);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK());
if (res != DownloadResult::NOP) {
if (res == DownloadResult::ERROR) {
if (++errorCount >= 10) {
qCritical() << "data for block" << bNum << "...FAILED";
return res;
}
} else {
qInfo() << "data for block" << bNum << "OK";
return res;
}
} else {
noAnswerCount += 1; // no answer by now
}
}
// wait max. about 3 seconds
return DownloadResult::TIMEOUT;
}
Update::DownloadResult Update::dc_downloadBinary(QByteArray const &b) const {
int const nBlocks = (((b.size())%64)==0) ? (b.size()/64) : (b.size()/64)+1;
qInfo() << "total number of bytes to send to dc" << b.size();
qInfo() << "total number of blocks to send to dc" << nBlocks;
int bNum = 0;
DownloadResult res = DownloadResult::OK;
while (res != DownloadResult::ERROR && bNum < nBlocks) {
if ((res = sendNextAddress(bNum)) != DownloadResult::ERROR) {
if ((res = sendNextDataBlock(b, bNum)) != DownloadResult::ERROR) {
bNum += 1;
}
}
}
qInfo() << "nBlocks" << nBlocks;
//if (res != DownloadResult::ERROR) {
// always send last block, even when there are no data !!!
int const rest = b.size() % 64;
int const offset = b.size() - rest;
char const *startAddress = b.constData() + offset;
uint8_t local[66];
memset(local, 0x00, sizeof(local));
if (rest > 0) {
memcpy(local, startAddress, rest);
}
//for (int i=0; i<4; ++i) {
// printf("*** %04d ", bNum);
// for (int j=0; j < 16; ++j) {
// printf("%02x ", local[i*16 + j]);
// } printf("\n");
//}
// bl_sendLastBlock(local);
m_hw->bl_sendLastBlock();
qInfo() << "last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK());
return res;
}
bool Update::startBootloader() const {
qDebug() << "starting bootloader...";
int nTry = 5;
while (--nTry >= 0) {
m_hw->bl_startBL();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
m_hw->bl_checkBL();
if (m_hw->bl_isUp()) {
qInfo() << "starting bootloader...OK";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return true;
}
}
qCritical() << "starting bootloader...FAILED";
return false;
}
bool Update::stopBootloader() const {
qDebug() << "stopping bootloader...";
int nTry = 5;
while (--nTry >= 0) {
m_hw->bl_stopBL();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (!m_hw->bl_isUp()) {
qInfo() << "stopping bootloader...OK";
return true;
}
}
qCritical() << "stopping bootloader...FAILED";
return false;
}
// br is a index into a table, used for historical reasons.
bool Update::openSerial(int br, QString baudrate, QString comPort) const {
qDebug() << "opening serial" << br << baudrate << comPort << "...";
if (m_hw->dc_openSerial(br, baudrate, comPort, 1)) { // 1 for connect
qInfo() << "opening serial" << br << baudrate << comPort << "...OK";
return true;
}
qCritical() << "opening serial" << br << baudrate << comPort << "...FAILED";
return false;
}
void Update::closeSerial() const {
m_hw->dc_closeSerial();
}
bool Update::resetDeviceController() const {
qDebug() << "resetting device controller...";
//if (stopBootloader()) { // first stop a (maybe) running bootloader
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
m_hw->bl_rebootDC();
// wait maximally 3 seconds, before starting bootloader
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
qInfo() << "resetting device controller...OK";
return true;
//}
//qCritical() << "stopping bootloader...FAILED";
//return false;
}
QByteArray Update::loadBinaryDCFile(QString filename) const {
qDebug() << "loading dc binary" << filename << "...";
QFile file(filename); // closed in destructor call
if (!file.exists()) {
qCritical() << file.fileName() << "does not exist";
return QByteArray();
}
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "cannot open file" << file.fileName();
return QByteArray();
}
qInfo() << "loading dc binary" << filename << "...OK";
return file.readAll();
}
bool Update::downloadBinaryToDC(QString const &bFile) const {
qDebug() << "sending" << bFile << "to dc...";
QByteArray const dcBinary = loadBinaryDCFile(bFile);
if (dcBinary.size() > 0) {
if (dc_downloadBinary(dcBinary) != DownloadResult::OK) {
qCritical() << "sending" << bFile << "to dc...FAILED";
return false;
} else {
qInfo() << "sending" << bFile << "to dc...OK";
}
} else {
qCritical() << "sending" << bFile << "to dc...FAILED";
qCritical() << "loading binary" << bFile << "FAILED";
return false;
}
return true;
}
bool Update::updateBinary(char const *fileToSendToDC) { bool Update::updateBinary(char const *fileToSendToDC) {
QFile fn(fileToSendToDC); // return true; // debug
bool r; return m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface);
if ((r = fn.exists()) == true) {
QString const linkTarget = fn.symLinkTarget();
qCritical() << "updating binary (dc): link target" << linkTarget;
// debug
//r = m_hw->dc_updateDC(linkTarget, m_baudrate, m_serialInterface);
qCritical() << "updating binary (dc): "
<< linkTarget << ((r == true) ? "OK" : "ERROR");
} else {
qCritical() << "symlink" << fileToSendToDC << "does not exist";
}
return r;
} }
bool Update::updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC) { bool Update::updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC) {
qCritical() << "updating printer template: " << fileToSendToDC; // return true; // debug
return true; // debug
QVector<int> printTemplates{ nrOfTemplate }; QVector<int> printTemplates{ nrOfTemplate };
QVector<QString> filesToSend{ fileToSendToDC }; QVector<QString> filesToSend{ fileToSendToDC };
//return m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER, return m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER,
// printTemplates, filesToSend, printTemplates, filesToSend,
// QString(m_baudrate), QString(m_baudrate),
// QString(m_serialInterface)); QString(m_serialInterface));
} }
QStringList Update::getOpenLines() { QStringList Update::getOpenLines() {
@ -445,6 +167,7 @@ bool Update::doUpdate() {
# #
*/ */
// qCritical() << "Device Controller SW-version" << m_hw->dc_getSWversion();
if (!m_init) { if (!m_init) {
return false; return false;
@ -470,19 +193,19 @@ bool Update::doUpdate() {
QString const &result = lst[COLUMN_RESULT]; QString const &result = lst[COLUMN_RESULT];
if ((!request.contains("DOWNLOAD") && !request.contains("EXECUTE")) || if ((!request.contains("DOWNLOAD") && !request.contains("EXECUTE")) ||
!result.contains("N/A")) { !result.contains("N/A")) {
qCritical() << "parsing error for" << m_update_ctrl_file.fileName(); qCritical() << "Parsing error for" << m_update_ctrl_file.fileName();
return false; return false;
} }
if (name.contains("dc2c") && name.endsWith(".bin")) { if (name.contains("dc2c") && name.endsWith(".bin")) {
if ((res = updateBinary(name.toStdString().c_str())) == true) { if ((res = updateBinary(name.toStdString().c_str())) == true) {
qInfo() << "downloaded binary" << name; qInfo() << "Downloaded" << name;
} }
} else } else
if (name.contains("DC2C_print") && name.endsWith(".json")) { if (name.contains("DC2C_print") && name.endsWith(".json")) {
int i = name.indexOf("DC2C_print"); int i = name.indexOf("DC2C_print");
int templateIdx = name.mid(i).midRef(10, 2).toInt(); int templateIdx = name.mid(i).midRef(10, 2).toInt();
if ((res = updatePrinterConf(templateIdx, name.toStdString().c_str())) == true) { if ((res = updatePrinterConf(templateIdx, name.toStdString().c_str())) == true) {
qInfo() << "downloaded printer template" << name; qInfo() << "Downloaded" << name;
} }
} else } else
if (name.contains("opkg")) { if (name.contains("opkg")) {

View File

@ -4,10 +4,9 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QFile> #include <QFile>
#include <QDir>
#include <QByteArray>
#include "plugins/interfaces.h" #include "interfaces.h"
#include "DCPlugin/include/hwapi.h"
#ifdef PTU5 #ifdef PTU5
#define SERIAL_PORT "ttymxc2" #define SERIAL_PORT "ttymxc2"
@ -16,6 +15,9 @@
#endif #endif
class Update; class Update;
struct ScopedPointerCustomDeleter {
static void cleanup(Update *pointer);
};
// TODO: check hardware compatibility // TODO: check hardware compatibility
// TODO: opkg commandos // TODO: opkg commandos
@ -23,7 +25,7 @@ class Update;
class Update : public QObject { class Update : public QObject {
Q_OBJECT Q_OBJECT
hwinf *m_hw; QScopedPointer<hwinf> m_hw;
char const *m_serialInterface; char const *m_serialInterface;
char const *m_baudrate; char const *m_baudrate;
QFile m_update_ctrl_file; QFile m_update_ctrl_file;
@ -39,34 +41,16 @@ class Update : public QObject {
QStringList split(QString line, QChar sep = ','); QStringList split(QString line, QChar sep = ',');
bool execUpdateScript(); bool execUpdateScript();
public: public:
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; explicit Update(QString update_ctrl_file,
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn);
explicit Update(hwinf *hw,
QString update_ctrl_file,
QString workingDir = ".", QString workingDir = ".",
QObject *parent = nullptr, QObject *parent = nullptr,
hwinf *hw = nullptr,
char const *serialInterface = SERIAL_PORT, char const *serialInterface = SERIAL_PORT,
char const *baudrate = "115200"); char const *baudrate = "115200");
virtual ~Update() override; virtual ~Update() override;
bool doUpdate(); bool doUpdate();
private: bool const m_delete;
DownloadResult sendStatus(int ret) const;
DownloadResult sendNextAddress(int bNum) const;
DownloadResult sendNextDataBlock(QByteArray const &b, int bNum) const;
DownloadResult dc_downloadBinary(QByteArray const &binary) const;
bool startBootloader() const;
bool stopBootloader() const;
bool openSerial(int br, QString baudrate, QString comPort) const;
void closeSerial() const;
bool resetDeviceController() const;
QByteArray loadBinaryDCFile(QString filename) const;
bool downloadBinaryToDC(QString const &bFile) const;
}; };
#endif // UPDATE_H_INCLUDED #endif // UPDATE_H_INCLUDED

View File

@ -1,66 +0,0 @@
#include "worker.h"
#include "update.h"
#include <QCoreApplication>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QFileInfo>
#include <QDir>
#include <QThread>
#include "message_handler.h"
#include "plugins/interfaces.h"
Worker::Worker(QString update_ctrl_file, QString workingDir)
: m_update_ctrl_file(update_ctrl_file)
, m_workingDir(workingDir)
, m_workerThread("workerThread") {
this->moveToThread(&m_workerThread);
m_workerThread.start();
QThread::usleep(100000);
int cnt = 0;
while (!m_workerThread.isRunning()) {
if (++cnt > 5) {
qCritical() << "starting worker thread FAILED";
return;
}
QThread::sleep(1);
}
connect(this, SIGNAL(workNow()), this, SLOT(work()), Qt::QueuedConnection);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(update()));
m_timer.setSingleShot(true);
m_timer.start(1000);
}
Worker::~Worker() {
int cnt = 0;
m_workerThread.quit();
while (!m_workerThread.isFinished()) {
if (!m_workerThread.wait(1000)) {
if (++cnt > 5) {
qCritical() << "stopping worker thread FAILED";
return;
}
}
}
}
void Worker::update() {
qCritical() << __func__ << ":" << __LINE__;
emit workNow();
}
void Worker::work() {
qCritical() << __func__ << ":" << __LINE__;
//Update m_update(m_update_ctrl_file, m_workingDir);
QThread::sleep(3);
//if (m_update.doUpdate()) {
//}
m_workerThread.quit();
QApplication::quit();
}

View File

@ -1,30 +0,0 @@
#ifndef WORKER_H_INCLUDED
#define WORKER_H_INCLUDED
#include <QObject>
#include <QString>
#include <QTimer>
#include "worker_thread.h"
class Worker : public QObject {
Q_OBJECT
QString m_update_ctrl_file;
QString m_workingDir;
WorkerThread m_workerThread;
QTimer m_timer;
public:
explicit Worker(QString update_ctrl_file, QString workingDir);
~Worker();
void quit() { return m_workerThread.quit(); }
signals:
void workNow();
public slots:
void work();
void update();
};
#endif // WORKER_H_INCLUDED

View File

@ -1,13 +0,0 @@
#include "worker_thread.h"
WorkerThread::WorkerThread(QString const &name,
QObject *parent) : QThread(parent) {
this->setObjectName(name);
}
WorkerThread::~WorkerThread() {
}
//void WorkerThread::run() {
//
//}

View File

@ -1,17 +0,0 @@
#ifndef WORKER_THREAD_H_INCLUDED
#define WORKER_THREAD_H_INCLUDED
#include <QThread>
#include <QString>
class WorkerThread : public QThread {
Q_OBJECT
public:
WorkerThread(QString const &name, QObject *parent = nullptr);
virtual ~WorkerThread();
protected:
// virtual void run();
};
#endif // WORKER_THREAD_H_INCLUDED