Compare commits
4 Commits
2b5fca73a2
...
35d40e3b3c
Author | SHA1 | Date | |
---|---|---|---|
35d40e3b3c | |||
71a6b82d58 | |||
de75ef32d9 | |||
3bac92c711 |
73
OnDemandUpdatePTU.pro
Normal file
73
OnDemandUpdatePTU.pro
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# QT -= gui
|
||||||
|
QT += core
|
||||||
|
QT += widgets serialport
|
||||||
|
QT += network
|
||||||
|
|
||||||
|
TARGET = up_dev_ctrl
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
# CONFIG -= app_bundle
|
||||||
|
|
||||||
|
# DEFINES+=LinuxDesktop
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||||
|
|
||||||
|
# custom target for 'git subtree'
|
||||||
|
# subtree.target = subtree
|
||||||
|
# subtree.commands = git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash
|
||||||
|
# subtree.depends =
|
||||||
|
# QMAKE_EXTRA_UNIX_TARGETS += subtree
|
||||||
|
|
||||||
|
! exists(DCPlugin) {
|
||||||
|
$$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||||
|
} else {
|
||||||
|
# $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash")
|
||||||
|
}
|
||||||
|
|
||||||
|
# You can make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
contains( CONFIG, PTU5 ) {
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
|
||||||
|
CONFIG += link_pkgconfig
|
||||||
|
lessThan(QT_MAJOR_VERSION, 5): PKGCONFIG += qextserialport
|
||||||
|
QMAKE_CXXFLAGS += -std=c++11 # for GCC >= 4.7
|
||||||
|
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||||
|
ARCH = PTU5
|
||||||
|
DEFINES+=PTU5
|
||||||
|
}
|
||||||
|
contains( CONFIG, DesktopLinux ) {
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
|
||||||
|
lessThan(QT_MAJOR_VERSION, 5): CONFIG += extserialport
|
||||||
|
# QMAKE_CC = ccache $$QMAKE_CC
|
||||||
|
# QMAKE_CXX = ccache $$QMAKE_CXX
|
||||||
|
QMAKE_CXXFLAGS += -std=c++11
|
||||||
|
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||||
|
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
|
||||||
|
ARCH = DesktopLinux
|
||||||
|
DEFINES+=DesktopLinux
|
||||||
|
}
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.cpp \
|
||||||
|
update.cpp \
|
||||||
|
message_handler.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
update.h \
|
||||||
|
message_handler.h \
|
||||||
|
DCPlugin/include/interfaces.h
|
||||||
|
|
||||||
|
OTHER_FILES += \
|
||||||
|
/opt/app/tools/atbupdate/update_log.csv
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Default rules for deployment.
|
||||||
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
!isEmpty(target.path): INSTALLS += target
|
BIN
doc/update_ptu.pdf
Normal file
BIN
doc/update_ptu.pdf
Normal file
Binary file not shown.
110
doc/update_ptu.tex
Normal file
110
doc/update_ptu.tex
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
\documentclass[12pt]{article}
|
||||||
|
\usepackage{euler}
|
||||||
|
\usepackage[english]{babel}
|
||||||
|
\usepackage{lipsum}
|
||||||
|
\usepackage[colorlinks=true, urlcolor=blue, linkcolor=red]{hyperref}
|
||||||
|
\newcounter{Chapcounter}
|
||||||
|
\newcommand\showmycounter{\addtocounter{Chapcounter}{1}\themycounter}
|
||||||
|
\newcommand{\chapter}[1]
|
||||||
|
{{\centering
|
||||||
|
\addtocounter{Chapcounter}{1} \Large \underline{\textbf{ \color{blue} Chapter \theChapcounter: ~#1}} }
|
||||||
|
\addcontentsline{toc}{section}{ \color{blue} Chapter:~\theChapcounter~~ #1}
|
||||||
|
}
|
||||||
|
\hypersetup{colorlinks=true}
|
||||||
|
\hypersetup{linkcolor=black}
|
||||||
|
|
||||||
|
\title{Update PTU}
|
||||||
|
\author{Gerhard Hoffmann}
|
||||||
|
\date{\today}
|
||||||
|
|
||||||
|
\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
|
||||||
|
|
||||||
|
\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: Update}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\chapter{Update-Tool "up\_dev\_ctrl"}
|
||||||
|
\section{up\_dev\_ctrl}
|
||||||
|
\label{UpdateTool}
|
||||||
|
|
||||||
|
The update-tool is a Qt binary ("up\_dev\_ctrl") and called by the
|
||||||
|
system-controller application. It is installed under
|
||||||
|
\begin{center}
|
||||||
|
\fbox{
|
||||||
|
/opt/app/tools/atbupdate/up\_dev\_ctrl
|
||||||
|
}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
and has two responsibilities:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Call update-script "update\_psa".
|
||||||
|
\item Update the device controller firmware.
|
||||||
|
\end{itemize}
|
||||||
|
\subsection{Calling the update-script "update\_psa"}
|
||||||
|
The update-script "update\_psa" is about executing all git-commands
|
||||||
|
necessary to clone and pull a customer repository.
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\chapter{Update-Script "update\_psa"}
|
||||||
|
\section{update\_psa}
|
||||||
|
\label{UpdateScript}
|
||||||
|
|
||||||
|
Inside of such a
|
||||||
|
repository, there are at least the following directories:
|
||||||
|
\begin{itemize}
|
||||||
|
\item {\bf etc}
|
||||||
|
\item {\bf etc/dc}\newline
|
||||||
|
Contains the device controller firmware as binary file.
|
||||||
|
\item {\bf etc/psa\_config}\newline
|
||||||
|
Contains the printer template files (JSON).
|
||||||
|
\item {\bf etc/psa\_tariff}\newline
|
||||||
|
Contains the tariff files (JSON).
|
||||||
|
\item {\bf etc/psa\_update}\newline
|
||||||
|
Contains a single file for opkg-commands.
|
||||||
|
\end{itemize}
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\chapter{Annex}
|
||||||
|
\section{Structure of a customer git-repository}
|
||||||
|
\label{repostructure}
|
||||||
|
|
||||||
|
\section{Structure of "update\_log.csv"}
|
||||||
|
\label{updatelogcsv}
|
||||||
|
|
||||||
|
\section{The package manager "opkg"}
|
||||||
|
\label{opkg}
|
||||||
|
\end{document}
|
26
main.cpp
26
main.cpp
@ -5,7 +5,6 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
|
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
#include "DCPlugin/include/hwapi.h"
|
#include "DCPlugin/include/hwapi.h"
|
||||||
|
|
||||||
@ -15,6 +14,7 @@
|
|||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
|
||||||
@ -26,12 +26,16 @@
|
|||||||
|
|
||||||
class Work : public QRunnable {
|
class Work : public QRunnable {
|
||||||
QString m_update_ctrl_file;
|
QString m_update_ctrl_file;
|
||||||
|
QString m_workingDir;
|
||||||
public:
|
public:
|
||||||
explicit Work(QString update_ctrl_file)
|
explicit Work(QString update_ctrl_file, QString workingDir)
|
||||||
: m_update_ctrl_file(update_ctrl_file) {}
|
: m_update_ctrl_file(update_ctrl_file)
|
||||||
|
, m_workingDir(workingDir) {
|
||||||
|
}
|
||||||
void run() {
|
void run() {
|
||||||
Update m_update(m_update_ctrl_file);
|
Update m_update(m_update_ctrl_file, m_workingDir);
|
||||||
m_update.doUpdate();
|
// if (m_update.doUpdate()) {
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,13 +49,15 @@ int main(int argc, char *argv[]) {
|
|||||||
//setDebugLevel(QtMsgType::QtDebugMsg);
|
//setDebugLevel(QtMsgType::QtDebugMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
|
QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
|
||||||
if (argc == 2) {
|
if (value.size() == 0) {
|
||||||
update_ctrl_file = argv[1];
|
qputenv("XDG_RUNTIME_DIR", "/run/user/0");
|
||||||
}
|
}
|
||||||
qInfo() << "Using" << update_ctrl_file << "as update logfile";
|
|
||||||
|
|
||||||
Work work(update_ctrl_file);
|
QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
|
||||||
|
QString const workingDir = (argc == 2) ? argv[1] : ".";
|
||||||
|
|
||||||
|
Work work(update_ctrl_file, workingDir);
|
||||||
work.setAutoDelete(false);
|
work.setAutoDelete(false);
|
||||||
QThreadPool *threadPool = QThreadPool::globalInstance();
|
QThreadPool *threadPool = QThreadPool::globalInstance();
|
||||||
threadPool->start(&work);
|
threadPool->start(&work);
|
||||||
|
34
update.cpp
34
update.cpp
@ -6,6 +6,7 @@
|
|||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
#include "DCPlugin/include/hwapi.h"
|
#include "DCPlugin/include/hwapi.h"
|
||||||
@ -13,6 +14,7 @@
|
|||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#define COLUMN_REQUEST (0)
|
#define COLUMN_REQUEST (0)
|
||||||
#define COLUMN_NAME (1)
|
#define COLUMN_NAME (1)
|
||||||
@ -26,6 +28,7 @@ void ScopedPointerCustomDeleter::cleanup(Update *update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Update::Update(QString update_ctrl_file,
|
Update::Update(QString update_ctrl_file,
|
||||||
|
QString workingDir,
|
||||||
QObject *parent,
|
QObject *parent,
|
||||||
hwinf *hw,
|
hwinf *hw,
|
||||||
char const *serialInterface,
|
char const *serialInterface,
|
||||||
@ -36,9 +39,12 @@ Update::Update(QString update_ctrl_file,
|
|||||||
, 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_init(true)
|
, m_init(true)
|
||||||
, m_delete(hw == nullptr) {
|
, m_delete(hw == nullptr) {
|
||||||
|
|
||||||
|
execUpdateScript();
|
||||||
|
|
||||||
if (!m_update_ctrl_file.exists()) {
|
if (!m_update_ctrl_file.exists()) {
|
||||||
qCritical() << "Update-file" << m_update_ctrl_file.fileName()
|
qCritical() << "Update-file" << m_update_ctrl_file.fileName()
|
||||||
<< "does not exist";
|
<< "does not exist";
|
||||||
@ -64,6 +70,34 @@ Update::Update(QString update_ctrl_file,
|
|||||||
Update::~Update() {
|
Update::~Update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Update::execUpdateScript() {
|
||||||
|
// path of update-script 'update_psa'
|
||||||
|
QString update_psa("/opt/app/tools/atbupdate/update_psa --wdir ");
|
||||||
|
update_psa += m_workingDir;
|
||||||
|
|
||||||
|
//QStringList const params(QStringList() << "-c" << update_psa);
|
||||||
|
|
||||||
|
QScopedPointer<QProcess> p(new QProcess(this));
|
||||||
|
p->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
|
||||||
|
p->start(update_psa);
|
||||||
|
if (p->waitForStarted(1000)) {
|
||||||
|
if (p->state() == QProcess::ProcessState::Running) {
|
||||||
|
if (p->waitForFinished(60000)) {
|
||||||
|
QString output = p->readAllStandardOutput().toStdString().c_str();
|
||||||
|
QStringList lst = output.split('\n');
|
||||||
|
for (int i = 0; i < lst.size(); ++i) {
|
||||||
|
qDebug() << lst[i];
|
||||||
|
}
|
||||||
|
qInfo() << "EXECUTED" << update_psa;
|
||||||
|
return ((p->exitStatus() == QProcess::NormalExit)
|
||||||
|
&& (p->exitCode() == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Update::updateBinary(char const *fileToSendToDC) {
|
bool Update::updateBinary(char const *fileToSendToDC) {
|
||||||
return m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface);
|
return m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface);
|
||||||
}
|
}
|
||||||
|
57
update.h
Normal file
57
update.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef UPDATE_H_INCLUDED
|
||||||
|
#define UPDATE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include "interfaces.h"
|
||||||
|
#include "DCPlugin/include/hwapi.h"
|
||||||
|
|
||||||
|
#ifdef PTU5
|
||||||
|
#define SERIAL_PORT "ttymxc2"
|
||||||
|
#else
|
||||||
|
#define SERIAL_PORT "ttyUSB0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Update;
|
||||||
|
struct ScopedPointerCustomDeleter {
|
||||||
|
static void cleanup(Update *pointer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: check hardware compatibility
|
||||||
|
// TODO: opkg commandos
|
||||||
|
|
||||||
|
class Update : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QScopedPointer<hwinf> m_hw;
|
||||||
|
char const *m_serialInterface;
|
||||||
|
char const *m_baudrate;
|
||||||
|
QFile m_update_ctrl_file;
|
||||||
|
QFile m_update_ctrl_file_copy;
|
||||||
|
QString m_workingDir;
|
||||||
|
|
||||||
|
bool m_init;
|
||||||
|
|
||||||
|
bool updateBinary(char const *fileToSendToDC);
|
||||||
|
bool updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC);
|
||||||
|
bool finishUpdate(bool finish);
|
||||||
|
QStringList getOpenLines();
|
||||||
|
QStringList split(QString line);
|
||||||
|
static constexpr QChar SEPARATOR = QChar(',');
|
||||||
|
|
||||||
|
bool execUpdateScript();
|
||||||
|
public:
|
||||||
|
explicit Update(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;
|
||||||
|
};
|
||||||
|
#endif // UPDATE_H_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user