From e8b3bb1aa0c0396e265efa9703c73d8ca1aed30d Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 13:54:41 +0100 Subject: [PATCH 1/9] Interface: 1.2.1 (add additional TICKET_VARIANTs) --- src/ATBAPP/DeviceControllerInterface.h | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ATBAPP/DeviceControllerInterface.h b/src/ATBAPP/DeviceControllerInterface.h index 8ad9581..e6d0439 100644 --- a/src/ATBAPP/DeviceControllerInterface.h +++ b/src/ATBAPP/DeviceControllerInterface.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "ATBAPPplugin.h" @@ -212,10 +213,11 @@ signals: Q_DECLARE_INTERFACE(DeviceControllerInterface, - "eu.atb.ptu.plugin.DeviceControllerInterface/1.2.0") + "eu.atb.ptu.plugin.DeviceControllerInterface/1.2.1") namespace nsDeviceControllerInterface { + Q_NAMESPACE enum class PLUGIN_STATE : quint8 { NOT_INITIALIZED = 0, @@ -240,7 +242,19 @@ namespace nsDeviceControllerInterface { enum class TICKET_VARIANT : quint8 { + INVALID, + NO_TICKET, PARKING_TICKET, + PARKING_TICKET_CAR, + PARKING_TICKET_VAN, + PARKING_TICKET_CAMPER, + DAY_TICKET, + DAY_TICKET_ADULT, + DAY_TICKET_TEEN, + DAY_TICKET_CHILD, + DAY_TICKET_CAR, + DAY_TICKET_VAN, + DAY_TICKET_CAMPER, RECEIPT, ERROR_RECEIPT, START_RECEIPT, // e.g. Szeged Start @@ -249,6 +263,12 @@ namespace nsDeviceControllerInterface { FOOD_STAMP, FREE_TICKET }; + Q_ENUM_NS(TICKET_VARIANT) + + inline uint qHash(const nsDeviceControllerInterface::TICKET_VARIANT &key, uint seed = 0) + { + return ::qHash(static_cast(key), seed); + } enum class COIN_PROCESSOR : quint8 { CHANGER, @@ -270,4 +290,6 @@ namespace nsDeviceControllerInterface { }; } + + #endif // DEVICECONTROLLERINTERFACE_H From 03b192fb605ebe517383528cd78be6154ed26190 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 13:57:36 +0100 Subject: [PATCH 2/9] Read ticket templates from config: - config group is [TICKET_TEMPLATES] - reads list of printer templates for each TICKET_VARIANT --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 48 ++++++++++++++++++++++++ src/ATBAPP/ATBDeviceControllerPlugin.h | 3 ++ 2 files changed, 51 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 3a843d3..0008dc4 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -45,6 +45,7 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con QString printerLocaleString = settings.value("ATBDeviceControllerPlugin/printerLocale", "de_DE").toString().toLatin1(); this->printerLocale = QLocale(printerLocaleString); + this->initTicketTemplateList(&settings); this->init_sc_dbus(); @@ -140,6 +141,53 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con } +void ATBDeviceControllerPlugin::initTicketTemplateList(const QSettings * settings) +{ + QList templateList; + QString templateListString; + + + QMetaEnum metaTicketVariants = QMetaEnum::fromType(); + for (int i = 0; i < metaTicketVariants.keyCount(); i++) { + const char* ticketVariant_char = metaTicketVariants.key(i); + quint8 intValue = metaTicketVariants.value(i); + + // DEBUG + //qCritical() << " processing TICKET_VARIANT::" << ticketVariant_char; + + QString configKey = QString("TICKET_TEMPLATES/") + ticketVariant_char; + templateListString = settings->value(configKey, "1,2,3").toString(); + + // DEBUG + //qCritical() << " configKey: " << configKey; + //qCritical() << " templateListString: " << templateListString; + + QStringList templateListStringList = templateListString.split(",", QString::SplitBehavior::SkipEmptyParts); + + quint8 templateEntry; + bool ok; + for (const auto & ListEntry : templateListStringList) { + templateEntry = ListEntry.toInt(&ok); + if (ok) { + templateList.append(templateEntry); + } + } + + // DEBUG + /* + QStringList elements; + for (const auto &item : templateList) { + elements << QString::number(item); + } + qCritical() << " template list: " << elements.join(','); + */ + + this->ticketTemplateList.insert(static_cast(intValue), templateList); + templateList.clear(); + } +} + + void ATBDeviceControllerPlugin::sendDeviceParameter(const QJsonObject &jsonObject) { diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index 53f562b..ee536c2 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -140,6 +140,9 @@ private: Ticket * currentTicket; QLocale printerLocale; + QHash> ticketTemplateList; + + void initTicketTemplateList(const QSettings * settings); void prepareDynTemplateData(); void private_setupDynTemplateData_START_RECEIPT(struct T_dynDat *dynTicketData, Ticket *ticket); From a03dfe87a5b9fcb90d7b37ec266d8923b442ade5 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 14:07:23 +0100 Subject: [PATCH 3/9] requestPrintTicket: improve debug output: print template list --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 0008dc4..8ab025e 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -735,8 +735,17 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface:: qCritical() << "------------------------------------------------------------------------"; qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()"; qCritical() << " TICKET_VARIANT: " << ticketVariant; + if (ticketVariant == nsDeviceControllerInterface::TICKET_VARIANT::FOOD_STAMP) { qCritical() << " dyn1_list: " << printingData["dyn1_list"].toStringList(); qCritical() << " dyn2_list: " << printingData["dyn2_list"].toStringList(); + } + QStringList listElements; + for (const auto &item : templateList) { + listElements << QString::number(item); + } + qCritical() << " template list: " << listElements.join(','); + + qCritical() << "------------------------------------------------------------------------"; From 1abd6bfa907745e7f8e5c2515f2d4ea1f56653d9 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 14:25:33 +0100 Subject: [PATCH 4/9] default templateList is empty --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 8ab025e..3409d49 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -156,7 +156,7 @@ void ATBDeviceControllerPlugin::initTicketTemplateList(const QSettings * setting //qCritical() << " processing TICKET_VARIANT::" << ticketVariant_char; QString configKey = QString("TICKET_TEMPLATES/") + ticketVariant_char; - templateListString = settings->value(configKey, "1,2,3").toString(); + templateListString = settings->value(configKey, "").toString(); // DEBUG //qCritical() << " configKey: " << configKey; From cbc0dd0ad693e3444baff56fe37a930849ab2263 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 14:26:40 +0100 Subject: [PATCH 5/9] Ticket: Use printer templates from config --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 5 +- src/ATBAPP/support/Ticket.cpp | 74 ++++++++++++++++++++---- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index 3409d49..bae1ab3 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -726,10 +726,7 @@ void ATBDeviceControllerPlugin::onNewVoltage(uint32_t voltage) */ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::TICKET_VARIANT ticketVariant, const QHash & printingData) { - QList templateList; - - // TODO: read template list from .ini - + QList templateList = this->ticketTemplateList[ticketVariant]; // DEBUG qCritical() << "------------------------------------------------------------------------"; diff --git a/src/ATBAPP/support/Ticket.cpp b/src/ATBAPP/support/Ticket.cpp index fdab619..8dff45e 100644 --- a/src/ATBAPP/support/Ticket.cpp +++ b/src/ATBAPP/support/Ticket.cpp @@ -50,25 +50,42 @@ bool Ticket::initNew(TICKET_VARIANT ticketVariant, const QList & templat qCritical() << " -> " << ticketVariant; int multiplicatorInt = 1; // default + quint8 headerTemplate; + quint8 multiTemplate; + quint8 footerTemplate; switch (this->ticketVariant) { - case TICKET_VARIANT::PARKING_TICKET: - break; - case TICKET_VARIANT::RECEIPT: - break; - case TICKET_VARIANT::ERROR_RECEIPT: - break; case TICKET_VARIANT::START_RECEIPT: - this->_templateList << 21 << 22 << 23; + if (templateList.isEmpty()) { + this->_templateList << 21 << 22 << 23; + } + else { + this->_templateList = templateList; + } break; case TICKET_VARIANT::STOP_RECEIPT: - this->_templateList << 24 << 25 << 26; + if (templateList.isEmpty()) { + this->_templateList << 24 << 25 << 26; + } + else { + this->_templateList = templateList; + } break; case TICKET_VARIANT::FINE_PAYMENT: - this->_templateList << 24 << 25 << 26; + if (templateList.isEmpty()) { + this->_templateList << 24 << 25 << 26; + } + else { + this->_templateList = templateList; + } break; case TICKET_VARIANT::FREE_TICKET: - this->_templateList << 24 << 25 << 26; + if (templateList.isEmpty()) { + this->_templateList << 24 << 25 << 26; + } + else { + this->_templateList = templateList; + } break; case TICKET_VARIANT::FOOD_STAMP: if (printingData.contains("dyn1_list")) { @@ -78,19 +95,52 @@ bool Ticket::initNew(TICKET_VARIANT ticketVariant, const QList & templat this->dyn2List = printingData["dyn2_list"].toStringList(); } + if (templateList.isEmpty()) { + headerTemplate = 0; + multiTemplate = 1; + footerTemplate = 2; + } + else + if (templateList.size() == 2) { + headerTemplate = 0; + multiTemplate = templateList.at(0); + footerTemplate = templateList.at(1); + } + else + if (templateList.size() == 3) { + headerTemplate = templateList.at(0); + multiTemplate = templateList.at(1); + footerTemplate = templateList.at(2); + } + else { + headerTemplate = 0; + multiTemplate = 1; + footerTemplate = 2; + } + + // header is optional: + if (headerTemplate != 0) { + this->_templateList << headerTemplate; + } + if (printingData.contains("multiplicator")) { multiplicatorInt = printingData["multiplicator"].toInt(); for (int i = 1; i < multiplicatorInt; i++) { - this->_templateList << 1; + this->_templateList << multiTemplate; } // last template: - this->_templateList << 2; + this->_templateList << footerTemplate; + } + else { + this->_templateList = templateList; } // DEBUG FOOD_STAMP: qCritical() << " --> printingData[\"multiplicator\"]" << multiplicatorInt; break; + default: + this->_templateList = templateList; } From fbfbe3d2436d376bf0bffad179bb7f1d9b93ba29 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Wed, 12 Mar 2025 16:12:44 +0100 Subject: [PATCH 6/9] prepareDynTemplateData: setup for all TICKET_VARIANTs --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 41 ++++++++++++++++++++++++ src/ATBAPP/ATBDeviceControllerPlugin.h | 1 + 2 files changed, 42 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index bae1ab3..b50e05a 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -1164,10 +1164,13 @@ void ATBDeviceControllerPlugin::prepareDynTemplateData() private_setupDynTemplatData_FINE_PAYMENT(dynTicketData, this->currentTicket); break; case nsDeviceControllerInterface::TICKET_VARIANT::RECEIPT: + private_setupDynTemplateData_DEFAULT(dynTicketData, this->currentTicket); break; case nsDeviceControllerInterface::TICKET_VARIANT::ERROR_RECEIPT: + private_setupDynTemplateData_DEFAULT(dynTicketData, this->currentTicket); break; case nsDeviceControllerInterface::TICKET_VARIANT::PARKING_TICKET: + private_setupDynTemplateData_DEFAULT(dynTicketData, this->currentTicket); break; case nsDeviceControllerInterface::TICKET_VARIANT::FREE_TICKET: private_setupDynTemplatData_FREE_TICKET(dynTicketData, this->currentTicket); @@ -1175,6 +1178,9 @@ void ATBDeviceControllerPlugin::prepareDynTemplateData() case nsDeviceControllerInterface::TICKET_VARIANT::FOOD_STAMP: private_setupDynTemplatData_FOOD_STAMP(dynTicketData, this->currentTicket); break; + default: + private_setupDynTemplateData_DEFAULT(dynTicketData, this->currentTicket); + break; } // C-Programmierung: wird hier nur 'licensePlate' gedruckt? @@ -1330,6 +1336,41 @@ void ATBDeviceControllerPlugin::private_setupDynTemplatData_FREE_TICKET(struct T // ! and yes... 'ParkingEndDate' is 'currentTime' } +void ATBDeviceControllerPlugin::private_setupDynTemplateData_DEFAULT(struct T_dynDat *dynTicketData, Ticket *ticket) +{ + QDateTime parkingEndDateTime = QDateTime::fromString(ticket->getPrintingData()["parkingEnd"].toString(), Qt::ISODate); + QDateTime currentDateTime = QDateTime::fromString(ticket->getPrintingData()["currentDateTime"].toString(), Qt::ISODate); + + QString parkingEndDateString = TicketUtils::getLocaleDateString(this->printerLocale, parkingEndDateTime.date()); + QString currentDateString = TicketUtils::getLocaleDateString(this->printerLocale, currentDateTime.date()); + + + // 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_parkingEndTime = codec->fromUnicode(parkingEndDateTime.toString("hh:mm")); + memcpy((char*)dynTicketData->parkingEnd, ba_parkingEndTime.data(), std::min(ba_parkingEndTime.size(),8)); + + QByteArray ba_parkingEndDate = codec->fromUnicode(parkingEndDateString); + memcpy((char*)dynTicketData->currentTime, ba_parkingEndDate.data(), std::min(ba_parkingEndDate.size(),8)); + // ! and yes... 'ParkingEndDate' is 'currentTime' + + QByteArray ba_currentDate = codec->fromUnicode(currentDateString); + memcpy((char*)dynTicketData->currentDate, ba_currentDate.data(), std::min(ba_currentDate.size(),8)); + + // Product-Text + QByteArray ba_productText = codec->fromUnicode(ticket->getPrintingData()["productText"].toString()); + memcpy((char*)dynTicketData->dynDat5, ba_productText.data(), std::min(ba_productText.size(),8)); + + // Ticket-Number + QByteArray ba_ticketNumber = codec->fromUnicode(ticket->getPrintingData()["ticketNumber"].toString()); + memcpy((char*)dynTicketData->dynDat7, ba_ticketNumber.data(), std::min(ba_ticketNumber.size(),8)); +} /************************************************************************************************ * cash payment diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.h b/src/ATBAPP/ATBDeviceControllerPlugin.h index ee536c2..e8378aa 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.h +++ b/src/ATBAPP/ATBDeviceControllerPlugin.h @@ -145,6 +145,7 @@ private: void initTicketTemplateList(const QSettings * settings); void prepareDynTemplateData(); + void private_setupDynTemplateData_DEFAULT(struct T_dynDat *dynTicketData, Ticket *ticket); 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); From c8508a0c62efac393d85a13419394a0fb4aea463 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Tue, 25 Mar 2025 12:26:18 +0100 Subject: [PATCH 7/9] Read config TICKET_TEMPLATES: read list- or string-value --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index b50e05a..c7a7c56 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -156,7 +156,12 @@ void ATBDeviceControllerPlugin::initTicketTemplateList(const QSettings * setting //qCritical() << " processing TICKET_VARIANT::" << ticketVariant_char; QString configKey = QString("TICKET_TEMPLATES/") + ticketVariant_char; - templateListString = settings->value(configKey, "").toString(); + QVariant raw_templateList = settings->value(configKey, ""); + if (raw_templateList.type() == QVariant::StringList) { + templateListString = raw_templateList.toStringList().join(","); + } else { + templateListString = raw_templateList.toString(); + } // DEBUG //qCritical() << " configKey: " << configKey; From 24a1390a11245f99f74eadb4798878a95bcb5891 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Mon, 7 Apr 2025 14:30:27 +0200 Subject: [PATCH 8/9] Interface: add TICKET_VARIANTS for FIXED_PRICE_TICKETS --- src/ATBAPP/DeviceControllerInterface.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ATBAPP/DeviceControllerInterface.h b/src/ATBAPP/DeviceControllerInterface.h index e6d0439..7217a9f 100644 --- a/src/ATBAPP/DeviceControllerInterface.h +++ b/src/ATBAPP/DeviceControllerInterface.h @@ -261,6 +261,16 @@ namespace nsDeviceControllerInterface { STOP_RECEIPT, // e.g. Szeged Stop FINE_PAYMENT, // e.g. Klaipeda FOOD_STAMP, + FIXED_PRICE_1, + FIXED_PRICE_2, + FIXED_PRICE_3, + FIXED_PRICE_4, + FIXED_PRICE_5, + FIXED_PRICE_6, + FIXED_PRICE_7, + FIXED_PRICE_8, + FIXED_PRICE_9, + FIXED_PRICE_10, FREE_TICKET }; Q_ENUM_NS(TICKET_VARIANT) From 10b0e494b232f97b81518dfa994671b310bb0866 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Tue, 8 Apr 2025 08:58:29 +0200 Subject: [PATCH 9/9] requestPrintTicket: switch to legacy, if no template list is configured --- src/ATBAPP/ATBDeviceControllerPlugin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ATBAPP/ATBDeviceControllerPlugin.cpp b/src/ATBAPP/ATBDeviceControllerPlugin.cpp index c7a7c56..308dcec 100644 --- a/src/ATBAPP/ATBDeviceControllerPlugin.cpp +++ b/src/ATBAPP/ATBDeviceControllerPlugin.cpp @@ -733,6 +733,15 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface:: { QList templateList = this->ticketTemplateList[ticketVariant]; + if (templateList.isEmpty()) { + qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()"; + qCritical() << " TICKET_VARIANT: " << ticketVariant; + qCritical() << " -> templateList is empty!"; + qCritical() << " -> switching to legacy interface"; + this->requestPrintTicket(printingData); + return; + } + // DEBUG qCritical() << "------------------------------------------------------------------------"; qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()";