Compare commits

...

21 Commits
1.2.1 ... 2.1.0

Author SHA1 Message Date
58f50b0ea6 Fix: implement unresolved symbol 2024-03-11 15:30:13 +01:00
bc5beb4b96 Fix: init variable 2024-03-11 15:29:47 +01:00
2a0aa2abe2 Merge branch 'PrintProducts' into pu/integration 2024-03-11 14:21:22 +01:00
f94f33862f Printing: dynamically set template dyn-data using Ticket-class
See DC_printer_interface.graphml/pdf
2024-03-11 14:06:05 +01:00
b7cedf5444 Add class Ticket 2024-03-11 14:02:52 +01:00
f81369944c FOOD_STAMP: build template list ...
Ths last template printed is different (this includes e.g. a full cut
whereas the other templates have only a semi-cut.
2024-03-08 13:09:19 +01:00
6072970bf0 Rework Printing: add private methods depending on TICKET_VARIANT 2024-03-08 13:06:53 +01:00
8659627171 Add object variable currentTicketType 2024-03-08 13:04:28 +01:00
d5786aa5ab Add COIN_PROCESSER::NONE (machine without coin processing) 2024-03-08 12:44:41 +01:00
ba7d801330 Update DeviceController Interface 1.1.3 (TICKET_VARIANT::FOOD_STAMP) 2024-03-08 10:50:07 +01:00
19ce57e680 PersistentData: save only if data has changed 2024-02-29 08:56:59 +01:00
d0ee6d175e Print tickets for products DAY_TICKET_ADULT, DAY_TICKET_TEEN 2024-02-28 16:42:35 +01:00
3eaf98fb09 Change product-names 2024-02-21 16:34:23 +01:00
bab7423965 Propagate Signal coinAttached 2024-02-21 16:33:39 +01:00
a76e3cd10e Update interfaces.h 2024-02-21 16:31:26 +01:00
eb1eab690b Update DeviceControllerInterface 1.1.2 (coinAttached-Signal) 2024-02-21 16:29:21 +01:00
7ae4ddd851 Use global interfaces.h 2024-01-31 13:42:51 +01:00
0cc89cefab Read dc-firmware-version: filter return value (null-character) 2024-01-31 12:22:18 +01:00
14755cd5b4 Start physical layer, if only master lib is available (e.g. in Szeged) 2024-01-31 11:38:32 +01:00
d2efe566c5 Add persistentData to store dc-fw-version
Reading dc-fw-version is somehow complicated ...
Id does not work reliable on startup, so we do read it also on every
diagRequest().
Version string is then stored in persistent data.
This data can be used e.g. by other tools to show the
device-controller-firmware-version.
2024-01-31 11:34:00 +01:00
b058b6aee0 Changer: skip polling, if amount due to change is 0 2024-01-25 14:26:19 +01:00
12 changed files with 851 additions and 136 deletions

View File

@@ -30,7 +30,14 @@ contains( CONFIG, PTU5 ) {
QMAKE_CXXFLAGS += -std=c++11 QMAKE_CXXFLAGS += -std=c++11
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments } linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5 ARCH = PTU5
INCLUDEPATH += $$PTU5BASEPATH/qt/libs/deviceController/include/
LIBS += -L$$PTU5BASEPATH/qt/libs/deviceController/library
LIBS += -lCAslave
LIBS += -lCAmaster
} }
contains( CONFIG, PTU5_YOCTO ) { contains( CONFIG, PTU5_YOCTO ) {
@@ -38,8 +45,8 @@ contains( CONFIG, PTU5_YOCTO ) {
PTU5BASEPATH = /opt/devel/ptu5 PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5 ARCH = PTU5
# add qmqtt lib LIBS += -lCAslave
#LIBS += -lQt5Qmqtt LIBS += -lCAmaster
} }
TARGET = ATBDeviceControllerPlugin TARGET = ATBDeviceControllerPlugin
@@ -69,7 +76,6 @@ DEFINES += QT_DEPRECATED_WARNINGS
# ATBAPP interface # ATBAPP interface
HEADERS += \ HEADERS += \
include/interfaces.h \
src/ATBAPP/ATBAPPplugin.h \ src/ATBAPP/ATBAPPplugin.h \
src/ATBAPP/DeviceControllerDiag.h \ src/ATBAPP/DeviceControllerDiag.h \
src/ATBAPP/DeviceControllerInterface.h \ src/ATBAPP/DeviceControllerInterface.h \
@@ -80,7 +86,9 @@ HEADERS += \
src/ATBAPP/support/CashUtils.h \ src/ATBAPP/support/CashUtils.h \
src/ATBAPP/support/DBusControllerInterface.h \ src/ATBAPP/support/DBusControllerInterface.h \
src/ATBAPP/support/JSON.h \ src/ATBAPP/support/JSON.h \
src/ATBAPP/support/PTUSystem.h src/ATBAPP/support/PTUSystem.h \
src/ATBAPP/support/PersistentData.h \
src/ATBAPP/support/Ticket.h
SOURCES += \ SOURCES += \
src/ATBAPP/ATBHealthEvent.cpp \ src/ATBAPP/ATBHealthEvent.cpp \
@@ -91,7 +99,9 @@ SOURCES += \
src/ATBAPP/support/CashUtils.cpp \ src/ATBAPP/support/CashUtils.cpp \
src/ATBAPP/support/DBusControllerInterface.cpp \ src/ATBAPP/support/DBusControllerInterface.cpp \
src/ATBAPP/support/JSON.cpp \ src/ATBAPP/support/JSON.cpp \
src/ATBAPP/support/PTUSystem.cpp src/ATBAPP/support/PTUSystem.cpp \
src/ATBAPP/support/PersistentData.cpp \
src/ATBAPP/support/Ticket.cpp
DISTFILES += \ DISTFILES += \
generate-version.sh generate-version.sh

View File

@@ -24,7 +24,8 @@ struct T_emp
// dynamic: // dynamic:
uint8_t state; // step counter of EMP (electronic coin checker) FSM (finite state machine): uint8_t state; // step counter of EMP (electronic coin checker) FSM (finite state machine):
// 0=start command /*
// 0=start command
// 1=powered, do emp ini, send reset // 1=powered, do emp ini, send reset
// 2=delay // 2=delay
// 3=wait for response, requesting status after response // 3=wait for response, requesting status after response
@@ -39,7 +40,7 @@ struct T_emp
// 90: stop all, 1s delay // 90: stop all, 1s delay
// 99: off, all stopped // 99: off, all stopped
*/
uint8_t pollingRunning; uint8_t pollingRunning;
uint8_t paymentRunning; uint8_t paymentRunning;
@@ -238,6 +239,7 @@ struct T_dynamicCondition
uint8_t lastVDoorState; uint8_t lastVDoorState;
uint8_t lastCBstate; uint8_t lastCBstate;
char paymentInProgress; char paymentInProgress;
// Version Szeged: aug2023
// 0: stopped by timeout // 0: stopped by timeout
// 1: running 2: wait4lastCoin // 1: running 2: wait4lastCoin
// 3: payment stopped manually, coins in Escrow // 3: payment stopped manually, coins in Escrow
@@ -246,6 +248,21 @@ struct T_dynamicCondition
// 6: coins encashed 7:coins returned // 6: coins encashed 7:coins returned
// 8: CoinChecker or MDB on Error // 8: CoinChecker or MDB on Error
// since Schoenau with bill and changer, nov2023
//0 = no payment
//will be set to 1 by cash_startCollection()
//neu 1: wait for devices getting ready for payment
//2 = payment,
//3 = wait for last coin/bill
//4 = Bezahlvorgang manuell beendet
//5 = payment stopped autom, amount collected, coins in Escrow
//6 = Bezahlvorgang beendet weil ZK voll
//4,5,6: payment done, keep on polling, wait for cash or return command
//7 = encash collected money from coin escrow into cash box
//8 = return "amountToReturn", can be complete inserted amount or only overpayment
//9 = wait for changer result
//10= print refund receipt with "amountToReturn"
char res1; char res1;
uint16_t U_Batt; uint16_t U_Batt;
@@ -397,6 +414,7 @@ struct T_bna
}; };
class DownloadThread;
class hwinf class hwinf
{ {
@@ -2252,14 +2270,23 @@ public:
virtual void bna_requestCurrentNotes() const {} virtual void bna_requestCurrentNotes() const {}
// send command to DC in order to get transaction data // send command to DC in order to get transaction data
virtual uint8_t bna_getCurrentNotes(uint16_t latestBill, uint16_t *currentNotes) const { virtual uint8_t bna_getCurrentNotes(uint16_t latestBill, uint16_t *currentNotes) const
{
Q_UNUSED(latestBill); Q_UNUSED(latestBill);
Q_UNUSED(currentNotes); Q_UNUSED(currentNotes);
return 0; return 0;
} }
// returns number of collected bank notes since start-command (current transaction) // returns number of collected bank notes since start-command (current transaction)
// latestBill: last accepted bank note, value in cent // return value: numbers of bills or 99 in case of error
// currentNotes an array with up to 16 (further) notes collected // latestBill: not used
// in case of error: currentNotes[0,1,2,3] = 1..4 error number(s)
// in normal case:
// currentNotes[0]: last bill in cent (e.g. 1000 = 10€)
// currentNotes[1]: bin 1 = bill is still in escrow else bill is stacked
// note: by now (dec2023) escrow is not used, bills always go to stacker (box)
// currentNotes[2]: total sum of bills in cent, low word (16bit)
// currentNotes[3]: total sum of bills in cent, high word (16bit)
virtual void bna_requestStackerLevel() const {} virtual void bna_requestStackerLevel() const {}
@@ -2273,9 +2300,73 @@ public:
// countOfBills[1] for 10€ and so on // countOfBills[1] for 10€ and so on
// download device controller
virtual bool dcDownloadRequest(QString const &fileToDownload) const {
Q_UNUSED(fileToDownload);
return false;
}
virtual bool dcDownloadRequested() const { return false; }
virtual bool dcDownloadResetRequest() const { return false; }
virtual bool dcDownloadRequestAck() const { return false; }
virtual bool dcDownloadRunning() const { return false; }
virtual bool dcDownloadFinished() { return false; }
virtual bool dcDownloadReportStart() const { return false; }
virtual bool dcDownloadReportRunning() const { return true; }
virtual bool dcDownloadReportFinished() { return true; }
virtual bool dcDownloadThreadStart() { return false; }
virtual bool dcDownloadThreadRunning() const { return true; }
virtual void dcDownloadThreadFinalize(DownloadThread *) {}
virtual bool dcDownloadThreadFinished() const { return true; }
virtual bool dcDownloadReportThreadStart() { return false; }
virtual bool dcDownloadReportThreadRunning() const { return true; }
virtual void dcDownloadReportThreadFinalize() {}
virtual void dcDownloadReportThreadQuit() {}
virtual bool dcDownloadReportThreadFinished() const { return true; }
virtual QString dcDownloadFileName() const { return ""; }
virtual bool dcDownloadSetRequested(bool requested) {
Q_UNUSED(requested); return false;
}
virtual bool dcDownloadSetRunning(bool running) {
Q_UNUSED(running); return false;
}
virtual bool dcDownloadSetFinished(bool finished) {
Q_UNUSED(finished); return false;
}
virtual void dcDownloadSetTotalBlockNumber(uint16_t totalBlockNumber) {
Q_UNUSED(totalBlockNumber);
}
virtual void dcDownloadSetCurrentBlockNumber(uint16_t currentBlockNumber) {
Q_UNUSED(currentBlockNumber);
}
virtual bool dcDownloadGetRequested() const { return false; }
virtual bool dcDownloadGetRunning() const { return false; }
virtual bool dcDownloadGetFinished() const { return false; }
virtual uint16_t dcDownloadGetTotalBlockNumber() const { return 0; }
virtual uint16_t dcDownloadGetCurrentBlockNumber() const { return 0; }
virtual QObject const *getAPI() { return nullptr; }
signals: signals:
/*
NOTE: the difference between a virtual Qt signal and a normal Qt signal:
A Qt virtual signal is a connection that is established using a pointer
or reference and is not connected to an object or data. It is therefore
not bound to a particular object, but to a specific class (object type).
Qt virtual signals are useful because they allow you to create
connections without worrying about whether an object or a specific data
element has been destroyed.
https://www.youtube.com/watch?v=HTH3VFfqsXw
*/
virtual void hwapi_reportDCDownloadStatus(QString const&) const {}
virtual void hwapi_reportDCDownloadSuccess(QString const&) const {}
virtual void hwapi_reportDCDownloadFailure(QString const&) const {}
virtual void hwapi_templatePrintFinished_OK(void) const=0; virtual void hwapi_templatePrintFinished_OK(void) const=0;
virtual void hwapi_templatePrintFinished_Err(void) const=0; virtual void hwapi_templatePrintFinished_Err(void) const=0;
@@ -2299,6 +2390,7 @@ signals:
virtual void hwapi_doorCBinAndAllDoorsClosed(void) const=0; virtual void hwapi_doorCBinAndAllDoorsClosed(void) const=0;
virtual void hwapi_doorAllDoorsClosed(void) const=0; virtual void hwapi_doorAllDoorsClosed(void) const=0;
virtual void hwapi_coinAttached() const = 0;
// NOTE: declaring a "pure virtual" "signal" should be an error and thus not valid. // NOTE: declaring a "pure virtual" "signal" should be an error and thus not valid.
/* GH Version, bringt Fehler /* GH Version, bringt Fehler

View File

@@ -47,6 +47,7 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent)
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByEscrow()), this, SLOT(onCashPayStopByEscrow()), Qt::QueuedConnection); connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByEscrow()), this, SLOT(onCashPayStopByEscrow()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByError()), this, SLOT(onCashPayStopByError()), Qt::QueuedConnection); connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByError()), this, SLOT(onCashPayStopByError()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByTimeout()), this, SLOT(onCashPayStopByTimeout()), Qt::QueuedConnection); connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByTimeout()), this, SLOT(onCashPayStopByTimeout()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_coinAttached()), this, SIGNAL(coinAttached()), Qt::QueuedConnection); // check for errors, switch to mode IDLE
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorServiceDoorOpened()), this, SLOT(onServiceDoorOpened()), Qt::QueuedConnection); // switch to ModeSERVICE connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorServiceDoorOpened()), this, SLOT(onServiceDoorOpened()), Qt::QueuedConnection); // switch to ModeSERVICE
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorVaultDoorOpened()), this, SLOT(onVaultDoorOpened()), Qt::QueuedConnection); // Screen?? with message connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorVaultDoorOpened()), this, SLOT(onVaultDoorOpened()), Qt::QueuedConnection); // Screen?? with message
@@ -60,12 +61,17 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent)
dynamic_cast<QObject*>(hw)->moveToThread(hwThread); dynamic_cast<QObject*>(hw)->moveToThread(hwThread);
hwThread->start(); hwThread->start();
QString persistentDataFile = "/mnt/system_data/dc_persistentData.dat";
this->persistentData = new PersistentData(persistentDataFile);
this->diag = new DeviceControllerDiag(this); this->diag = new DeviceControllerDiag(this->persistentData, this);
connect(this->diag, &DeviceControllerDiag::newVoltage, this, &ATBDeviceControllerPlugin::onNewVoltage); connect(this->diag, &DeviceControllerDiag::newVoltage, this, &ATBDeviceControllerPlugin::onNewVoltage);
// currentSelectedTicketType - number of used "Kombiticket" (deprecated) use TICKET_VARIANT in future
this->currentSelectedTicketType = 0; this->currentSelectedTicketType = 0;
this->currentTicket = new Ticket(TICKET_VARIANT::PARKING_TICKET, this);
this->currentCashState = CASH_STATE::CACHE_EMPTY; this->currentCashState = CASH_STATE::CACHE_EMPTY;
this->cashStartAmountInt = 0; this->cashStartAmountInt = 0;
@@ -101,6 +107,11 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con
// this is necessary to init the CashAgentLib (!) // this is necessary to init the CashAgentLib (!)
hw->vend_failed(); hw->vend_failed();
// read sw-version and store it in persistentData, if changed
QString dc_fw_version = hw->dc_getSWversion().remove(QChar('\0'));
qCritical() << "ATBDeviceControllerPlugin: DC firmware version: " << dc_fw_version;
this->persistentData->setDCFirmwareVersion(dc_fw_version);
this->persistentData->serializeToFile();
// text encoding for printer // text encoding for printer
this->codec = QTextCodec::codecForName(printerEncoding); this->codec = QTextCodec::codecForName(printerEncoding);
@@ -133,6 +144,11 @@ void ATBDeviceControllerPlugin::startPhysicalLayer()
return; return;
} }
qCritical() << "ATBDeviceControllerPlugin::startPhysicalLayer() " << endl
<< " -> use master lib " << endl
<< " -> start physical layer";
// open serial port // open serial port
hw->dc_openSerial(5, "115200", this->serialPortName, 1); hw->dc_openSerial(5, "115200", this->serialPortName, 1);
@@ -141,6 +157,10 @@ void ATBDeviceControllerPlugin::startPhysicalLayer()
void ATBDeviceControllerPlugin::stopPhysicalLayer() void ATBDeviceControllerPlugin::stopPhysicalLayer()
{ {
// store persistent data
this->persistentData->serializeToFile();
// skip, if we use slave lib
if (!this->isMaster) return; if (!this->isMaster) return;
if (this->pluginState == PLUGIN_STATE::NOT_INITIALIZED) if (this->pluginState == PLUGIN_STATE::NOT_INITIALIZED)
@@ -538,86 +558,40 @@ void ATBDeviceControllerPlugin::onNewVoltage(uint32_t voltage)
/**
* @brief ATBDeviceControllerPlugin::requestPrintTicket
* @param ticketVariant
* @param printingData
*
* Setup (initNew()) Ticket-Object
*
*/
void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::TICKET_VARIANT ticketVariant, const QHash<QString, QVariant> & printingData) void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::TICKET_VARIANT ticketVariant, const QHash<QString, QVariant> & printingData)
{ {
struct T_dynDat *dynTicketData = new T_dynDat; QList<quint8> templateList;
memset(dynTicketData, 0, sizeof(*dynTicketData));
QDateTime parkingEndDateTime = QDateTime::fromString(printingData["parkingEnd"].toString(), Qt::ISODate); // TODO: read template list from .ini
QDateTime currentDateTime = QDateTime::fromString(printingData["currentDateTime"].toString(), Qt::ISODate);
QString parkingEndDateString = this->printerLocale.toString(parkingEndDateTime.date(), QLocale::ShortFormat);
QString currentDateString = this->printerLocale.toString(currentDateTime.date(), QLocale::ShortFormat);
// set dynamic printer data:
QByteArray ba_licenseplate = codec->fromUnicode(printingData["licenseplate"].toString());
memcpy((char*)dynTicketData->licensePlate, ba_licenseplate.data(), std::min(ba_licenseplate.size(),8));
QByteArray ba_amount = codec->fromUnicode(printingData["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));
// STAN for Szeged Start/Stop: must be 9 digits
// --------------------------------------------------------------------------------------
QString stan = codec->fromUnicode(printingData["STAN"].toString());
qCritical() << " requestPrintTicket() STAN = " << stan;
QString stan1;
QString stan2;
if (stan.length() == 9) {
stan1 = " " + stan.mid(0,3);
stan2 = stan.mid(3,3) + " " + stan.mid(6,3);
}
else {
qCritical() << "ASSERT: ATBDeviceControllerPlugin::requestPrintTicket() invalid STAN: " << stan;
stan1 = " 000";
stan2 = "000 000";
}
QByteArray ba_stan1 = codec->fromUnicode(stan1);
QByteArray ba_stan2 = codec->fromUnicode(stan2);
// --------------------------------------------------------------------------------------
this->templateList.clear();
switch (ticketVariant) {
case nsDeviceControllerInterface::TICKET_VARIANT::START_RECEIPT:
qCritical() << " -> TICKET_VARIANT::START_RECEIPT";
memcpy((char*)dynTicketData->dynDat6, ba_stan1.data(), std::min(ba_stan1.size(),8));
memcpy((char*)dynTicketData->dynDat7, ba_stan2.data(), std::min(ba_stan2.size(),8));
this->templateList << 21 << 22 << 23;
break;
case nsDeviceControllerInterface::TICKET_VARIANT::STOP_RECEIPT:
qCritical() << " -> TICKET_VARIANT::STOP_RECEIPT";
memcpy((char*)dynTicketData->dynDat6, ba_stan1.data(), std::min(ba_stan1.size(),8));
memcpy((char*)dynTicketData->dynDat7, ba_stan2.data(), std::min(ba_stan2.size(),8));
this->templateList << 24 << 25 << 26;
break;
case nsDeviceControllerInterface::TICKET_VARIANT::RECEIPT:
break;
case nsDeviceControllerInterface::TICKET_VARIANT::ERROR_RECEIPT:
break;
case nsDeviceControllerInterface::TICKET_VARIANT::PARKING_TICKET:
break;
}
// DEBUG // DEBUG
qCritical() << "------------------------------------------------------------------------";
qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()"; qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()";
for (int i =0; i < this->templateList.size(); ++i) { qCritical() << " TICKET_VARIANT: " << ticketVariant;
qCritical() << " template: " << this->templateList.at(i); qCritical() << " dyn1_list: " << printingData["dyn1_list"].toStringList();
} qCritical() << " dyn2_list: " << printingData["dyn2_list"].toStringList();
qCritical() << "------------------------------------------------------------------------";
if (!this->currentTicket->initNew(ticketVariant, templateList, printingData)) {
this->errorCode = this->currentTicket->getErrorCode();
this->errorDescription = this->currentTicket->getErrorCode();
qCritical() << "ERROR: ticket->initNew: " << ticketVariant;
this->onPrintFinishedERR();
return;
}
/* /*
if (!this->hw->dc_isPortOpen()) { if (!this->hw->dc_isPortOpen()) {
qCritical() << " ... serial port is not open!"; qCritical() << " ... serial port is not open!";
@@ -626,26 +600,7 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::
} }
*/ */
// TODO: wird hier nur 'licensePlate' gedruckt? this->prepareDynTemplateData();
if (!this->hw->prn_sendDynamicPrnValues(dynTicketData->licensePlate)) {
this->errorCode = "hwapi::prn_sendDynamicPrnValues";
this->errorDescription = "hwapi method 'hwapi::prn_sendDynamicPrnValues' result is false";
qCritical() << "ERROR:";
qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket( " << endl
<< " licenseplate = " << printingData["licenseplate"] << endl
<< " amount = " << printingData["amount"] << endl
<< " parkingEnd = " << printingData["parkingEnd"] << endl
<< " currentTime = " << printingData["currentTime"] << endl
<< " currentDate = " << printingData["currentDate"] << endl
<< " stan = " << printingData["STAN"] << endl;
this->onPrintFinishedERR();
return;
}
QTimer::singleShot(1000, this, SLOT(onPrinterDataPreparedForTemplates()));
} }
void ATBDeviceControllerPlugin::requestPrintReceipt(const QHash<QString, QVariant> & printingData) void ATBDeviceControllerPlugin::requestPrintReceipt(const QHash<QString, QVariant> & printingData)
@@ -794,24 +749,37 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
// 2 - Card / ShortTimeParking // 2 - Card / ShortTimeParking
// 3 - Cash / DayTicket // 3 - Cash / DayTicket
// 4 - Card / DayTicket // 4 - Card / DayTicket
// 00744 - NeuhauserVT/NAZ:
// 1 - Erwachsene
// 2 - Jugendliche
// 00741 - NeuhauserVT/Linsinger Maschinenbau
// t.b.d.
QString paymentType = printingData["paymentType"].toString(); // must be "CASH" | "CARD" QString paymentType = printingData["paymentType"].toString(); // must be "CASH" | "CARD"
QString productName = printingData["product"].toString(); // must be "ShortTimeParking" | "DayTicket" QString productName = printingData["product"].toString(); // must be "ShortTimeParking" | "DayTicket"
if ( (paymentType == "CASH") && (productName == "ShortTimeParking") ) { if ( (paymentType == "CASH") && (productName == "SHORT_TERM_PARKING") ) {
this->currentSelectedTicketType = 1; // "Kombiticket #1"
}
else
if ( (paymentType == "CARD") && (productName == "SHORT_TERM_PARKING") ) {
this->currentSelectedTicketType = 2; // "Kombiticket #2"
}
else
if ( (paymentType == "CASH") && (productName == "DAY_TICKET") ) {
this->currentSelectedTicketType = 3; // "Kombiticket #3"
}
else
if ( (paymentType == "CARD") && (productName == "DAY_TICKET") ) {
this->currentSelectedTicketType = 4; // "Kombiticket #4"
}
else
if ( productName == "DAY_TICKET_ADULT") {
this->currentSelectedTicketType = 1; this->currentSelectedTicketType = 1;
} }
else else
if ( (paymentType == "CARD") && (productName == "ShortTimeParking") ) { if ( productName == "DAY_TICKET_TEEN") {
this->currentSelectedTicketType = 2; this->currentSelectedTicketType = 2;
} }
else
if ( (paymentType == "CASH") && (productName == "DayTicket") ) {
this->currentSelectedTicketType = 3;
}
else
if ( (paymentType == "CARD") && (productName == "DayTicket") ) {
this->currentSelectedTicketType = 4;
}
else { else {
qCritical() << "ERROR: requestPrintTicket(): invalid payment data:"; qCritical() << "ERROR: requestPrintTicket(): invalid payment data:";
qCritical() << " paymentType = " << paymentType << endl qCritical() << " paymentType = " << paymentType << endl
@@ -826,7 +794,7 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
void ATBDeviceControllerPlugin::onPrinterDataPreparedForTemplates() void ATBDeviceControllerPlugin::onPrinterDataPreparedForTemplates()
{ {
if (this->templateList.isEmpty()) return; if (this->currentTicket->templateList()->isEmpty()) return;
this->onPrinterPrintNextTemplate(); this->onPrinterPrintNextTemplate();
} }
@@ -871,30 +839,37 @@ void ATBDeviceControllerPlugin::onPrinterWaitForPrintingTicket()
void ATBDeviceControllerPlugin::onPrinterPrintNextTemplate() void ATBDeviceControllerPlugin::onPrinterPrintNextTemplate()
{ {
// template list must not be empty // template list must not be empty
if (this->templateList.isEmpty()) { if (this->currentTicket->templateList()->isEmpty()) {
this->onPrintFinishedERR(); this->onPrintFinishedERR();
return; return;
} }
qCritical() << " ... print template " << this->templateList.first(); qCritical() << " ... print template " << this->currentTicket->templateList()->first();
if (!this->hw->prn_printTemplate(this->templateList.first())) { if (!this->hw->prn_printTemplate(this->currentTicket->templateList()->first())) {
this->errorCode = "hwapi::prn_printTemplate"; this->errorCode = "hwapi::prn_printTemplate";
this->errorDescription = QString("hwapi method 'hwapi::onPrinterPrintNextTemplate(%1)' result is false").arg(this->templateList.first()); this->errorDescription = QString("hwapi method 'hwapi::onPrinterPrintNextTemplate(%1)' result is false").arg(this->currentTicket->templateList()->first());
this->onPrintFinishedERR(); this->onPrintFinishedERR();
return; return;
} }
this->templateList.removeFirst(); this->currentTicket->templateList()->removeFirst();
this->currentTicket->setCurrentTemplateProcessed();
if (templateList.isEmpty()) { if (this->currentTicket->templateList()->isEmpty()) {
// all templates are printed // all templates are printed
QTimer::singleShot(2000, this, SLOT(onPrinterWaitForPrintingTicket())); QTimer::singleShot(2000, this, SLOT(onPrinterWaitForPrintingTicket()));
} }
else { else {
// print next template
QTimer::singleShot(2000, this, SLOT(onPrinterPrintNextTemplate()));
}
if (this->currentTicket->hasTemplateDynData()) {
// set new dyn data:
QTimer::singleShot(2000, this, SLOT(onPrinterPrepareDynTemplateData()));
}
else {
// print next template
QTimer::singleShot(2000, this, SLOT(onPrinterPrintNextTemplate()));
}
}
} }
/************************************************************************************************ /************************************************************************************************
@@ -927,6 +902,141 @@ void ATBDeviceControllerPlugin::onPrintFinishedERR()
void ATBDeviceControllerPlugin::onPrinterPrepareDynTemplateData()
{
this->prepareDynTemplateData();
}
void ATBDeviceControllerPlugin::prepareDynTemplateData()
{
struct T_dynDat *dynTicketData = new T_dynDat;
memset(dynTicketData, 0, sizeof(*dynTicketData));
// setup dynTicketData dependent on currentTicket
// DEBUG:
qCritical() << "---------------------------------------------------";
qCritical() << "ATBDeviceControllerPlugin::prepareDynTemplateData():";
qCritical() << " -> currentProcessedTemplateNumber: " << this->currentTicket->getCurrentProcessedTemplateNumber();
qCritical() << " -> this->currentTicket->variant(): " << this->currentTicket->variant();
qCritical() << "---------------------------------------------------";
switch (this->currentTicket->variant()) {
case nsDeviceControllerInterface::TICKET_VARIANT::START_RECEIPT:
private_setupDynTemplateData_START_RECEIPT(dynTicketData, this->currentTicket);
break;
case nsDeviceControllerInterface::TICKET_VARIANT::STOP_RECEIPT:
private_setupDynTemplatData_STOP_RECEIPT(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::FOOD_STAMP:
private_setupDynTemplatData_FOOD_STAMP(dynTicketData, this->currentTicket);
break;
}
// C-Programmierung: wird hier nur 'licensePlate' gedruckt?
if (!this->hw->prn_sendDynamicPrnValues(dynTicketData->licensePlate)) {
this->errorCode = "hwapi::prn_sendDynamicPrnValues";
this->errorDescription = "hwapi method 'hwapi::prn_sendDynamicPrnValues' result is false";
qCritical() << "ERROR: hw->prn_sendDynamicPrnValues";
this->onPrintFinishedERR();
return;
}
QTimer::singleShot(1000, this, SLOT(onPrinterDataPreparedForTemplates()));
}
void ATBDeviceControllerPlugin::private_setupDynTemplateData_START_RECEIPT(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 = this->printerLocale.toString(parkingEndDateTime.date(), QLocale::ShortFormat);
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_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));
// STAN for Szeged Start/Stop: must be 9 digits
// --------------------------------------------------------------------------------------
QString stan = codec->fromUnicode(ticket->getPrintingData()["STAN"].toString());
qCritical() << " requestPrintTicket() STAN = " << stan;
QString stan1;
QString stan2;
if (stan.length() == 9) {
stan1 = " " + stan.mid(0,3);
stan2 = stan.mid(3,3) + " " + stan.mid(6,3);
}
else {
qCritical() << "ASSERT: ATBDeviceControllerPlugin::requestPrintTicket() invalid STAN: " << stan;
stan1 = " 000";
stan2 = "000 000";
}
QByteArray ba_stan1 = codec->fromUnicode(stan1);
QByteArray ba_stan2 = codec->fromUnicode(stan2);
// --------------------------------------------------------------------------------------
memcpy((char*)dynTicketData->dynDat6, ba_stan1.data(), std::min(ba_stan1.size(),8));
memcpy((char*)dynTicketData->dynDat7, ba_stan2.data(), std::min(ba_stan2.size(),8));
}
void ATBDeviceControllerPlugin::private_setupDynTemplatData_STOP_RECEIPT(struct T_dynDat *dynTicketData, Ticket *ticket)
{
// same as START_RECEIPT
this->private_setupDynTemplateData_START_RECEIPT(dynTicketData, ticket);
}
void ATBDeviceControllerPlugin::private_setupDynTemplatData_FOOD_STAMP(struct T_dynDat *dynTicketData, Ticket *ticket)
{
quint8 currentProcessedTemplateNumber = ticket->getCurrentProcessedTemplateNumber();
// TODO: check DynXList size / or ensure that DynXList has value
// "Mitarbeiter-Nummer": dynPr1 -> licenceplate
QString currentEMP_Nr = ticket->getDyn1List().at(currentProcessedTemplateNumber);
QByteArray ba_licenseplate = codec->fromUnicode(currentEMP_Nr);
memcpy((char*)dynTicketData->licensePlate, ba_licenseplate.data(), std::min(ba_licenseplate.size(),8));
// "Lauf.Nr": dynPr2 -> vendingPrice
QString currentStampNumber = ticket->getDyn2List().at(currentProcessedTemplateNumber);
QByteArray ba_amount = codec->fromUnicode(currentStampNumber);
memcpy((char*)dynTicketData->vendingPrice, ba_amount.data(), std::min(ba_amount.size(),8));
// DEBUG
qCritical() << "-------------------------------------------------------";
qCritical() << "private_setupDynTemplatData_FOOD_STAMP()";
qCritical() << " currentProcessedTemplateNumber: " << currentProcessedTemplateNumber;
qCritical() << " currentEMP_Nr: " << currentEMP_Nr;
qCritical() << " currentStampNumber: " << currentStampNumber;
qCritical() << "-------------------------------------------------------";
}
/************************************************************************************************ /************************************************************************************************
* cash payment * cash payment
*/ */
@@ -1105,10 +1215,24 @@ void ATBDeviceControllerPlugin::onCashChangerState()
amountCoinsChangedInt = amountInt - this->cashStartAmountInt; amountCoinsChangedInt = amountInt - this->cashStartAmountInt;
} }
else { else {
amountCoinsChangedInt = 0; amountCoinsChangedInt = 0;
} }
QString amountCoinsChangedString = QString::number(amountCoinsChangedInt); QString amountCoinsChangedString = QString::number(amountCoinsChangedInt);
// if we do not need to give change:
if (amountCoinsChangedInt == 0) {
emit this->cashPaymentFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
amountCoinsString, // coins
amountNotesString, // notes
amountCoinsChangedString, // change
"",
"");
changerStateRequestCounter = 0;
lastChangerResult = 0;
return;
}
// get changer state ------------------------------------------------ // get changer state ------------------------------------------------
// Note: 'returnedAmount'-parameter is missleading here! // Note: 'returnedAmount'-parameter is missleading here!
@@ -1294,6 +1418,10 @@ bool ATBDeviceControllerPlugin::private_loadCashAgentLib(QString pluginName)
qCritical() << "ATBDeviceControllerPlugin: loaded CashAgentLib"; qCritical() << "ATBDeviceControllerPlugin: loaded CashAgentLib";
if (this->isMaster) {
QTimer::singleShot(500, this, &ATBDeviceControllerPlugin::startPhysicalLayer);
}
return true; return true;
} }

View File

@@ -7,12 +7,13 @@
#include "src/ATBAPP/DeviceControllerInterface.h" #include "src/ATBAPP/DeviceControllerInterface.h"
#include "src/ATBAPP/ATBAPPplugin.h" #include "src/ATBAPP/ATBAPPplugin.h"
#include "src/ATBAPP/DeviceControllerDiag.h" #include "src/ATBAPP/DeviceControllerDiag.h"
#include "src/ATBAPP/support/Ticket.h"
#include "version.h" #include "version.h"
#include "support/PersistentData.h"
#include <DeviceController/interfaces.h>
#include "interfaces.h"
#include <unistd.h> #include <unistd.h>
@@ -20,11 +21,11 @@
class DBusControllerInterface; class DBusControllerInterface;
class QTextCodec; class QTextCodec;
using namespace nsDeviceControllerInterface; using namespace nsDeviceControllerInterface;
class QSettings; class QSettings;
class ATBDeviceControllerPlugin : class ATBDeviceControllerPlugin :
public DeviceControllerInterface public DeviceControllerInterface
{ {
@@ -94,8 +95,6 @@ private:
QString errorDescription; QString errorDescription;
QString pluginInfo; QString pluginInfo;
QList<int> templateList;
QString serialPortName; QString serialPortName;
bool useDebug; bool useDebug;
@@ -112,6 +111,8 @@ private:
DeviceControllerDiag* diag; DeviceControllerDiag* diag;
PersistentData *persistentData;
uint32_t cashStartAmountInt; uint32_t cashStartAmountInt;
@@ -129,8 +130,17 @@ private:
// dbus // dbus
int init_sc_dbus(); int init_sc_dbus();
// printer privates ----------------------------------------------------------------------------
Ticket * currentTicket;
QLocale printerLocale; QLocale printerLocale;
void prepareDynTemplateData();
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);
// ---------------------------------------------------------------------------------------------
private slots: private slots:
// printer // printer
@@ -140,6 +150,8 @@ private slots:
void onPrinterWaitForPrintingTicket(); void onPrinterWaitForPrintingTicket();
void onPrinterWaitForPrintingReceipt(); void onPrinterWaitForPrintingReceipt();
void onPrinterPrepareDynTemplateData();
void onPrintFinishedOK(); void onPrintFinishedOK();
void onPrintFinishedERR(); void onPrintFinishedERR();

View File

@@ -5,13 +5,14 @@
#include <QUuid> #include <QUuid>
#include <QDebug> #include <QDebug>
DeviceControllerDiag::DeviceControllerDiag(QObject *parent) DeviceControllerDiag::DeviceControllerDiag(PersistentData *pData, QObject *parent)
: QObject(parent) : QObject(parent)
, coinProcessorType(nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW) , coinProcessorType(nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW)
, billAcceptor(nsDeviceControllerInterface::BILL_ACCEPTOR::NO) , billAcceptor(nsDeviceControllerInterface::BILL_ACCEPTOR::NO)
, eventReceiver(nullptr) , eventReceiver(nullptr)
, isRequestRunning(false) , isRequestRunning(false)
, flagInterruptDiag(false) , flagInterruptDiag(false)
, pData(pData)
{ {
diagRequestTimeoutTimer = new QTimer(this); diagRequestTimeoutTimer = new QTimer(this);
diagRequestTimeoutTimer->setInterval(1000*20); // 20s diagRequestTimeoutTimer->setInterval(1000*20); // 20s
@@ -42,6 +43,16 @@ void DeviceControllerDiag::diagRequest()
this->diagRequestTimeoutTimer->start(); this->diagRequestTimeoutTimer->start();
this->private_startDiag(); this->private_startDiag();
// read dc-fw-version:
/* note: dc_getSWVersion() returns always 32 characters (QString)...
* if no version string could be read it will contain 32 null-characters:
* "\u0000\u0000..."
*/
QString dc_fw_version = hw->dc_getSWversion().remove(QChar('\0'));
qCritical() << "ATBDeviceControllerPlugin: DC firmware version: " << dc_fw_version;
this->pData->setDCFirmwareVersion(dc_fw_version);
this->pData->serializeToFile();
} }
@@ -219,6 +230,9 @@ void DeviceControllerDiag::sub_componentAssessment()
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
switch (devPara.kindOfCoinChecker) { switch (devPara.kindOfCoinChecker) {
case 0:
this->coinProcessorType = nsDeviceControllerInterface::COIN_PROCESSOR::NONE;
break;
case 1: case 1:
case 2: case 2:
this->coinProcessorType = nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW; this->coinProcessorType = nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW;

View File

@@ -5,9 +5,12 @@
#include <QSet> #include <QSet>
#include <QTimer> #include <QTimer>
#include "ATBMachineEvent.h" #include <DeviceController/interfaces.h>
#include "interfaces.h"
#include "DeviceControllerInterface.h" #include "DeviceControllerInterface.h"
#include "ATBMachineEvent.h"
#include "support/PersistentData.h"
namespace DeviceController { namespace DeviceController {
@@ -60,7 +63,7 @@ class DeviceControllerDiag : public QObject
Q_OBJECT Q_OBJECT
public: public:
DeviceControllerDiag(QObject *parent = nullptr); DeviceControllerDiag(PersistentData *pData, QObject *parent = nullptr);
void init(hwinf* hw, QObject* eventReceiver); void init(hwinf* hw, QObject* eventReceiver);
@@ -90,7 +93,7 @@ private:
QSet<DeviceController::State> machineEventSet; QSet<DeviceController::State> machineEventSet;
PersistentData* pData;
private slots: private slots:
void onDiagRequestTimeoutTimerTimeout(); void onDiagRequestTimeoutTimerTimeout();

View File

@@ -104,6 +104,9 @@ signals:
const QString & errorCode, const QString & errorCode,
const QString & errorDescription); const QString & errorDescription);
void coinAttached();
/** /**
* emitted on e.g. a coin input * emitted on e.g. a coin input
*/ */
@@ -193,7 +196,7 @@ signals:
Q_DECLARE_INTERFACE(DeviceControllerInterface, Q_DECLARE_INTERFACE(DeviceControllerInterface,
"eu.atb.ptu.plugin.DeviceControllerInterface/1.1.1") "eu.atb.ptu.plugin.DeviceControllerInterface/1.1.3")
namespace nsDeviceControllerInterface { namespace nsDeviceControllerInterface {
@@ -226,11 +229,13 @@ namespace nsDeviceControllerInterface {
ERROR_RECEIPT, ERROR_RECEIPT,
START_RECEIPT, // e.g. Szeged Start START_RECEIPT, // e.g. Szeged Start
STOP_RECEIPT, // e.g. Szeged Stop STOP_RECEIPT, // e.g. Szeged Stop
FOOD_STAMP
}; };
enum class COIN_PROCESSOR : quint8 { enum class COIN_PROCESSOR : quint8 {
CHANGER, CHANGER,
ESCROW ESCROW,
NONE
}; };
enum class BILL_ACCEPTOR : quint8 { enum class BILL_ACCEPTOR : quint8 {

View File

@@ -2,7 +2,7 @@
#define CASHUTILS_H #define CASHUTILS_H
#include <QObject> #include <QObject>
#include "interfaces.h" #include <DeviceController/interfaces.h>
namespace CashUtils { namespace CashUtils {

View File

@@ -0,0 +1,145 @@
#include "PersistentData.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDateTime>
#include <QDataStream>
#include <QDebug>
PersistentData::PersistentData(const QString &datafileName, QObject *parent)
: QObject(parent)
, isChangedFlag(false)
{
// load persistant data, if available
this->filename = datafileName;
QFileInfo dataFileInfo(this->filename);
QString dataFilePath = dataFileInfo.path();
QDir dir;
if ( ! dir.exists(dataFilePath)) {
qCritical() << "Persistent data file does not exist!";
qCritical() << " --> create new: " << this->filename;
dir.mkpath(dataFilePath);
}
this->read();
}
void PersistentData::serializeToFile()
{
if (this->isChangedFlag) {
qCritical() << "PersistentData::isChanged -> save";
this->save();
}
}
void PersistentData::save()
{
QFile fileOut(this->filename);
if (fileOut.open(QIODevice::WriteOnly))
{
QDataStream out(&fileOut);
out.setVersion(QDataStream::Qt_4_6);
out << this->hash;
fileOut.flush();
fileOut.close();
this->isChangedFlag = false;
}
}
void PersistentData::read()
{
QFile fileIn(this->filename);
if (fileIn.open(QIODevice::ReadOnly))
{
QDataStream in(&fileIn);
in.setVersion(QDataStream::Qt_4_6);
in >> hash;
fileIn.close();
}
}
QVariant PersistentData::getParameter(const QString & key) const {
#if defined (ARCH_DesktopLinux)
// note: QVariant.toString() returns empty string for custom types
qDebug() << "VendingData::getParameter() key = " << key << " value = " << hash.value(key).toString();
#endif
return hash.value(key);
}
QVariant PersistentData::getParameter(const QString & key)
{
#if defined (ARCH_DesktopLinux)
// note: QVariant.toString() returns empty string for custom types
qDebug() << "VendingData::getParameter() key = " << key << " value = " << hash.value(key).toString();
#endif
return hash.value(key);
}
void PersistentData::setParameter(const QString & key, QVariant value)
{
this->isChangedFlag = true;
#if defined (ARCH_DesktopLinux)
// note: QVariant.toString() returns empty string for custom types
qDebug() << "VendingData::setParameter() key = " << key << " value = " << value.toString();
#endif
this->hash.insert(key, value);
}
void PersistentData::clearParameter(const QString & key)
{
this->isChangedFlag = true;
this->hash.remove(key);
}
bool PersistentData::hasParameter(const QString & key) const
{
return hash.contains(key);
}
uint PersistentData::getUintParameter(const QString & key) const
{
qDebug() << "PersistentData::getUintParameter() key = " << key << " value = " << hash.value(key).toString();
uint returnValue = 0;
bool ok;
returnValue = hash.value(key).toString().toUInt(&ok);
if (!ok) returnValue = 0;
return returnValue;
}
QList<QString> PersistentData::uniqueKeys() const {
return hash.uniqueKeys();
}
void PersistentData::setDCFirmwareVersion(const QString & fw_version)
{
// there must be a version string!
if (fw_version.size() < 1) return;
if (this->hash["dc_fw_version"].toString() != fw_version) {
this->isChangedFlag = true;
this->hash.insert("dc_fw_version", fw_version);
}
}
QString PersistentData::getDCFirmwareVersion()
{
return this->hash["dc_fw_version"].toString();
}

View File

@@ -0,0 +1,49 @@
#ifndef PERSISTENTDATA_H
#define PERSISTENTDATA_H
#include <QObject>
#include <QHash>
#include <QVariant>
#include <QList>
#include <QString>
class PersistentData : public QObject
{
Q_OBJECT
public:
explicit PersistentData(const QString &datafileName, QObject *parent = nullptr);
void setDCFirmwareVersion(const QString & fw_version);
QString getDCFirmwareVersion();
QVariant getParameter(const QString & key);
QVariant getParameter(const QString & key) const;
void setParameter(const QString & key, QVariant value);
void clearParameter(const QString & key);
bool hasParameter(const QString & key) const;
uint getUintParameter(const QString & key) const;
QList<QString> uniqueKeys() const;
public slots:
void serializeToFile();
signals:
private:
QHash<QString, QVariant> hash;
QString dc_fw_version;
QString filename;
void save();
void read();
bool isChangedFlag;
};
#endif // PERSISTENTDATA_H

View File

@@ -0,0 +1,169 @@
#include "Ticket.h"
#include <QDebug>
Ticket::Ticket(TICKET_VARIANT ticketVariant, QObject *parent )
: QObject(parent)
, ticketVariant(ticketVariant)
, _hasTemplateDynData(false)
{
}
TICKET_VARIANT Ticket::variant()
{
return this->ticketVariant;
}
QList<quint8> * Ticket::templateList()
{
return &(this->_templateList);
}
bool Ticket::hasTemplateDynData()
{
return this->_hasTemplateDynData;
}
quint8 Ticket::getCurrentProcessedTemplateNumber()
{
return this->currentProcessedTemplateNumber;
}
void Ticket::setCurrentTemplateProcessed()
{
this->currentProcessedTemplateNumber++;
}
bool Ticket::initNew(TICKET_VARIANT ticketVariant, const QList<quint8> & templateList, const QHash<QString, QVariant> & printingData)
{
this->clear();
this->ticketVariant = ticketVariant;
this->printingData = printingData;
this->_templateList = templateList;
this->currentProcessedTemplateNumber = 0;
// DEBUG
qCritical() << "Ticket::initNew():";
qCritical() << " -> " << ticketVariant;
int multiplicatorInt = 1; // default
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;
break;
case TICKET_VARIANT::STOP_RECEIPT:
this->_templateList << 24 << 25 << 26;
break;
case TICKET_VARIANT::FOOD_STAMP:
if (printingData.contains("dyn1_list")) {
this->_hasTemplateDynData = true;
this->dyn1List = printingData["dyn1_list"].toStringList();
this->dyn2List = printingData["dyn2_list"].toStringList();
}
if (printingData.contains("multiplicator")) {
multiplicatorInt = printingData["multiplicator"].toInt();
for (int i = 1; i < multiplicatorInt; i++) {
this->_templateList << 1;
}
// last template:
this->_templateList << 2;
}
// DEBUG FOOD_STAMP:
qCritical() << " --> printingData[\"multiplicator\"]" << multiplicatorInt;
break;
}
// DEBUG
QString templateListString;
for (int i =0; i < this->_templateList.size(); ++i) {
templateListString.append(QString(" %1").arg(this->_templateList.at(i)));
}
qCritical() << " -> templates: " << templateListString;
return true;
}
void Ticket::clear()
{
this->ticketVariant = TICKET_VARIANT::PARKING_TICKET;
this->printingData.clear();
this->_templateList.clear();
this->errorCode.clear();
this->errorDescription.clear();
this->_hasTemplateDynData = false;
this->dyn1List.clear();
this->dyn1List.clear();
}
QString Ticket::getErrorCode() { return this->errorCode; }
QString Ticket::getErrorDescription() { return this->errorDescription; }
/**
*/
QStringList Ticket::getDyn1List()
{
return this->dyn1List;
}
QStringList Ticket::getDyn2List()
{
return this->dyn2List;
}
QHash<QString, QVariant> & Ticket::getPrintingData()
{
return this->printingData;
}
/************************************************************************************************
* operator
*
*/
QDebug operator<<(QDebug debug, TICKET_VARIANT ticketVariant)
{
switch (ticketVariant) {
case TICKET_VARIANT::PARKING_TICKET:
debug << "TICKET_VARIANT::PARKING_TICKET";
break;
case TICKET_VARIANT::RECEIPT:
debug << "TICKET_VARIANT::RECEIPT";
break;
case TICKET_VARIANT::ERROR_RECEIPT:
debug << "TICKET_VARIANT::ERROR_RECEIPT";
break;
case TICKET_VARIANT::START_RECEIPT:
debug << "TICKET_VARIANT::START_RECEIPT";
break;
case TICKET_VARIANT::STOP_RECEIPT:
debug << "TICKET_VARIANT::STOP_RECEIPT";
break;
case TICKET_VARIANT::FOOD_STAMP:
debug << "TICKET_VARIANT::FOOD_STAMP";
break;
}
return debug;
}

View File

@@ -0,0 +1,88 @@
#ifndef TICKET_H
#define TICKET_H
#include <QObject>
#include <QHash>
#include "../DeviceControllerInterface.h"
using namespace nsDeviceControllerInterface;
QDebug operator<<(QDebug debug, TICKET_VARIANT ticketVariant);
class Ticket : public QObject
{
Q_OBJECT
public:
Ticket(TICKET_VARIANT ticketVariant, QObject *parent = nullptr);
bool initNew(TICKET_VARIANT ticketVariant, const QList<quint8> & templateList, const QHash<QString, QVariant> & printingData);
void clear();
TICKET_VARIANT variant();
QList<quint8> * templateList();
/**
* @brief getPrintingData - generic getter for printingData
* Used mainly for simple tickets (single tickets e.g. ParkingTicket)
* @return
*/
QHash<QString, QVariant> & getPrintingData();
/**
* @brief hasTemplateDynData
* @return true, if ticket has dynamic data for each template.
*
* This depends on TICKET_VARIANT and printingData
*/
bool hasTemplateDynData();
/**
* @brief getDyn1List
* contains dynamic template data
* The size of the lists must be exactly the same as the number of templates.
*/
QStringList getDyn1List();
QStringList getDyn2List();
quint8 getCurrentProcessedTemplateNumber();
/**
* Mark current template as processed
*/
void setCurrentTemplateProcessed();
// error handling
QString getErrorCode();
QString getErrorDescription();
private:
TICKET_VARIANT ticketVariant;
// printingData from application
QHash<QString, QVariant> printingData;
// templateList, from .ini or created by ticketVariant...
QList<quint8> _templateList;
bool _hasTemplateDynData;
quint8 currentProcessedTemplateNumber;
QStringList dyn1List;
QStringList dyn2List;
// error handling
QString errorCode;
QString errorDescription;
};
#endif // TICKET_H