From 8fc88662d382e82824dbe208bd5b6f385901c1cd Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 21 Jun 2023 10:55:12 +0200 Subject: [PATCH 1/8] Add ATBMachineEvent class (QEvent) --- DCPlugin.pro | 2 + src/ATBAPP/ATBDeviceControllerPlugin.cpp | 5 +- src/ATBAPP/ATBDeviceControllerPlugin.h | 2 +- src/ATBAPP/ATBMachineEvent.cpp | 66 ++++++++++++++++++++++++ src/ATBAPP/ATBMachineEvent.h | 47 +++++++++++++++++ src/ATBAPP/DeviceControllerInterface.h | 8 ++- 6 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 src/ATBAPP/ATBMachineEvent.cpp create mode 100644 src/ATBAPP/ATBMachineEvent.h diff --git a/DCPlugin.pro b/DCPlugin.pro index ee20c98..d1abb70 100644 --- a/DCPlugin.pro +++ b/DCPlugin.pro @@ -73,11 +73,13 @@ HEADERS += \ src/ATBAPP/ATBAPPplugin.h \ src/ATBAPP/DeviceControllerInterface.h \ src/ATBAPP/ATBHealthEvent.h \ + src/ATBAPP/ATBMachineEvent.h \ src/ATBAPP/ATBDeviceControllerPlugin.h \ src/ATBAPP/Utils.h SOURCES += \ src/ATBAPP/ATBHealthEvent.cpp \ + src/ATBAPP/ATBMachineEvent.cpp \ src/ATBAPP/ATBDeviceControllerPlugin.cpp \ src/ATBAPP/Utils.cpp diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index e026cab..526c9d2 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -1,5 +1,6 @@ #include "src/ATBAPP/ATBDeviceControllerPlugin.h" #include "src/ATBAPP/ATBHealthEvent.h" +#include "src/ATBAPP/ATBMachineEvent.h" #include "src/ATBAPP/Utils.h" #include @@ -51,9 +52,9 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : ATBDeviceControllerPlugin::~ATBDeviceControllerPlugin() {} -PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *healthEventReceiver, const QSettings & settings) +PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, const QSettings & settings) { - this->healthEventReceiver = healthEventReceiver; + this->eventReceiver = eventReceiver; // read variables from setting QString serialPort = settings.value("DEVICE_CONTROLLER/serialPort", "ttymxc2").toString(); diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 177bbdd..4022b6c 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -90,7 +90,7 @@ private: PLUGIN_STATE pluginState; - QObject* healthEventReceiver; + QObject* eventReceiver; hwinf* hw; diff --git a/src/ATBAPP/ATBMachineEvent.cpp b/src/ATBAPP/ATBMachineEvent.cpp new file mode 100644 index 0000000..a7c10bb --- /dev/null +++ b/src/ATBAPP/ATBMachineEvent.cpp @@ -0,0 +1,66 @@ +/* Machine Event + * + * Used e.g. to send events to ISMAS + * + * Note: It's an Event, not a State! + * -> An Event may cause a transition to a different state, depending on the current state. + * -> Compare to edge/level trigger: Event is an "edge", State is a "level" + * => Do not mix both + * + */ +#include + +#include "ATBMachineEvent.h" + + +ATBMachineEvent::ATBMachineEvent( + const QString & id, + const QString & deviceName, // PTU/PRINTER/DC/... + EVENT_CLASS eventClass, // reason of event: Error/Warning/Alarm + const QString & name, // 'Event': "E001", "W003" + const int state, + const QString & parameter, + const QString & secondLevelInfo) + : QEvent(ATB_MACHINE_EVENT) + , eventId(id) + , deviceName(deviceName) + , machineEventClass(eventClass) + , eventName(name) + , eventState(state) + // timestamp including timezone offset + , timestamString(QDateTime::currentDateTime().toOffsetFromUtc( + QDateTime::currentDateTime().offsetFromUtc()).toString(Qt::ISODate) + ) + , parameterString(parameter) + , secondLevelInfoString(secondLevelInfo) +{ + +} + + +QString ATBMachineEvent::getEventClassString(EVENT_CLASS eventClass) +{ + switch (eventClass) { + case EVENT_CLASS::WARNING: + return "WARNING"; + break; + case EVENT_CLASS::ERROR: + return "ERROR"; + break; + case EVENT_CLASS::ALARM: + return "ALARM"; + break; + case EVENT_CLASS::DEBUG: + return "DEBUG"; + break; + case EVENT_CLASS::STATE: + return "STATE"; + break; + case EVENT_CLASS::NOT_DEFINED: + return "NOT_DEFINED"; + break; + } + + return "NOT_DEFINED"; +} + diff --git a/src/ATBAPP/ATBMachineEvent.h b/src/ATBAPP/ATBMachineEvent.h new file mode 100644 index 0000000..5f74b22 --- /dev/null +++ b/src/ATBAPP/ATBMachineEvent.h @@ -0,0 +1,47 @@ +#ifndef ATBMACHINECONDITIONEVENT_H +#define ATBMACHINECONDITIONEVENT_H + +#include +#include + +enum class EVENT_CLASS : quint8; + +const QEvent::Type ATB_MACHINE_EVENT = static_cast(QEvent::User + 2); + + +class ATBMachineEvent : public QEvent +{ + +public: + explicit ATBMachineEvent(const QString & id, + const QString & deviceName, // PTU/PRINTER/DC/... + EVENT_CLASS eventClass, // reason of event: Error/Warning/Alarm + const QString & name, // 'Event': "E001", "W003" + const int state, + const QString & parameter, + const QString & secondLevelInfo + ); + + QString eventId; + QString deviceName; + EVENT_CLASS machineEventClass; + QString eventName; + int eventState; + QString timestamString; + QString parameterString; + QString secondLevelInfoString; + + static QString getEventClassString(EVENT_CLASS eventClass); +}; + + +enum class EVENT_CLASS : quint8 { + WARNING, + ERROR, + ALARM, + DEBUG, + STATE, + NOT_DEFINED +}; + +#endif // ATBMACHINEEVENT_H diff --git a/src/ATBAPP/DeviceControllerInterface.h b/src/ATBAPP/DeviceControllerInterface.h index 72278ab..49d7497 100644 --- a/src/ATBAPP/DeviceControllerInterface.h +++ b/src/ATBAPP/DeviceControllerInterface.h @@ -24,7 +24,13 @@ class DeviceControllerInterface : public QObject public: virtual ~DeviceControllerInterface() {} - virtual nsDeviceControllerInterface::PLUGIN_STATE initDCPlugin(QObject *healthEventReceiver, + /** + * @brief initDCPlugin + * @param eventReceiver - QObject to receive ATBMachineEvents or HealthEvents + * @param settings + * @return + */ + virtual nsDeviceControllerInterface::PLUGIN_STATE initDCPlugin(QObject *eventReceiver, const QSettings & settings) = 0; // TASKS: Cash handling ------------------------------------------------------- From 6a19fd7608182675b49d22dfcead876349f996cf Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 08:44:16 +0200 Subject: [PATCH 2/8] Add class DeviceControllerDiag to supervise DeviceController state --- DCPlugin.pro | 2 + src/ATBAPP/ATBDeviceControllerPlugin.h | 5 + src/ATBAPP/DeviceControllerDiag.cpp | 373 +++++++++++++++++++++++++ src/ATBAPP/DeviceControllerDiag.h | 49 ++++ 4 files changed, 429 insertions(+) create mode 100644 src/ATBAPP/DeviceControllerDiag.cpp create mode 100644 src/ATBAPP/DeviceControllerDiag.h diff --git a/DCPlugin.pro b/DCPlugin.pro index d1abb70..8c31421 100644 --- a/DCPlugin.pro +++ b/DCPlugin.pro @@ -71,6 +71,7 @@ DEFINES += QT_DEPRECATED_WARNINGS HEADERS += \ include/interfaces.h \ src/ATBAPP/ATBAPPplugin.h \ + src/ATBAPP/DeviceControllerDiag.h \ src/ATBAPP/DeviceControllerInterface.h \ src/ATBAPP/ATBHealthEvent.h \ src/ATBAPP/ATBMachineEvent.h \ @@ -81,6 +82,7 @@ SOURCES += \ src/ATBAPP/ATBHealthEvent.cpp \ src/ATBAPP/ATBMachineEvent.cpp \ src/ATBAPP/ATBDeviceControllerPlugin.cpp \ + src/ATBAPP/DeviceControllerDiag.cpp \ src/ATBAPP/Utils.cpp DISTFILES += \ diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 4022b6c..3db8941 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -5,6 +5,8 @@ #include "src/ATBAPP/DeviceControllerInterface.h" #include "src/ATBAPP/ATBAPPplugin.h" +#include "src/ATBAPP/DeviceControllerDiag.h" + #include "version.h" @@ -94,6 +96,9 @@ private: hwinf* hw; + DeviceControllerDiag* diag; + + QTextCodec *codec; bool private_loadCashAgentLib(QString pluginName); diff --git a/src/ATBAPP/DeviceControllerDiag.cpp b/src/ATBAPP/DeviceControllerDiag.cpp new file mode 100644 index 0000000..ce6035e --- /dev/null +++ b/src/ATBAPP/DeviceControllerDiag.cpp @@ -0,0 +1,373 @@ +#include "DeviceControllerDiag.h" + +#include +#include +#include + +DeviceControllerDiag::DeviceControllerDiag(QObject *parent) + : QObject(parent) + , eventReceiver(nullptr) + , isRequestRunning(false) + , flagInterruptDiag(false) +{ + diagRequestTimeoutTimer = new QTimer(this); + diagRequestTimeoutTimer->setInterval(1000*20); // 20s + diagRequestTimeoutTimer->setSingleShot(true); + connect(diagRequestTimeoutTimer, &QTimer::timeout, this, &DeviceControllerDiag::onDiagRequestTimeoutTimerTimeout); +} + + +void DeviceControllerDiag::init(hwinf *hw, QObject* eventReceiver) +{ + this->hw = hw; + this->eventReceiver = eventReceiver; + + // make a system check on startup: + QTimer::singleShot(2000, this, &DeviceControllerDiag::diagRequest); +} + + +void DeviceControllerDiag::diagRequest() +{ + qCritical() << "DeviceControllerDiag::diagRequest()"; + + if (this->isRequestRunning) { + qCritical() << "DeviceControllerDiag::diagRequest() is already running"; + return; + } + this->isRequestRunning = true; + this->diagRequestTimeoutTimer->start(); + + this->private_startDiag(); +} + + +void DeviceControllerDiag::onDiagRequestTimeoutTimerTimeout() +{ + qCritical() << "DeviceControllerDiag::onDiagRequestTimeoutTimerTimeout()"; + this->flagInterruptDiag = true; +} + +void DeviceControllerDiag::private_startDiag() +{ + // check for DiagRequestTimeoutTimerTimeout: + if (this->flagInterruptDiag) { + qCritical() << "DeviceControllerDiag::private_startDiag() interrupted!"; + this->private_finishedDiag(0xff); + return; + } + + bool result; + result = hw->sys_areDCdataValid(); + + if (result) { + QTimer::singleShot(200, this, &DeviceControllerDiag::sys_superviseSystem); + } + else { + qCritical() << "DeviceControllerDiag::private_startDiag() DCdata is not valid"; + + + this->private_finishedDiag(0xfe); + + // try it again + // -> this results in a seg. fault after ~10 loops! + //QTimer::singleShot(200, this, &DeviceControllerDiag::private_startDiag); + } +} + +void DeviceControllerDiag::sys_superviseSystem() +{ // this function proofs if vending is possible depending of doors state + + struct T_dynamicCondition *dynMaCond=0; + struct T_moduleCondition *modCond=0; + + // check for DiagRequestTimeoutTimerTimeout: + if (this->flagInterruptDiag) { + qCritical() << "DeviceControllerDiag::sys_superviseSystem() interrupted!"; + this->private_finishedDiag(0xff); + return; + } + + if (!hw->sys_areDCdataValid()) + { + // es gibt keinerlei gültige Daten vom DC + qCritical() << "DeviceControllerDiag::sys_superviseSystem() no valid data!"; + this->private_finishedDiag(0xfe); + return; + } + + // jetzt sind die DC-Daten aktuell, also reinholen: + hw->sys_getDynMachineConditions(dynMaCond); + hw->sys_getDeviceConditions(modCond); + + if (!modCond->allModulesChecked) + { + // noch keine Testergebnisse + if (dynMaCond->startupTestIsRunning) { + // TODO? + } + + QTimer::singleShot(200, this, &DeviceControllerDiag::sys_superviseSystem); + return; + } + + // all doors: 99: undefined 0:closed 1:open + if (dynMaCond->lowerDoor || dynMaCond->upperDoor) { + // Service or battery door is open, goto INTRUSION MODE + qCritical() << "DeviceControllerDiag::sys_superviseSystem() Service or battery door is open, goto INTRUSION MODE"; + this->private_finishedDiag(0xFD); + return; + } + if (dynMaCond->middleDoor) { + // vault door is open, goto INTRUSION MODE + qCritical() << "DeviceControllerDiag::sys_superviseSystem() vault door is open, goto INTRUSION MODE"; + this->private_finishedDiag(0xFE); + return; + } + + uint8_t proposedError = sub_componentAssessment(); + if (proposedError) { + // All doors are closed but errors found, goto OOO MODE (out-of-order) + qCritical() << "DeviceControllerDiag::sys_superviseSystem() All doors are closed but errors found, goto OOO MODE (out-of-order)"; + this->private_finishedDiag(proposedError); + return; + } + + // everything fine + qCritical() << "DeviceControllerDiag::sys_superviseSystem() everything fine"; + this->private_finishedDiag(0x00); +} + + + +uint8_t DeviceControllerDiag::sub_componentAssessment() +{ + // this function decides if vending mode is possible, independant from door + // return >0 in case of error + + struct T_moduleCondition *modCond=0; + hw->sys_getDeviceConditions(modCond); + + struct T_dynamicCondition *dynMaCond=0; + hw->sys_getDynMachineConditions(dynMaCond); + + struct T_devices *devPara=0; + if (modCond->rtc>=200) + return 1; + if (modCond->printer==200 || modCond->printer==201) // 200: not connected 201: printer-HW-error 202: no paper + return 2; + if (modCond->printer==202) + return 3; + + if (modCond->coinBlocker>=200) + return 4; + if (modCond->mdbBus>=200) + return 5; + if (modCond->intEe>=200) + return 6; + + if (devPara->kindOfCoinChecker==1 || devPara->kindOfCoinChecker==2) // 0: without 1=EMP820 2=EMP900 3=currenza c² (MW) + { + if (modCond->coinChecker>=200 || modCond->coinEscrow>=200) + { + // Fehler Münzver. + return 7; + } + if (modCond->coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok + { + return 8; + } + } else + if (devPara->kindOfCoinChecker==3) + { + if (modCond->changer>=200) + { + // Fehler Münzver. + return 7; + } + if (modCond->coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok + { + return 8; + } + } + + if ( modCond->billReader>=200 && devPara->BillAcceptor>0) + { + // Fehler BNA + return 9; + } + + if (dynMaCond->onAlarm>0) + return 10; + + if (dynMaCond->modeAbrech>0) + return 11; + + if (dynMaCond->nowCardTest>0) + return 12; + + if (dynMaCond->startupTestIsRunning>0) + return 13; + + if (modCond->voltage>=200) + return 14; + if (modCond->temper>=200) + return 15; + + return 0; +} + + +uint8_t DeviceControllerDiag::sys_getSystemErrors() +{ + // 0: everything fine 1..15: errors + /* 1: real time clock error + 2: printer error + 3: no paper + 4: coin blocker + 5: mdb error + 6: mem error int.ee. + 7: error coin validator + 8: coin safe missed or full + 9: bill acceptor error + 10: alarm / intrusion + 11: cash box change is ongoing + 12: card test running + 13: startup-test is running + 14: voltage error + 15: temperature error + */ + return this->sub_componentAssessment(); +} + +/** + * @brief DeviceControllerDiag::private_finishedDiag + * @param result - result value from 'sub_componentAssessment()', + * - 0xFF on timer interrupt + * - 0xFE no valid data from DeviceController + * - 0xFD Service or battery door is open + * - 0xFE vault door is open + */ +void DeviceControllerDiag::private_finishedDiag(uint8_t result) +{ + this->diagRequestTimeoutTimer->stop(); + this->isRequestRunning = false; + this->flagInterruptDiag = false; + + if (result == 0) return; + + qCritical() << "DeviceControllerDiag::private_finishedDiag() result: " << result; + + + if (this->eventReceiver == nullptr) { + qCritical() << "DeviceControllerDiag: no eventReceiver"; + return; + } + + if (result > 15 && result != 0xFE) return; + + + // Errors are in this range 1...15: + QString eventId = QUuid::createUuid().toString(QUuid::WithoutBraces).mid(0, 8); + QString eventName; + EVENT_CLASS eventClass = EVENT_CLASS::STATE; + QString parameter; + switch (result) { + case 1: // real time clock error + eventName = "E001"; + eventClass = EVENT_CLASS::ERROR; + parameter = "real time clock error"; + break; + case 2: // printer error + eventName = "E002"; + eventClass = EVENT_CLASS::ERROR; + parameter = "printer error"; + break; + case 3: // no paper + eventName = "E003"; + eventClass = EVENT_CLASS::ERROR; + parameter = "no paper"; + break; + case 4: // coin blocker + eventName = "E004"; + eventClass = EVENT_CLASS::ERROR; + parameter = "coin blocker"; + break; + case 5: // mdb error + eventName = "E005"; + eventClass = EVENT_CLASS::ERROR; + parameter = "mdb error"; + break; + case 6: // mem error int.ee. + eventName = "E006"; + eventClass = EVENT_CLASS::ERROR; + parameter = "mem error int.ee."; + break; + case 7: // error coin validator + eventName = "E007"; + eventClass = EVENT_CLASS::ERROR; + parameter = "error coin validator"; + break; + case 8: // coin safe missed or full + eventName = "E008"; + eventClass = EVENT_CLASS::ERROR; + parameter = "coin safe missed or full"; + break; + case 9: // bill acceptor error + eventName = "E009"; + eventClass = EVENT_CLASS::ERROR; + parameter = "bill acceptor error"; + break; + case 10: // alarm / intrusion + eventName = "E010"; + eventClass = EVENT_CLASS::ERROR; + parameter = "alarm / intrusion"; + break; + case 11: // cash box change is ongoing + eventName = "E011"; + eventClass = EVENT_CLASS::STATE; + parameter = "cash box change is ongoing"; + break; + case 12: // card test running + eventName = "E012"; + eventClass = EVENT_CLASS::STATE; + parameter = "card test running"; + break; + case 13: // startup-test is running + eventName = "E013"; + eventClass = EVENT_CLASS::STATE; + parameter = "startup-test is running"; + break; + case 14: // voltage error + eventName = "E014"; + eventClass = EVENT_CLASS::ERROR; + parameter = "voltage error"; + break; + case 15: // temperature error + eventName = "E015"; + eventClass = EVENT_CLASS::STATE; + parameter = "temperature error"; + break; + case 0xFE: // no valid data from DeviceController + eventName = "E254"; + eventClass = EVENT_CLASS::STATE; + parameter = "no valid data from DeviceController"; + break; + } + + + ATBMachineEvent *machineEvent = new ATBMachineEvent( + eventId, + "DC", + eventClass, + eventName, + 1, + parameter, + "" // second level info + ); + + //emit diagResponse(machineEvent); + + QCoreApplication::postEvent(eventReceiver, machineEvent); + +} diff --git a/src/ATBAPP/DeviceControllerDiag.h b/src/ATBAPP/DeviceControllerDiag.h new file mode 100644 index 0000000..f09bf6f --- /dev/null +++ b/src/ATBAPP/DeviceControllerDiag.h @@ -0,0 +1,49 @@ +#ifndef DEVICECONTROLLERDIAG_H +#define DEVICECONTROLLERDIAG_H + +#include +#include + +#include "ATBMachineEvent.h" +#include "interfaces.h" + +class DeviceControllerDiag : public QObject +{ + Q_OBJECT + +public: + DeviceControllerDiag(QObject *parent = nullptr); + + void init(hwinf* hw, QObject* eventReceiver); + +public slots: + void diagRequest(); + +signals: + void diagResponse(ATBMachineEvent* machineEvent); + + +private: + QObject *eventReceiver; + hwinf* hw; + + bool isRequestRunning; + bool flagInterruptDiag; + + QTimer *diagRequestTimeoutTimer; + + uint8_t sub_componentAssessment(); + uint8_t sys_getSystemErrors(); + +private slots: + void onDiagRequestTimeoutTimerTimeout(); + + void private_startDiag(); // diag entry method + void private_finishedDiag(uint8_t result); // diag exit method + + void sys_superviseSystem(); + + +}; + +#endif // DEVICECONTROLLERDIAG_H From 31f178b241dc199f53013d9d6df84c4a21b8cb34 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 08:46:18 +0200 Subject: [PATCH 3/8] Remove unused includes --- src/ATBAPP/ATBDeviceControllerPlugin.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 3db8941..074f08d 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -14,9 +14,6 @@ #include "interfaces.h" #include -#include -#include -#include class QTextCodec; From 4a7022fd008b0e8043869a252b15908287d05603 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 08:50:10 +0200 Subject: [PATCH 4/8] Use diag on closing doors --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 19 +++++++++++++------ src/ATBAPP/ATBDeviceControllerPlugin.h | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 526c9d2..ab0b676 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -10,13 +10,16 @@ #include #include #include +#include +#include #include -ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : - pluginState(PLUGIN_STATE::NOT_INITIALIZED) +ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) + : pluginState(PLUGIN_STATE::NOT_INITIALIZED) + , eventReceiver(nullptr) { this->setParent(parent); @@ -26,9 +29,6 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : return; } - - - //connect(dynamic_cast(hw), SIGNAL(hwapi_templatePrintFinished_OK()), this, SLOT(onPrintFinishedOK()), Qt::QueuedConnection); //connect(dynamic_cast(hw), SIGNAL(hwapi_templatePrintFinished_Err()), this, SLOT(onPrintFinishedERR()), Qt::QueuedConnection); @@ -46,6 +46,9 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : connect(dynamic_cast(hw), SIGNAL(hwapi_doorAllDoorsClosed()), this, SLOT(onAllDoorsClosed()), Qt::QueuedConnection); // check for errors, switch to mode IDLE + this->diag = new DeviceControllerDiag(this); + + this->currentSelectedTicketType = 0; this->currentCashState = CASH_STATE::CACHE_EMPTY; } @@ -74,7 +77,7 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con // text encoding for printer this->codec = QTextCodec::codecForName(printerEncoding); - + this->diag->init(this->hw, this->eventReceiver); this->pluginState = PLUGIN_STATE::INITIALIZED; @@ -271,6 +274,8 @@ void ATBDeviceControllerPlugin::onCBinAndAllDoorsClosed() { qCritical() << "ATBDeviceControllerPlugin::onCBinAndAllDoorsClosed()"; + this->diag->diagRequest(); + // TODO: Stop background task "ACCOUNT" QTimer::singleShot(2000, this, SIGNAL(requestModeIDLE())); @@ -695,6 +700,8 @@ const QString ATBDeviceControllerPlugin::getString(nsDeviceControllerInterface:: } + + /************************************************************************************************ * ... end */ diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 074f08d..24c78cc 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -39,7 +39,7 @@ public: // ---------------------------------------------------------------------------- // interface: - PLUGIN_STATE initDCPlugin(QObject *healthEventReceiver, const QSettings & settings); + PLUGIN_STATE initDCPlugin(QObject *eventReceiver, const QSettings & settings); // TASKS: Cash handling ------------------------------------------------------- void requestStartCashInput(const QString & amount); From a4d74ed0f74444e748bc97a90fd3618ac2941c1b Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 12:14:55 +0200 Subject: [PATCH 5/8] Update printing ticket (version 2.1) Use hwapi::prn_getPrintResult() to detect print result. --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 29 +++++++++++++++++++++--- src/ATBAPP/ATBDeviceControllerPlugin.h | 1 + 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index ab0b676..e55a044 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -407,15 +407,38 @@ void ATBDeviceControllerPlugin::onPrinterDataPrepared() { this->hw->prn_printKombiticket(this->currentSelectedTicketType); - // FAKE SIGNAL: - QTimer::singleShot(4000, this, SLOT(onPrintFinishedOK())); - + // note: calling prn_getPrintResult() immediately may result in wrong answer! + // We have to wait "about some seconds" until calling this function! + QTimer::singleShot(4000, this, SLOT(onPrinterWaitForPrinting())); // old: use printer templates: // this->currentTemplate = 1; // this->onPrinterPrintNextTemplate(); } +void ATBDeviceControllerPlugin::onPrinterWaitForPrinting() +{ + quint8 printerResult = this->hw->prn_getPrintResult(); + + switch (printerResult) { + case 0: // still printing + qCritical() << "--> printer: WaitForPrinting"; + QTimer::singleShot(2000, this, SLOT(onPrinterWaitForPrinting())); + break; + case 1: // printing finished, Ok + this->onPrintFinishedOK(); + break; + case 2: // printing finished, Error + this->onPrintFinishedERR(); + break; + default: + qCritical() << "DC Error: wait for printing"; + this->onPrintFinishedERR(); + break; + } + +} + void ATBDeviceControllerPlugin::onPrinterPrintNextTemplate() { diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 24c78cc..3586bcb 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -113,6 +113,7 @@ private slots: void onPrinterDataPrepared(); void onPrinterPrintNextTemplate(); + void onPrinterWaitForPrinting(); void onPrintFinishedOK(); void onPrintFinishedERR(); From ba3eabec2c71c694d4dfaebb6fd224cf50d87fcd Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 14:50:56 +0200 Subject: [PATCH 6/8] Execute diagRequest() on mode change to IDLE (i.e. after vending) --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index e55a044..486254a 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -100,6 +100,9 @@ void ATBDeviceControllerPlugin::onChangedProgramModeToSERVICE() void ATBDeviceControllerPlugin::onChangedProgramModeToIDLE() { //hw->dc_autoRequest(false); // <-- TODO: ??? + + this->diag->diagRequest(); + } void ATBDeviceControllerPlugin::onChangedProgramModeToOOO() From 9cd10bfed8f47c04d8df9f9b2d2e126206465ab0 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 14:52:34 +0200 Subject: [PATCH 7/8] Diag: first working version to detect some system errors Drawbacks: - has to be called extra, no events or signals - lot of integer result values (where are they documented? Mapping?) --- src/ATBAPP/DeviceControllerDiag.cpp | 87 ++++++++++++++++------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/src/ATBAPP/DeviceControllerDiag.cpp b/src/ATBAPP/DeviceControllerDiag.cpp index ce6035e..2801671 100644 --- a/src/ATBAPP/DeviceControllerDiag.cpp +++ b/src/ATBAPP/DeviceControllerDiag.cpp @@ -61,25 +61,26 @@ void DeviceControllerDiag::private_startDiag() result = hw->sys_areDCdataValid(); if (result) { + qCritical() << "DeviceControllerDiag::private_startDiag() DCdata is valid"; QTimer::singleShot(200, this, &DeviceControllerDiag::sys_superviseSystem); } else { - qCritical() << "DeviceControllerDiag::private_startDiag() DCdata is not valid"; - - - this->private_finishedDiag(0xfe); + qCritical() << "DeviceControllerDiag::private_startDiag() DCdata is +++not+++ valid"; // try it again - // -> this results in a seg. fault after ~10 loops! - //QTimer::singleShot(200, this, &DeviceControllerDiag::private_startDiag); + QTimer::singleShot(200, this, &DeviceControllerDiag::private_startDiag); } } void DeviceControllerDiag::sys_superviseSystem() { // this function proofs if vending is possible depending of doors state - struct T_dynamicCondition *dynMaCond=0; - struct T_moduleCondition *modCond=0; + struct T_dynamicCondition dynMaCond; + struct T_moduleCondition modCond; + + + qCritical() << " sys_superviseSystem()"; + // check for DiagRequestTimeoutTimerTimeout: if (this->flagInterruptDiag) { @@ -97,34 +98,40 @@ void DeviceControllerDiag::sys_superviseSystem() } // jetzt sind die DC-Daten aktuell, also reinholen: - hw->sys_getDynMachineConditions(dynMaCond); - hw->sys_getDeviceConditions(modCond); + hw->sys_getDynMachineConditions(&dynMaCond); + hw->sys_getDeviceConditions(&modCond); - if (!modCond->allModulesChecked) + qCritical() << "DeviceControllerDiag::sys_superviseSystem() get condition data"; + if (!modCond.allModulesChecked) { // noch keine Testergebnisse - if (dynMaCond->startupTestIsRunning) { + if (dynMaCond.startupTestIsRunning) { // TODO? } + + qCritical() << " allModulesChecked is false --> call again"; + QTimer::singleShot(200, this, &DeviceControllerDiag::sys_superviseSystem); return; } // all doors: 99: undefined 0:closed 1:open - if (dynMaCond->lowerDoor || dynMaCond->upperDoor) { + if (dynMaCond.lowerDoor || dynMaCond.upperDoor) { // Service or battery door is open, goto INTRUSION MODE qCritical() << "DeviceControllerDiag::sys_superviseSystem() Service or battery door is open, goto INTRUSION MODE"; this->private_finishedDiag(0xFD); return; } - if (dynMaCond->middleDoor) { + if (dynMaCond.middleDoor) { // vault door is open, goto INTRUSION MODE qCritical() << "DeviceControllerDiag::sys_superviseSystem() vault door is open, goto INTRUSION MODE"; - this->private_finishedDiag(0xFE); + this->private_finishedDiag(0xFC); return; } + qCritical() << " --> call sub_componentAssessment()"; + uint8_t proposedError = sub_componentAssessment(); if (proposedError) { // All doors are closed but errors found, goto OOO MODE (out-of-order) @@ -145,73 +152,75 @@ uint8_t DeviceControllerDiag::sub_componentAssessment() // this function decides if vending mode is possible, independant from door // return >0 in case of error - struct T_moduleCondition *modCond=0; - hw->sys_getDeviceConditions(modCond); + struct T_moduleCondition modCond; + hw->sys_getDeviceConditions(&modCond); - struct T_dynamicCondition *dynMaCond=0; - hw->sys_getDynMachineConditions(dynMaCond); + struct T_dynamicCondition dynMaCond; + hw->sys_getDynMachineConditions(&dynMaCond); - struct T_devices *devPara=0; - if (modCond->rtc>=200) + struct T_devices devPara; + hw->sys_restoreDeviceParameter(&devPara); + + if (modCond.rtc>=200) return 1; - if (modCond->printer==200 || modCond->printer==201) // 200: not connected 201: printer-HW-error 202: no paper + if (modCond.printer==200 || modCond.printer==201) // 200: not connected 201: printer-HW-error 202: no paper return 2; - if (modCond->printer==202) + if (modCond.printer==202) return 3; - if (modCond->coinBlocker>=200) + if (modCond.coinBlocker>=200) return 4; - if (modCond->mdbBus>=200) + if (modCond.mdbBus>=200) return 5; - if (modCond->intEe>=200) + if (modCond.intEe>=200) return 6; - if (devPara->kindOfCoinChecker==1 || devPara->kindOfCoinChecker==2) // 0: without 1=EMP820 2=EMP900 3=currenza c² (MW) + if (devPara.kindOfCoinChecker==1 || devPara.kindOfCoinChecker==2) // 0: without 1=EMP820 2=EMP900 3=currenza c² (MW) { - if (modCond->coinChecker>=200 || modCond->coinEscrow>=200) + if (modCond.coinChecker>=200 || modCond.coinEscrow>=200) { // Fehler Münzver. return 7; } - if (modCond->coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok + if (modCond.coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok { return 8; } } else - if (devPara->kindOfCoinChecker==3) + if (devPara.kindOfCoinChecker==3) { - if (modCond->changer>=200) + if (modCond.changer>=200) { // Fehler Münzver. return 7; } - if (modCond->coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok + if (modCond.coinSafe>200) // 200: kasse fehlt 201: voll 100:fast voll 1:ok { return 8; } } - if ( modCond->billReader>=200 && devPara->BillAcceptor>0) + if ( modCond.billReader>=200 && devPara.BillAcceptor>0) { // Fehler BNA return 9; } - if (dynMaCond->onAlarm>0) + if (dynMaCond.onAlarm>0) return 10; - if (dynMaCond->modeAbrech>0) + if (dynMaCond.modeAbrech>0) return 11; - if (dynMaCond->nowCardTest>0) + if (dynMaCond.nowCardTest>0) return 12; - if (dynMaCond->startupTestIsRunning>0) + if (dynMaCond.startupTestIsRunning>0) return 13; - if (modCond->voltage>=200) + if (modCond.voltage>=200) return 14; - if (modCond->temper>=200) + if (modCond.temper>=200) return 15; return 0; From 80112f23b4cccdba9b375378127b417954d71e5a Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 22 Jun 2023 14:54:54 +0200 Subject: [PATCH 8/8] Simulate Account (-> because DeviceController ... ... functions currently do not provide usefull results. --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 486254a..d89fb54 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -199,6 +199,10 @@ void ATBDeviceControllerPlugin::private_checkAccountData() // cannot get accountData within ~10*500ms qCritical() << "checkAccountData() failed"; + // simulate: + this->private_getAccountData(); + + // TODO: create and send an HealthEvent... } } @@ -220,6 +224,9 @@ void ATBDeviceControllerPlugin::private_getAccountData() int numberOfCoinVariants = sizeof(retVR.coinsInVault); + // DEBUG + qCritical() << " NumberOfCoinVariants = " << numberOfCoinVariants; + // limit numberOfCoinVariants: if (numberOfCoinVariants > 16) { numberOfCoinVariants = 16; }