From ccc1bf2a991a898b8b4d7f03436052812cf6eed9 Mon Sep 17 00:00:00 2001 From: Gerhard Hoffmann Date: Fri, 16 Jun 2023 16:51:30 +0200 Subject: [PATCH] Add functionality from hwapi to download device controller to dc-hardware --- update.cpp | 319 +++++++++++++++++++++++++++++++++++++++++++++++++---- update.h | 34 ++++-- 2 files changed, 323 insertions(+), 30 deletions(-) diff --git a/update.cpp b/update.cpp index e1bce05..c42979c 100644 --- a/update.cpp +++ b/update.cpp @@ -8,43 +8,82 @@ #include #include -#include "interfaces.h" -#include "DCPlugin/include/hwapi.h" +#include "plugins/interfaces.h" #include #include #include #include +#include +#include +#include #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(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 printTemplates{ nrOfTemplate }; QVector 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")) { diff --git a/update.h b/update.h index fb3864d..5ce8665 100644 --- a/update.h +++ b/update.h @@ -4,9 +4,10 @@ #include #include #include +#include +#include -#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 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