Compare commits

...

31 Commits
2.1.0 ... 2.4.0

Author SHA1 Message Date
a43af8ab86 Print ticket-number on ticket 2024-08-07 15:29:12 +02:00
d7443974e2 requestPrintTicket() add new product names 2024-07-23 14:36:45 +02:00
346c953175 Print ticket FREE_TICKET 2024-07-23 11:01:13 +02:00
8cf6897a21 FREE_TICKET defaults to templates 24, 25, 26 2024-07-23 11:00:03 +02:00
69eb87e358 DeviceController Interface 1.1.6 (Ticket Variant FREE_TICKET) 2024-07-23 10:58:56 +02:00
8eab11479c Merge branch 'pu/klaipeda' into pu/integration 2024-07-15 15:30:54 +02:00
ac93e9e631 Send W255 on restart CArun 2024-07-15 11:09:37 +02:00
c1dd20ec4f Restart carun on consecutive E255 2024-07-15 11:09:28 +02:00
2d60a7bd5c Send W255 on restart CArun 2024-07-15 10:08:56 +02:00
6d7d9ade70 Restart carun on consecutive E255 2024-07-15 10:03:41 +02:00
72dbc8b858 Print receipt: encode QString 2024-06-27 11:55:35 +02:00
32d70abf44 Proposal for usage of TICKET_VARIANT::FINE_PAYMENT 2024-06-27 11:48:16 +02:00
c076090e03 DeviceController Interface 1.1.5 (Ticket Variant FINE_PAYMENT) 2024-06-27 11:46:40 +02:00
6c2717c56b Diag: check doors in sub_componentAssessment ...
... this prevents sending Operate "O000" in case of an opend door and
enables sending Operate "O000" after closing all doors because
'lastResult' has not changed.
2024-06-11 09:27:07 +02:00
816182c87b Diag: restart on E255 2024-06-03 12:49:33 +02:00
492d3a107a Diag: set timeout for diagRequest from config ...
Option: "ATBDeviceControllerPlugin/diagTimeout"
 Description: Timeout for diagRequest in seconds.
 Default value: 45s
2024-06-03 12:09:34 +02:00
962cd01eac Re-enable sending DC-State after closing doors 2024-06-03 11:53:58 +02:00
d66363da46 Diag: Temperatur warning: E004 (Error) -> W004 (Warning) 2024-05-27 13:16:28 +02:00
7b25f86d6b CoinEscrow error is considered a warning (W010) 2024-05-17 14:08:07 +02:00
5a999a0494 Comment: proposal: MachineEvents with JSON-Parameter 2024-05-16 17:38:03 +02:00
ec18ac45e4 Send diagEvent E255 as ERROR 2024-05-16 17:37:29 +02:00
560b6d3221 Print: count undefined print result values and retry 2024-05-16 15:21:25 +02:00
b946dc5a92 T_dynData: do not dynamically create struct 2024-05-16 15:18:30 +02:00
ea7542a248 DiagRequest: start also on wakeupSimulation (mains powered machines) 2024-04-11 12:40:02 +02:00
4541699ec3 Load/init libCA in plugin init method (not in contructor) 2024-03-20 11:43:31 +01:00
87d50a05dd Check error-state if doors are closed 2024-03-19 13:43:45 +01:00
379a5d4e3e Diag: track ErrorState 2024-03-19 13:43:01 +01:00
6a08cf0b62 Implement new interface method sendDeviceParameter() 2024-03-18 17:02:49 +01:00
849305bc8f Update DeviceControllerInterface 1.1.4 2024-03-18 17:01:50 +01:00
a5c900b9fe Fix: send operate 2024-03-15 13:40:16 +01:00
70b488de66 Diag: send operate (O000) only if State has changed 2024-03-12 16:20:39 +01:00
7 changed files with 385 additions and 67 deletions

View File

@@ -30,13 +30,31 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent)
this->setParent(parent);
this->pluginInfo = QString::fromUtf8(pluginInfoString.c_str());
}
ATBDeviceControllerPlugin::~ATBDeviceControllerPlugin() {}
PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, const QSettings & settings)
{
this->eventReceiver = eventReceiver;
// read variables from setting
this->serialPortName = settings.value("ATBDeviceControllerPlugin/serialPort", "ttymxc2").toString();
QByteArray printerEncoding = settings.value("ATBDeviceControllerPlugin/printerEncoding", "ISO 8859-2").toString().toLatin1();
QString printerLocaleString = settings.value("ATBDeviceControllerPlugin/printerLocale", "de_DE").toString().toLatin1();
this->printerLocale = QLocale(printerLocaleString);
if (!this->private_loadCashAgentLib("")) {
return;
}
this->init_sc_dbus();
QString persistentDataFile = "/mnt/system_data/dc_persistentData.dat";
this->persistentData = new PersistentData(persistentDataFile);
// setup libCA:
if (!this->private_loadCashAgentLib("")) {
return PLUGIN_STATE::NOT_INITIALIZED;
}
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_OK()), this, SLOT(onPrintFinishedOK()), Qt::QueuedConnection);
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_Err()), this, SLOT(onPrintFinishedERR()), Qt::QueuedConnection);
@@ -61,12 +79,11 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent)
dynamic_cast<QObject*>(hw)->moveToThread(hwThread);
hwThread->start();
QString persistentDataFile = "/mnt/system_data/dc_persistentData.dat";
this->persistentData = new PersistentData(persistentDataFile);
this->diag = new DeviceControllerDiag(this->persistentData, this);
connect(this->diag, &DeviceControllerDiag::newVoltage, this, &ATBDeviceControllerPlugin::onNewVoltage);
int diagTimeout = settings.value("ATBDeviceControllerPlugin/diagTimeout", "45").toInt();
this->diag->setTimeout(diagTimeout);
// currentSelectedTicketType - number of used "Kombiticket" (deprecated) use TICKET_VARIANT in future
this->currentSelectedTicketType = 0;
@@ -75,19 +92,7 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent)
this->currentCashState = CASH_STATE::CACHE_EMPTY;
this->cashStartAmountInt = 0;
}
ATBDeviceControllerPlugin::~ATBDeviceControllerPlugin() {}
PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, const QSettings & settings)
{
this->eventReceiver = eventReceiver;
// read variables from setting
this->serialPortName = settings.value("ATBDeviceControllerPlugin/serialPort", "ttymxc2").toString();
QByteArray printerEncoding = settings.value("ATBDeviceControllerPlugin/printerEncoding", "ISO 8859-2").toString().toLatin1();
QString printerLocaleString = settings.value("ATBDeviceControllerPlugin/printerLocale", "de_DE").toString().toLatin1();
this->printerLocale = QLocale(printerLocaleString);
if (this->isMaster) {
@@ -134,6 +139,37 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con
}
void ATBDeviceControllerPlugin::sendDeviceParameter(const QJsonObject &jsonObject)
{
qCritical() << "ATBDeviceControllerPlugin::sendDeviceParameter:";
// extract location info and store location info in persistent data:
QJsonValue jsonSubVal;
jsonSubVal = jsonObject["Location"];
QString locationString = jsonSubVal.toString("");
if (locationString == "") {
qCritical() << " --> locationString NULL";
return;
}
uint16_t customerNr = PTUSystem::readCustomerNumber();
uint16_t machineNr = PTUSystem::readMachineNumber();
uint16_t borough = PTUSystem::readZoneNumber();
uint16_t zone = PTUSystem::readGroupNumber();
uint16_t alias = 0;
QByteArray locationBa = locationString.toLocal8Bit();
this->hw->sendMachineID(customerNr, machineNr, borough, zone, alias, locationBa.data());
}
void ATBDeviceControllerPlugin::startPhysicalLayer()
{
if (!this->isMaster) return;
@@ -196,20 +232,20 @@ void ATBDeviceControllerPlugin::reset()
// Handle Mode-Changes --------------------------------------------------------
void ATBDeviceControllerPlugin::onChangedProgramModeToSELL()
{
{
hw->dc_autoRequest(true);
hw->rtc_setDateTime();
hw->mdb_switchWake(0); // wakeup MDB components
}
void ATBDeviceControllerPlugin::onChangedProgramModeToSERVICE()
{
{
hw->dc_autoRequest(true);
hw->mdb_switchWake(0); // wakeup MDB components
}
void ATBDeviceControllerPlugin::onChangedProgramModeToIDLE()
{
{
hw->dc_autoRequest(true);
this->diag->diagRequest();
hw->mdb_switchWake(1);
@@ -506,6 +542,8 @@ void ATBDeviceControllerPlugin::onCBinAndAllDoorsClosed()
{
qCritical() << "ATBDeviceControllerPlugin::onCBinAndAllDoorsClosed()";
this->diag->diagReInit();
QTimer::singleShot(2000, this, SIGNAL(requestModeIDLE()));
this->dbus->finishedBackgroundTask("DOOR_OPEN");
@@ -519,10 +557,14 @@ void ATBDeviceControllerPlugin::onAllDoorsClosed()
{
qCritical() << "ATBDeviceControllerPlugin::onAllDoorsClosed()";
emit this->requestModeIDLE();
this->dbus->finishedBackgroundTask("DOOR_OPEN");
if (this->diag->isErrorState()) {
emit this->requestModeOOO();
}
else {
emit this->requestModeIDLE();
}
// TODO: check for errors and create a machine event
this->dbus->finishedBackgroundTask("DOOR_OPEN");
}
void ATBDeviceControllerPlugin::onNewVoltage(uint32_t voltage)
@@ -612,10 +654,22 @@ void ATBDeviceControllerPlugin::requestPrintReceipt(const QHash<QString, QVarian
void ATBDeviceControllerPlugin::requestPrintReceipt(const QString & printingString)
{
QByteArray ba = printingString.toUtf8();
QByteArray ba_receipt = this->codec->fromUnicode(printingString);
//QByteArray ba = printingString.toUtf8();
hw->prn_switchPower(true);
hw->prn_setFonts(8,12,0,0);
hw->prn_sendText(&ba);
hw->prn_sendText(&ba_receipt);
// DEBUG
//qCritical() << "---------------------------------------------------------------";
//qCritical() << "ATBDeviceControllerPlugin::requestPrintReceipt()";
//qCritical() << " receipt data:";
//qCritical() << QString(ba_receipt);
//qCritical() << "---------------------------------------------------------------";
this->printResultCheckCounter = 0;
QTimer::singleShot(4000, this, SLOT(onPrinterWaitForPrintingReceipt()));
//QTimer::singleShot(2000, this, [this](){ hw->prn_cut(3); } );
@@ -664,14 +718,16 @@ void ATBDeviceControllerPlugin::onPrinterWaitForPrintingReceipt()
void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant> & printingData)
{
struct T_dynDat *dynTicketData = new T_dynDat;
struct T_dynDat dynamicTicketData;
struct T_dynDat *dynTicketData = &dynamicTicketData;
memset(dynTicketData, 0, sizeof(*dynTicketData));
qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket( " << endl
<< " licenseplate = " << printingData["licenseplate"] << endl
<< " amount = " << printingData["amount"] << endl
<< " parkingEnd = " << printingData["parkingEnd"] << endl
<< " currentDateTime = " << printingData["currentDateTime"] << endl;
<< " currentDateTime = " << printingData["currentDateTime"] << endl
<< " ticketNumber = " << printingData["ticketNumber"] << endl;
QDateTime parkingEndDateTime = QDateTime::fromString(printingData["parkingEnd"].toString(), Qt::ISODate);
QDateTime currentDateTime = QDateTime::fromString(printingData["currentDateTime"].toString(), Qt::ISODate);
@@ -703,6 +759,10 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
QByteArray ba_currentDate = codec->fromUnicode(currentDateString);
memcpy((char*)dynTicketData->currentDate, ba_currentDate.data(), std::min(ba_currentDate.size(),8));
// Ticket-Number
QByteArray ba_ticketNumber = codec->fromUnicode(printingData["ticketNumber"].toString());
memcpy((char*)dynTicketData->dynDat7, ba_ticketNumber.data(), std::min(ba_ticketNumber.size(),8));
// DEBUG
/*
@@ -736,7 +796,8 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
<< " amount = " << printingData["amount"] << endl
<< " parkingEnd = " << printingData["parkingEnd"] << endl
<< " currentTime = " << printingData["currentTime"] << endl
<< " currentDate = " << printingData["currentDate"] << endl;
<< " currentDate = " << printingData["currentDate"] << endl
<< " ticketNumber = " << printingData["ticketNumber"] << endl;
this->onPrintFinishedERR();
@@ -757,19 +818,39 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
QString paymentType = printingData["paymentType"].toString(); // must be "CASH" | "CARD"
QString productName = printingData["product"].toString(); // must be "ShortTimeParking" | "DayTicket"
if ( (paymentType == "CASH") && (productName == "SHORT_TERM_PARKING") ) {
if ( (paymentType == "CASH") && ( (productName == "SHORT_TERM_PARKING") ||
(productName == "SHORT_TERM_PARKING_CAR") ||
(productName == "SHORT_TERM_PARKING_VAN") ||
(productName == "SHORT_TERM_PARKING_CAMPER")
))
{
this->currentSelectedTicketType = 1; // "Kombiticket #1"
}
else
if ( (paymentType == "CARD") && (productName == "SHORT_TERM_PARKING") ) {
if ( (paymentType == "CARD") && ( (productName == "SHORT_TERM_PARKING") ||
(productName == "SHORT_TERM_PARKING_CAR") ||
(productName == "SHORT_TERM_PARKING_VAN") ||
(productName == "SHORT_TERM_PARKING_CAMPER")
))
{
this->currentSelectedTicketType = 2; // "Kombiticket #2"
}
else
if ( (paymentType == "CASH") && (productName == "DAY_TICKET") ) {
if ( (paymentType == "CASH") && ( (productName == "DAY_TICKET") ||
(productName == "DAY_TICKET_CAR") ||
(productName == "DAY_TICKET_VAN") ||
(productName == "DAY_TICKET_CAMPER")
))
{
this->currentSelectedTicketType = 3; // "Kombiticket #3"
}
else
if ( (paymentType == "CARD") && (productName == "DAY_TICKET") ) {
if ( (paymentType == "CARD") && ( (productName == "DAY_TICKET") ||
(productName == "DAY_TICKET_CAR") ||
(productName == "DAY_TICKET_VAN") ||
(productName == "DAY_TICKET_CAMPER")
))
{
this->currentSelectedTicketType = 4; // "Kombiticket #4"
}
else
@@ -805,6 +886,7 @@ void ATBDeviceControllerPlugin::onPrinterDataPrepared()
// note: calling prn_getPrintResult() immediately may result in wrong answer!
// We have to wait "about some seconds" until calling this function!
this->printResultCheckCounter = 0;
QTimer::singleShot(4000, this, SLOT(onPrinterWaitForPrintingTicket()));
// old: use printer templates:
@@ -828,8 +910,17 @@ void ATBDeviceControllerPlugin::onPrinterWaitForPrintingTicket()
this->onPrintFinishedERR();
break;
default:
qCritical() << "DC Error: wait for printing";
this->onPrintFinishedERR();
// result value is not defined (-> workaround for DC misbehaviour)
if (this->printResultCheckCounter < 10) {
this->printResultCheckCounter++;
qCritical() << "DC print result undefined: " << printerResult;
QTimer::singleShot(1000, this, SLOT(onPrinterWaitForPrintingTicket()));
}
else {
qCritical() << "DC Error: wait for printing";
this->onPrintFinishedERR();
}
break;
}
@@ -857,6 +948,7 @@ void ATBDeviceControllerPlugin::onPrinterPrintNextTemplate()
if (this->currentTicket->templateList()->isEmpty()) {
// all templates are printed
this->printResultCheckCounter = 0;
QTimer::singleShot(2000, this, SLOT(onPrinterWaitForPrintingTicket()));
}
else {
@@ -908,7 +1000,8 @@ void ATBDeviceControllerPlugin::onPrinterPrepareDynTemplateData()
}
void ATBDeviceControllerPlugin::prepareDynTemplateData()
{
struct T_dynDat *dynTicketData = new T_dynDat;
struct T_dynDat dynamicTicketData;
struct T_dynDat *dynTicketData = &dynamicTicketData;
memset(dynTicketData, 0, sizeof(*dynTicketData));
// setup dynTicketData dependent on currentTicket
@@ -927,12 +1020,18 @@ void ATBDeviceControllerPlugin::prepareDynTemplateData()
case nsDeviceControllerInterface::TICKET_VARIANT::STOP_RECEIPT:
private_setupDynTemplatData_STOP_RECEIPT(dynTicketData, this->currentTicket);
break;
case nsDeviceControllerInterface::TICKET_VARIANT::FINE_PAYMENT:
private_setupDynTemplatData_FINE_PAYMENT(dynTicketData, this->currentTicket);
break;
case nsDeviceControllerInterface::TICKET_VARIANT::RECEIPT:
break;
case nsDeviceControllerInterface::TICKET_VARIANT::ERROR_RECEIPT:
break;
case nsDeviceControllerInterface::TICKET_VARIANT::PARKING_TICKET:
break;
case nsDeviceControllerInterface::TICKET_VARIANT::FREE_TICKET:
private_setupDynTemplatData_FREE_TICKET(dynTicketData, this->currentTicket);
break;
case nsDeviceControllerInterface::TICKET_VARIANT::FOOD_STAMP:
private_setupDynTemplatData_FOOD_STAMP(dynTicketData, this->currentTicket);
break;
@@ -1035,6 +1134,62 @@ void ATBDeviceControllerPlugin::private_setupDynTemplatData_FOOD_STAMP(struct T_
qCritical() << "-------------------------------------------------------";
}
void ATBDeviceControllerPlugin::private_setupDynTemplatData_FINE_PAYMENT(struct T_dynDat *dynTicketData, Ticket *ticket)
{
QDateTime currentDateTime = QDateTime::fromString(ticket->getPrintingData()["currentDateTime"].toString(), Qt::ISODate);
QString currentDateString = this->printerLocale.toString(currentDateTime.date(), QLocale::ShortFormat);
// set dynamic printer data:
QByteArray ba_licenseplate = codec->fromUnicode(ticket->getPrintingData()["licenseplate"].toString());
memcpy((char*)dynTicketData->licensePlate, ba_licenseplate.data(), std::min(ba_licenseplate.size(),8));
QByteArray ba_amount = codec->fromUnicode(ticket->getPrintingData()["amount"].toString());
memcpy((char*)dynTicketData->vendingPrice, ba_amount.data(), std::min(ba_amount.size(),8)); // Szeged
memcpy((char*)dynTicketData->dynDat6, ba_amount.data(), std::min(ba_amount.size(),8)); // Schoenau
QByteArray ba_currentDate = codec->fromUnicode(currentDateString);
memcpy((char*)dynTicketData->currentDate, ba_currentDate.data(), std::min(ba_currentDate.size(),8));
QByteArray ba_ticketId = codec->fromUnicode(ticket->getPrintingData()["ticketId"].toString());
memcpy((char*)dynTicketData->dynDat7, ba_amount.data(), std::min(ba_ticketId.size(),8));
}
void ATBDeviceControllerPlugin::private_setupDynTemplatData_FREE_TICKET(struct T_dynDat *dynTicketData, Ticket *ticket)
{
QDateTime currentDateTime = QDateTime::fromString(ticket->getPrintingData()["currentDateTime"].toString(), Qt::ISODate);
QString currentDateString = this->printerLocale.toString(currentDateTime.date(), QLocale::ShortFormat);
// set dynamic printer data:
QByteArray ba_licenseplate = codec->fromUnicode(ticket->getPrintingData()["licenseplate"].toString());
memcpy((char*)dynTicketData->licensePlate, ba_licenseplate.data(), std::min(ba_licenseplate.size(),8));
QByteArray ba_amount = codec->fromUnicode(ticket->getPrintingData()["amount"].toString());
memcpy((char*)dynTicketData->vendingPrice, ba_amount.data(), std::min(ba_amount.size(),8)); // Szeged
memcpy((char*)dynTicketData->dynDat6, ba_amount.data(), std::min(ba_amount.size(),8)); // Schoenau
QByteArray ba_currentDate = codec->fromUnicode(currentDateString);
memcpy((char*)dynTicketData->currentDate, ba_currentDate.data(), std::min(ba_currentDate.size(),8));
// FREE_TICKET needs parking endtime:
QDateTime parkingEndDateTime = QDateTime::fromString(ticket->getPrintingData()["parkingEnd"].toString(), Qt::ISODate);
QByteArray ba_parkingEndTime = codec->fromUnicode(parkingEndDateTime.toString("hh:mm"));
memcpy((char*)dynTicketData->parkingEnd, ba_parkingEndTime.data(), std::min(ba_parkingEndTime.size(),8));
QString parkingEndDateString = this->printerLocale.toString(parkingEndDateTime.date(), QLocale::ShortFormat);
QByteArray ba_parkingEndDate = codec->fromUnicode(parkingEndDateString);
memcpy((char*)dynTicketData->currentTime, ba_parkingEndDate.data(), std::min(ba_parkingEndDate.size(),8));
// ! and yes... 'ParkingEndDate' is 'currentTime'
}
/************************************************************************************************
@@ -1466,7 +1621,7 @@ int ATBDeviceControllerPlugin::init_sc_dbus()
void ATBDeviceControllerPlugin::onWokeUp(uchar source)
{
if (source == 0x01) {
if (source == 0x01 || source == 0xFE) {
// woke up from device controller
this->diag->diagRequest();
}

View File

@@ -44,6 +44,8 @@ public:
// interface:
PLUGIN_STATE initDCPlugin(QObject *eventReceiver, const QSettings & settings);
void sendDeviceParameter(const QJsonObject & jsonObject);
// TASKS: Cash handling -------------------------------------------------------
void requestStartCashInput(const QString & amount);
void requestStopCashInput();
@@ -127,6 +129,9 @@ private:
// counts failed hw->log_chkIfVaultRecordAvailable()
int accountCheckCounter;
// counts faild hw->prn-getPrintResult()
int printResultCheckCounter;
// dbus
int init_sc_dbus();
@@ -139,6 +144,8 @@ private:
void private_setupDynTemplateData_START_RECEIPT(struct T_dynDat *dynTicketData, Ticket *ticket);
void private_setupDynTemplatData_STOP_RECEIPT(struct T_dynDat *dynTicketData, Ticket *ticket);
void private_setupDynTemplatData_FOOD_STAMP(struct T_dynDat *dynTicketData, Ticket *ticket);
void private_setupDynTemplatData_FINE_PAYMENT(struct T_dynDat *dynTicketData, Ticket *ticket);
void private_setupDynTemplatData_FREE_TICKET(struct T_dynDat *dynTicketData, Ticket *ticket);
// ---------------------------------------------------------------------------------------------
private slots:

View File

@@ -15,7 +15,7 @@ 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
EVENT_CLASS eventClass, // reason of event: Error/Warning/Alarm
const QString & name, // 'Event': "E001", "W003"
const int state,
const QString & parameter,

View File

@@ -5,6 +5,11 @@
#include <QUuid>
#include <QDebug>
#include <QProcess>
#include "support/JSON.h"
DeviceControllerDiag::DeviceControllerDiag(PersistentData *pData, QObject *parent)
: QObject(parent)
, coinProcessorType(nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW)
@@ -12,10 +17,13 @@ DeviceControllerDiag::DeviceControllerDiag(PersistentData *pData, QObject *paren
, eventReceiver(nullptr)
, isRequestRunning(false)
, flagInterruptDiag(false)
, lastState(DeviceController::State::INITIAL_STATE)
, _isErrorState(false)
, pData(pData)
, E255counter(0)
{
diagRequestTimeoutTimer = new QTimer(this);
diagRequestTimeoutTimer->setInterval(1000*20); // 20s
diagRequestTimeoutTimer->setInterval(1000*45);
diagRequestTimeoutTimer->setSingleShot(true);
connect(diagRequestTimeoutTimer, &QTimer::timeout, this, &DeviceControllerDiag::onDiagRequestTimeoutTimerTimeout);
}
@@ -31,6 +39,17 @@ void DeviceControllerDiag::init(hwinf *hw, QObject* eventReceiver)
}
void DeviceControllerDiag::diagReInit()
{
this->machineEventSet.clear();
this->_isErrorState = false;
}
void DeviceControllerDiag::setTimeout(int timeout)
{
this->diagRequestTimeoutTimer->setInterval(1000 * timeout);
}
void DeviceControllerDiag::diagRequest()
{
qCritical() << "DeviceControllerDiag::diagRequest()";
@@ -62,6 +81,24 @@ void DeviceControllerDiag::onDiagRequestTimeoutTimerTimeout()
this->flagInterruptDiag = true;
}
bool DeviceControllerDiag::isErrorState()
{
return this->_isErrorState;
}
bool DeviceControllerDiag::isOperatingState()
{
return !this->_isErrorState;
}
QSet<DeviceController::State> DeviceControllerDiag::getCurrentMachineState()
{
return this->machineEventSet;
}
void DeviceControllerDiag::private_startDiag()
{
// check for DiagRequestTimeoutTimerTimeout:
@@ -70,6 +107,20 @@ void DeviceControllerDiag::private_startDiag()
this->private_sendDiagEvent(DeviceController::State::E255);
this->isRequestRunning = false;
this->flagInterruptDiag = false;
if (this->E255counter > 5) {
this->restartCArun();
}
else {
this->E255counter++;
// try it again, until success:
QTimer::singleShot(400, this, &DeviceControllerDiag::diagRequest);
/**
* But please note:
* - diag does currently not stop suspend (start a background task)
* - diag is called again in ModeOOO wokeup()
*/
}
return;
}
@@ -104,6 +155,8 @@ void DeviceControllerDiag::sys_superviseSystem()
this->private_sendDiagEvent(DeviceController::State::E255);
this->flagInterruptDiag = false;
this->isRequestRunning = false;
if (this->E255counter > 5) { this->restartCArun(); }
else { this->E255counter++; }
return;
}
@@ -114,6 +167,8 @@ void DeviceControllerDiag::sys_superviseSystem()
this->private_sendDiagEvent(DeviceController::State::E254);
this->diagRequestTimeoutTimer->stop();
this->isRequestRunning = false;
if (this->E255counter > 5) { this->restartCArun(); }
else { this->E255counter++; }
return;
}
@@ -126,7 +181,7 @@ void DeviceControllerDiag::sys_superviseSystem()
{
// noch keine Testergebnisse
if (dynMaCond.startupTestIsRunning) {
// TODO?
qCritical() << " startupTestIsRunning --> call again";
}
@@ -136,18 +191,6 @@ void 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_sendDiagEvent(DeviceController::State::E253);
}
if (dynMaCond.middleDoor) {
// vault door is open, goto INTRUSION MODE
qCritical() << "DeviceControllerDiag::sys_superviseSystem() vault door is open, goto INTRUSION MODE";
this->private_sendDiagEvent(DeviceController::State::E252);
}
qCritical() << " --> call sub_componentAssessment()";
sub_componentAssessment();
@@ -181,6 +224,21 @@ void DeviceControllerDiag::sub_componentAssessment()
this->private_sendDiagEvent(DeviceController::State::A000);
}
// check for open doors
// all doors: 99: undefined 0:closed 1:open
if (dynMaCond.lowerDoor || dynMaCond.upperDoor) {
// Service or battery door is open
flag_sendOperate = false;
qCritical() << "DeviceControllerDiag::sys_superviseSystem() Service or battery door is open, goto INTRUSION MODE";
this->private_sendDiagEvent(DeviceController::State::E253);
}
if (dynMaCond.middleDoor) {
// vault door is open
flag_sendOperate = false;
qCritical() << "DeviceControllerDiag::sys_superviseSystem() vault door is open, goto INTRUSION MODE";
this->private_sendDiagEvent(DeviceController::State::E252);
}
// check for invalid states:
if (modCond.rtc>=200) {
@@ -224,7 +282,8 @@ void DeviceControllerDiag::sub_componentAssessment()
}
if (modCond.coinEscrow>=200) {
flag_sendOperate = false;
this->private_sendDiagEvent(DeviceController::State::E010);
// coinEscrow>200 is considered a warning:
this->private_sendDiagEvent(DeviceController::State::W010);
}
}
// -----------------------------------------------------------------------------------------------
@@ -246,7 +305,8 @@ void DeviceControllerDiag::sub_componentAssessment()
{
if (modCond.coinEscrow>=200) {
flag_sendOperate = false;
this->private_sendDiagEvent(DeviceController::State::E010);
// coinEscrow>200 is considered a warning:
this->private_sendDiagEvent(DeviceController::State::W010);
}
if (modCond.coinSafe==201) { // full
flag_sendOperate = false;
@@ -318,7 +378,7 @@ void DeviceControllerDiag::sub_componentAssessment()
}
if (modCond.temper>=200) {
flag_sendOperate = false;
this->private_sendDiagEvent(DeviceController::State::E004);
this->private_sendDiagEvent(DeviceController::State::W004);
}
// check for warnings
@@ -365,7 +425,6 @@ void DeviceControllerDiag::private_sendDiagEvent(DeviceController::State result)
{
qCritical() << "DeviceControllerDiag::private_sendDiagEvent() result: " << result;
if (this->eventReceiver == nullptr) {
qCritical() << "DeviceControllerDiag: no eventReceiver";
return;
@@ -388,61 +447,81 @@ void DeviceControllerDiag::private_sendDiagEvent(DeviceController::State result)
QString parameter;
switch (result) {
case DeviceController::State::INITIAL_STATE:
break;
case DeviceController::State::A000: // alarm / intrusion
eventClass = EVENT_CLASS::ALARM;
parameter = "alarm / intrusion";
this->_isErrorState = true;
break;
case DeviceController::State::E002: // real time clock error
eventClass = EVENT_CLASS::ERROR;
parameter = "real time clock error";
this->_isErrorState = true;
break;
case DeviceController::State::E003: // voltage error
eventClass = EVENT_CLASS::ERROR;
parameter = "voltage error";
this->_isErrorState = true;
break;
case DeviceController::State::E004: // temperature error
eventClass = EVENT_CLASS::ERROR;
parameter = "temperature error";
this->_isErrorState = true;
break;
case DeviceController::State::E007: // coin safe full
eventClass = EVENT_CLASS::ERROR;
parameter = "coin safe full";
this->_isErrorState = true;
break;
case DeviceController::State::E008: // bill acceptor full
eventClass = EVENT_CLASS::ERROR;
parameter = "bill acceptor full";
this->_isErrorState = true;
break;
case DeviceController::State::E009: // no cash box
eventClass = EVENT_CLASS::ERROR;
parameter = "no cash box";
this->_isErrorState = true;
break;
case DeviceController::State::E010: // coin escrow
eventClass = EVENT_CLASS::ERROR;
parameter = "coin escrow";
this->_isErrorState = true;
break;
case DeviceController::State::W010: // coin escrow
eventClass = EVENT_CLASS::WARNING;
parameter = "coin escrow";
break;
case DeviceController::State::E011: // mem error int.ee.
eventClass = EVENT_CLASS::ERROR;
parameter = "mem error int.ee.";
this->_isErrorState = true;
break;
case DeviceController::State::E018: // no paper
eventClass = EVENT_CLASS::ERROR;
parameter = "no paper";
this->_isErrorState = true;
break;
case DeviceController::State::E020: // printer error
eventClass = EVENT_CLASS::ERROR;
parameter = "printer error";
this->_isErrorState = true;
break;
case DeviceController::State::E025: // coin blocker
eventClass = EVENT_CLASS::ERROR;
parameter = "coin blocker";
this->_isErrorState = true;
break;
case DeviceController::State::E026: // error coin validator
eventClass = EVENT_CLASS::ERROR;
parameter = "error coin validator";
this->_isErrorState = true;
break;
case DeviceController::State::E034: // mdb error
eventClass = EVENT_CLASS::ERROR;
parameter = "mdb error";
this->_isErrorState = true;
break;
case DeviceController::State::E071: // cash box change is ongoing
@@ -471,16 +550,21 @@ void DeviceControllerDiag::private_sendDiagEvent(DeviceController::State result)
parameter = "no valid data from DeviceController";
break;
case DeviceController::State::E255: // no valid data from DeviceController
eventClass = EVENT_CLASS::STATE;
parameter = "";
qCritical() << " ... ignore " << QMetaEnum::fromType<DeviceController::State>().valueToKey(result);
return;
eventClass = EVENT_CLASS::ERROR;
parameter = "no valid data from DeviceController";
break;
case DeviceController::State::O000: // everything is fine
this->machineEventSet.clear();
this->_isErrorState = false;
eventClass = EVENT_CLASS::OPERATE;
parameter = "";
qCritical() << " ... everything fine";
if (this->lastState == DeviceController::State::O000) {
qCritical() << " ... everything fine, no state change -> skip sending";
return;
}
else {
qCritical() << " ... everything fine";
}
break;
case DeviceController::State::W001: // paper low
@@ -499,8 +583,23 @@ void DeviceControllerDiag::private_sendDiagEvent(DeviceController::State result)
eventClass = EVENT_CLASS::WARNING;
parameter = "temperatur warning";
break;
case DeviceController::State::W255: // restart carun
eventClass = EVENT_CLASS::WARNING;
parameter = "restart carun";
break;
}
this->lastState = result;
/**
* Variant: send 'parameter' as JSON:
*
JSON::setPrettySerialize(false);
JSON::JsonObject json = JSON::objectBuilder()
->set("description", parameter)
->create();
QString parameterJsonString = JSON::serialize(json);
*/
ATBMachineEvent *machineEvent = new ATBMachineEvent(
eventId,
@@ -512,10 +611,18 @@ void DeviceControllerDiag::private_sendDiagEvent(DeviceController::State result)
"" // second level info
);
//emit diagResponse(machineEvent);
QCoreApplication::postEvent(eventReceiver, machineEvent);
}
/**
* reset / restart / reinit deviceController
*/
void DeviceControllerDiag::restartCArun()
{
this->E255counter = 0;
this->private_sendDiagEvent(DeviceController::State::W255);
QProcess::startDetached("/bin/systemctl", {"restart", "carun"});
}

View File

@@ -29,6 +29,7 @@ namespace DeviceController {
E008,
E009,
E010,
W010, // Coin Escrow
E011,
E018,
@@ -52,7 +53,11 @@ namespace DeviceController {
W001,
W002,
W003,
W004
W004,
W255,
INITIAL_STATE
};
Q_ENUM_NS(State)
}
@@ -70,9 +75,32 @@ public:
nsDeviceControllerInterface::COIN_PROCESSOR coinProcessorType;
nsDeviceControllerInterface::BILL_ACCEPTOR billAcceptor;
/**
* return true, if machineEventSet contains an error
*/
bool isErrorState();
bool isOperatingState();
QSet<DeviceController::State> getCurrentMachineState();
void setTimeout(int timeout);
public slots:
/**
* start diag request
*/
void diagRequest();
/**
* reset / re-init diag request.
* Called e.g. when doors are closed.
*/
void diagReInit();
/**
* reset / restart / reinit deviceController
*/
void restartCArun();
signals:
void diagResponse(ATBMachineEvent* machineEvent);
@@ -91,10 +119,14 @@ private:
int lastVoltage;
DeviceController::State lastState;
QSet<DeviceController::State> machineEventSet;
bool _isErrorState;
PersistentData* pData;
int E255counter;
private slots:
void onDiagRequestTimeoutTimerTimeout();
@@ -103,7 +135,6 @@ private slots:
void sys_superviseSystem();
};
#endif // DEVICECONTROLLERDIAG_H

View File

@@ -5,6 +5,7 @@
#include <QSettings>
#include <QString>
#include <QJsonObject>
#include "ATBAPPplugin.h"
@@ -39,6 +40,12 @@ public:
virtual nsDeviceControllerInterface::PLUGIN_STATE initDCPlugin(QObject *eventReceiver,
const QSettings & settings) = 0;
/**
* e.g. send location
*/
virtual void sendDeviceParameter(const QJsonObject & jsonObject) = 0;
// TASKS: Cash handling -------------------------------------------------------
/**
* enables coin input
@@ -196,7 +203,7 @@ signals:
Q_DECLARE_INTERFACE(DeviceControllerInterface,
"eu.atb.ptu.plugin.DeviceControllerInterface/1.1.3")
"eu.atb.ptu.plugin.DeviceControllerInterface/1.1.6")
namespace nsDeviceControllerInterface {
@@ -229,7 +236,9 @@ namespace nsDeviceControllerInterface {
ERROR_RECEIPT,
START_RECEIPT, // e.g. Szeged Start
STOP_RECEIPT, // e.g. Szeged Stop
FOOD_STAMP
FINE_PAYMENT, // e.g. Klaipeda
FOOD_STAMP,
FREE_TICKET
};
enum class COIN_PROCESSOR : quint8 {

View File

@@ -64,6 +64,12 @@ bool Ticket::initNew(TICKET_VARIANT ticketVariant, const QList<quint8> & templat
case TICKET_VARIANT::STOP_RECEIPT:
this->_templateList << 24 << 25 << 26;
break;
case TICKET_VARIANT::FINE_PAYMENT:
this->_templateList << 24 << 25 << 26;
break;
case TICKET_VARIANT::FREE_TICKET:
this->_templateList << 24 << 25 << 26;
break;
case TICKET_VARIANT::FOOD_STAMP:
if (printingData.contains("dyn1_list")) {
this->_hasTemplateDynData = true;
@@ -160,6 +166,9 @@ QDebug operator<<(QDebug debug, TICKET_VARIANT ticketVariant)
case TICKET_VARIANT::STOP_RECEIPT:
debug << "TICKET_VARIANT::STOP_RECEIPT";
break;
case TICKET_VARIANT::FINE_PAYMENT:
debug << "TICKET_VARIANT::FINE_PAYMENT";
break;
case TICKET_VARIANT::FOOD_STAMP:
debug << "TICKET_VARIANT::FOOD_STAMP";
break;