Compare commits
No commits in common. "35d40e3b3c84472157f9542feb5a800af89d58da" and "2b5fca73a269422bcf0f9470f9bb5a010e02d978" have entirely different histories.
35d40e3b3c
...
2b5fca73a2
@ -1,73 +0,0 @@
|
|||||||
# 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
|
|
Binary file not shown.
@ -1,110 +0,0 @@
|
|||||||
\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,6 +5,7 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@ -14,7 +15,6 @@
|
|||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
|
||||||
@ -26,16 +26,12 @@
|
|||||||
|
|
||||||
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, QString workingDir)
|
explicit Work(QString update_ctrl_file)
|
||||||
: 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, m_workingDir);
|
Update m_update(m_update_ctrl_file);
|
||||||
// if (m_update.doUpdate()) {
|
m_update.doUpdate();
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,15 +45,13 @@ int main(int argc, char *argv[]) {
|
|||||||
//setDebugLevel(QtMsgType::QtDebugMsg);
|
//setDebugLevel(QtMsgType::QtDebugMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
|
QString update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
|
||||||
if (value.size() == 0) {
|
if (argc == 2) {
|
||||||
qputenv("XDG_RUNTIME_DIR", "/run/user/0");
|
update_ctrl_file = argv[1];
|
||||||
}
|
}
|
||||||
|
qInfo() << "Using" << update_ctrl_file << "as update logfile";
|
||||||
|
|
||||||
QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
|
Work work(update_ctrl_file);
|
||||||
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,7 +6,6 @@
|
|||||||
#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"
|
||||||
@ -14,7 +13,6 @@
|
|||||||
#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)
|
||||||
@ -28,7 +26,6 @@ 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,
|
||||||
@ -39,12 +36,9 @@ 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";
|
||||||
@ -70,34 +64,6 @@ 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
57
update.h
@ -1,57 +0,0 @@
|
|||||||
#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