Compare commits
10 Commits
57b82094c8
...
f52dec9124
Author | SHA1 | Date | |
---|---|---|---|
f52dec9124 | |||
07942153c3 | |||
bac848f6be | |||
ccc1bf2a99 | |||
c8487a7541 | |||
dc90705f24 | |||
c4c503080e | |||
e2d9c5aa90 | |||
60f845aa8d | |||
fa0c31d9e4 |
@ -3,9 +3,11 @@ QT += core
|
||||
QT += widgets serialport
|
||||
QT += network
|
||||
|
||||
TARGET = up_dev_ctrl
|
||||
TARGET = ATBUpdateDC
|
||||
|
||||
CONFIG += c++11
|
||||
INCLUDEPATH += plugins
|
||||
|
||||
CONFIG += c++17
|
||||
# CONFIG -= app_bundle
|
||||
|
||||
# DEFINES+=LinuxDesktop
|
||||
@ -18,11 +20,11 @@ QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
# subtree.depends =
|
||||
# QMAKE_EXTRA_UNIX_TARGETS += subtree
|
||||
|
||||
! exists(DCPlugin) {
|
||||
$$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||
} else {
|
||||
# ! exists(DCPlugin) {
|
||||
# $$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||
# } else {
|
||||
# $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||
}
|
||||
# }
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
@ -52,20 +54,27 @@ contains( CONFIG, DesktopLinux ) {
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
update.cpp \
|
||||
message_handler.cpp
|
||||
message_handler.cpp \
|
||||
worker.cpp \
|
||||
worker_thread.cpp
|
||||
|
||||
HEADERS += \
|
||||
update.h \
|
||||
message_handler.h \
|
||||
DCPlugin/include/interfaces.h
|
||||
worker.h \
|
||||
worker_thread.h \
|
||||
plugins/interfaces.h
|
||||
|
||||
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
|
||||
# git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||
# git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||
include(./DCPlugin/DCPlugin.pri)
|
||||
# include(./DCPlugin/DCPlugin.pri)
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
|
Binary file not shown.
@ -2,6 +2,7 @@
|
||||
\usepackage{euler}
|
||||
\usepackage[english]{babel}
|
||||
\usepackage{lipsum}
|
||||
\usepackage{multirow}
|
||||
\usepackage[colorlinks=true, urlcolor=blue, linkcolor=red]{hyperref}
|
||||
\newcounter{Chapcounter}
|
||||
\newcommand\showmycounter{\addtocounter{Chapcounter}{1}\themycounter}
|
||||
@ -19,44 +20,58 @@
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
\chapter{Introduction}
|
||||
\section{Motivation}
|
||||
The two main components of a PSA are
|
||||
\begin{itemize}
|
||||
\item PTU software.
|
||||
\item Device controller (DC) firmware.
|
||||
\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
|
||||
Hence, each customer is assigned an own git-repository, which will be loaded
|
||||
("cloned") on the PSA when configuring the machine for the first time.\par
|
||||
Two special tools, the {\bf UpdateController} (a \href{https://doc.qt.io/qt-5/}{Qt}
|
||||
binary [{\bf \nameref{UpdateTool}}]) and the {\bf UpdateScript}
|
||||
(a \href{https://www.gnu.org/software/bash/manual/bash.html}{bash}
|
||||
script [{\bf \nameref{UpdateScript}}]), work together to finish a PSA installation.\par
|
||||
% \chapter{Introduction}
|
||||
\section{Motivation}
|
||||
|
||||
The two main components of a PSA are
|
||||
\begin{itemize}
|
||||
\item PTU software.
|
||||
\item Device controller (DC) firmware.
|
||||
\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
|
||||
Hence, each customer is assigned an own git-repository, which will be loaded
|
||||
("cloned") on the PSA when configuring the machine for the first time.\par
|
||||
Two special tools, the {\bf UpdateController} (a \href{https://doc.qt.io/qt-5/}{Qt}
|
||||
binary [{\bf \nameref{UpdateTool}}]) and the {\bf UpdateScript}
|
||||
(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}
|
||||
For the initial configuration, a PSA loads a customer-specific git-repository,
|
||||
which structure is detailed below [{\bf \nameref{repostructure}}].\par
|
||||
The "git clone" for the repository is done by the UpdateScript [{\bf \nameref{UpdateScript}}].
|
||||
It updates the file
|
||||
\begin{center}
|
||||
\fbox{
|
||||
/opt/app/tools/atbupdate/update\_log.csv
|
||||
}
|
||||
\end{center}
|
||||
which will be interpreted by the UpdateController [{\bf \nameref{UpdateTool}}].
|
||||
The structure of {\bf update\_log.csv} is detailed below [{\bf \nameref{updatelogcsv}}].\par
|
||||
Each line of {\bf update\_log.csv} represents a command for the UpdateController,
|
||||
which will either download certain files to the DC or execute some
|
||||
\href{https://openwrt.org/docs/guide-user/additional-software/opkg}{opkg}
|
||||
commands [{\bf \nameref{opkg}}].
|
||||
\section{PSA: Initial configuration}
|
||||
|
||||
For the initial configuration, a PSA loads a customer-specific git-repository,
|
||||
which structure is detailed below [{\bf \nameref{repostructure}}].\par
|
||||
The "git clone" for the repository is done by the UpdateScript [{\bf \nameref{UpdateScript}}].
|
||||
It updates the file
|
||||
\begin{center}
|
||||
\fbox{
|
||||
/opt/app/tools/atbupdate/update\_log.csv
|
||||
}
|
||||
\end{center}
|
||||
which will be interpreted by the UpdateController [{\bf \nameref{UpdateTool}}].
|
||||
The structure of [{\bf \nameref{updatelogcsv}}] is detailed below.\par
|
||||
Each line of update\_log.csv represents a command for the UpdateController,
|
||||
which will either download certain files to the DC or execute some
|
||||
\href{https://openwrt.org/docs/guide-user/additional-software/opkg}{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.
|
||||
|
||||
\newpage
|
||||
|
||||
\chapter{Update-Tool "up\_dev\_ctrl"}
|
||||
% \chapter{Update-Tool "up\_dev\_ctrl"}
|
||||
\section{up\_dev\_ctrl}
|
||||
\label{UpdateTool}
|
||||
|
||||
@ -79,7 +94,7 @@
|
||||
|
||||
\newpage
|
||||
|
||||
\chapter{Update-Script "update\_psa"}
|
||||
% \chapter{Update-Script "update\_psa"}
|
||||
\section{update\_psa}
|
||||
\label{UpdateScript}
|
||||
|
||||
@ -98,13 +113,60 @@
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\chapter{Annex}
|
||||
%\chapter{Annex}
|
||||
\section{Structure of a customer git-repository}
|
||||
\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{Structure of "update\_log.csv"}
|
||||
\label{updatelogcsv}
|
||||
\section{update\_log.csv}
|
||||
\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"}
|
||||
\label{opkg}
|
||||
|
||||
\section{Known problems}
|
||||
\end{document}
|
||||
|
56
main.cpp
56
main.cpp
@ -5,8 +5,7 @@
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "interfaces.h"
|
||||
#include "DCPlugin/include/hwapi.h"
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
@ -17,6 +16,10 @@
|
||||
#include <QDir>
|
||||
|
||||
#include "update.h"
|
||||
#include "worker_thread.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
@ -24,20 +27,13 @@
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#endif
|
||||
|
||||
class Work : public QRunnable {
|
||||
QString m_update_ctrl_file;
|
||||
QString m_workingDir;
|
||||
public:
|
||||
explicit Work(QString update_ctrl_file, QString workingDir)
|
||||
: 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()) {
|
||||
// }
|
||||
}
|
||||
};
|
||||
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[]) {
|
||||
@ -54,15 +50,29 @@ int main(int argc, char *argv[]) {
|
||||
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 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;
|
||||
|
||||
std::thread t(doWork, update_ctrl_file, workingDir);
|
||||
|
||||
int ret = a.exec();
|
||||
t.join();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
81
main.cpp.bck
Normal file
81
main.cpp.bck
Normal file
@ -0,0 +1,81 @@
|
||||
#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;
|
||||
}
|
54
main.cpp.bck2
Normal file
54
main.cpp.bck2
Normal file
@ -0,0 +1,54 @@
|
||||
#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;
|
||||
}
|
62
main.cpp.bck3
Normal file
62
main.cpp.bck3
Normal file
@ -0,0 +1,62 @@
|
||||
#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;
|
||||
}
|
@ -3,8 +3,7 @@
|
||||
#include <QDateTime>
|
||||
#include <cstring>
|
||||
|
||||
#define OUTPUT_LEN (20)
|
||||
|
||||
#define OUTPUT_LEN (512)
|
||||
|
||||
static bool installedMsgHandler = false;
|
||||
static QtMsgType debugLevel = QtInfoMsg;
|
||||
@ -41,49 +40,10 @@ QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
|
||||
/// return app.exec();
|
||||
/// }
|
||||
///
|
||||
#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)
|
||||
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
|
||||
static constexpr const char *format = "hh:mm:ss";
|
||||
// static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
const char *file = context.file ? context.file : "";
|
||||
const char *function = context.function ? context.function : "";
|
||||
@ -97,54 +57,65 @@ void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
}
|
||||
qint64 const currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
|
||||
int const fractional_part = currentMSecsSinceEpoch % 1000;
|
||||
char buf[OUTPUT_LEN]{};
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
QDateTime const datetime = QDateTime::fromMSecsSinceEpoch(currentMSecsSinceEpoch);
|
||||
switch (type) {
|
||||
case QtDebugMsg: {
|
||||
if (debugLevel <= QtDebugMsg) {
|
||||
// fprintf(stderr, "%*.*s CTX %s (%s:%u) ->\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
// "", function, file, context.line);
|
||||
//fprintf(stderr, "%*.*s.%03d DEBG %s\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
// datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
// 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);
|
||||
if (debugLevel == QtDebugMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d DEBG %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
localMsg.constData());
|
||||
}
|
||||
} break;
|
||||
case QtInfoMsg: {
|
||||
if (debugLevel <= QtInfoMsg) {
|
||||
fprintf(stderr, "%*.*s.%03d INFO %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
localMsg.constData(), file, context.line);
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d INFO %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
localMsg.constData());
|
||||
}
|
||||
} break;
|
||||
case QtWarningMsg: {
|
||||
if (debugLevel <= QtWarningMsg) {
|
||||
fprintf(stderr, "%*.*s.%03d WARN %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
localMsg.constData(), file, context.line);
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg || debugLevel == QtWarningMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d WARN %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
localMsg.constData());
|
||||
}
|
||||
} break;
|
||||
case QtCriticalMsg: {
|
||||
if (debugLevel <= QtCriticalMsg) {
|
||||
fprintf(stderr, "%*.*s.%03d CRIT %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
localMsg.constData(), file, context.line);
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
|
||||
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d CRIT %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
localMsg.constData());
|
||||
}
|
||||
} break;
|
||||
case QtFatalMsg: {
|
||||
if (debugLevel <= QtFatalMsg) {
|
||||
fprintf(stderr, "%*.*s.%03d FATAL %s (%s:%u)\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
localMsg.constData(), file, context.line);
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
|
||||
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg
|
||||
|| debugLevel == QtFatalMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d FATAL %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
localMsg.constData());
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.toString(format).toStdString().c_str(), fractional_part,
|
||||
datetime.time().toString(format).toStdString().c_str(), fractional_part,
|
||||
msg.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
2929
plugins/interfaces.h
2929
plugins/interfaces.h
File diff suppressed because it is too large
Load Diff
BIN
plugins/libCAmaster.so
Normal file
BIN
plugins/libCAmaster.so
Normal file
Binary file not shown.
319
update.cpp
319
update.cpp
@ -8,43 +8,82 @@
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "DCPlugin/include/hwapi.h"
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#include <QSharedMemory>
|
||||
#include <QScopedPointer>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QThread>
|
||||
#include <QDateTime>
|
||||
#include <QPluginLoader>
|
||||
|
||||
#define COLUMN_REQUEST (0)
|
||||
#define COLUMN_NAME (1)
|
||||
#define COLUMN_DATE_TIME (2)
|
||||
#define COLUMN_RESULT (3)
|
||||
|
||||
void ScopedPointerCustomDeleter::cleanup(Update *update) {
|
||||
if (update->m_delete) {
|
||||
delete update;
|
||||
hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
hwinf *hw = nullptr;
|
||||
if (plugInDir.exists()) {
|
||||
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(QString update_ctrl_file,
|
||||
Update::Update(hwinf *hw,
|
||||
QString update_ctrl_file,
|
||||
QString workingDir,
|
||||
QObject *parent,
|
||||
hwinf *hw,
|
||||
char const *serialInterface,
|
||||
char const *baudrate)
|
||||
: QObject(parent)
|
||||
, m_hw(hw != nullptr ? hw : new hwapi())
|
||||
, m_hw(hw)
|
||||
, m_serialInterface(serialInterface)
|
||||
, m_baudrate(baudrate)
|
||||
, m_update_ctrl_file(update_ctrl_file)
|
||||
, m_update_ctrl_file_copy(update_ctrl_file + ".copy")
|
||||
, m_workingDir(workingDir)
|
||||
, m_init(true)
|
||||
, m_delete(hw == nullptr) {
|
||||
, m_init(true) {
|
||||
|
||||
// qCritical() << "workingDir" << m_workingDir;
|
||||
|
||||
// m_hw->dc_autoRequest(false);
|
||||
|
||||
return;
|
||||
|
||||
execUpdateScript();
|
||||
|
||||
if (!m_update_ctrl_file.exists()) {
|
||||
@ -67,6 +106,8 @@ Update::Update(QString update_ctrl_file,
|
||||
m_init = false;
|
||||
}
|
||||
qDebug() << "Opened" << m_update_ctrl_file_copy.fileName();
|
||||
|
||||
//QApplication::processEvents();
|
||||
}
|
||||
|
||||
Update::~Update() {
|
||||
@ -78,6 +119,14 @@ bool Update::execUpdateScript() {
|
||||
update_psa += m_workingDir;
|
||||
|
||||
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);
|
||||
|
||||
@ -102,19 +151,248 @@ bool Update::execUpdateScript() {
|
||||
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) {
|
||||
// return true; // debug
|
||||
return m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface);
|
||||
QFile fn(fileToSendToDC);
|
||||
bool r;
|
||||
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) {
|
||||
// return true; // debug
|
||||
qCritical() << "updating printer template: " << fileToSendToDC;
|
||||
return true; // debug
|
||||
QVector<int> printTemplates{ nrOfTemplate };
|
||||
QVector<QString> filesToSend{ fileToSendToDC };
|
||||
return m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER,
|
||||
printTemplates, filesToSend,
|
||||
QString(m_baudrate),
|
||||
QString(m_serialInterface));
|
||||
//return m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER,
|
||||
// printTemplates, filesToSend,
|
||||
// QString(m_baudrate),
|
||||
// QString(m_serialInterface));
|
||||
}
|
||||
|
||||
QStringList Update::getOpenLines() {
|
||||
@ -167,7 +445,6 @@ bool Update::doUpdate() {
|
||||
#
|
||||
*/
|
||||
|
||||
// qCritical() << "Device Controller SW-version" << m_hw->dc_getSWversion();
|
||||
|
||||
if (!m_init) {
|
||||
return false;
|
||||
@ -193,19 +470,19 @@ bool Update::doUpdate() {
|
||||
QString const &result = lst[COLUMN_RESULT];
|
||||
if ((!request.contains("DOWNLOAD") && !request.contains("EXECUTE")) ||
|
||||
!result.contains("N/A")) {
|
||||
qCritical() << "Parsing error for" << m_update_ctrl_file.fileName();
|
||||
qCritical() << "parsing error for" << m_update_ctrl_file.fileName();
|
||||
return false;
|
||||
}
|
||||
if (name.contains("dc2c") && name.endsWith(".bin")) {
|
||||
if ((res = updateBinary(name.toStdString().c_str())) == true) {
|
||||
qInfo() << "Downloaded" << name;
|
||||
qInfo() << "downloaded binary" << name;
|
||||
}
|
||||
} else
|
||||
if (name.contains("DC2C_print") && name.endsWith(".json")) {
|
||||
int i = name.indexOf("DC2C_print");
|
||||
int templateIdx = name.mid(i).midRef(10, 2).toInt();
|
||||
if ((res = updatePrinterConf(templateIdx, name.toStdString().c_str())) == true) {
|
||||
qInfo() << "Downloaded" << name;
|
||||
qInfo() << "downloaded printer template" << name;
|
||||
}
|
||||
} else
|
||||
if (name.contains("opkg")) {
|
||||
|
34
update.h
34
update.h
@ -4,9 +4,10 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QByteArray>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "DCPlugin/include/hwapi.h"
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
@ -15,9 +16,6 @@
|
||||
#endif
|
||||
|
||||
class Update;
|
||||
struct ScopedPointerCustomDeleter {
|
||||
static void cleanup(Update *pointer);
|
||||
};
|
||||
|
||||
// TODO: check hardware compatibility
|
||||
// TODO: opkg commandos
|
||||
@ -25,7 +23,7 @@ struct ScopedPointerCustomDeleter {
|
||||
class Update : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QScopedPointer<hwinf> m_hw;
|
||||
hwinf *m_hw;
|
||||
char const *m_serialInterface;
|
||||
char const *m_baudrate;
|
||||
QFile m_update_ctrl_file;
|
||||
@ -41,16 +39,34 @@ class Update : public QObject {
|
||||
QStringList split(QString line, QChar sep = ',');
|
||||
|
||||
bool execUpdateScript();
|
||||
|
||||
public:
|
||||
explicit Update(QString update_ctrl_file,
|
||||
enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
|
||||
|
||||
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn);
|
||||
|
||||
|
||||
explicit Update(hwinf *hw,
|
||||
QString update_ctrl_file,
|
||||
QString workingDir = ".",
|
||||
QObject *parent = nullptr,
|
||||
hwinf *hw = nullptr,
|
||||
char const *serialInterface = SERIAL_PORT,
|
||||
char const *baudrate = "115200");
|
||||
virtual ~Update() override;
|
||||
bool doUpdate();
|
||||
|
||||
bool const m_delete;
|
||||
private:
|
||||
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
|
||||
|
66
worker.cpp
Normal file
66
worker.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#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();
|
||||
}
|
30
worker.h
Normal file
30
worker.h
Normal file
@ -0,0 +1,30 @@
|
||||
#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
|
13
worker_thread.cpp
Normal file
13
worker_thread.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "worker_thread.h"
|
||||
|
||||
WorkerThread::WorkerThread(QString const &name,
|
||||
QObject *parent) : QThread(parent) {
|
||||
this->setObjectName(name);
|
||||
}
|
||||
|
||||
WorkerThread::~WorkerThread() {
|
||||
}
|
||||
|
||||
//void WorkerThread::run() {
|
||||
//
|
||||
//}
|
17
worker_thread.h
Normal file
17
worker_thread.h
Normal file
@ -0,0 +1,17 @@
|
||||
#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
|
Loading…
x
Reference in New Issue
Block a user