Compare commits

...

28 Commits
1.1.1 ... 1.2.3

Author SHA1 Message Date
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
bdb0f9911b Print: set font on bank-receipt 2024-01-08 17:29:44 +01:00
c679b489ba Merge branch 'pu/AccountMessage' into pu/integration 2023-12-22 10:08:38 +01:00
1c643c6caf Update DeviceControllerInterface to 1.1.1 2023-12-22 09:26:13 +01:00
246e23bffd Fix: typo 2023-12-18 08:21:08 +01:00
07bb1bde50 Send interface signal on VaultDoor opened 2023-12-15 11:54:36 +01:00
81a70bf387 Upate DeviceControllerInterface to 1.1.0 2023-12-15 11:29:08 +01:00
012f3430c5 Rework for getAmountOfInsertedNotes due to wrong description in interface 2023-12-14 15:48:37 +01:00
80c7992d5b Start autoRequest allways ...
... we need this!
2023-12-13 09:23:03 +01:00
c603313d73 PrintTicket: skip check of serial port 2023-12-11 18:32:37 +01:00
b3ad8e1ee9 Interrupt DiagRequest on error 2023-12-11 18:32:27 +01:00
bee611651c Update interfaces.h 2023-12-08 12:42:58 +01:00
25cb23a587 Send cashPaymentFinished() onCashChangerState() ...
This is for checking changer result and includes lot of debug code!
2023-12-08 12:41:57 +01:00
05113057b0 CashUtils: is not a class, it is a namespace 2023-12-08 12:33:46 +01:00
7affcb0313 Update DeviceControllerInterface 1.0.3
Signal cashPaymentFinished()
2023-12-04 10:31:52 +01:00
60c4d5896a Set 'printerLocale' from settings 2023-12-01 15:07:29 +01:00
d2a0491bba cashInputFinished: return coins/notes/change 2023-11-30 18:18:43 +01:00
96db7be126 Add object variable cashStartAmountInt
Used to track proposed change amount.
2023-11-30 18:17:44 +01:00
247abb7520 Add class CashUtils: utility methods for CashProcessing 2023-11-30 18:15:07 +01:00
e95de7f9e4 Print: dates in QLocale::ShortFormat
Note: this needs test!
Expected behaviour is that date format switches with language switch!
This my be no problem in most cases however, e.g. in some cases there
would be a different date format on the tickets.
2023-11-30 16:33:47 +01:00
8c1aa26145 Update DeviceControllerInterface 1.0.2
Send cashInputFinished with coins/notes/change
2023-11-30 12:04:11 +01:00
30de664991 MDBwake: switch on/off during ModeSELL/ModeSERVICE 2023-11-30 09:27:57 +01:00
f938a75742 Account: read bill stacker values 2023-11-29 16:10:38 +01:00
49a13fd333 Account: insert NOTEs 2023-11-29 12:31:52 +01:00
07d812f5d9 Account: count coins from 1..X 2023-11-29 12:31:05 +01:00
11 changed files with 702 additions and 37 deletions

View File

@@ -77,9 +77,11 @@ HEADERS += \
src/ATBAPP/ATBMachineEvent.h \
src/ATBAPP/ATBDeviceControllerPlugin.h \
src/ATBAPP/Utils.h \
src/ATBAPP/support/CashUtils.h \
src/ATBAPP/support/DBusControllerInterface.h \
src/ATBAPP/support/JSON.h \
src/ATBAPP/support/PTUSystem.h
src/ATBAPP/support/PTUSystem.h \
src/ATBAPP/support/PersistentData.h
SOURCES += \
src/ATBAPP/ATBHealthEvent.cpp \
@@ -87,9 +89,11 @@ SOURCES += \
src/ATBAPP/ATBDeviceControllerPlugin.cpp \
src/ATBAPP/DeviceControllerDiag.cpp \
src/ATBAPP/Utils.cpp \
src/ATBAPP/support/CashUtils.cpp \
src/ATBAPP/support/DBusControllerInterface.cpp \
src/ATBAPP/support/JSON.cpp \
src/ATBAPP/support/PTUSystem.cpp
src/ATBAPP/support/PTUSystem.cpp \
src/ATBAPP/support/PersistentData.cpp
DISTFILES += \
generate-version.sh

View File

@@ -1834,6 +1834,9 @@ public:
virtual uint8_t prn_getPrintResult() const {
return 0;
}
// return: 0: just printing, wait
// 1: OK - last print was succesful
// 2: error - not printed
@@ -2273,7 +2276,32 @@ public:
signals:
virtual void hwapi_templatePrintFinished_OK(void) const=0;
virtual void hwapi_templatePrintFinished_Err(void) const=0;
virtual void hwapi_coinCollectionJustStarted(void) const=0;
virtual void hwapi_coinCollectionAborted(void) const=0;
virtual void hwapi_gotNewCoin(void) const=0;
virtual void hwapi_payStopByMax(void) const=0;
virtual void hwapi_payStopByPushbutton(void) const=0;
virtual void hwapi_payStopByEscrow(void) const=0;
virtual void hwapi_payStopByError(void) const=0;
virtual void hwapi_payStopByTimeout(void) const=0;
virtual void hwapi_payCancelled(void) const=0;
virtual void hwapi_coinProcessJustStopped(void) const=0;
virtual void hwapi_doorServiceDoorOpened(void) const=0;
virtual void hwapi_doorVaultDoorOpened(void) const=0;
virtual void hwapi_doorCoinBoxRemoved(void) const=0;
virtual void hwapi_doorCoinBoxInserted(void) const=0;
virtual void hwapi_doorCBinAndAllDoorsClosed(void) const=0;
virtual void hwapi_doorAllDoorsClosed(void) const=0;
// NOTE: declaring a "pure virtual" "signal" should be an error and thus not valid.
/* GH Version, bringt Fehler
void hwapi_templatePrintFinished_OK() const;
void hwapi_templatePrintFinished_Err() const;
@@ -2296,6 +2324,7 @@ signals:
void hwapi_doorCoinBoxInserted() const;
void hwapi_doorCBinAndAllDoorsClosed() const;
void hwapi_doorAllDoorsClosed() const;
*/
};

View File

@@ -5,6 +5,7 @@
#include "src/ATBAPP/support/JSON.h"
#include "src/ATBAPP/support/DBusControllerInterface.h"
#include "src/ATBAPP/support/PTUSystem.h"
#include "src/ATBAPP/support/CashUtils.h"
#include <QTimer>
#include <QThread>
@@ -59,13 +60,16 @@ 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);
this->diag = new DeviceControllerDiag(this->persistentData, this);
connect(this->diag, &DeviceControllerDiag::newVoltage, this, &ATBDeviceControllerPlugin::onNewVoltage);
this->currentSelectedTicketType = 0;
this->currentCashState = CASH_STATE::CACHE_EMPTY;
this->cashStartAmountInt = 0;
}
ATBDeviceControllerPlugin::~ATBDeviceControllerPlugin() {}
@@ -77,13 +81,17 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con
// 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) {
// open serial port
hw->dc_openSerial(5, "115200", this->serialPortName, 1);
hw->dc_autoRequest(true);
}
hw->dc_autoRequest(true);
hw->dc_setNewCustomerNumber(PTUSystem::readCustomerNumber());
hw->dc_setNewMachineNumber(PTUSystem::readMachineNumber());
hw->dc_setNewZone(PTUSystem::readZoneNumber());
@@ -94,6 +102,11 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *eventReceiver, con
// this is necessary to init the CashAgentLib (!)
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
this->codec = QTextCodec::codecForName(printerEncoding);
@@ -126,6 +139,11 @@ void ATBDeviceControllerPlugin::startPhysicalLayer()
return;
}
qCritical() << "ATBDeviceControllerPlugin::startPhysicalLayer() " << endl
<< " -> use master lib " << endl
<< " -> start physical layer";
// open serial port
hw->dc_openSerial(5, "115200", this->serialPortName, 1);
@@ -134,6 +152,10 @@ void ATBDeviceControllerPlugin::startPhysicalLayer()
void ATBDeviceControllerPlugin::stopPhysicalLayer()
{
// store persistent data
this->persistentData->serializeToFile();
// skip, if we use slave lib
if (!this->isMaster) return;
if (this->pluginState == PLUGIN_STATE::NOT_INITIALIZED)
@@ -170,19 +192,22 @@ void ATBDeviceControllerPlugin::reset()
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->dc_autoRequest(true);
hw->mdb_switchWake(0); // wakeup MDB components
}
void ATBDeviceControllerPlugin::onChangedProgramModeToIDLE()
{
//hw->dc_autoRequest(false); // <-- TODO: ???
hw->dc_autoRequest(true);
this->diag->diagRequest();
hw->mdb_switchWake(1);
}
@@ -197,11 +222,11 @@ void ATBDeviceControllerPlugin::requestStartCashInput(const QString & amount)
{
qCritical() << "Start Cash vending with amount = " << amount;
uint32_t amountInt = static_cast<uint32_t>(amount.toUInt());
this->cashStartAmountInt = static_cast<uint32_t>(amount.toUInt());
if (amountInt == 0) amountInt = UINT_MAX;
if (this->cashStartAmountInt == 0) this->cashStartAmountInt = UINT_MAX;
hw->cash_startPayment(amountInt);
hw->cash_startPayment(this->cashStartAmountInt);
}
void ATBDeviceControllerPlugin::requestStopCashInput()
@@ -215,7 +240,33 @@ void ATBDeviceControllerPlugin::requestStopCashInput()
void ATBDeviceControllerPlugin::cashCollect()
{
hw->vend_success();
this->currentCashState = CASH_STATE::CACHE_EMPTY;
// inserted amount
uint32_t amountInt = this->hw->getInsertedAmount();
QString amountString = QString::number(amountInt);
// inserted coins
uint32_t amountCoinsInt = CashUtils::getAmountOfInsertedCoins(this->hw);
QString amountCoinsString = QString::number(amountCoinsInt);
// inserted notes
uint32_t amountNotesInt = CashUtils::getAmountOfInsertedNotes(this->hw);
QString amountNotesString = QString::number(amountNotesInt);
if (this->coinProcessor() == nsDeviceControllerInterface::COIN_PROCESSOR::CHANGER) {
QTimer::singleShot(1000, this, &ATBDeviceControllerPlugin::onCashChangerState);
}
else {
emit this->cashPaymentFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
amountCoinsString, // coins
amountNotesString, // notes
0, // proposed change
"",
"");
this->currentCashState = CASH_STATE::CACHE_EMPTY;
}
}
void ATBDeviceControllerPlugin::cashAbort()
@@ -340,9 +391,9 @@ void ATBDeviceControllerPlugin::private_getAccountData()
accountData.insert("accountStartTime", startDateTime);
//-------------------------------------------------------------------------
// COINS in Vault: --------------------------------------------------------
int numberOfCoinVariants = sizeof(retVR.coinsInVault);
int numberOfCoinVariants = sizeof(retVR.coinsInVault)/sizeof(retVR.coinsInVault[0]);
// DEBUG
qCritical() << " NumberOfCoinVariants = " << numberOfCoinVariants;
@@ -352,14 +403,36 @@ void ATBDeviceControllerPlugin::private_getAccountData()
accountData.insert("NumberOfCoinVariants", numberOfCoinVariants);
for (int i = 0; i < numberOfCoinVariants; ++i) {
accountData.insert("COIN_" + QString::number(i) + "_Quantity", retVR.coinsInVault[i]);
accountData.insert("COIN_" + QString::number(i) + "_Value", retVR.coinDenomination[i]);
accountData.insert("COIN_" + QString::number(i+1) + "_Quantity", retVR.coinsInVault[i]);
accountData.insert("COIN_" + QString::number(i+1) + "_Value", retVR.coinDenomination[i]);
// DEBUG
qCritical() << "COIN_" + QString::number(i) + "_Quantity = " << accountData["COIN_" + QString::number(i) + "_Quantity"];
qCritical() << "COIN_" + QString::number(i) + "_Value = " << accountData["COIN_" + QString::number(i) + "_Value"];
qCritical() << "COIN_" + QString::number(i+1) + "_Quantity = " << accountData["COIN_" + QString::number(i) + "_Quantity"];
qCritical() << "COIN_" + QString::number(i+1) + "_Value = " << accountData["COIN_" + QString::number(i) + "_Value"];
}
// NOTES in stacker: --------------------------------------------------------
int numberOfBillVariants = sizeof(retVR.billsInStacker)/sizeof(retVR.billsInStacker[0]);
// DEBUG
qCritical() << " numberOfBillVariants = " << numberOfBillVariants;
// limit numberOfBillVariants:
if (numberOfBillVariants > 16) { numberOfBillVariants = 16; }
accountData.insert("NumberOfBillVariants", numberOfBillVariants);
for (int i = 0; i < numberOfBillVariants; ++i) {
accountData.insert("NOTE_" + QString::number(i+1) + "_Quantity", retVR.billsInStacker[i]);
accountData.insert("NOTE_" + QString::number(i+1) + "_Value", retVR.billDenom[i]);
// DEBUG
qCritical() << "NOTE_" + QString::number(i+1) + "_Quantity = " << accountData["NOTE_" + QString::number(i+1) + "_Quantity"];
qCritical() << "NOTE_" + QString::number(i+1) + "_Value = " << accountData["NOTE_" + QString::number(i+1) + "_Value"];
}
emit requestAccountResponse(accountData);
}
@@ -381,9 +454,6 @@ void ATBDeviceControllerPlugin::onServiceDoorOpened()
void ATBDeviceControllerPlugin::onVaultDoorOpened()
{
// TODO:
// - show special screen / message on screen
// - create an HealthEvent (-> ISMAS-Event)
qCritical() << "ATBDeviceControllerPlugin::onVaultDoorOpened()";
// ... to detect alarm etc.
@@ -394,7 +464,13 @@ void ATBDeviceControllerPlugin::onVaultDoorOpened()
// BackgroundTask("ACCOUNT") is finished, if account message is sent to ISMAS!
this->dbus->startBackgroundTask("DOOR_OPEN");
// do not: emit this->requestModeSERVICE();
emit this->requestModeACCOUNT();
// send service message, delayed:
QTimer::singleShot(1000, this, [this](){
emit this->showServiceText(nsDeviceControllerInterface::SERVICE_TEXT::VAULT_DOOR_OPENED, "Please remove coinbox");
hw->prn_cut(3);
} );
}
void ATBDeviceControllerPlugin::onCoinBoxRemoved()
@@ -404,12 +480,17 @@ void ATBDeviceControllerPlugin::onCoinBoxRemoved()
// BackgroundTask("ACCOUNT") is finished, if account message is sent to ISMAS!
this->dbus->startBackgroundTask("ACCOUNT");
emit this->showServiceText(nsDeviceControllerInterface::SERVICE_TEXT::COIN_BOX_REMOVED, "Please insert coinbox");
QTimer::singleShot(4000, this, SLOT(private_startAccount()));
}
void ATBDeviceControllerPlugin::onCoinBoxInserted()
{
qCritical() << "ATBDeviceControllerPlugin::onCoinBoxInserted()";
emit this->showServiceText(nsDeviceControllerInterface::SERVICE_TEXT::COIN_BOX_INSERTED, "Please close vault door");
// emit this->showServiceText(0x1234);
}
/**
@@ -481,6 +562,10 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::
QDateTime parkingEndDateTime = QDateTime::fromString(printingData["parkingEnd"].toString(), Qt::ISODate);
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));
@@ -492,11 +577,11 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::
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(parkingEndDateTime.toString("yy.MM.dd"));
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(currentDateTime.toString("yy.MM.dd"));
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
@@ -548,11 +633,13 @@ void ATBDeviceControllerPlugin::requestPrintTicket(nsDeviceControllerInterface::
}
/*
if (!this->hw->dc_isPortOpen()) {
qCritical() << " ... serial port is not open!";
this->onPrintFinishedERR();
return;
}
*/
// TODO: wird hier nur 'licensePlate' gedruckt?
if (!this->hw->prn_sendDynamicPrnValues(dynTicketData->licensePlate)) {
@@ -587,6 +674,7 @@ void ATBDeviceControllerPlugin::requestPrintReceipt(const QString & printingStri
{
QByteArray ba = printingString.toUtf8();
hw->prn_switchPower(true);
hw->prn_setFonts(8,12,0,0);
hw->prn_sendText(&ba);
QTimer::singleShot(4000, this, SLOT(onPrinterWaitForPrintingReceipt()));
@@ -648,6 +736,9 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
QDateTime parkingEndDateTime = QDateTime::fromString(printingData["parkingEnd"].toString(), Qt::ISODate);
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);
/* -----------------------------------------------------------------------------------------
* note: the following highly depends on printer template files!
* -----------------------------------------------------------------------------------------
@@ -665,11 +756,11 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
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(parkingEndDateTime.toString("yy.MM.dd"));
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(currentDateTime.toString("yy.MM.dd"));
QByteArray ba_currentDate = codec->fromUnicode(currentDateString);
memcpy((char*)dynTicketData->currentDate, ba_currentDate.data(), std::min(ba_currentDate.size(),8));
@@ -686,12 +777,13 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
// DEBUG
qCritical() << "ATBDeviceControllerPlugin::requestPrintTicket()";
/*
if (!this->hw->dc_isPortOpen()) {
qCritical() << " ... serial port is not open!";
this->onPrintFinishedERR();
return;
}
*/
// TODO: wird hier nur 'licensePlate' gedruckt?
if (!this->hw->prn_sendDynamicPrnValues(dynTicketData->licensePlate)) {
@@ -904,6 +996,9 @@ void ATBDeviceControllerPlugin::onCashPayStopByEscrow()
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::ERROR_BACKEND,
amountString,
"",
"",
"",
"",
"");
}
@@ -919,6 +1014,9 @@ void ATBDeviceControllerPlugin::onCashPayStopByError()
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::ERROR_BACKEND,
amountString,
"",
"",
"",
"",
"");
}
@@ -934,6 +1032,9 @@ void ATBDeviceControllerPlugin::onCashPayStopByTimeout()
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::ERROR_BACKEND,
amountString,
"",
"",
"",
"",
"");
}
@@ -942,19 +1043,206 @@ void ATBDeviceControllerPlugin::onCashPayStopedSuccess()
// DEBUG
qCritical() << "ATBDeviceControllerPlugin::onCashPayStopedSuccess()";
// inserted amount
uint32_t amountInt = this->hw->getInsertedAmount();
QString amountString = QString::number(amountInt);
qCritical() << " insertedAmount (int) = " << amountInt;
qCritical() << " insertedAmount = " << amountString;
// inserted coins
uint32_t amountCoinsInt = CashUtils::getAmountOfInsertedCoins(this->hw);
QString amountCoinsString = QString::number(amountCoinsInt);
// inserted notes
uint32_t amountNotesInt = CashUtils::getAmountOfInsertedNotes(this->hw);
QString amountNotesString = QString::number(amountNotesInt);
// amount due to change
uint32_t amountDueToChangeInt;
if (amountInt > this->cashStartAmountInt) {
amountDueToChangeInt = amountInt - this->cashStartAmountInt;
}
else {
amountDueToChangeInt = 0;
}
QString amountDueToChangeString = QString::number(amountDueToChangeInt);
// DEBUG
qCritical() << "---------------------------------------------------------";
qCritical() << "ATBDeviceControllerPlugin::onCashPayStopedSuccess()";
qCritical() << "";
qCritical() << " amountInt: " << amountInt;
qCritical() << " amountString: " << amountString;
qCritical() << "";
qCritical() << " amountNotesInt: " << amountNotesInt;
qCritical() << " amountNotesString: " << amountNotesString;
qCritical() << "";
qCritical() << " amountCoinsInt: " << amountCoinsInt;
qCritical() << " amountCoinsString: " << amountCoinsString;
qCritical() << "";
qCritical() << " this->cashStartAmountInt: " << this->cashStartAmountInt;
qCritical() << " amountDueToChangeInt: " << amountDueToChangeInt;
qCritical() << " amountDueToChangeString: " << amountDueToChangeString;
qCritical() << "---------------------------------------------------------";
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
amountCoinsString, // coins
amountNotesString, // notes
amountDueToChangeString, // proposed change
"",
"");
}
void ATBDeviceControllerPlugin::onCashChangerState()
{
uint32_t amountThatCouldNotBeChangedInt;
static int changerStateRequestCounter = 0;
static uint8_t lastChangerResult = 0;
// inserted amount
uint32_t amountInt = this->hw->getInsertedAmount();
QString amountString = QString::number(amountInt);
// inserted coins
uint32_t amountCoinsInt = CashUtils::getAmountOfInsertedCoins(this->hw);
QString amountCoinsString = QString::number(amountCoinsInt);
// inserted notes
uint32_t amountNotesInt = CashUtils::getAmountOfInsertedNotes(this->hw);
QString amountNotesString = QString::number(amountNotesInt);
// amount due to change
uint32_t amountCoinsChangedInt;
if (amountInt > this->cashStartAmountInt) {
amountCoinsChangedInt = amountInt - this->cashStartAmountInt;
}
else {
amountCoinsChangedInt = 0;
}
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 ------------------------------------------------
// Note: 'returnedAmount'-parameter is missleading here!
// 'returnedAmount' is the amount which could not be changed!
lastChangerResult = hw->changer_getChangeResult(&amountThatCouldNotBeChangedInt);
// DEBUG
qCritical() << "---------------------------------------------------------";
qCritical() << "ATBDeviceControllerPlugin::onCashChangerState()";
qCritical() << " changerStateRequestCounter: " << changerStateRequestCounter;
qCritical() << " lastChangerResult: " << lastChangerResult;
qCritical() << " amountThatCouldNotBeChangedInt: " << amountThatCouldNotBeChangedInt;
qCritical() << "";
qCritical() << " amountInt: " << amountInt;
qCritical() << " amountString: " << amountString;
qCritical() << "";
qCritical() << " amountCoinsInt: " << amountCoinsInt;
qCritical() << " amountCoinsString: " << amountCoinsString;
qCritical() << "";
qCritical() << " amountNotesInt: " << amountNotesInt;
qCritical() << " amountNotesString: " << amountNotesString;
qCritical() << "";
qCritical() << " this->cashStartAmountInt: " << this->cashStartAmountInt;
qCritical() << " amountCoinsChangedInt: " << amountCoinsChangedInt;
qCritical() << " amountCoinsChangedString: " << amountCoinsChangedString;
qCritical() << "---------------------------------------------------------";
if (lastChangerResult == 1) { // change is returned
QString amountCoinsChangedString = QString::number(amountCoinsChangedInt);
emit this->cashPaymentFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
amountCoinsString, // coins
amountNotesString, // notes
amountCoinsChangedString, // change
"",
"");
changerStateRequestCounter = 0;
lastChangerResult = 0;
return;
}
else
if (lastChangerResult == 0) { // not yet started
qCritical() << "ATBDeviceControllerPlugin::onCashChangerState(): ERROR: change not yet started: amount due to return: " << amountCoinsChangedString;
}
else
if (lastChangerResult == 2) { // only partial return
qCritical() << "ATBDeviceControllerPlugin::onCashChangerState(): ERROR: only partial return: amount due to return: " << amountCoinsChangedString;
}
else
if (lastChangerResult == 3) { // no return possible
qCritical() << "ATBDeviceControllerPlugin::onCashChangerState(): ERROR: no return possible: amount due to return: " << amountCoinsChangedString;
}
else {
qCritical() << "ATBDeviceControllerPlugin::onCashChangerState(): ERROR: invalid changerState (" << lastChangerResult << ")";
}
// handle timeout ------------------------------------------------
if (changerStateRequestCounter > 15) {
QString errorCode;
QString errorDescription;
switch (lastChangerResult) {
case 0: // not yet started
errorCode = "DC::CHANGER::START";
errorDescription = "Changer does not start";
break;
case 1: // amount returned
// This error should not occur!
errorCode = "DC::CHANGER::INVALID";
errorDescription = "Changer returned amount";
break;
case 2: // only partial return
errorCode = "DC::CHANGER::CHANGE";
errorDescription = "Changer does only partial return";
break;
case 3: // no return possible
errorCode = "DC::CHANGER::CHANGE_NOT_POSSIBLE";
errorDescription = "Changing not possible";
break;
default:
break;
}
emit this->cashPaymentFinished(nsDeviceControllerInterface::RESULT_STATE::ERROR_BACKEND,
amountString,
amountCoinsString,
amountNotesString,
0,
errorCode,
errorDescription);
changerStateRequestCounter = 0;
lastChangerResult = 0;
return;
}
// restart changer check:
changerStateRequestCounter++;
QTimer::singleShot(1000, this, &ATBDeviceControllerPlugin::onCashChangerState);
}
/**
@@ -1035,6 +1323,10 @@ bool ATBDeviceControllerPlugin::private_loadCashAgentLib(QString pluginName)
qCritical() << "ATBDeviceControllerPlugin: loaded CashAgentLib";
if (this->isMaster) {
QTimer::singleShot(500, this, &ATBDeviceControllerPlugin::startPhysicalLayer);
}
return true;
}

View File

@@ -2,6 +2,7 @@
#define ATBDEVICECONTROLLERPLUGIN_H
#include <QObject>
#include <QLocale>
#include "src/ATBAPP/DeviceControllerInterface.h"
#include "src/ATBAPP/ATBAPPplugin.h"
@@ -9,7 +10,7 @@
#include "version.h"
#include "support/PersistentData.h"
#include "interfaces.h"
@@ -111,6 +112,10 @@ private:
DeviceControllerDiag* diag;
PersistentData *persistentData;
uint32_t cashStartAmountInt;
QTextCodec *codec;
@@ -126,6 +131,8 @@ private:
// dbus
int init_sc_dbus();
QLocale printerLocale;
private slots:
// printer
@@ -146,6 +153,7 @@ private slots:
void onCashPayStopByEscrow();
void onCashPayStopByError();
void onCashPayStopByTimeout();
void onCashChangerState();
// doors and hardware contacts
void onServiceDoorOpened();

View File

@@ -5,13 +5,14 @@
#include <QUuid>
#include <QDebug>
DeviceControllerDiag::DeviceControllerDiag(QObject *parent)
DeviceControllerDiag::DeviceControllerDiag(PersistentData *pData, QObject *parent)
: QObject(parent)
, coinProcessorType(nsDeviceControllerInterface::COIN_PROCESSOR::ESCROW)
, billAcceptor(nsDeviceControllerInterface::BILL_ACCEPTOR::NO)
, eventReceiver(nullptr)
, isRequestRunning(false)
, flagInterruptDiag(false)
, pData(pData)
{
diagRequestTimeoutTimer = new QTimer(this);
diagRequestTimeoutTimer->setInterval(1000*20); // 20s
@@ -42,6 +43,16 @@ void DeviceControllerDiag::diagRequest()
this->diagRequestTimeoutTimer->start();
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();
}
@@ -57,6 +68,8 @@ void DeviceControllerDiag::private_startDiag()
if (this->flagInterruptDiag) {
qCritical() << "DeviceControllerDiag::private_startDiag() interrupted!";
this->private_sendDiagEvent(DeviceController::State::E255);
this->isRequestRunning = false;
this->flagInterruptDiag = false;
return;
}
@@ -89,6 +102,8 @@ void DeviceControllerDiag::sys_superviseSystem()
if (this->flagInterruptDiag) {
qCritical() << "DeviceControllerDiag::sys_superviseSystem() interrupted!";
this->private_sendDiagEvent(DeviceController::State::E255);
this->flagInterruptDiag = false;
this->isRequestRunning = false;
return;
}
@@ -97,6 +112,8 @@ void DeviceControllerDiag::sys_superviseSystem()
// es gibt keinerlei gültige Daten vom DC
qCritical() << "DeviceControllerDiag::sys_superviseSystem() no valid data!";
this->private_sendDiagEvent(DeviceController::State::E254);
this->diagRequestTimeoutTimer->stop();
this->isRequestRunning = false;
return;
}

View File

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

View File

@@ -15,6 +15,9 @@ namespace nsDeviceControllerInterface {
enum class TICKET_VARIANT : quint8;
enum class COIN_PROCESSOR : quint8;
enum class BILL_ACCEPTOR : quint8;
enum class SERVICE_TEXT : quint16;
}
@@ -119,16 +122,38 @@ signals:
*/
void cashInputFinished(nsDeviceControllerInterface::RESULT_STATE resultState,
const QString & newCashValue,
/* additional variables? */
const QString & coinValue,
const QString & noteValue,
const QString & changeValue,
const QString & errorCode,
const QString & errorDescription);
/**
* emitted if cashPayment has been finished, e.g. in result to task cashCollect():
* -> ticket should be printed sucessfully
* -> coins in excrow or changer are given back to user
* Provides data for logging, especially changed value
*/
void cashPaymentFinished(nsDeviceControllerInterface::RESULT_STATE resultState,
const QString & newCashValue, // total inserted amount amount
const QString & coinValue, // inserted amount, paid with coins
const QString & noteValue, // inserted amount, paid with notes
const QString & changeValue, // amount changed by changer/escrow
const QString & errorCode,
const QString & errorDescription);
/**
* emitted e.g. if service door is opened
*/
void requestModeSERVICE();
/**
* emitted e.g. if vault door is opened
*/
void requestModeACCOUNT();
/**
* emitted e.g. if doors are closed
*/
@@ -145,7 +170,10 @@ signals:
void requestAccountResponse(const QHash<QString, QVariant> & accountData);
/**
* show text messages in service mode
*/
void showServiceText(nsDeviceControllerInterface::SERVICE_TEXT serviceText, const QString & text);
/**
@@ -165,7 +193,7 @@ signals:
Q_DECLARE_INTERFACE(DeviceControllerInterface,
"eu.atb.ptu.plugin.DeviceControllerInterface/1.0.1")
"eu.atb.ptu.plugin.DeviceControllerInterface/1.1.1")
namespace nsDeviceControllerInterface {
@@ -209,6 +237,14 @@ namespace nsDeviceControllerInterface {
YES,
NO
};
enum class SERVICE_TEXT : quint16 {
SERVICE_DOOR_OPENED,
VAULT_DOOR_OPENED,
COIN_BOX_REMOVED,
COIN_BOX_INSERTED
/* t.b.d. */
};
}
#endif // DEVICECONTROLLERINTERFACE_H

View File

@@ -0,0 +1,74 @@
#include "CashUtils.h"
#include <QDebug>
#define MAX_COINS 64
#define MAX_NOTES 16
/*****************************************************************************
* Get current inserted coins
*
* getAllInsertedCoins(uint16_t *types, uint16_t *values)
* all inserted coins of this past transaction are stored, max 64
*/
uint32_t CashUtils::getAmountOfInsertedCoins(hwinf* hw)
{
uint32_t result = 0;
uint16_t types[MAX_COINS];
uint16_t values[MAX_COINS];
hw->getAllInsertedCoins(types, values);
for (int i = 0; i < MAX_COINS; i++) {
result += values[i];
}
return result;
}
/*****************************************************************************
* Get current inserted notes
*
* virtual uint8_t bna_getCurrentNotes(uint16_t latestBill, uint16_t *currentNotes) const =0;
* returns number of collected bank notes since start-command (current transaction)
* latestBill: last accepted bank note, value in cent
* currentNotes an array with up to 16 (further) notes collected
*
*/
uint32_t CashUtils::getAmountOfInsertedNotes(hwinf* hw)
{
uint32_t result = 0;
uint8_t numberOfInsertedNotes;
uint16_t beforeArray = 0;
uint16_t currentNotes[4];
uint16_t afterArray = 0;
numberOfInsertedNotes = hw->bna_getCurrentNotes(0, currentNotes);
if ( (beforeArray != 0) || (afterArray != 0) ) {
qCritical() << "CashUtils::getAmountOfInsertedNotes() ERROR: Array";
}
if (numberOfInsertedNotes == 99) {
// Error
qCritical() << "CashUtils::getAmountOfInsertedNotes() ERROR: ";
for (int i = 0; i < 4; i++) {
qCritical() << " currentNotes[" << i << "] = " << currentNotes[i];
}
}
else {
// no error
result = currentNotes[3];
result = ( result << 16 ) | currentNotes[2];
}
// DEBUG
qCritical() << "--------------------------------------------------";
qCritical() << "CashUtils::getAmountOfInsertedNotes()";
qCritical() << " numberOfInsertedNotes = " << numberOfInsertedNotes;
qCritical() << " result = " << result;
qCritical() << "--------------------------------------------------";
return result;
}

View File

@@ -0,0 +1,14 @@
#ifndef CASHUTILS_H
#define CASHUTILS_H
#include <QObject>
#include "interfaces.h"
namespace CashUtils {
uint32_t getAmountOfInsertedCoins(hwinf* hw);
uint32_t getAmountOfInsertedNotes(hwinf* hw);
}
#endif // CASHUTILS_H

View File

@@ -0,0 +1,140 @@
#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()
{
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();
}
}
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