diff --git a/DownloadDCJsonFiles/update.cpp b/DownloadDCJsonFiles/update.cpp new file mode 100644 index 0000000..8b90456 --- /dev/null +++ b/DownloadDCJsonFiles/update.cpp @@ -0,0 +1,332 @@ +#include "update.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined (Q_OS_UNIX) || defined (Q_OS_LINUX) +#include "unistd.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define UPDATE_OPKG (1) +#define UPDATE_DC (0) + +static const QMap 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(); + exit(-1); + } + + qCritical() << "loadDCPlugin() plugin directory:" << plugInDir.absolutePath(); + qCritical() << "loadDCPlugin() plugin file name:" << pluginLoader.fileName(); + + if (!pluginLoader.isLoaded()) { + qCritical() << pluginLoader.errorString(); + exit(-2); + } + QObject *plugin = pluginLoader.instance(); + if (!plugin) { + qCritical() << "cannot start instance"; + exit(-3); + } + if (! (hw = qobject_cast(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; +} + +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(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_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 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() { + // unloadDCPlugin(); +} + +bool Update::doUpdate(QStringList const &filesToWorkOn) { + + 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-SLAVE-PLUGIN NOT CONNECTED"; + return false; + } + qCritical() << "ERROR!!! DC DATA NOT VALID -> CA-SLAVE-PLUGIN NOT CONNECTED (" << tries << ")"; + m_hw->dc_autoRequest(true); + QThread::msleep(500); + } + + bool res = false; + + QList::const_iterator it; + for (it = filesToWorkOn.cbegin(); it != filesToWorkOn.cend(); ++it) { + QString const &fToWorkOn = QDir::cleanPath(m_customerRepository + QDir::separator() + it->trimmed()); + 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))) { + qCritical() << + QString("DOWNLOADED PRINTER TEMPLATE %1 WITH INDEX=%2") + .arg(fToWorkOn) + .arg(templateIdx); + } + } + } else if (fToWorkOn.contains("DC2C_cash", Qt::CaseInsensitive) + && fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) { + res = true; + if ((res = updateCashConf(fToWorkOn))) { + qCritical() << QString("DOWNLOADED CASH TEMPLATE %1").arg(fToWorkOn); + } + } else if (fToWorkOn.contains("DC2C_conf", Qt::CaseInsensitive) + && fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) { + res = true; + if ((res= updateConfig(fToWorkOn))) { + qCritical() << QString("DOWNLOADED CONFIG TEMPLATE %1").arg(fToWorkOn); + } + } else if (fToWorkOn.contains("DC2C_device", Qt::CaseInsensitive) + && fToWorkOn.endsWith(".json", Qt::CaseInsensitive)) { + res = true; + if ((res = updateDeviceConf(fToWorkOn))) { + qCritical() << QString("DOWNLOADED DEVICE TEMPLATE %1").arg(fToWorkOn); + } + } else { + qCritical() << "UNKNOWN JSON FILE NAME" << fToWorkOn; + res = false; + } + } + + return res; +} + +bool Update::downloadJson(enum FileTypeJson type, + int templateIdx, + QString jsFileToSendToDC) const { + + 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) { + qCritical() << "SYS NOT READY FOR SENDING AFTER 5 SECONDS"; + break; + } + } + + bool ret = false; + QString msg; + lst.clear(); + if (ready) { + 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 + 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(':'); + */ + + ret = true; + } else { + qCritical() << QString("ERROR SEND JSON-FILE %1 TO DC").arg(file.fileName()); + } + } else { + qCritical() << QString("SIZE OF %1 TOO BIG (%2 BYTES)").arg(jsFileToSendToDC).arg(fi.size()); + } + } else { + qCritical() << QString("CAN NOT OPEN ") + jsFileToSendToDC + " FOR READING"; + } + } else { + qCritical() << (QString(jsFileToSendToDC) + " DOES NOT EXIST"); + } + } + + m_hw->dc_autoRequest(false); + qDebug() << "SET AUTO-REQUEST=FALSE"; + QThread::sleep(1); // make sure the auto-request flag is acknowledged + + return ret; +} + +bool Update::updatePrinterTemplate(int templateIdx, QString jsFile) const { + return downloadJson(FileTypeJson::PRINTER, templateIdx, jsFile); +} + +bool Update::updateConfig(QString jsFile) { + return downloadJson(FileTypeJson::CONFIG, 0, jsFile); +} + +bool Update::updateCashConf(QString jsFile) { + return downloadJson(FileTypeJson::CASH, 0, jsFile); +} + +bool Update::updateDeviceConf(QString jsFile) { + return downloadJson(FileTypeJson::DEVICE, 0, jsFile); +} diff --git a/DownloadDCJsonFiles/update.h b/DownloadDCJsonFiles/update.h new file mode 100644 index 0000000..6ab35b7 --- /dev/null +++ b/DownloadDCJsonFiles/update.h @@ -0,0 +1,105 @@ +#ifndef UPDATE_H_INCLUDED +#define UPDATE_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef PTU5 +#define SERIAL_PORT "ttymxc2" +#else +#define SERIAL_PORT "ttyUSB0" +#endif + +class Update : public QObject { + Q_OBJECT + + hwinf *m_hw = nullptr; + char const *m_serialInterface; + char const *m_baudrate; + QString m_customerRepository; + QString m_customerNrStr; + QString m_branchName; + QString m_pluginName; + QString m_workingDir; + bool m_maintenanceMode; + bool m_dryRun; + bool m_sys_areDCdataValid; + + static QPluginLoader pluginLoader; + +public: + enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; + enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; + + static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn); + static bool unloadDCPlugin(); + static QStringList split(QString line, QChar sep = ','); + + + explicit Update(QString customerRepository, + QString customerNrStr, + QString branchName, + QString plugInDir, + QString pluginName, + QString workingDir, + bool dryRun = false, + QObject *parent = nullptr, + char const *serialInterface = SERIAL_PORT, + char const *baudrate = "115200"); + + virtual ~Update() override; + + bool doUpdate(QStringList const &jsonFilesToDownload); + + bool updatePrinterTemplate(int templateIdx, QString fname) const; + bool updateConfig(QString jsFileToSendToDC); + bool updateCashConf(QString jsFileToSendToDC); + bool updateDeviceConf(QString jsFileToSendToDC); + + bool downloadJson(enum FileTypeJson type, int templateIdx, + QString jsFileToSendToDC) const; + +/* + bool checkDownloadedJsonVersions(QStringList const& jsonFileNames); + + hwinf *hw() { return m_hw; } + hwinf const *hw() const { return m_hw; } + + //QString customerId() { return m_customerId; } + //QString const customerId() const { return m_customerId; } + + QString branchName() { return m_branchName; } + QString const branchName() const { return m_branchName; } + + //QString repositoryPath() { return m_repositoryPath; } + //QString const repositoryPath() const { return m_repositoryPath; } + +private: + static QString jsonType(enum FileTypeJson type); + bool openSerial(int br, QString baudrate, QString comPort) const; + void closeSerial() const; + bool isSerialOpen() const; + bool resetDeviceController() const; + QByteArray loadBinaryDCFile(QString filename) const; + bool downloadBinaryToDC(QString const &bFile) const; + bool updateBinary(QString const &fileToSendToDC); + QStringList getDcSoftAndHardWareVersion(); + QString getFileVersion(QString const& jsonFile); + +private slots: + void readyReadStandardOutput(); + void readyReadStandardError(); + void finished(int exitCode, QProcess::ExitStatus exitStatus); + void onReportDCDownloadStatus(QString const &status); + void onReportDCDownloadSuccess(QString const &msg); + void onReportDCDownloadFailure(QString const &errorMsg); +*/ +}; +#endif // UPDATE_H_INCLUDED