1024 lines
38 KiB
C++
1024 lines
38 KiB
C++
#include "update.h"
|
|
#include "worker.h"
|
|
#include "utils.h"
|
|
#include "update_dc_event.h"
|
|
#include "mainwindow.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QApplication>
|
|
#include <QFile>
|
|
#include <QTemporaryFile>
|
|
#include <QDebug>
|
|
#include <QTextStream>
|
|
#include <QRegularExpression>
|
|
#include <QRegExp>
|
|
#include <QApplication>
|
|
|
|
#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX)
|
|
#include "unistd.h"
|
|
#endif
|
|
|
|
#include <DeviceController/interfaces.h>
|
|
|
|
#include <QSharedMemory>
|
|
#include <QScopedPointer>
|
|
#include <QDir>
|
|
#include <QThread>
|
|
#include <QDateTime>
|
|
#include <QPluginLoader>
|
|
#include <QMap>
|
|
|
|
#define UPDATE_OPKG (1)
|
|
#define UPDATE_DC (0)
|
|
|
|
static const QMap<QString, int> baudrateMap = {
|
|
{"1200" , 0}, {"9600" , 1}, {"19200" , 2}, {"38400" , 3},
|
|
{"57600" , 4}, {"115200" , 5}
|
|
};
|
|
|
|
QPluginLoader Update::pluginLoader;
|
|
|
|
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);
|
|
pluginLoader.setFileName(pluginLibName);
|
|
// static QPluginLoader pluginLoader(pluginLibName);
|
|
if (!pluginLoader.load()) {
|
|
qCritical() << "in directory" << plugInDir.absolutePath();
|
|
qCritical() << "cannot load plugin" << pluginLoader.fileName();
|
|
qCritical() << pluginLoader.errorString();
|
|
}
|
|
|
|
qCritical() << "loadDCPlugin() plugin directory:" << plugInDir.absolutePath();
|
|
qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName();
|
|
|
|
if (!pluginLoader.isLoaded()) {
|
|
qCritical() << pluginLoader.errorString();
|
|
}
|
|
QObject *plugin = pluginLoader.instance();
|
|
if (!plugin) {
|
|
qCritical() << "cannot start instance";
|
|
}
|
|
if (! (hw = qobject_cast<hwinf *>(plugin))) {
|
|
qCritical() << "cannot cast plugin" << plugin << "to hwinf";
|
|
}
|
|
} else {
|
|
qCritical() << pluginLibName << "does not exist";
|
|
}
|
|
} else {
|
|
qCritical() << "plugins directory" << plugInDir.absolutePath()
|
|
<< "does not exist";
|
|
}
|
|
return hw;
|
|
}
|
|
|
|
bool Update::unloadDCPlugin() {
|
|
if (pluginLoader.unload()) {
|
|
qCritical() << "unloaded plugin" << pluginLoader.fileName();
|
|
// Note: will re-instantiate the library !
|
|
// QObject *rootObject = pluginLoader.instance();
|
|
// if (rootObject) {
|
|
// qCritical() << "reloaded plugin: root object again available";
|
|
// return false;
|
|
// }
|
|
// qCritical()unloaded plugin: root object gone";
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
class hwapi;
|
|
Update::Update(Worker *worker,
|
|
QString customerRepository,
|
|
QString customerNrStr,
|
|
QString branchName,
|
|
QString plugInDir,
|
|
QString pluginName,
|
|
QString workingDir,
|
|
bool dryRun,
|
|
QObject *parent,
|
|
char const *serialInterface,
|
|
char const *baudrate)
|
|
: QObject(parent)
|
|
, m_hw(loadDCPlugin(QDir(plugInDir), pluginName))
|
|
, m_worker(worker)
|
|
, m_serialInterface(serialInterface)
|
|
, m_baudrate(baudrate)
|
|
, m_customerRepository(customerRepository)
|
|
, m_customerNrStr(customerNrStr)
|
|
, m_branchName(branchName)
|
|
, m_pluginName(pluginName)
|
|
, m_workingDir(workingDir)
|
|
, m_dryRun(dryRun)
|
|
, m_sys_areDCdataValid(false) {
|
|
|
|
if (!m_hw) {
|
|
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_hw == nullptr -> ca-slave plugin not loaded";
|
|
} else {
|
|
int tries = 20;
|
|
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
|
|
// must deliver 'true', only then are all data from hwapi valid
|
|
if (--tries < 0) {
|
|
qCritical() << "ERROR!!! DC DATA NOT VALID -> CA-MASTER-PLUGIN NOT CONNECTED";
|
|
break;
|
|
}
|
|
m_hw->dc_autoRequest(true);
|
|
QThread::msleep(500);
|
|
}
|
|
|
|
qCritical() << "(" << __func__ << ":" << __LINE__ << ") m_sys_areDCDataValid ..."
|
|
<< m_sys_areDCdataValid;
|
|
|
|
#if 0
|
|
QObject const *obj = m_hw->getAPI();
|
|
Q_ASSERT(obj != nullptr);
|
|
|
|
QDebug critical = qCritical();
|
|
critical << "connect() to onReportDCDownloadStatus() ...";
|
|
if (!connect(obj,
|
|
SIGNAL(hwapi_reportDCDownloadStatus(QString const&)),
|
|
this,
|
|
SLOT(onReportDCDownloadStatus(QString const &)))) {
|
|
critical << "FAILED";
|
|
} else critical << "DONE";
|
|
|
|
critical = qCritical();
|
|
critical << "connect() to onReportDCDownloadSuccess() ...";
|
|
if (!connect(obj,
|
|
SIGNAL(hwapi_reportDCDownloadSuccess(QString const&)), this,
|
|
SLOT(onReportDCDownloadSuccess(QString const &)))) {
|
|
critical << "FAILED";
|
|
} else critical << "DONE";
|
|
|
|
critical = qCritical();
|
|
critical << "connect() to onReportDCDownloadFailure() ...";
|
|
if (!connect(obj,
|
|
SIGNAL(hwapi_reportDCDownloadFailure(QString const &)), this,
|
|
SLOT(onReportDCDownloadFailure(QString const &)))) {
|
|
critical << "FAILED";
|
|
} else critical << "DONE";
|
|
#endif
|
|
}
|
|
}
|
|
|
|
Update::~Update() {
|
|
}
|
|
|
|
void Update::onReportDCDownloadStatus(QString const &status) {
|
|
emit m_worker->showStatusMessage("DL", status);
|
|
}
|
|
|
|
void Update::onReportDCDownloadSuccess(QString const &msg) {
|
|
qCritical() << "msg" << msg;
|
|
}
|
|
|
|
void Update::onReportDCDownloadFailure(QString const &errorMsg) {
|
|
qCritical() << "msg" << errorMsg;
|
|
}
|
|
|
|
|
|
|
|
// br is a index into a table, used for historical reasons.
|
|
bool Update::openSerial(int br, QString baudrate, QString comPort) const {
|
|
if (m_hw) {
|
|
qDebug() << "opening serial" << br << baudrate << comPort << "...";
|
|
if (m_hw->dc_openSerial(br, baudrate, comPort, 1) == true) { // 1 for connect
|
|
Utils::printInfoMsg(
|
|
QString("OPENING SERIAL %1").arg(br)
|
|
+ " " + baudrate + " " + comPort + "...OK");
|
|
|
|
// m_hw->dc_autoRequest(true);
|
|
m_hw->dc_autoRequest(false);
|
|
QThread::sleep(1);
|
|
|
|
Utils::printInfoMsg(QString("IS PORT OPEN %1").arg(m_hw->dc_isPortOpen()));
|
|
return true;
|
|
}
|
|
|
|
Utils::printCriticalErrorMsg(
|
|
QString("OPENING SERIAL %1").arg(br)
|
|
+ " " + baudrate + " " + comPort + "...FAILED");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Update::closeSerial() const {
|
|
qInfo() << "CLOSED SERIAL" << m_baudrate << m_serialInterface;
|
|
if (m_hw) {
|
|
m_hw->dc_closeSerial();
|
|
}
|
|
}
|
|
|
|
bool Update::isSerialOpen() const {
|
|
return m_hw ? m_hw->dc_isPortOpen() : false;
|
|
}
|
|
|
|
/*
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// USING THE DC BOOTLOADER
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
1 : bl_reboot() // send to application, want DC2 to reset (in order to
|
|
// start the bootloader)
|
|
//
|
|
// NOTE: this function is NOT reliable !!! Sometimes it
|
|
// simply does not work, in which case bl_startBL,
|
|
// bl_checkBL and bl_isUp do not work as well.
|
|
// Alas, there is no feedback if bl_reboot worked!
|
|
//
|
|
// NOTE: this function can be called only once per
|
|
// minute, because once called again, the controller
|
|
// performs some self-checks consuming some time.
|
|
//
|
|
// NOTE: after a successful bl_reboot(), the device is
|
|
// waiting about 4 seconds in the bootloader. To stay in
|
|
// the bootloader, we have to send the command
|
|
// bl_startBL(), which is kind of a misnomer, as it
|
|
// should be bl_doNotLeaveBL().
|
|
//
|
|
2 : bl_startBL(): // send within 4s after DC power-on, otherwise
|
|
// bootloader is left.
|
|
//
|
|
// NOTE: a running bootloader is a MUST for the download
|
|
// process of a device controller firmware as it does
|
|
// the actual writing of the memory (the bl_reboot()
|
|
// from above erases the available memory).
|
|
//
|
|
3 : bl_check(): // send command to verify if bl is up
|
|
//
|
|
// NOTE: this command is kind of a request that we want
|
|
// to check if the bootloader is up. The device
|
|
// (actually the bootloader) responds with its version.
|
|
//
|
|
4 : bl_isUp(): // returns true if bl is up and running
|
|
//
|
|
// NOTE: we know what the bootloader version actually is
|
|
// as the bootloader does not change. By comparing the
|
|
// string received in the previous step with this known
|
|
// version string we know if the bootloader is up.
|
|
//
|
|
// NOTE FOR ALL PREVIOUS STEPS: execute them in their
|
|
// own slots each to be sure to receive any possible
|
|
// responds from the device.
|
|
//
|
|
5 : bl_sendAddress(blockNumber)
|
|
// send start address, nr of 64-byte block, start with 0
|
|
// will be sent only for following block-numbers:
|
|
// 0, 1024, 2048, 3072 and 4096, so basically every
|
|
// 64kByte.
|
|
// for other addresses nothing happens
|
|
|
|
6 : bl_wasSendingAddOK()
|
|
// return val: 0: no response by now
|
|
// 1: error
|
|
// 10: OK
|
|
|
|
7 : bl_sendDataBlock()
|
|
// send 64 byte from bin file
|
|
|
|
8 : bl_sendLastBlock()
|
|
// send this command after all data are transferred
|
|
|
|
9 : bl_wasSendingDataOK()
|
|
// return val: 0: no response by now
|
|
// 1: error
|
|
// 10: OK
|
|
|
|
10 : bl_stopBL() // leave bl and start (the new) application
|
|
//
|
|
// NOTE: this function MUST work under all conditions.
|
|
// Alas, there is no direct result for this command, so
|
|
// the only way of knowing it was successful is to ask
|
|
// the device if the bootloader is still running.
|
|
// There is no problem to repeat this command until the
|
|
// bootloader is really not running anymore.
|
|
*/
|
|
bool Update::updateBinary(QString const &fileToSendToDC) {
|
|
qInfo() << "UPDATING DEVICE CONTROLLER FIRMWARE BINARY" << fileToSendToDC;
|
|
|
|
return false;
|
|
|
|
#if 0
|
|
QFile fn(fileToSendToDC);
|
|
if (!fn.exists()) {
|
|
// output via CONSOLE() etc
|
|
return false;
|
|
}
|
|
|
|
bool bl_isUp = false;
|
|
if (m_hw->bl_completeStart()) {
|
|
int cnt = 5;
|
|
while (--cnt > 0) {
|
|
if (m_hw->bl_isUp()) {
|
|
bl_isUp = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bl_isUp) {
|
|
return false;
|
|
}
|
|
|
|
if (!m_hw->bl_storeFirmware(fileToSendToDC)) {
|
|
m_hw->bl_stopBL();
|
|
return false;
|
|
}
|
|
|
|
uint16_t const nrOfFirmwareBlocks = m_hw->bl_getNrOfFirmwareBlocks();
|
|
|
|
for (uint16_t blockNr = 0; blockNr <= nrOfFirmwareBlocks; ++blockNr) {
|
|
m_hw->bl_blockAutoLoad(blockNr);
|
|
|
|
int sleepTime = 0;
|
|
while (1) {
|
|
if (sleepTime > 1500) {
|
|
m_hw->bl_stopBL();
|
|
return false;
|
|
}
|
|
|
|
int8_t const r = m_hw->bl_blockAutoResponse();
|
|
|
|
// after every "bl_blockAutoLoad()" call this until response
|
|
// retval 0: wait 1: OK, blk was sent 2: OK, transfer complete
|
|
// 3: error despite repeating, cancel. probably bin file corrupted
|
|
// Max duration: 3x no response from BL = 900ms
|
|
|
|
switch(r) {
|
|
case 1:
|
|
/* fall through */
|
|
case 2:
|
|
sleepTime = 0;
|
|
break;
|
|
case 0: {
|
|
QThread::msleep(100);
|
|
sleepTime += 100;
|
|
} break;
|
|
case 3:
|
|
m_hw->bl_stopBL();
|
|
return false;
|
|
default:
|
|
m_hw->bl_stopBL();
|
|
return false; // unknown error code
|
|
}
|
|
}
|
|
|
|
m_hw->bl_stopBL();
|
|
}
|
|
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
QString Update::jsonType(enum FileTypeJson type) {
|
|
switch (type) {
|
|
case FileTypeJson::CASH: return "CASH";
|
|
case FileTypeJson::CONFIG: return "CONFIG";
|
|
case FileTypeJson::PRINTER: return "PRINTER";
|
|
case FileTypeJson::SERIAL: return "SERIAL";
|
|
case FileTypeJson::DEVICE: return "DEVICE";
|
|
case FileTypeJson::TIME: return "TIME";
|
|
}
|
|
return "N/A";
|
|
}
|
|
|
|
bool Update::downloadJson(enum FileTypeJson type,
|
|
int templateIdx,
|
|
QString jsFileToSendToDC) const {
|
|
|
|
if (m_hw) {
|
|
m_hw->dc_autoRequest(true); // downloading Json needs the AutoEmission flag
|
|
qDebug() << "SET AUTO-REQUEST=TRUE";
|
|
QThread::sleep(1); // make sure the auto-request flag is acknowledged
|
|
|
|
QStringList lst;
|
|
bool ready = false;
|
|
int nTry = 25;
|
|
while ((ready = m_hw->sys_ready4sending()) == false) {
|
|
QThread::msleep(200);
|
|
if (--nTry <= 0) {
|
|
QString msg("SYS NOT READY FOR SENDING AFTER 5 SECONDS");
|
|
Utils::printCriticalErrorMsg(msg);
|
|
lst << msg;
|
|
|
|
if (m_worker) {
|
|
m_worker->ISMAS(lst) << (m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
lst.clear();
|
|
if (ready) {
|
|
QString msg;
|
|
QFile file(jsFileToSendToDC);
|
|
QFileInfo fi(jsFileToSendToDC); // max. size of template file is 800 bytes
|
|
if (file.exists()) {
|
|
if (file.open(QIODevice::ReadOnly)) {
|
|
if (fi.size() > 0 && fi.size() <= 800) {
|
|
QByteArray ba = file.readAll();
|
|
|
|
// kindOfFile: 1=config, 2=device, 3=cash, 4=serial, 5=time, 6=printer
|
|
// nrOfTemplate=1...32 if kindOfFile==6
|
|
// content = content of the Json file, max 800byte ascii signs
|
|
|
|
// type == kindOfFile
|
|
if (m_hw->sys_sendJsonFileToDc((uint8_t)(type),
|
|
templateIdx,
|
|
(uint8_t *)ba.data())) {
|
|
|
|
/*
|
|
* Note: the machine id is contained in DC2C_conf.json.
|
|
* The idea was to use this to check if the download of
|
|
* the json-file was correct. It did not work, as the
|
|
* update of the PSA (to reflect a change in the
|
|
* machine id) did not happen immediately.
|
|
*
|
|
m_hw->dc_autoRequest(true);
|
|
QThread::msleep(500);
|
|
|
|
// testing
|
|
m_hw->request_ReadbackMachineID();
|
|
QThread::msleep(500);
|
|
|
|
uint8_t data[64];
|
|
memset(data, 0x00, sizeof(data));
|
|
uint8_t length = 0;
|
|
|
|
m_hw->readback_machineIDdata(&length, data);
|
|
|
|
QThread::msleep(500);
|
|
|
|
QByteArray ba((const char*)data, length);
|
|
|
|
qCritical() << length << "MACHINE ID =" << ba.toHex(':');
|
|
*/
|
|
|
|
if (m_worker) {
|
|
lst.clear();
|
|
if (templateIdx >= 1 && templateIdx <= 32) {
|
|
lst << QString("LOADED %1 (%2) TO DC").arg(fi.fileName()).arg(templateIdx);
|
|
} else {
|
|
lst << QString("LOADED %1 (%2) TO DC").arg(fi.fileName()).arg((uint8_t)type);
|
|
}
|
|
m_worker->ISMAS(lst) << (m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE));
|
|
}
|
|
} else {
|
|
msg = QString("ERROR SEND JSON-FILE %1 TO DC").arg(file.fileName());
|
|
Utils::printCriticalErrorMsg(msg);
|
|
lst << msg;
|
|
if (m_worker) {
|
|
m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE);
|
|
}
|
|
}
|
|
} else {
|
|
msg = QString("SIZE OF %1 TOO BIG (%2 BYTES)").arg(jsFileToSendToDC).arg(fi.size());
|
|
Utils::printCriticalErrorMsg(msg);
|
|
lst << msg;
|
|
if (m_worker) {
|
|
m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE);
|
|
}
|
|
}
|
|
} else {
|
|
msg = QString("CAN NOT OPEN ") + jsFileToSendToDC + " FOR READING";
|
|
Utils::printCriticalErrorMsg(msg);
|
|
lst << msg;
|
|
|
|
if (m_worker) {
|
|
m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE);
|
|
}
|
|
}
|
|
} else {
|
|
msg = QString(jsFileToSendToDC) + " DOES NOT EXIST";
|
|
Utils::printCriticalErrorMsg(msg);
|
|
lst << msg;
|
|
|
|
if (m_worker) {
|
|
m_worker->GUI(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_hw->dc_autoRequest(false);
|
|
qDebug() << "SET AUTO-REQUEST=FALSE";
|
|
QThread::sleep(1); // make sure the auto-request flag is acknowledged
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Update::updatePrinterTemplate(int templateIdx, QString jsFile) const {
|
|
return downloadJson(FileTypeJson::PRINTER, templateIdx, jsFile);
|
|
}
|
|
|
|
bool Update::updateConfig(QString jsFile) {
|
|
// IMPORTANT: the JSON-file has a 'title'-line: the value MUST be 'DC2C_config'
|
|
return downloadJson(FileTypeJson::CONFIG, 0, jsFile);
|
|
}
|
|
|
|
bool Update::updateCashConf(QString jsFile) {
|
|
// IMPORTANT: the JSON-file has a 'title'-line: the value MUST be 'DC2C_cash '
|
|
// Note the twp spaces after DC2C_cash !!
|
|
return downloadJson(FileTypeJson::CASH, 0, jsFile);
|
|
}
|
|
|
|
bool Update::updateDeviceConf(QString jsFile) {
|
|
// IMPORTANT: the JSON-file has a 'title'-line: the value MUST be 'DC2C_device'
|
|
return downloadJson(FileTypeJson::DEVICE, 0, jsFile);
|
|
}
|
|
|
|
QStringList Update::split(QString line, QChar sep) {
|
|
QStringList lst;
|
|
QString next;
|
|
int start = 0, end;
|
|
|
|
while ((end = line.indexOf(sep, start)) != -1) {
|
|
next = line.mid(start, end - start).trimmed();
|
|
lst << next;
|
|
start = end + 1;
|
|
}
|
|
next = line.mid(start, end - start).trimmed();
|
|
lst << next;
|
|
|
|
return lst;
|
|
}
|
|
|
|
void Update::readyReadStandardOutput() {
|
|
QProcess *p = (QProcess *)sender();
|
|
QByteArray buf = p->readAllStandardOutput();
|
|
qCritical() << buf;
|
|
}
|
|
|
|
void Update::readyReadStandardError() {
|
|
QProcess *p = (QProcess *)sender();
|
|
QByteArray buf = p->readAllStandardError();
|
|
qCritical() << buf;
|
|
}
|
|
|
|
void Update::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
|
QProcess *p = (QProcess *)sender();
|
|
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
|
|
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
|
}
|
|
|
|
QStringList Update::getDcSoftAndHardWareVersion() {
|
|
if (m_hw) {
|
|
m_hw->dc_autoRequest(true);
|
|
QThread::sleep(1); // make sure the timer-slots are active
|
|
|
|
for (int i=0; i < 3; ++i) { // send explicit reuests to get
|
|
// current SW/HW-versions
|
|
m_hw->request_DC2_SWversion();
|
|
m_hw->request_DC2_HWversion();
|
|
QThread::sleep(1);
|
|
}
|
|
|
|
QString const &hwVersion = m_hw->dc_getHWversion().toLower().trimmed();
|
|
QString const &swVersion = m_hw->dc_getSWversion().toLower().trimmed();
|
|
|
|
m_hw->dc_autoRequest(false);
|
|
QThread::sleep(1); // make sure the timer-slots are inactive
|
|
|
|
if (!hwVersion.isEmpty() && !swVersion.isEmpty()) {
|
|
return QStringList() << hwVersion << swVersion;
|
|
}
|
|
}
|
|
|
|
return QStringList() << "DC HW-version not available"
|
|
<< "DC SW-version not available";
|
|
}
|
|
|
|
QString Update::getFileVersion(QString const& jsonFileName) {
|
|
// "version":"15.10.2023 14:55 02.00.06",
|
|
static const QRegularExpression re("^.*(\\\"[Vv]ersion\\\":)([\\s\\\"]{0,})([^,\\\"]{0,}).*$");
|
|
|
|
QString fileVersion("");
|
|
QFile inputFile(QDir::cleanPath(m_customerRepository + QDir::separator() + jsonFileName));
|
|
|
|
if (inputFile.exists()) {
|
|
if (inputFile.open(QIODevice::ReadOnly)) {
|
|
QTextStream in(&inputFile);
|
|
while (!in.atEnd()) {
|
|
QString line = in.readLine();
|
|
|
|
QRegularExpressionMatch match;
|
|
int idx = line.indexOf(re, 0, &match);
|
|
if (idx != -1) {
|
|
int const lastCaptured = match.lastCapturedIndex();
|
|
// the dc only sends 16 Byte
|
|
fileVersion = match.captured(lastCaptured);
|
|
fileVersion.truncate(16);
|
|
break;
|
|
}
|
|
}
|
|
inputFile.close();
|
|
}
|
|
} else {
|
|
// qCritical() << "ERROR" << inputFile.fileName() << "does not exist";
|
|
}
|
|
|
|
return fileVersion;
|
|
}
|
|
|
|
bool Update::checkDownloadedJsonVersions(QStringList const& jsonFileNames) {
|
|
|
|
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
|
|
|
|
uint8_t jsonNr = 0;
|
|
|
|
QString const &fName = jsonFileNames[i];
|
|
|
|
// send one request for every single version
|
|
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
|
// 6=printer template 1 ..... 36= template 32
|
|
|
|
if (fName.endsWith("conf.json")) {
|
|
jsonNr = 1;
|
|
} else
|
|
if (fName.endsWith("device.json")) {
|
|
jsonNr = 2;
|
|
} else
|
|
if (fName.endsWith("cash.json")) {
|
|
jsonNr = 3;
|
|
} else {
|
|
QRegularExpressionMatch match;
|
|
static const QRegularExpression re("^(.*print)([0-3][0-9])\\.json\\s*$");
|
|
int idx = fName.indexOf(re, 0, &match);
|
|
if (idx != -1) {
|
|
QString captured = match.captured(match.lastCapturedIndex());
|
|
bool ok = false;
|
|
int n = captured.toInt(&ok);
|
|
if (ok) {
|
|
// note: the '5' is correct
|
|
jsonNr = n + 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (jsonNr != 0) {
|
|
// send one request for every single version
|
|
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
|
// 5=printer template 1 ..... 36= template 32
|
|
|
|
m_hw->sys_requestJsonVersions(jsonNr);
|
|
QThread::msleep(500);
|
|
|
|
char buf[64];
|
|
memset(buf, 0x00, sizeof(buf));
|
|
m_hw->sys_getJsonVersions(jsonNr, buf);
|
|
buf[16] = '\0'; // the DC only handles 16 bytes
|
|
|
|
static const QByteArray cb(16, (char)0xff);
|
|
|
|
QString const installedVersion(QString::fromStdString(buf));
|
|
QString const fileVersion = getFileVersion(jsonFileNames[i]);
|
|
|
|
QFileInfo fi(jsonFileNames[i]);
|
|
|
|
qCritical() << endl;
|
|
qCritical() << " json request nr:" << jsonNr;
|
|
|
|
if (installedVersion == fileVersion) {
|
|
qCritical() << " json file:" << fi.fileName();
|
|
qCritical() << " installed version in DC:" << installedVersion;
|
|
} else
|
|
if (cb == QByteArray(buf) && fileVersion == "") {
|
|
qCritical() << "unknown json file (repo and DC):" << fi.fileName();
|
|
} else {
|
|
qCritical() << " json file:" << fi.fileName();
|
|
qCritical() << " installed version in DC:" << installedVersion;
|
|
qCritical() << " file version in repository:" << fileVersion;
|
|
}
|
|
|
|
} else {
|
|
qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QMap<QString, QString>
|
|
Update::getInstalledJsonVersions(QStringList const& jsonFileNames) {
|
|
QMap<QString, QString> map;
|
|
|
|
if (!m_hw) {
|
|
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
|
<< "ERROR!!! m_hw == nullptr";
|
|
return map;
|
|
}
|
|
|
|
int tries = 20;
|
|
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
|
|
// must deliver 'true', only then are all data from hwapi valid
|
|
if (--tries < 0) {
|
|
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
|
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED";
|
|
return map;
|
|
}
|
|
qCritical() << "(" << __func__ << ":" << __LINE__ << "):"
|
|
<< "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED (" << tries << ")";
|
|
m_hw->dc_autoRequest(true);
|
|
QThread::msleep(500);
|
|
}
|
|
|
|
for (QStringList::size_type i=0; i < jsonFileNames.size(); ++i) {
|
|
|
|
uint8_t jsonNr = 0;
|
|
|
|
QString const &fName = jsonFileNames[i];
|
|
|
|
// send one request for every single version
|
|
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
|
// 6=printer template 1 ..... 36= template 32
|
|
|
|
if (fName.endsWith("conf.json")) {
|
|
jsonNr = 1;
|
|
} else
|
|
if (fName.endsWith("device.json")) {
|
|
jsonNr = 2;
|
|
} else
|
|
if (fName.endsWith("cash.json")) {
|
|
jsonNr = 3;
|
|
} else {
|
|
QRegularExpressionMatch match;
|
|
static const QRegularExpression re("^(.*print)([0-3][0-9])\\.json\\s*$");
|
|
int idx = fName.indexOf(re, 0, &match);
|
|
if (idx != -1) {
|
|
QString captured = match.captured(match.lastCapturedIndex());
|
|
bool ok = false;
|
|
int n = captured.toInt(&ok);
|
|
if (ok) {
|
|
// note: use 5 (instead of 4 -> index has been shifted)
|
|
jsonNr = n + 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (jsonNr != 0) {
|
|
// send one request for every single version
|
|
// jsonNr=1...36, 1=config file (cust.Nr) 2=devices 3=cash 4=res.
|
|
// 5=printer template 1 ..... 36= template 32
|
|
|
|
m_hw->sys_requestJsonVersions(jsonNr);
|
|
QThread::msleep(500);
|
|
|
|
char buf[64];
|
|
memset(buf, 0x00, sizeof(buf));
|
|
m_hw->sys_getJsonVersions(jsonNr, buf);
|
|
buf[16] = '\0'; // the DC only handles 16 bytes
|
|
|
|
static const QByteArray cb(16, (char)0xff);
|
|
|
|
QString const installedVersion(QString::fromStdString(buf));
|
|
QString const fileVersion = getFileVersion(jsonFileNames[i]);
|
|
|
|
QFileInfo fi(jsonFileNames[i]);
|
|
|
|
if (cb == QByteArray(buf)) {
|
|
map.insert(fi.fileName(), "inst.vers.not.avail");
|
|
} else {
|
|
map.insert(fi.fileName(), installedVersion);
|
|
}
|
|
|
|
qCritical() << endl;
|
|
qCritical() << " json request nr:" << jsonNr;
|
|
|
|
if (installedVersion == fileVersion) {
|
|
qCritical() << " json file:" << fi.fileName();
|
|
qCritical() << " installed version in DC:" << installedVersion;
|
|
} else
|
|
if (cb == QByteArray(buf) && fileVersion == "") {
|
|
qCritical() << "unknown json file (repo and DC):" << fi.fileName();
|
|
} else {
|
|
qCritical() << " json file:" << fi.fileName();
|
|
qCritical() << " installed version in DC:" << installedVersion;
|
|
qCritical() << " file version in repository:" << fileVersion;
|
|
}
|
|
|
|
} else {
|
|
qCritical() << "CANNOT FIND JSON-NR FOR" << fName;
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
bool Update::doUpdate(int &displayIndex, QStringList const &filesToWorkOn) {
|
|
|
|
if (!m_hw) {
|
|
Utils::printInfoMsg("CA-PLUGIN NOT LOADED");
|
|
return false;
|
|
}
|
|
|
|
int tries = 20;
|
|
while ((m_sys_areDCdataValid = m_hw->sys_areDCdataValid()) == false) {
|
|
// must deliver 'true', only then are all data from hwapi valid
|
|
if (--tries < 0) {
|
|
Utils::printCriticalErrorMsg("ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED");
|
|
return false;
|
|
}
|
|
Utils::printCriticalErrorMsg("DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED");
|
|
m_hw->dc_autoRequest(true);
|
|
QThread::msleep(500);
|
|
}
|
|
|
|
bool res = false;
|
|
bool dcDownloadPossible = true;
|
|
|
|
QList<QString>::const_iterator it;
|
|
for (it = filesToWorkOn.cbegin(); it != filesToWorkOn.cend(); ++it) {
|
|
m_worker->startProgressLoop();
|
|
QString const &fToWorkOn = QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed());
|
|
if (fToWorkOn.endsWith("/dc2c.bin") && dcDownloadPossible) {
|
|
#if 0
|
|
// download for dc possible only once
|
|
// download of device-controller should always be the last step
|
|
dcDownloadPossible = false;
|
|
|
|
if (!m_hw->dcDownloadRequest(fToWorkOn)) { // initiate download process
|
|
qCritical() << "DOWNLOAD-REQUEST-ERROR FOR" << fToWorkOn;
|
|
continue;
|
|
}
|
|
|
|
QThread::sleep(2);
|
|
|
|
int tries = 5;
|
|
while (!m_hw->dcDownloadRunning()) { // may take some time
|
|
if (--tries < 0) {
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") DOWNLOAD NOT RUNNING";
|
|
break;
|
|
}
|
|
QThread::sleep(1);
|
|
continue;
|
|
}
|
|
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") DOWNLOAD RUNNING";
|
|
|
|
QThread::sleep(2);
|
|
|
|
tries = 5;
|
|
while (!m_hw->dcDownloadReportThreadStart()) { // may take some time
|
|
if (--tries < 0) {
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") REPORT THREAD NOT STARTED";
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") REPORT THREAD STARTED";
|
|
|
|
QThread::sleep(2);
|
|
|
|
tries = 5;
|
|
while (!m_hw->dcDownloadReportRunning()) { // may take some time
|
|
if (--tries < 0) {
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") DOWNLOAD REPORT NOT RUNNING";
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__ << ") DOWNLOAD REPORT RUNNING";
|
|
|
|
tries = 1200;
|
|
while (m_hw->dcDownloadReportRunning()) {
|
|
QThread::msleep(1000);
|
|
if (--tries < 0) {
|
|
qCritical() << QDateTime::currentDateTime().toString(Qt::ISODate)
|
|
<< "(" << __func__ << ":" << __LINE__
|
|
<< ") DOWNLOAD REPORT STILL RUNNING AFTER 20mins";
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
bool updateBinaryRes = true;
|
|
|
|
// CONSOLE()
|
|
#if 0
|
|
m_hw->dc_autoRequest(false);// default: turn auto-request setting off
|
|
QThread::sleep(1); // wait to be sure that there are no more
|
|
// commands sent to dc-hardware
|
|
|
|
if ((updateBinaryRes = updateBinary(fToWorkOn)) == true) {
|
|
|
|
// qCritical() << "downloaded binary" << fToWorkOn;
|
|
|
|
++displayIndex;
|
|
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(2, ' ') + QString(")")
|
|
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
|
Worker::UPDATE_STEP_DONE);
|
|
}
|
|
|
|
m_hw->dc_autoRequest(true); // turn auto-request setting on
|
|
|
|
// qInfo() << "SET AUTO-REQUEST=TRUE";
|
|
|
|
QStringList const &versions = Update::getDcSoftAndHardWareVersion();
|
|
if (versions.size() >= 2) {
|
|
if (updateBinaryRes == true) {
|
|
qInfo() << "dc-hardware-version (UPDATED)" << versions[0];
|
|
qInfo() << "dc-firmware-version (UPDATED)" << versions[1];
|
|
} else {
|
|
qInfo() << "dc-hardware-version (NOT UPDATED)" << versions[0];
|
|
qInfo() << "dc-firmware-version (NOT UPDATED)" << versions[1];
|
|
}
|
|
}
|
|
#endif
|
|
res = updateBinaryRes;
|
|
|
|
} else if (fToWorkOn.contains("DC2C_print", Qt::CaseInsensitive)
|
|
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
|
res = true;
|
|
int i = fToWorkOn.indexOf("DC2C_print", Qt::CaseInsensitive);
|
|
int const templateIdx = fToWorkOn.mid(i).midRef(10, 2).toInt();
|
|
if ((templateIdx < 1) || (templateIdx > 32)) {
|
|
qCritical() << "WRONG TEMPLATE INDEX" << templateIdx;
|
|
res = false;
|
|
} else {
|
|
if ((res = updatePrinterTemplate(templateIdx, fToWorkOn))) {
|
|
if (m_worker) {
|
|
QStringList lst(QString("DL:%1 (%2)").arg(QFileInfo(fToWorkOn).fileName()).arg(templateIdx));
|
|
m_worker->ISMAS(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_JSON_FILE_SUCCESS);
|
|
|
|
++displayIndex;
|
|
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
|
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
|
Worker::UPDATE_STEP_DONE);
|
|
}
|
|
}
|
|
}
|
|
} else if (fToWorkOn.contains("DC2C_cash", Qt::CaseInsensitive)
|
|
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
|
res = true;
|
|
if ((res = updateCashConf(fToWorkOn))) {
|
|
if (m_worker) {
|
|
QStringList lst(QString("DL:%1").arg(QFileInfo(fToWorkOn).fileName()));
|
|
m_worker->ISMAS(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_CASH_FILE_SUCCESS);
|
|
|
|
++displayIndex;
|
|
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
|
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
|
Worker::UPDATE_STEP_DONE);
|
|
}
|
|
}
|
|
} else if (fToWorkOn.contains("DC2C_conf", Qt::CaseInsensitive)
|
|
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
|
res = true;
|
|
if ((res= updateConfig(fToWorkOn))) {
|
|
if (m_worker) {
|
|
QStringList lst(QString("DL:%1").arg(QFileInfo(fToWorkOn).fileName()));
|
|
m_worker->ISMAS(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_CONFIG_FILE_SUCCESS);
|
|
|
|
++displayIndex;
|
|
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
|
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
|
Worker::UPDATE_STEP_DONE);
|
|
}
|
|
}
|
|
} else if (fToWorkOn.contains("DC2C_device", Qt::CaseInsensitive)
|
|
&& fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) {
|
|
res = true;
|
|
if ((res = updateDeviceConf(fToWorkOn))) {
|
|
if (m_worker) {
|
|
QStringList lst(QString("DL:%1").arg(QFileInfo(fToWorkOn).fileName()));
|
|
m_worker->ISMAS(lst) << (m_worker->CONSOLE(lst) << Worker::UPDATE_STEP::DOWNLOAD_DEVICE_FILE_SUCCESS);
|
|
|
|
++displayIndex;
|
|
emit m_worker->appendText(QString("\n(") + QString("%1").arg(displayIndex).rightJustified(3, ' ') + QString(")")
|
|
+ QString(" Update ") + QFileInfo(fToWorkOn).fileName(),
|
|
Worker::UPDATE_STEP_DONE);
|
|
}
|
|
}
|
|
} else {
|
|
qCritical() << "UNKNOWN JSON FILE NAME" << fToWorkOn;
|
|
res = false;
|
|
}
|
|
// m_worker->stopProgressLoop();
|
|
// m_worker->setProgress(100);
|
|
|
|
if (res == false) {
|
|
break;
|
|
}
|
|
} // for (it = openLines.cbegin(); it != openLines.end(); ++it) {
|
|
|
|
m_hw->dc_autoRequest(true); // ALWAYS turn autoRequest ON
|
|
qDebug() << "SET AUTO-REQUEST=TRUE";
|
|
|
|
return res;
|
|
}
|