Add first version which at least complies.

This commit is contained in:
Gerhard Hoffmann 2023-11-10 11:59:00 +01:00
parent a21fa5fce9
commit 26c1f0143e
35 changed files with 11235 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.user

87
ATBAPP.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef ATBAPP_H
#define ATBAPP_H
#include <QObject>
#include <QMetaType>
enum class PROGRAM_MODE : quint8 {
IDLE = 1,
SELL_ENABLE = 2,
SELL = 3,
SERVICE = 4,
OOO = 5
};
QDebug operator<<(QDebug debug, PROGRAM_MODE mode);
namespace CC_VARIANT {
enum class TERMINAL : quint8 {
NO_TERMINAL,
INGENICO_CCTOPP,
INGENICO_CHIP_AND_PIN,
CCV,
FEIG_CCTOPP,
FEIG_CHIP_AND_PIN
};
}
namespace PAYMENT_VARIANTS {
enum class CASH_VARIANT : quint8 {
NO_CASH,
CoinsOnly,
CoinsAndNotes
};
}
enum class PAYMENT_POINTINTIME : quint8 {
PAY_ON_ARRIVAL,
PAY_ON_EXIT,
IGNORE
};
/*********************************************************************
* APP_ACTION
*
*/
/* QVariant.toString() returns empty string for custom types, even if
there is a .toString() method defined.
From QT5.2 onwards there are new methods in QMetaType for registering
comperator and converter methods:
QMetaType::registerComparators()
QMetaType::registerConverter()
see: https://doc.qt.io/qt-5/qmetatype.html#registerComparators
*/
enum class APP_ACTION : int {
DEFAULT_ACTION = 0x00,
LICENSEPLATE_INPUT = 0x01, // License Plate Input
PARKINGTIME_INPUT = 0x02, // Parking Time Input
CARD_PAYMENT = 0x03, // CardPayment
CHOOSE_PAYEMENT = 0x04, // Choose payment variant
COIN_PAYMENT_PAYUP = 0x05,
COIN_PAYMENT_PAYDOWN = 0x06,
SEND_D0_CALC = 0x07,
};
Q_DECLARE_METATYPE(APP_ACTION)
QDebug operator<<(QDebug debug, APP_ACTION action);
enum class CP_STATE : quint8 {
NO_STATE = 0x00,
LICENSEPLATE_INPUT = 0x01, // with accessInformation only
PARKINGTIME_INPUT = 0x02, // with accessInformation and parkingtime
CARDINFO_INPUT = 0x03, // with accessInformation and cardInfo
};
Q_DECLARE_METATYPE(CP_STATE)
#endif // ATBAPP_H

862
ATBHMIconfig.cpp Normal file
View File

@ -0,0 +1,862 @@
#include "ATBHMIconfig.h"
#include "atb_system.h"
#include <QDebug>
#include <QCoreApplication>
#include <QDir>
ATBHMIconfig::ATBHMIconfig(QObject *parent) : QObject(parent) {
this->initEarly();
this->initDefered();
}
ATBHMIconfig::~ATBHMIconfig() {
delete settings;
}
void ATBHMIconfig::initEarly() {
QString settings_file = QCoreApplication::applicationDirPath() + "/ATBQT.ini";
settings = new QSettings(settings_file, QSettings::IniFormat);
settings->setIniCodec("UTF-8");
configGroups = settings->childGroups();
// [COMMON]
settings->beginGroup("COMMON");
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
ComPortName = settings->value("com_port_name", "/dev/ttyS0").toString();
#else
ComPortName = settings->value("com_port_name", "/dev/pts/20").toString();
#endif
ComBaudRate = settings->value("com_baud_rate", "115200").toInt();
if ((ComBaudRate != 115200) &&
(ComBaudRate != 57600) &&
(ComBaudRate != 9600)) { ComBaudRate = 115200; }
lang1 = settings->value("lang1", "de_DE").toString();
lang2 = settings->value("lang2", "en_US").toString();
lang3 = settings->value("lang3", "fr_FR").toString();
lang4 = settings->value("lang4", "ja_JP").toString();
lang5 = settings->value("lang5", "nl-NL").toString();
useLanguage = static_cast<quint8>(settings->value("useLanguage", "255").toInt());
this->defaultLanguage = settings->value("defaultLanguage", "1").toInt();
if ((this->defaultLanguage < 1) || (this->defaultLanguage > 5)) {
this->defaultLanguage = 1;
}
usePayment = static_cast<quint8>(settings->value("usePayment", "255").toInt());
useVehicle = static_cast<quint8>(settings->value("useVehicle", "255").toInt());
useProduct = static_cast<quint8>(settings->value("useProduct", "255").toInt());
textfilename = settings->value("textfile", "HMI_Texte.xml").toString();
#if defined (ARCH_DesktopLinux)
QString filename = textfilename.split("/").last();
textfilename = qApp->applicationDirPath() + "/text/" + filename;
#endif
#if defined (ARCH_DesktopLinux)
logfilename = QDir::homePath() + "/ATBAPP_VMC.log";
#else
logfilename = settings->value("logfile", "/var/log/atbqt.log").toString();
#endif
oooServiceNumber = settings->value("ooo_serviceNumber", "").toString();
oooServiceEmail = settings->value("ooo_serviceEmail", "").toString();
oooAlternativeLocation = settings->value("ooo_alternativeLocation", "").toString();
alternativeLogoFilename = settings->value("alternativeLogoFile").toString();
this->features = 0;
// deprecated:
qmPath = qApp->applicationDirPath() + "/translations";
settings->endGroup();
/*
* note: PSA configuration settings are not stored in ini-file
*/
cust_nr = "0";
group_nr = "0";
zone_nr = "0";
machine_nr = "0";
validPSAconfig = false;
}
void ATBHMIconfig::initDefered() {
bool ok = false;
// [COMMON]
settings->beginGroup("COMMON");
SuspendMethode = settings->value("suspend_methode", "sysfs").toString();
SuspendProgram = settings->value("suspend_program", "").toString();
SuspendTime = settings->value("suspend_time", "10").toString();
if (settings->value("feature_Log", "on").toString() == "on" ||
settings->value("feature_Log", "on").toString() == "yes" )
{ this->setFeatureLog(); }
else { this->unsetFeatureLog(); }
if (settings->value("feature_TouchFeedback", "on").toString() == "on" ||
settings->value("feature_TouchFeedback", "on").toString() == "yes" )
{ this->setFeatureTF(); }
else { this->unsetFeatureTF(); }
if (settings->value("feature_DisplayControl", "off").toString() == "on" ||
settings->value("feature_DisplayControl", "off").toString() == "yes" )
{ this->setFeatureDC(); }
else { this->unsetFeatureDC(); }
if (settings->value("feature_StartButton", "on").toString() == "on" ||
settings->value("feature_StartButton", "on").toString() == "yes" )
{ this->setFeatureStartButton(); }
else { this->unsetFeatureStartButton(); }
if (settings->value("feature_selfOOO", "on").toString() == "on" ||
settings->value("feature_selfOOO", "on").toString() == "yes" )
{ this->setFeatureSelfOOO(); }
else { this->unsetFeatureSelfOOO(); }
if (settings->value("feature_DBusDisplayControl", "on").toString() == "on" ||
settings->value("feature_DBusDisplayControl", "on").toString() == "yes" )
{ this->setFeatureDBusDisplayControl(); }
else { this->unsetFeatureDBusDisplayControl(); }
if (settings->value("feature_DBusSuspendControl", "on").toString() == "on" ||
settings->value("feature_DBusSuspendControl", "on").toString() == "yes" )
{ this->setFeatureDBusSuspendControl(); }
else { this->unsetFeatureDBusSuspendControl(); }
if (settings->value("feature_ShowParkingTime", "on").toString() == "on" ||
settings->value("feature_ShowParkingTime", "on").toString() == "yes" )
{ this->setFeatureShowParkingTime(); }
else { this->unsetFeatureShowParkingTime(); }
touch_feedback_gpio = settings->value("touch_feedback_gpio", "121").toString();
touch_feedback_on_value = settings->value("touch_feedback_on_value", "0").toString();
touch_feedback_off_value = settings->value("touch_feedback_off_value", "1").toString();
QString ooo_mode = settings->value("ooo_mode", "useDisk").toString();
if (ooo_mode == "useDisk")
this->oooMode = OOO_MODE::USE_PARKDISK;
else if (ooo_mode == "otherMachine")
this->oooMode = OOO_MODE::USE_OTHER_MACHINE;
else
this->oooMode = OOO_MODE::DEFAULT;
characterSet = settings->value("CharacterSet", "ISO 8859-15").toByteArray();
qrCodeLink = settings->value("QRCodeLink", "").toString();
SellTimeoutTime = settings->value("sellTimeout_time", "60").toString();
this->privateReadInputDevices();
this->lpLocalExample = settings->value("LicencePlateExampleString", "HOAB123").toString();
#if defined (USE_BARCODESCANNER)
if (settings->value("useBarcode", "on").toString() == "on" ||
settings->value("useBarcode", "on").toString() == "yes" )
{ this->useBarcode = true; }
else { this->useBarcode = false; }
#endif // USE_BARCODESCANNER
#ifdef USE_RFIDREADER
if (settings->value("useRFID", "on").toString() == "on" ||
settings->value("useRFID", "on").toString() == "yes" )
{ this->useRFID = true; }
else { this->useRFID = false; }
#endif
// DEBUG
qDebug() << "ATBHMIconfig::initDefered() com_port_name = " << ComPortName;
qDebug() << "ATBHMIconfig::initDefered() touch_feedback_gpio = " << touch_feedback_gpio;
// DEBUG: write settings to file:
/*
settings->setValue("com_port_name", this->ComPortName);
settings->setValue("lang1", "de_DE");
settings->setValue("lang2", "en_US");
settings->setValue("lang3", "fr_FR");
settings->setValue("lang4", "ja_JP");
settings->setValue("textfile", "HMI_Texte.xml");
settings->setValue("logfile", "/var/log/atbqt.log");
settings->setValue("feature_Log", false);
settings->setValue("feature_TouchFeedback", true);
settings->setValue("feature_DisplayControl", true);
settings->setValue("feature_SystemSuspend", true);
settings->setValue("suspend_methode", "sysfs");
settings->setValue("suspend_program", "");
settings->setValue("suspend_time", 10);
settings->setValue("touch_feedback_gpio", 121);
settings->setValue("touch_feedback_on_value", 0);
settings->setValue("touch_feedback_off_value", 1);
*/
this->HelpButtonUsed = settings->value("showHelpButton", "0").toBool();
this->InfoButtonUsed = settings->value("showInfoButton", "0").toBool();
this->ScreenChangeTimeoutTime = settings->value("screenChangeTimeoutTime", "10").toUInt();
settings->endGroup();
// [PAYMENT]
settings->beginGroup("PAYMENT");
QString cashVariantString = settings->value("cashVariant", "CoinsOnly").toString();
if (cashVariantString == "CoinsOnly") {
this->cashVariant = PAYMENT_VARIANTS::CASH_VARIANT::CoinsOnly;
}
else
if (cashVariantString == "CoinsAndNotes") {
this->cashVariant = PAYMENT_VARIANTS::CASH_VARIANT::CoinsAndNotes;
}
else {
// Default
this->cashVariant = PAYMENT_VARIANTS::CASH_VARIANT::CoinsOnly;
}
this->currencySymbol = settings->value("currencySymbol", "").toString();
QString paymentPointInTimeString = settings->value("paymentPointInTime", "poe").toString();
if (paymentPointInTimeString == "poe") {
this->paymentPointInTime = PAYMENT_POINTINTIME::PAY_ON_EXIT;
}
else
if (paymentPointInTimeString == "poa") {
this->paymentPointInTime = PAYMENT_POINTINTIME::PAY_ON_ARRIVAL;
}
else
if (paymentPointInTimeString == "ign") {
this->paymentPointInTime = PAYMENT_POINTINTIME::IGNORE;
}
else {
// Default
this->paymentPointInTime = PAYMENT_POINTINTIME::PAY_ON_EXIT;
}
if (settings->value("useHonestPayment", "on").toString() == "on" ||
settings->value("useHonestPayment", "on").toString() == "yes" )
{ this->honestPayment = true; }
else { this->honestPayment = false; }
settings->endGroup();
// [CUSTOMER]
settings->beginGroup("CUSTOMER");
this->DiscountUsed = settings->value("DiscountUsed", "1").toBool();
this->QRCodeReceiptUsed = settings->value("QRCodeReceiptUsed", "1").toBool();
settings->endGroup();
#ifdef USE_EXTERNAL_TICKETMANAGER
// [BARCODE_VERIFICATION]
settings->beginGroup("BARCODE_VERIFICATION");
this->endOfSellingTime = settings->value("EndOfSellingTime", "06:00").toString();
this->blockingTimeMin = settings->value("BlockingTime_Min", "15").toInt(&ok);
if (!ok) this->blockingTimeMin = 15;
settings->endGroup();
#endif
#ifdef USE_ISMAS
// [ISMAS]
settings->beginGroup("ISMAS");
this->ismasHost = settings->value("ISMAS_HOST", "87.139.50.222").toString();
this->ismasPort = settings->value("ISMAS_PORT", "10000").toInt(&ok);
this->ismasID = settings->value("ISMAS_ID", "").toString();
if (settings->value("ISMAS_DEBUG", "on").toString() == "on" ||
settings->value("ISMAS_DEBUG", "on").toString() == "yes")
{ this->ismasDebug = true; }
else { this->ismasDebug = false; }
if (settings->value("ISMAS_CheckEntries", "on").toString() == "on" ||
settings->value("ISMAS_CheckEntries", "on").toString() == "yes")
{ this->ismasCheckEntries = true; }
else { this->ismasCheckEntries = false; }
this->ismasConnectionTimeout = settings->value("ISMAS_ConnectionTimeout", "2").toInt(&ok);
if (!ok) this->ismasConnectionTimeout = 2;
if (settings->value("usePinGenerator", "off").toString() == "on" ||
settings->value("usePinGenerator", "off").toString() == "yes" )
{ this->usePINgenerator = true; }
else { this->usePINgenerator = false; }
settings->endGroup();
#endif
// [ERRORCODE_MAPPING]
if (settings->childGroups().contains("ERRORCODE_MAPPING")) {
settings->beginGroup("ERRORCODE_MAPPING");
QStringList ErrorCodes = settings->childKeys();
for (int i = 0; i < ErrorCodes.size(); ++i) {
errorTextHash.insert(ErrorCodes.at(i), settings->value(ErrorCodes.at(i),"").toString());
}
settings->endGroup();
}
qDebug() << ok;
}
QSettings * ATBHMIconfig::getSettingsPtr() { return this->settings; }
const QSettings & ATBHMIconfig::getSettings() { return *(this->settings); }
QString ATBHMIconfig::getComPortName() { return this->ComPortName; }
QString ATBHMIconfig::getSuspendMethode() { return this->SuspendMethode; }
QString ATBHMIconfig::getSuspendProgram() { return this->SuspendProgram; }
/***********************************************************************************************
* get suspend time (-> time, after system goes to suspend) in seconds
*/
QString ATBHMIconfig::getSuspendTime() { return this->SuspendTime; }
/***********************************************************************************************
* get sell timout time (-> time, after system switched back to mode idle, if we do not have
* any user inputs or vmc messages during sell mode) in seconds
*/
QString ATBHMIconfig::getSellTimeoutTime() { return this->SellTimeoutTime; }
quint32 ATBHMIconfig::getHMIScreenChangeTimeoutTime() { return this->ScreenChangeTimeoutTime; }
QString ATBHMIconfig::getQmPath() { return this->qmPath; }
bool ATBHMIconfig::hasFeatureTF() { return ((this->features & this->featureMaskTF) != 0); }
bool ATBHMIconfig::hasFeatureLog() { return ((this->features & this->featureMaskLog) != 0); }
bool ATBHMIconfig::hasFeatureDC() { return ((this->features & this->featureMaskDC) != 0); }
bool ATBHMIconfig::hasFeatureStartButton() { return ((this->features & this->featureMaskStartButton) != 0); }
bool ATBHMIconfig::hasFeatureSelfOOO() { return ((this->features & this->featureMaskSelfOOO) != 0); }
bool ATBHMIconfig::hasFeatureDBusDisplayControl() { return ((this->features & this->featureMaskDBusDisplayControl) != 0); }
bool ATBHMIconfig::hasFeatureDBusSuspendControl() { return ((this->features & this->featureMaskDBusSuspendControl) != 0); }
bool ATBHMIconfig::hasFeatureShowParkingTime() { return ((this->features & this->featureMaskShowParkingTime) != 0); }
void ATBHMIconfig::setFeatureTF() { this->features |= this->featureMaskTF; }
void ATBHMIconfig::unsetFeatureTF() { this->features &= ~(this->featureMaskTF); }
void ATBHMIconfig::setFeatureLog() { this->features |= this->featureMaskLog; }
void ATBHMIconfig::unsetFeatureLog() { this->features &= ~(this->featureMaskLog); }
void ATBHMIconfig::setFeatureStartButton() { this->features |= this->featureMaskStartButton; }
void ATBHMIconfig::unsetFeatureStartButton() { this->features &= ~(this->featureMaskStartButton); }
void ATBHMIconfig::setFeatureSelfOOO() { this->features |= this->featureMaskSelfOOO; }
void ATBHMIconfig::unsetFeatureSelfOOO() { this->features &= ~(this->featureMaskSelfOOO); }
void ATBHMIconfig::setFeatureDC()
{
// this features are mutually exclusive
if (this->hasFeatureDBusDisplayControl()) {
this->unsetFeatureDBusDisplayControl();
}
this->features |= this->featureMaskDC;
}
void ATBHMIconfig::unsetFeatureDC() { this->features &= ~(this->featureMaskDC); }
void ATBHMIconfig::setFeatureDBusDisplayControl()
{
// this features are mutually exclusive
if (this->hasFeatureDC()) {
this->unsetFeatureDC();
}
this->features |= this->featureMaskDBusDisplayControl;
}
void ATBHMIconfig::setFeatureDBusSuspendControl()
{
this->features |= this->featureMaskDBusSuspendControl;
}
void ATBHMIconfig::unsetFeatureDBusDisplayControl() { this->features &= ~(this->featureMaskDBusDisplayControl); }
void ATBHMIconfig::unsetFeatureDBusSuspendControl() { this->features &= ~(this->featureMaskDBusSuspendControl); }
void ATBHMIconfig::setFeatureShowParkingTime() { this->features |= this->featureMaskShowParkingTime; }
void ATBHMIconfig::unsetFeatureShowParkingTime() { this->features &= ~(this->featureMaskShowParkingTime); }
QString ATBHMIconfig::getTouchFeedbackGPIO() { return this->touch_feedback_gpio; }
QString ATBHMIconfig::getTouchFeedbackOnValue() { return this->touch_feedback_on_value; }
QString ATBHMIconfig::getTouchFeedbackOffValue() { return this->touch_feedback_off_value; }
QString ATBHMIconfig::getTextfileName() { return this->textfilename; }
QString ATBHMIconfig::getAlternativeLogoFilename() { return this->alternativeLogoFilename; }
#ifdef USE_BARCODESCANNER
bool ATBHMIconfig::getUseBarcodeScanner() { return this->useBarcode; }
QString & ATBHMIconfig::getBarcodeScannerInputDevice() { return this->barcodeScannerInputDeviceName; }
#endif
#ifdef USE_RFIDREADER
bool ATBHMIconfig::getUseRFIDReader() { return this->useRFID; }
QString & ATBHMIconfig::getRFIDReaderInputDevice() { return this->rfidReaderInputDeviceName; }
#endif
PAYMENT_VARIANTS::CASH_VARIANT ATBHMIconfig::getCashVariant() { return this->cashVariant; }
bool ATBHMIconfig::discountIsUsed() { return this->DiscountUsed; }
bool ATBHMIconfig::qrCodeReceiptIsUsed() { return this->QRCodeReceiptUsed; }
#ifdef USE_EXTERNAL_TICKETMANAGER
/**********************************************************************
* for barcode verification:
*
* EndOfSellingTime: time, when all daily data (e.g. blocking list) is reset
* BlockingTime: time, in minutes, how long a verified ticket is blocked for reentry
*/
QString ATBHMIconfig::getEndOfSellingTime() { return this->endOfSellingTime; }
int ATBHMIconfig::getBlockingTime() { return this->blockingTimeMin; }
#endif
QString ATBHMIconfig::getLang(int lang)
{
switch (lang) {
case 1: return this->lang1;
break;
case 2: return this->lang2;
break;
case 3: return this->lang3;
break;
case 4: return this->lang4;
break;
case 5: return this->lang5;
break;
default: return "";
}
}
/**
* Returns the ordered list of configured languages.
* { <lang1>, <lang2>, ... , <langN> }
* This languages should be available in text file.
*/
QStringList ATBHMIconfig::getConfiguredLanguages()
{
QStringList langs;
langs << lang1 << lang2 << lang3 << lang4 << lang5;
return langs;
}
QString ATBHMIconfig::getCountry(int country)
{
switch (country) {
case 1: return this->country1;
break;
case 2: return this->country2;
break;
case 3: return this->country3;
break;
case 4: return this->country4;
break;
case 5: return this->country5;
break;
default: return "";
}
}
bool ATBHMIconfig::isLanguageUsed(int lang)
{
switch (lang) {
case 1: return (this->useLanguage & 0x80) ? (true) : (false);
break;
case 2: return (this->useLanguage & 0x40) ? (true) : (false);
break;
case 3: return (this->useLanguage & 0x20) ? (true) : (false);
break;
case 4: return (this->useLanguage & 0x10) ? (true) : (false);
break;
case 5: return (this->useLanguage & 0x08) ? (true) : (false);
break;
default: return false;
}
}
bool ATBHMIconfig::isInfoButtonUsed() { return this->InfoButtonUsed; }
bool ATBHMIconfig::isHelpButtonUsed() { return this->HelpButtonUsed; }
bool ATBHMIconfig::isPaymentUsed(int payment)
{
switch (payment) {
case 1: return (this->usePayment & 0x80) ? (true) : (false);
break;
case 2: return (this->usePayment & 0x40) ? (true) : (false);
break;
case 3: return (this->usePayment & 0x20) ? (true) : (false);
break;
case 4: return (this->usePayment & 0x10) ? (true) : (false);
break;
default: return false;
}
}
bool ATBHMIconfig::isVehicleUsed(int vehicle)
{
switch (vehicle) {
case 1: return (this->useVehicle & 0x80) ? (true) : (false);
break;
case 2: return (this->useVehicle & 0x40) ? (true) : (false);
break;
case 3: return (this->useVehicle & 0x20) ? (true) : (false);
break;
case 4: return (this->useVehicle & 0x10) ? (true) : (false);
break;
case 5: return (this->useVehicle & 0x08) ? (true) : (false);
break;
case 6: return (this->useVehicle & 0x04) ? (true) : (false);
break;
case 7: return (this->useVehicle & 0x02) ? (true) : (false);
break;
case 8: return (this->useVehicle & 0x01) ? (true) : (false);
break;
default: return false;
}
}
bool ATBHMIconfig::isProductUsed(int product)
{
switch (product) {
case 1: return (this->useProduct & 0x80) ? (true) : (false);
break;
case 2: return (this->useProduct & 0x40) ? (true) : (false);
break;
case 3: return (this->useProduct & 0x20) ? (true) : (false);
break;
case 4: return (this->useProduct & 0x10) ? (true) : (false);
break;
case 5: return (this->useProduct & 0x08) ? (true) : (false);
break;
case 6: return (this->useProduct & 0x04) ? (true) : (false);
break;
case 7: return (this->useProduct & 0x02) ? (true) : (false);
break;
case 8: return (this->useProduct & 0x01) ? (true) : (false);
break;
default: return false;
}
}
QString ATBHMIconfig::getLogFileName()
{
return this->logfilename;
}
int ATBHMIconfig::getDefaultLanguage()
{
return this->defaultLanguage;
}
void ATBHMIconfig::setDefaultLanguage(quint8 lang)
{
this->defaultLanguage = lang;
}
int ATBHMIconfig::getComBaudRate()
{
return this->ComBaudRate;
}
/********************************************************************************
* Funktions for storing some machine specific configuration data in filesystem.
*
* Note: this functions must reduce write operations to flash memory.
* Therefore, first the data values are read from memory and compared to the new ones.
* Only changed values should be written.
* Additionally, open files, read their values and compare this values is time consuming.
* So we store this values also in our config-object and do only a comparisson if values
* have changed.
*
*
*/
QString & ATBHMIconfig::getCustNr()
{
if (!this->validPSAconfig) { this->readPSAConfig(); }
return this->cust_nr;
}
QString & ATBHMIconfig::getGroupNr()
{
if (!this->validPSAconfig) { this->readPSAConfig(); }
return this->group_nr;
}
QString & ATBHMIconfig::getZoneNr()
{
if (!this->validPSAconfig) { this->readPSAConfig(); }
return this->zone_nr;
}
QString & ATBHMIconfig::getMachineNr()
{
if (!this->validPSAconfig) { this->readPSAConfig(); }
return this->machine_nr;
}
quint8 ATBHMIconfig::readPSAConfig()
{
this->cust_nr = ATB_system::readPSAConfigString("/etc/cust_nr");
this->group_nr = ATB_system::readPSAConfigString("/etc/group_nr");
this->zone_nr = ATB_system::readPSAConfigString("/etc/zone_nr");
this->machine_nr = ATB_system::readPSAConfigString("/etc/machine_nr");
this->validPSAconfig = true;
return 1;
}
void ATBHMIconfig::setCustNr(const QString& cust_nr)
{
if (! validPSAconfig) { this->readPSAConfig(); }
// compare to cached value:
if (cust_nr != this->cust_nr) { // Customer number has changed
ATB_system::setPSAConfigString("/etc/cust_nr", cust_nr);
this->cust_nr = cust_nr;
}
}
void ATBHMIconfig::setGroupNr(const QString& group_nr)
{
if (! validPSAconfig) { this->readPSAConfig(); }
// compare to cached value:
if (group_nr != this->group_nr) {
ATB_system::setPSAConfigString("/etc/group_nr", group_nr);
this->group_nr = group_nr;
}
}
void ATBHMIconfig::setZoneNr(const QString& zone_nr)
{
if (! validPSAconfig) { this->readPSAConfig(); }
// compare to cached value:
if (zone_nr != this->zone_nr) {
ATB_system::setPSAConfigString("/etc/zone_nr", zone_nr);
this->zone_nr = zone_nr;
}
}
void ATBHMIconfig::setMachineNr(const QString &machine_nr)
{
if (! validPSAconfig) { this->readPSAConfig(); }
// compare to cached value:
if (machine_nr != this->machine_nr) {
ATB_system::setPSAConfigString("/etc/machine_nr", machine_nr);
this->machine_nr = machine_nr;
}
}
OOO_MODE ATBHMIconfig::getOOOMode()
{
return this->oooMode;
}
QString ATBHMIconfig::getOOOModeString()
{
switch (this->oooMode) {
case OOO_MODE::USE_OTHER_MACHINE:
return QString("otherMachine");
break;
case OOO_MODE::USE_PARKDISK:
return QString("useDisk");
break;
default:
return "";
}
return "";
}
QString ATBHMIconfig::getOOOServiceNumber()
{
return this->oooServiceNumber;
}
QString ATBHMIconfig::getOOOServiceEmail()
{
return this->oooServiceEmail;
}
QString ATBHMIconfig::getOOOAlternativeLocation()
{
return this->oooAlternativeLocation;
}
QString ATBHMIconfig::getLicensePlateExampleString()
{
return this->lpLocalExample;
}
QString ATBHMIconfig::getQrCodeLink()
{
return this->qrCodeLink;
}
const QByteArray & ATBHMIconfig::getDefaultCharacterSet() const
{
return this->characterSet;
}
const QString & ATBHMIconfig::getPaymentCurrencySymbol()
{
return this->currencySymbol;
}
PAYMENT_POINTINTIME ATBHMIconfig::getPaymentPointInTime()
{
return this->paymentPointInTime;
}
bool ATBHMIconfig::useHonestPayment()
{
return this->honestPayment;
}
/***************************************************************************
* public slot to re-read config
*
* This slot could be called e.g. on a mode switch from 'service' to 'sell' or vv.
*/
void ATBHMIconfig::reReadSettings()
{
this->privateReadInputDevices();
}
/* private common function to set/read input device names.
*/
void ATBHMIconfig::privateReadInputDevices()
{
#if defined (USE_BARCODESCANNER)
barcodeScannerInputDeviceName = ATB_system::getEventDeviceName(ATB_system::EVENT_DEVICE_BARCODEREADER);
#endif // USE_BARCODESCANNER
#if defined (USE_RFIDREADER)
rfidReaderInputDeviceName = ATB_system::getEventDeviceName(ATB_system::EVENT_DEVICE_RFIDREADER);
#endif // USE_RFIDREADER
}
/***************************************************************************
* ISMAS
*/
#ifdef USE_ISMAS
QString ATBHMIconfig::getISMASHost() { return this->ismasHost; }
quint16 ATBHMIconfig::getISMASPort() { return this->ismasPort; }
bool ATBHMIconfig::isIsmasDebug() { return this->ismasDebug; }
bool ATBHMIconfig::IsmasCheckEntries() { return this->ismasCheckEntries; }
quint16 ATBHMIconfig::getIsmasConnectionTimeout() { return this->ismasConnectionTimeout; }
bool ATBHMIconfig::UsePINgenerator() { return this->usePINgenerator; }
QString ATBHMIconfig::getISMASId()
{
// if no ismasID is defined, we use customer Number (-> "ATB device Id" in Multipass)
if (this->ismasID == "") {
return this->getCustNr();
}
return this->ismasID;
}
#endif
/***************************************************************************
* public methods for ErrorCode
*/
QString ATBHMIconfig::getErrorText(const QString & errorCode)
{
return errorTextHash.value(errorCode);
}
/***************************************************************************
* get tools name/path
*/
/*****************************************************************************
* check availability of network diag tool
*
* possible install path for networkDiag:
* 1) /usr/bin/atb_networkDiag
* 2) /opt/app/tools/networkDiag
* 3) /opt/app/atb_networkDiag/networkDiag
*
* Check, if file exists and if it is executable,
* Return path/name for binary.
*/
QString & ATBHMIconfig::getNetworkDiagTool()
{
// search list for config file:
QStringList binFileList;
// check, if file exists and if it is executable
#if defined (ARCH_PTU4)
binFileList << "/usr/bin/atbNetworkDiag"
<< "/opt/app/tools/networkDiag"
<< "/opt/app/atbNetworkDiag/networkDiag";
#else
binFileList << QDir::homePath().append("/atbNetworkDiag");
#endif
// using C++11 range based loop: -> take first file, which is readable
for (const auto& filename : binFileList) {
if (QFileInfo(filename).isExecutable()) {
this->networkDiagToolName = filename;
break;
}
}
return this->networkDiagToolName;
}

338
ATBHMIconfig.h Normal file
View File

@ -0,0 +1,338 @@
#ifndef ATBHMICONFIG_H
#define ATBHMICONFIG_H
#include <QObject>
#include <QSettings>
#include <ATBAPP.h>
#include "version.h"
/***************************************
* Sample configuration:
*
* [General]
* com_port_name=/dev/pts/16
* machine_nr=99
*
* suspend_methode=sysfs
* suspend_program=
* suspend_time=10
*
* touch_feedback=on
* touch_feedback_gpio=115 // 115 = beep; 121 = vibration motor
* touch_feedback_on_value=0 // 0 (buzzer) 1 (vibration)
* touch_feedback_off_value=1 // 1 (buzzer) 0 (vibration)
*
* log=on // loggin is on
*
* lang1=de_DE
* lang2=en_US
* lang3=fr_FR
* lang4=ja_JP
*
* textfile=HMI_Texte.xml
*
*/
enum class OOO_MODE : quint8;
class ATBHMIconfig : public QObject
{
Q_OBJECT
QString ComPortName;
QString SuspendMethode;
QString SuspendProgram;
QString SuspendTime;
QString SellTimeoutTime;
QString qmPath;
QString touch_feedback_gpio;
QString touch_feedback_on_value;
QString touch_feedback_off_value;
QString lang1;
QString lang2;
QString lang3;
QString lang4;
QString lang5;
quint8 useLanguage;
quint8 useVehicle;
quint8 useProduct;
quint8 usePayment;
QString country1;
QString country2;
QString country3;
QString country4;
QString country5;
QSettings *settings;
quint16 features;
static const quint16 featureMaskTF = 0x0001;
static const quint16 featureMaskLog = 0x0002;
static const quint16 featureMaskDC = 0x0004; // manuell display control, (in future deprecated)
static const quint16 featureMaskSusp = 0x0008; // manuell suspend control, (in future deprecated)
static const quint16 featureMaskStartButton = 0x0010;
static const quint16 featureMaskSelfOOO = 0x0020;
static const quint16 featureMaskDBusDisplayControl = 0x0040;
static const quint16 featureMaskDBusSuspendControl = 0x0080;
static const quint16 featureMaskShowParkingTime = 0x0100;
QString logfilename;
QString textfilename;
QString alternativeLogoFilename;
QString oooServiceNumber;
QString oooServiceEmail;
QString oooAlternativeLocation;
QString qrCodeLink;
QString lpLocalExample;
QString currencySymbol;
#ifdef USE_BARCODESCANNER
bool useBarcode;
QString barcodeScannerInputDeviceName;
#endif
#ifdef USE_RFIDREADER
bool useRFID;
QString rfidReaderInputDeviceName;
#endif
#ifdef USE_EXTERNAL_TICKETMANAGER
// for ticket management
QString endOfSellingTime;
int blockingTimeMin;
#endif
quint8 defaultLanguage;
bool HelpButtonUsed;
bool InfoButtonUsed;
bool DiscountUsed;
bool QRCodeReceiptUsed;
int ComBaudRate;
QString cust_nr;
QString group_nr;
QString zone_nr;
QString machine_nr;
bool validPSAconfig;
QByteArray characterSet;
#ifdef USE_ISMAS
QString ismasHost;
quint16 ismasPort;
QString ismasID;
bool ismasDebug;
bool ismasCheckEntries;
quint16 ismasConnectionTimeout;
bool usePINgenerator;
#endif
quint32 ScreenChangeTimeoutTime;
PAYMENT_VARIANTS::CASH_VARIANT cashVariant;
// ErrorCode-mapping
QHash<QString,QString> errorTextHash;
public:
explicit ATBHMIconfig(QObject *parent = nullptr);
~ATBHMIconfig();
QSettings *getSettingsPtr();
const QSettings & getSettings();
void initEarly();
void initDefered();
QString getComPortName();
QString getSuspendMethode();
QString getSuspendProgram();
QString getSuspendTime();
QString getSellTimeoutTime();
quint32 getHMIScreenChangeTimeoutTime();
QString getQmPath();
QString getLang(int lang);
QString getCountry(int country);
bool isLanguageUsed(int lang);
bool isInfoButtonUsed();
bool isHelpButtonUsed();
bool isPaymentUsed(int payment);
bool isVehicleUsed(int vehicle);
bool isProductUsed(int product);
bool isProcductUsed(int product);
QString getTouchFeedbackGPIO();
QString getTouchFeedbackOnValue();
QString getTouchFeedbackOffValue();
bool hasFeatureTF(); // touch feedback
bool hasFeatureLog(); // log serial communication
bool hasFeatureDC(); // display control
bool hasFeatureStartButton(); // StartButton
bool hasFeatureSelfOOO(); // self ooo capability
bool hasFeatureDBusDisplayControl();
bool hasFeatureDBusSuspendControl();
bool hasFeatureShowParkingTime(); // show parking time in addition to parking end time
QString getTextfileName();
QString getAlternativeLogoFilename();
const QByteArray & getDefaultCharacterSet() const;
QString getOOOServiceNumber();
QString getOOOServiceEmail();
QString getOOOAlternativeLocation();
QString getLicensePlateExampleString();
QString getQrCodeLink();
const QString & getPaymentCurrencySymbol();
#ifdef USE_BARCODESCANNER
bool getUseBarcodeScanner();
QString & getBarcodeScannerInputDevice();
#endif
#ifdef USE_RFIDREADER
bool getUseRFIDReader();
QString & getRFIDReaderInputDevice();
#endif
#ifdef USE_EXTERNAL_TICKETMANAGER
QString getEndOfSellingTime();
int getBlockingTime();
#endif
#ifdef USE_ISMAS
QString getISMASHost();
quint16 getISMASPort();
QString getISMASId();
bool isIsmasDebug();
bool IsmasCheckEntries();
bool UsePINgenerator();
quint16 getIsmasConnectionTimeout();
#endif
void setFeatureTF();
void unsetFeatureTF();
void setFeatureLog();
void unsetFeatureLog();
void setFeatureDC();
void unsetFeatureDC();
void setFeatureStartButton();
void unsetFeatureStartButton();
void setFeatureSelfOOO();
void unsetFeatureSelfOOO();
void setFeatureDBusDisplayControl();
void unsetFeatureDBusDisplayControl();
void setFeatureDBusSuspendControl();
void unsetFeatureDBusSuspendControl();
void setFeatureShowParkingTime();
void unsetFeatureShowParkingTime();
QString getLogFileName();
int getDefaultLanguage();
QStringList getConfiguredLanguages();
int getComBaudRate();
QString getErrorText(const QString & errorCode);
// machine configuration
QString & getCustNr();
QString & getGroupNr();
QString & getZoneNr();
QString & getMachineNr();
quint8 readPSAConfig();
PAYMENT_VARIANTS::CASH_VARIANT getCashVariant();
bool discountIsUsed();
bool qrCodeReceiptIsUsed();
// service programs
QString & getNetworkDiagTool();
//QString & getPTUConfig();
//QString & getPTUUpdate();
OOO_MODE getOOOMode();
QString getOOOModeString();
PAYMENT_POINTINTIME getPaymentPointInTime();
bool useHonestPayment();
QStringList configGroups;
private:
OOO_MODE oooMode;
PAYMENT_POINTINTIME paymentPointInTime;
bool honestPayment;
void privateReadInputDevices();
QString networkDiagToolName;
signals:
public slots:
void setDefaultLanguage(quint8 lang);
void setCustNr(const QString& cust_nr);
void setGroupNr(const QString& group_nr);
void setZoneNr(const QString& zone_nr);
void setMachineNr(const QString& machine_nr);
void reReadSettings();
};
enum class OOO_MODE : quint8 {
DEFAULT = 0,
USE_PARKDISK = 1,
USE_OTHER_MACHINE = 2
};
#endif // ATBHMICONFIG_H

2745
AppControl.cpp Normal file

File diff suppressed because it is too large Load Diff

242
AppControl.h Normal file
View File

@ -0,0 +1,242 @@
#ifndef APPCONTROL_H
#define APPCONTROL_H
#include <QObject>
#include "version.h"
#include "atb_system.h"
#include "ATBAPP.h"
#include "plugins/PluginManager.h"
#include "plugins/CC/CCInterface.h"
#include "plugins/CalculatePrice/CalculatePriceInterface.h"
#include "support/VendingData.h"
#include "CalculatePrice/CalculatePriceDefault.h"
class VMC;
class ATBHMIconfig;
class VendingData;
class QTimer;
class AppControl : public QObject {
Q_OBJECT
public:
explicit AppControl(QObject *parent = nullptr);
PROGRAM_MODE getCurrentProgramMode();
bool requestProgramMode(PROGRAM_MODE newProgramMode);
bool isProgramModeSELL();
bool isProgramModeSELL_ENABLE();
bool isProgramModeSERVICE();
bool isProgramModeIDLE();
bool isProgramModeOOO();
public slots:
void onRequestOfflineProcessing();
// e.g. by button event,
// by vmc screen command,
// by vmc data display command
// ...
void restartSellModeTimeoutTimer();
// slots for LED configuration:
void LEDs_default();
void LEDs_ooo();
// CC-Plugin
void onCCStartTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCConfirmTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCCancelTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCRevertTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCBookTotalTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCCancelPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void onCCRequestCardInfoResult(nsCCInterface::RESULT_STATE resultState, QString & result);
// CalculatePricePlugin
#ifdef USE_CALCULATEPRICE_PLUGIN
void onCalculatePrice(QString & licensePlate);
void onCalculatePrice(uint parktime);
void onCalculatePrice(QString & cardInfo, QString & cardTransactionInfo);
void onCalculatePrice();
void onCalculatedPrice(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const PriceInfo & priceInfo,
const QString & errorCode,
const QString & errorDescription);
void onProcessTransaction(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & errorCode,
const QString & errorDescription);
QChar private_getAccessInformationField(const QString & accessInformationType);
QString private_calculatedPrice(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const PriceInfo & priceInfo,
const QString & errorCode,
const QString & errorDescription);
#endif // USE_CALCULATEPRICE_PLUGIN
// vmc control
void onVMCFormatedString(FormatedStringList data);
void onVMCSellData(quint8 nr,QString data);
// deprecated vmc control for cc
// this allows cc control by screens
void onVMC_ccStartTransaction();
void onVMC_ccCancelTransaction();
void onVMC_ccConfirmTransaction();
void onVMC_ccStartPreauthorisation();
void onVMC_ccCancelPreauthorisation();
void onVMC_ccConfirmPreauthorisation();
void onVMC_ccStartReadCard();
// new control interface
void onControl_switchMode(quint16 mode);
void onControl_switchScreen(quint16 screen);
void onControl_setText(quint16 screenNr, quint16 textNr, quint16 lang, QString text);
void onShowCurrentIdle();
void onShowCurrentOOO();
// vendingData
void onSetVendingData(QString key, QByteArray value);
signals:
// signals for signaling a mode change to sub-modules:
void changedProgramMode(PROGRAM_MODE newProgramMode);
void changedModeToSELL();
void changedModeToSERVICE();
void changedModeToIDLE();
void changedModeToOOO();
void doOfflineProcessing();
// cc
protected:
bool eventFilter(QObject *obj, QEvent *ev);
private:
PROGRAM_MODE programmode;
ATBHMIconfig *config;
ATB_system *system;
VMC *vmc;
VendingData *vendingData;
PluginManager *pluginManager;
void private_setupProgramModeSELL();
void private_setupProgramModeSELL_ENABLE();
void private_setupProgramModeSERVICE();
void private_setupProgramModeIDLE();
void private_setupProgramModeOOO();
void private_unsetProgramModeSERVICE();
void private_unsetProgramModeOOO();
// plugins
CCInterface *cc;
CalculatePriceInterface *calcPriceBackend;
// init methods called from constructor
void private_initCCPlugin();
void private_initCalculatePricePlugin();
void private_initSimulationPlugin();
// timers
QTimer *sellModeTimeoutTimer;
// flag to prepare for OOO in next idle
quint8 prepareInternalOOO;
// action processing
quint8 startAction(APP_ACTION action);
#if defined (ARCH_DesktopLinux)
void private_screenshot();
#endif
#if defined (CUST00318)
// hack for 00318/Nexobility
void private_CUST00318_handle_CC_ERROR_0x13();
#endif
// mouse detection
#if defined (ARCH_PTU4)
QFileSystemWatcher *pInputDeviceWatcher;
void setMouse(const QString & mouseDeviceFile, const QString & touchDeviceFile);
void closeMouse(const QString & mouseDeviceFile, const QString & touchDeviceFile);
bool mousePresent;
#endif
private slots:
// firstRun -> things done with running event loop
void firstRun();
// timers
void onSellModeTimerTimeout();
/********************************************
* CC - Slots
*/
void onCCStartTransaction();
void onCCStartConfirmTransaction();
void onCCCancelTransaction();
void onCCStartPreauthorisation();
void onCCConfirmPreauthorisation();
void onCCCancelPreauthorisationRequest();
void onCCPrintReceipt();
void onCCErrorBackend(QString & result);
void onCCStartReadCard();
/*******************************************/
// called, if system was woken up
void onWakeUp();
/********************************************
* Barcode / QR-Code - Slots
*/
#ifdef USE_BARCODESCANNER
// called, if a barcode was read from scanner
void onReadBarcode(QString & barcode);
// called, if a new barcode should be created and sent to vmc
void onRequestNewBarcode();
#endif
/*******************************************/
#if defined (Q_WS_QWS)
void onInputDeviceWatcher_directoryChanged(const QString& path);
#endif
/********************************************
* ISMAS
*/
void onProcessed_QRCode(QHash<QString, QByteArray> data);
/********************************************
* Signal System Errors
*/
void onSignalSystemErrors(const QString & errorCode, const QString & errorDescription);
};
#endif // APPCONTROL_H

View File

@ -0,0 +1,103 @@
TEMPLATE = lib
CONFIG += plugin
QT += gui
QT += serialport
INCLUDEPATH+=$$_PRO_FILE_PWD_
INCLUDEPATH+=$$_PRO_FILE_PWD_/support
INCLUDEPATH+=$$_PRO_FILE_PWD_/plugins
INCLUDEPATH+=$$_PRO_FILE_PWD_/include
INCLUDEPATH+=$$_PRO_FILE_PWD_/HMI
INCLUDEPATH+=$$_PRO_FILE_PWD_/HMI/screens
INCLUDEPATH+=$$_PRO_FILE_PWD_/HMI/support
INCLUDEPATH+=$$_PRO_FILE_PWD_/src
INCLUDEPATH+=$$_PRO_FILE_PWD_/src/ATBAPP
INCLUDEPATH+=$$_PRO_FILE_PWD_/src/ATBAPP/support
INCLUDEPATH+=$$_PRO_FILE_PWD_/src/ATBAPP/support/VMC
QMAKE_CXXFLAGS += -Wno-deprecated-copy -O
# default
ARCH = PTU5
DEFINES+=ATB_QT_VERSION=\\\"5.11\\\"
contains( CONFIG, DesktopLinux ) {
QMAKE_CC = ccache $$QMAKE_CC
QMAKE_CXX = ccache $$QMAKE_CXX
QMAKE_CXXFLAGS += -std=c++11
# QMAKE_CXXFLAGS += -Wno-deprecated-ctor
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
ARCH = DesktopLinux
}
contains( CONFIG, PTU5 ) {
# QMAKE_CC = ccache $$QMAKE_CC
# QMAKE_CXX = ccache $$QMAKE_CXX
QMAKE_CXXFLAGS += -std=c++11
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
CONFIG += link_pkgconfig
ARCH = PTU5
}
contains( CONFIG, PTU5_YOCTO ) {
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
PTU5BASEPATH = /opt/devel/ptu5
ARCH = PTU5
# add qmqtt lib
#LIBS += -lQt5Qmqtt
}
TARGET = ATBVMCPlugin
#DESTDIR = ../plugins
INTERFACE = VMCInterface
INTERFACE_DEFINITION = $${PWD}/src/ATBAPP/VMCInterface.h
DEFINES += VMCPLUGIN_LIBRARY
# Default rules for deployment.
#qnx: target.path = /tmp/$${TARGET}/bin
#else: unix:!android: target.path = /opt/$${TARGET}/bin
#!isEmpty(target.path): INSTALLS += target
# ATBAPP interface
HEADERS += \
AppControl.h \
ATBHMIconfig.h \
atb_system.h \
include/interfaces.h \
src/ATBAPP/VMCInterface.h \
src/ATBAPP/ATBVMCPlugin.h \
src/ATBAPP/UnifiedDCVMCInterface.h \
src/ATBAPP/support/VMC/com_interface.h \
src/ATBAPP/support/VMC/ReceiveBuffer.h \
src/ATBAPP/support/VMC/SendBuffer.h \
src/ATBAPP/support/VMC/vmc.h \
src/ATBAPP/support/VendingData.h
SOURCES += \
atb_system.cpp \
AppControl.cpp \
ATBHMIconfig.cpp \
src/ATBAPP/ATBVMCPlugin.cpp \
src/ATBAPP/support/VMC/com_interface.cpp \
src/ATBAPP/support/VMC/ReceiveBuffer.cpp \
src/ATBAPP/support/VMC/SendBuffer.cpp \
src/ATBAPP/support/VMC/vmc.cpp \
src/ATBAPP/support/VendingData.cpp
DISTFILES += \
generate-version.sh
# Define how to create version.h
VERSION_H = $$PWD/include/version.h
version.output = $$PWD/include/version.h
version.commands = $$PWD/generate-version.sh $${ARCH} $${TARGET} $${INTERFACE} $${INTERFACE_DEFINITION} $${VERSION_H}
version.depends = FORCE
version.input = VERSION_H
version.variable_out = HEADERS
QMAKE_EXTRA_COMPILERS += version
QMAKE_CLEAN += $${PWD}/include/version.h

723
atb_system.cpp Normal file
View File

@ -0,0 +1,723 @@
#include "atb_system.h"
#include "ATBHMIconfig.h"
#include <QDebug>
#include <QProcess>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QTextStream>
#include <QString>
#include <QTimer>
ATB_system::ATB_system(ATBHMIconfig *config, QObject *parent) :
QObject(parent)
{
this->config = config;
this->tf_gpio = nullptr;
#if defined (ARCH_PTU2)
if (config->hasFeatureTF()) init_touch_feedback();
#elif defined (ARCH_PTU4)
if (config->hasFeatureTF()) init_touch_feedback();
#endif
}
ATB_system::~ATB_system()
{
if (config->hasFeatureTF()) {
delete(this->tf_gpio_outstream);
delete(this->tf_gpio);
}
}
void ATB_system::executeSystemCommand(quint16 cmd, QByteArray data)
{
Q_UNUSED(data);
switch (cmd) {
case SYS_COMMAND_SLEEP:
qDebug() << "ATB_system::executeSystemCommand(): " << cmd;
dbus_permitSuspend();
break;
case SYS_COMMAND_DIMLOW:
if (config->hasFeatureDBusDisplayControl()) {
dbus_DimControlStart();
} else {
this->DimLow();
}
break;
case SYS_COMMAND_DIMHIGH:
if (config->hasFeatureDBusDisplayControl()) {
dbus_DimHighPermanent();
} else {
this->DimHigh();
}
break;
case SYS_COMMAND_BEEP:
if (config->hasFeatureTF()) this->Beep();
break;
case SYS_COMMAND_MACHINE_NUMBER: // deprecated and not used
// setMachineNumber(data);
break;
case SYS_COMMAND_LED_CONTROL:
this->privateConfigLED(data);
break;
case SYS_COMMAND_HALT:
this->halt();
break;
case SYS_COMMAND_REBOOT:
this->reboot();
break;
default:
qDebug() << "ATB_system::executeSystemCommand(): unknown command: " << cmd;
break;
}
}
/*****************************************************************************
* stubs for display control
*
* this methodes should later be scriptable an call corresponding methodes
* in DisplayControl via DBus.
*/
void ATB_system::DimLow() { return; }
void ATB_system::DimHigh()
{
//if (config->hasFeatureDC())
// this->dc->DimHigh();
}
//void ATB_system::Dim(quint8 value) { if (config->hasFeatureDC()) this->dc->Dim((uchar)value); }
void ATB_system::DimStart() { return; }
void ATB_system::DimStop() { return; }
/*****************************************************************************
*/
void ATB_system::Beep() {
qDebug() << "ATB_system::Beep(): now i should make a beep!";
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QTimer::singleShot (BEEPTIMEOUT, this, SLOT(BeepStop()) );
*(this->tf_gpio_outstream) << config->getTouchFeedbackOnValue();
this->tf_gpio_outstream->flush();
#endif
}
void ATB_system::BeepStop() {
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
*(this->tf_gpio_outstream) << config->getTouchFeedbackOffValue();
this->tf_gpio_outstream->flush();
#endif
}
int ATB_system::init_touch_feedback() {
#if defined (ARCH_PTU2)
QString GPIODirName("/sys/class/gpio/");
QString directionFileName;
QString valueFileName;
// # echo 129 > /sys/class/gpio/export
QFile file("/sys/class/gpio/export");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << config->getTouchFeedbackGPIO();
file.close();
// check, if gpio-dir was created
GPIODirName.append("gpio");
GPIODirName.append(config->getTouchFeedbackGPIO());
QFileInfo fileinfo1(GPIODirName);
if (! fileinfo1.isDir() ) {
qDebug() << "ATB_system::init_touch_feedback(): \"" << GPIODirName << "\" is not a directory";
config->unsetFeatureTF();
return -1;
}
directionFileName = GPIODirName + "/direction";
QFileInfo fileinfo2(directionFileName);
if (! fileinfo2.isWritable() ) {
qDebug() << "ATB_system::init_touch_feedback(): \"" << directionFileName << "\" is not writable";
config->unsetFeatureTF();
return -1;
}
// # echo out > /sys/class/gpio/gpio129/direction
QFile directionfile(directionFileName);
directionfile.open(QIODevice::ReadWrite | QIODevice::Text);
QTextStream out2(&directionfile);
out2 << "out";
out2.flush();
// re-read 'direction' for confirmation
// -> the following is disabled because this sometimes failed
//QTextStream in(&directionfile);
//QString line = in.readLine();
//if (line != "out") {
// qDebug() << "ATB_system::init_touch_feedback(): re-read directionfile failed";
// config->unsetFeatureTF();
// return -1;
//}
directionfile.close();
// open gpio file
valueFileName = GPIODirName + "/value";
this->tf_gpio = new QFile(valueFileName);
this->tf_gpio->open(QIODevice::WriteOnly);
this->tf_gpio_outstream = new QTextStream(this->tf_gpio);
qDebug() << "ATB_system::init_touch_feedback(): GPIODirName = \"" << GPIODirName << "\"";
qDebug() << "ATB_system::init_touch_feedback(): valueFileName = \"" << valueFileName << "\"";
#elif defined (ARCH_PTU4)
QString sysfs_buzzer("/sys/class/leds/Buzzer/brightness");
this->tf_gpio = new QFile(sysfs_buzzer);
tf_gpio->open(QIODevice::WriteOnly);
this->tf_gpio_outstream = new QTextStream(this->tf_gpio);
#endif
return 1;
}
/********************************************************************************
* set date/time
*
* Datestring format: YYYY-MM-DD hh:mm[:ss]
* This is a format that is accepted both by busybox-date (e.g. PTU2) and by
* coreutils-date.
*
* example:
* /bin/date -s "2015-08-05 17:55:00"
*
*/
void ATB_system::setDateTime(const QString & dateTimeString)
{
QString datetimeCMD = "/bin/date -s " + dateTimeString;
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QProcess::startDetached(datetimeCMD);
// the following does not work on PTU2:
//QProcess::startDetached ("/sbin/hwclock -w");
#endif
}
/********************************************************************************
* static functions to write single values to files.
*
* Used e.g. to store some machine specific settings like customer number or machine
* number in filesystem.
*
* This data should be updated rarely and the calling function must keep this in mind!
*
* Note: QFile::open() creates a file, if it is not existing.
*/
quint8 ATB_system::setPSAConfigInt(const QString &filename, quint16 iValue)
{
return setPSAConfigString(filename, QString::number(iValue));
}
quint8 ATB_system::setPSAConfigString(const QString & filename, const QString & sValue)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(filename);
#else
QFile file(QDir::homePath() + filename);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::setPSAConfigString() cannot open file: " << filename;
qDebug() << " file.errorString() = " << file.errorString();
return 0;
}
qDebug() << "ATB_system::setPSAConfigString() write file: " << filename;
QTextStream out(&file);
out << sValue;
out.flush();
file.close();
return 1;
}
quint16 ATB_system::readPSAConfigInt(const QString & filename)
{
bool ok;
quint16 result = (quint16)readPSAConfigString(filename).toInt(&ok);
if (!ok) {
result = 0;
}
return result;
}
QString ATB_system::readPSAConfigString(const QString & filename)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFileInfo fileinfo(filename);
#else
QFileInfo fileinfo(QDir::homePath() + filename);
#endif
if (! fileinfo.isReadable() ) {
qDebug() << "ATB_system::readPSAConfigString(): \"" << filename << "\" is not readable";
return 0;
}
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(filename);
#else
QFile file(QDir::homePath() + filename);
#endif
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "ATB_system::readPSAConfigString() cannot open file: " << filename;
return 0;
}
QTextStream in(&file);
QString stringValue = in.readLine(100);
qDebug() << "ATB_system::readPSAConfigString() stringValue = " << stringValue;
file.close();
return stringValue;
}
/********************************************************************************
* LED control interface
*
*/
void ATB_system::onConfigLED(LED_NAME LED, LED_TRIGGER trigger, quint16 delayOn, quint16 delayOff)
{
QString LEDPath = "/sys/class/leds/";
QString LEDName = "";
QString LEDtrigger = "";
// DEBUG
// ////////
switch (LED) {
#if defined (ARCH_PTU2)
case ATB_LED1: LEDName.append("atb_led1"); break;
case ATB_LED2: LEDName.append("atb_led2"); break;
case ATB_LED3: LEDName.append("atb_led3"); break;
case ATB_LED4: LEDName.append("atb_led4"); break;
#elif defined (ARCH_PTU4)
case ATB_LED1: LEDName.append("D504"); break;
case ATB_LED2: LEDName.append("D503"); break;
case ATB_LED3: LEDName.append("D502"); break;
case ATB_LED4: LEDName.append("D501"); break;
#endif
default: return;
}
switch (trigger) {
case LED_TRIGGER_NONE: LEDtrigger.append("none"); break;
case LED_TRIGGER_TIMER: LEDtrigger.append("timer"); break;
#if defined (ARCH_PTU2)
case LED_TRIGGER_DEFAULT_ON: LEDtrigger.append("default-on"); break;
#elif defined (ARCH_PTU4)
/* note: ptu4 leds currently do not support 'default-on' trigger
* workaround is to set delay_off to '0'
*/
case LED_TRIGGER_DEFAULT_ON: LEDtrigger.append("timer");
trigger = LED_TRIGGER_TIMER;
delayOn = 1;
delayOff = 0;
break;
#endif
default: return;
}
QString filename = LEDPath + LEDName + "/trigger";
// set trigger
this->privateSetLEDTrigger(filename, LEDtrigger);
// set delays for trigger 'timer'
if (trigger == LED_TRIGGER_TIMER) {
// set delay on
if (delayOn != 0) {
filename = LEDPath + LEDName + "/delay_on";
this->privateSetLEDDelayOn(filename, QString::number(delayOn));
}
// set delay off
if (delayOff != 0) {
filename = LEDPath + LEDName + "/delay_off";
this->privateSetLEDDelayOn(filename, QString::number(delayOff));
}
}
return;
}
/*****************************************************************************
* wrapper function for LED control.
*
* TODO: Test, check: plausibillity, cmd.lenght(), type casts to LED_NAME, LED_TRIGGER
*/
void ATB_system::privateConfigLED(const QByteArray & cmd)
{
quint16 delayOn = (quint8)cmd.at(3) + ((quint16)(cmd.at(2) << 8));
quint16 delayOff = (quint8)cmd.at(5) + ((quint16)(cmd.at(4) << 8));
this->onConfigLED((LED_NAME)cmd.at(0), (LED_TRIGGER)cmd.at(1), delayOn, delayOff);
}
void ATB_system::privateSetLEDTrigger(const QString & led, const QString & trigger)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << trigger;
out.flush();
file.close();
}
void ATB_system::privateSetLEDDelayOn(const QString & led, const QString & delayOn)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << delayOn;
out.flush();
file.close();
}
void ATB_system::privateSetLEDDelayOff(const QString & led, const QString & delayOff)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << delayOff;
out.flush();
file.close();
}
/*****************************************************************************
* functions for switching blink button on/off
* This is only available on PTU4
*/
void ATB_system::switchBlinkButtonOn()
{
this->privateSwitchBlinkButton(true);
}
void ATB_system::switchBlinkButtonOff()
{
this->privateSwitchBlinkButton(false);
}
void ATB_system::privateSwitchBlinkButton(bool on)
{
#if defined (ARCH_PTU2)
#elif defined (ARCH_PTU4)
QString BlinkLED("/sys/class/leds/TIMER_RESET/brightness");
QFile file(BlinkLED);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::privateSwitchBlinkButton() cannot open file: " << BlinkLED;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
QTextStream out(&file);
if (on) { out << "0"; }
else { out << "1"; }
out.flush();
file.close();
#else
Q_UNUSED(on)
#endif
}
/*****************************************************************************
* halt system.
*
*/
void ATB_system::halt()
{
QProcess::startDetached("/sbin/halt");
}
/*****************************************************************************
* reboot system.
*
*/
void ATB_system::reboot()
{
QProcess::startDetached("/sbin/reboot");
}
/*****************************************************************************
* functions for wake vmc
* This is only available on PTU4
*/
void ATB_system::onWakeVMC()
{
#if defined (ARCH_PTU2)
#elif defined (ARCH_PTU4)
if (config->hasFeatureDBusSuspendControl()) {
this->dbus_wakeSystem();
}
#endif
}
/*****************************************************************************
* get event device name by a type:
*
* e.g. type is TOUCHSCREEN:
* getEventDeviceName(TOUCHSCREEN) returns "/dev/input/event0"
*
*/
QString ATB_system::getEventDeviceName(DEVICE_TYPE type)
{
QString procDevices = "/proc/bus/input/devices";
QFile inFile(procDevices);
if (!inFile.open(QFile::ReadOnly)) {
qCritical() << "ATB_system::getEventDeviceName() ERROR open()" << procDevices;
return "";
}
QTextStream textInStream(&inFile);
QString line;
QString N_RegExp;
QString DeviceTypeName;
int lineCounter = 0;
bool typeFound = false;
QString H_RegExp = "^H: Handlers"; // H: Handlers=kbd event2
QString eventDeviceName = "";
QString eventPart;
QStringList devNames;
QString DeviceNamePattern;
//PTU4 Touchscreen N: Name="atmel_mxt_ts T100 touchscreen"
//PTU4 GPIO kys N: Name="gpio_keys.6"
//RFID Reader, Stronglink SL040 N: Name="StrongLink USB CardReader"
//2D Scanner, Datalogig DSE0420 N: Name="Datalogic ADC Inc. Handheld Barcode Scanner" VID: 05f9, PID:4005
//2D Scanner, Datalogig DSM0400 N: Name="Datalogic Handheld Barcode Scanner" VID: 05f9, PID:4005
//2D Scanner, Honeywell N56000 N: Name="Honeywell Imaging & Mobility N5600"
//2D Scanner, Newland FM3080 N: Name="Newland Auto-ID NLS-FM3080V2-20 USB POS KBW" VID: 1eab, PID:0022
//2D Scanner, Opticon MDI-4000 N: Name="Opticon Opticon USB Barcode Reader"
//USB Mouse N: Name="Logitech USB-PS/2 Optical Mouse"
/* Datalogic DSE0420
I: Bus=0003 Vendor=05f9 Product=4005 Version=0110
N: Name="Datalogic ADC Inc. Handheld Barcode Scanner"
P: Phys=usb-700000.ehci-2.3/input2
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.3/1-2.3:1.2/input/input14
U: Uniq=S/N G16C15795
H: Handlers=kbd event3
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
/* Datalogic DSM04XX
I: Bus=0003 Vendor=05f9 Product=4005 Version=0110
N: Name="Datalogic Handheld Barcode Scanner"
P: Phys=usb-700000.ehci-2.3/input0
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.3/1-2.3:1.0/input/input15
U: Uniq=S/N G21FA0180
H: Handlers=kbd event3
B: PROP=0
B: EV=120013
B: KEY=e080ffdf 1cfffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
/*
I: Bus=0003 Vendor=1eab Product=0022 Version=0110
N: Name="Newland Auto-ID NLS-FM3080V2-20 USB POS KBW"
P: Phys=usb-700000.ehci-2.2/input0
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.2/1-2.2:1.0/input/input6
U: Uniq=FM3080V2-20-BH00017
H: Handlers=kbd event2
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
switch (type) {
case EVENT_DEVICE_BARCODEREADER:
N_RegExp = "^N: Name=.+(Barcode|Honeywell Imaging|Newland Auto).+";
DeviceTypeName = "1D/2D-Scanner";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_TOUCHSCREEN:
N_RegExp = "^N: Name=.+touch.+";
DeviceTypeName = "Touchscreen";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_GPIO_KEYBOARD:
N_RegExp = "^N: Name=.+gpio.+";
DeviceTypeName = "gpio-keys";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_KEYBOARD:
N_RegExp = "^N: Name=.+touch.+";
DeviceTypeName = "keyboard";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_RFIDREADER:
N_RegExp = "^N: Name=.+Card.+";
DeviceTypeName = "card reader";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_USBMOUSE:
N_RegExp = "^N: Name=.+USB.+Mouse.+";
DeviceTypeName = "USB Mouse";
DeviceNamePattern = "mouse";
break;
}
qDebug() << "ATB_system::getEventDeviceName() N_RegExp = " << N_RegExp;
do {
line = textInStream.readLine();
// DEBUG
//qDebug() << " " << line;
// find "N:"-line:
if (line.contains(QRegExp(N_RegExp))) {
typeFound = true;
lineCounter = 0;
qDebug() << "ATB_system::getEventDeviceName() found N_RegExp = " << N_RegExp;
}
if (typeFound) {
// found "N:"-line, now search for "H:"-line;
// the corresponding "H:"-line should be within the next 7 following text lines.
// example lines:
// - "H: Handlers=event0 mouse0" -> for touchscreen on PTU4
// - "H: Handlers=event3 mouse1" -> for USB mouse on PTU4
lineCounter++;
if ( (lineCounter<=7) && (line.contains(QRegExp(H_RegExp))) ) {
eventPart = line.split("=", QString::SkipEmptyParts).takeLast();
devNames = eventPart.split(" ", QString::SkipEmptyParts);
for (int i=0; i<devNames.size(); i++ ) {
if (devNames.at(i).contains(DeviceNamePattern)) {
eventDeviceName = "/dev/input/" + devNames.at(i);
qDebug() << "ATB_system::getEventDeviceName() found device = " << eventDeviceName;
}
}
}
if ( lineCounter>7 ) {
lineCounter=0;
typeFound = false;
}
}
} while (!line.isNull());
if (eventDeviceName == "") {
qCritical() << "ATB_system::getEventDeviceName(): could not detect input event device type " << DeviceTypeName;
}
return eventDeviceName;
}

120
atb_system.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef ATB_SYSTEM_H
#define ATB_SYSTEM_H
#include <QObject>
#include <QFile>
#include <QTextStream>
#include "version.h"
#define SYS_COMMAND_SLEEP 0x0001
#define SYS_COMMAND_DIMLOW 0x0002
#define SYS_COMMAND_DIMHIGH 0x0003
#define SYS_COMMAND_BEEP 0x0004
#define SYS_COMMAND_MACHINE_NUMBER 0x0005
#define SYS_COMMAND_HALT 0x0006
#define SYS_COMMAND_REBOOT 0x0007
#define SYS_COMMAND_LED_CONTROL 0x3600
#if defined (ARCH_PTU2)
#define BEEPTIMEOUT 200
#elif defined (ARCH_PTU4)
#define BEEPTIMEOUT 100
#else
#define BEEPTIMEOUT 100
#endif
class ATBHMIconfig;
class ATB_system : public QObject {
Q_OBJECT
private:
int init_touch_feedback();
int init_sc_dbus();
ATBHMIconfig *config;
QFile *tf_gpio;
QTextStream *tf_gpio_outstream;
quint8 current_dim_value;
void privateConfigLED(const QByteArray & cmd);
void privateSetLEDTrigger(const QString & led, const QString & trigger);
void privateSetLEDDelayOn(const QString & led, const QString & delayOn);
void privateSetLEDDelayOff(const QString & led, const QString & delayOff);
void privateSwitchBlinkButton(bool on);
public:
explicit ATB_system(ATBHMIconfig *config, QObject *parent = nullptr);
~ATB_system();
static quint8 setPSAConfigInt(const QString & filename, quint16 iValue);
static quint16 readPSAConfigInt(const QString &filename);
static quint8 setPSAConfigString(const QString & filename, const QString & sValue);
static QString readPSAConfigString(const QString & filename);
enum LED_NAME {
ATB_LED1 = 1,
ATB_LED2,
ATB_LED3,
ATB_LED4
};
enum LED_TRIGGER {
LED_TRIGGER_NONE = 1,
LED_TRIGGER_TIMER,
LED_TRIGGER_DEFAULT_ON
};
enum DEVICE_TYPE {
EVENT_DEVICE_BARCODEREADER,
EVENT_DEVICE_TOUCHSCREEN,
EVENT_DEVICE_GPIO_KEYBOARD,
EVENT_DEVICE_KEYBOARD,
EVENT_DEVICE_RFIDREADER,
EVENT_DEVICE_USBMOUSE
};
static QString getEventDeviceName(DEVICE_TYPE type);
static quint8 setupInductionLoops();
void dbus_permitSuspend();
void dbus_preventSuspend();
void dbus_DimHighPermanent();
void dbus_DimControlStart();
void dbus_wakeSystem();
signals:
/* emitted, after waking up from suspend...
*/
void wakeUp();
public slots:
void executeSystemCommand(quint16 cmd, QByteArray data);
void DimHigh();
void DimLow();
void Dim(quint8 value);
void DimStart();
void DimStop();
void Beep();
void BeepStop();
void setDateTime(const QString &dateTimeString);
void onConfigLED(LED_NAME LED, LED_TRIGGER trigger, quint16 delayOn = 0, quint16 delayOff = 0);
void switchBlinkButtonOn();
void switchBlinkButtonOff();
void onWakeVMC();
void halt();
void reboot();
};
#endif // ATB_SYSTEM_H

157
generate-version.sh Executable file
View File

@ -0,0 +1,157 @@
#!/bin/bash
VERSION_STRING=""
#GIT='/cygdrive/c/Program Files \(x86\)/Git/bin/git'
GIT=git
parse_git_branch () {
$GIT branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/\1/"
}
ARCH=$1
TARGET=$2
INTERFACE=$3
INTERFACE_DEFINITION=$4
VERSION_H=$5
SCRIPT=$(readlink -f $0)
SCRIPTPATH=`dirname $SCRIPT`
OUTPUTDIR=$(pwd)
echo " current dir is : " $(pwd)
echo $SCRIPT
echo $SCRIPTPATH
echo "changing dir to script path: " $SCRIPTPATH
cd $SCRIPTPATH
# set version string ##################################################################
if [ -z $VERSION_STRING ] ; then
VERSION_STRING=$(date +%Y%m%d_%H%M)
fi
GIT_DESCRIBE=$($GIT describe --always)
GIT_BRANCH=$(parse_git_branch)
# extract path from branchname:
IFS='_' read -ra TMP_ARRAY <<< "${GIT_BRANCH}"
BRANCH_PATH=${TMP_ARRAY[0]}
# detect if we have a development version:
if [ ${#TMP_ARRAY[1]} -gt 0 ] ; then
DEV_SUFFIX="_dev"
else
DEV_SUFFIX=""
fi
# detect if git status is dirty
GIT_DESCRIBE_DIRTY=$($GIT describe --dirty)
if [ "${GIT_DESCRIBE_DIRTY:(-6)}" == "-dirty" ] ; then
DIRTY_SUFFIX="_dirty"
else
DIRTY_SUFFIX=""
fi
if [ -n "$DIRTY_SUFFIX" ] || [ -n "$DEV_SUFFIX" ] ; then
DEVDIRTY=true
else
DEVDIRTY=false
fi
# extract interface definition
#
#Q_DECLARE_INTERFACE(CCInterface,
# "eu.atb.ptu.plugin.CCInterface/2.9.0")
#Q_DECLARE_INTERFACE(DeviceControllerInterface,
# "eu.atb.ptu.plugin.DeviceControllerInterface/1.0")
# -> extract whole string within quotation marks
INTERFACE_VERSION=$(grep 'eu.atb.ptu.plugin.' ${INTERFACE_DEFINITION})
# get string within quotes:
INTERFACE_VERSION=`echo ${INTERFACE_VERSION} | awk -F \" '{print $2}'`
#
# write version.h
echo " TARGET is: $TARGET"
echo " ARCH is: $ARCH"
echo " "
echo " PluginName: $TARGET"
echo " Interface: $INTERFACE"
echo " InterfaceVersion: $INTERFACE_VERSION"
echo " "
echo " new version is: $VERSION_STRING"
echo " git describe is: $GIT_DESCRIBE"
echo " git branch is: $GIT_BRANCH"
echo " branch-path is: $BRANCH_PATH"
echo " "
echo " dev suffix: $DEV_SUFFIX"
echo " dirty suffix: $DIRTY_SUFFIX"
PLUGIN_VERSION=${VERSION_STRING}
#ATB_QT_GIT_DESCRIBE=${GIT_DESCRIBE}_${GIT_BRANCH}
PLUGIN_GIT_DESCRIBE=${GIT_DESCRIBE}_${BRANCH_PATH}${DEV_SUFFIX}${DIRTY_SUFFIX}
#TARGET=IngenicoZVT_CCPlugin
# build version.h #####################################################################
echo " building new version info (version.h) ..."
echo "#ifndef VERSION_H" > ${VERSION_H}
echo "#define VERSION_H" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "#define INTERFACE_VERSION \"${INTERFACE_VERSION}\"" >> ${VERSION_H}
echo "#define PLUGIN_VERSION \"${PLUGIN_VERSION}\"" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "#define PLUGIN_GIT_DESCRIBE \"${PLUGIN_GIT_DESCRIBE}\"" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "" >> ${VERSION_H}
cat <<EOT >> ${VERSION_H}
const std::string pluginInfoString = R"(
{
"Interface": "${INTERFACE}",
"InterfaceVersion": "${INTERFACE_VERSION}",
"PluginName": "${TARGET}",
"Version": "${PLUGIN_VERSION}",
"git-describe": "${PLUGIN_GIT_DESCRIBE}",
}
)";
EOT
echo "" >> ${VERSION_H}
echo "" >> ${VERSION_H}
if [ ${DEVDIRTY} == "true" ] ; then
echo "#define DEVDIRTY" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "" >> ${VERSION_H}
fi
echo "#define SYSTEM_ARCH \"${ARCH}\"" >> ${VERSION_H}
echo "#define ARCH_${ARCH}" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "" >> ${VERSION_H}
echo "#endif //VERSION_H" >> ${VERSION_H}

1468
include/interfaces.h Executable file

File diff suppressed because it is too large Load Diff

22
plugins/ATBAPPplugin.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef ATBAPPPLUGIN_H
#define ATBAPPPLUGIN_H
/***********************************************************
* a simple class with only one method for plugin info
*/
#include <QObject>
#include <QString>
class ATBAPPplugin
{
public:
virtual const QString & getPluginInfo() = 0;
};
Q_DECLARE_INTERFACE(ATBAPPplugin,
"eu.atb.ptu.plugin.ATBAPPplugin/0.9")
#endif // ATBAPPPLUGIN_H

147
plugins/CC/CCDummy.cpp Normal file
View File

@ -0,0 +1,147 @@
#include "CCDummy.h"
#include <QDebug>
using namespace nsCCInterface;
const std::string CCInterfacePluginInfoString = R"(
{
"PluginName": "CCDummy",
"Version": "1.0",
"git-describe": "",
}
)";
CCDummy::CCDummy(QObject *parent) :
QObject(parent),
errorCode(1),
errorDescription(""),
pluginState(PLUGIN_STATE::NOT_INITIALIZED)
{
this->pluginInfo = QString::fromUtf8(CCInterfacePluginInfoString.c_str());
}
CCDummy::~CCDummy()
{
}
PLUGIN_STATE CCDummy::initCCInterfacePlugin(QObject *healthEventReceiver, const QSettings & settings)
{
Q_UNUSED(healthEventReceiver)
qDebug() << "called CCDummy::initCalculatePricePlugin()";
qDebug() << " pluginName from setting is: " << settings.value("PLUGINS/CCPlugin", "").toString();
this->pluginState = PLUGIN_STATE::INITIALIZED;
return this->pluginState;
}
void CCDummy::requestReset()
{
}
void CCDummy::requestStartTransaction(quint32 amount)
{
Q_UNUSED(amount)
}
void CCDummy::requestCancelTransaction()
{
}
void CCDummy::requestRevertTransaction()
{
}
void CCDummy::requestConfirmTransaction()
{
}
void CCDummy::requestDayClose()
{
}
void CCDummy::requestCardInfo()
{
}
void CCDummy::requestPreAuthTransaction(quint32 amount)
{
Q_UNUSED(amount);
}
void CCDummy::requestCancelPreAuthTransaction(QString & receiptNumber)
{
Q_UNUSED(receiptNumber);
}
void CCDummy::requestBookTotalTransaction(quint32 amount, QString & receiptNumber)
{
Q_UNUSED(amount)
Q_UNUSED(receiptNumber)
}
void CCDummy::wakeupCC()
{
}
void CCDummy::sleepCC()
{
}
/************************************************************************************************
* Mandatory plugin methods
*
*/
PLUGIN_STATE CCDummy::getState()
{
return this->pluginState;
}
quint32 CCDummy::getLastError()
{
return this->errorCode;
}
const QString & CCDummy::getLastErrorDescription()
{
return this->errorDescription;
}
const QString & CCDummy::getPluginInfo()
{
return pluginInfo;
}

68
plugins/CC/CCDummy.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef CCDUMMY_H
#define CCDUMMY_H
#include <QObject>
#include "CCInterface.h"
#include "ATBAPPplugin.h"
class CCDummy : public QObject,
public CCInterface
{
Q_OBJECT
Q_INTERFACES(ATBAPPplugin)
Q_INTERFACES(CCInterface)
public:
CCDummy(QObject *parent = 0);
~CCDummy();
// interface:
nsCCInterface::PLUGIN_STATE initCCInterfacePlugin(QObject *healthEventReceiver, const QSettings & settings);
nsCCInterface::PLUGIN_STATE getState();
quint32 getLastError();
const QString & getLastErrorDescription();
// return a plugin description in JSON or XML
const QString & getPluginInfo();
public slots:
void requestReset();
void requestStartTransaction(quint32 amount);
void requestCancelTransaction();
void requestRevertTransaction();
void requestConfirmTransaction();
void requestDayClose();
void requestCardInfo();
void requestPreAuthTransaction(quint32 amount);
void requestCancelPreAuthTransaction(QString & receiptNumber);
void requestBookTotalTransaction(quint32 amount, QString & receiptNumber);
void wakeupCC();
void sleepCC();
signals:
void sendStartTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendCancelTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendRevertTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendConfirmTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendDayCloseResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendCardInfoResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendCancelPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
void sendBookTotalTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result);
private:
quint32 errorCode;
QString errorCodeString;
QString errorDescription;
QString pluginInfo;
nsCCInterface::PLUGIN_STATE pluginState;
};
#endif // CCDUMMY_H

86
plugins/CC/CCInterface.h Normal file
View File

@ -0,0 +1,86 @@
#ifndef CCINTERFACE_H
#define CCINTERFACE_H
#include <QtPlugin>
#include <QSettings>
#include <QString>
#include "ATBAPPplugin.h"
namespace nsCCInterface {
enum class PLUGIN_STATE : quint8;
enum class RESULT_STATE : quint8;
}
class CCInterface : public ATBAPPplugin
{
Q_INTERFACES(ATBAPPplugin)
public:
virtual ~CCInterface() {}
virtual nsCCInterface::PLUGIN_STATE initCCInterfacePlugin(QObject *healthEventReceiver, const QSettings & settings) = 0;
virtual nsCCInterface::PLUGIN_STATE getState() = 0;
virtual quint32 getLastError() = 0;
virtual const QString & getLastErrorDescription() = 0;
// return a plugin description in JSON or XML
// -> ATBAPPplugin::getPluginInfo()
public slots:
virtual void requestReset() = 0;
virtual void requestStartTransaction(quint32 amount) = 0;
virtual void requestCancelTransaction() = 0;
virtual void requestRevertTransaction() = 0;
virtual void requestConfirmTransaction() = 0;
virtual void requestDayClose() = 0;
virtual void requestCardInfo() = 0;
virtual void requestPreAuthTransaction(quint32 amount) = 0;
virtual void requestCancelPreAuthTransaction(QString & receiptNumber) = 0;
virtual void requestBookTotalTransaction(quint32 amount, QString & receiptNumber) = 0;
virtual void wakeupCC() = 0;
virtual void sleepCC() = 0;
signals:
virtual void sendStartTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendCancelTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendRevertTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendConfirmTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendDayCloseResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendCardInfoResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendCancelPreAuthTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
virtual void sendBookTotalTransactionResult(nsCCInterface::RESULT_STATE resultState, QString & result) = 0;
};
Q_DECLARE_INTERFACE(CCInterface,
"eu.atb.ptu.plugin.CCInterface/2.9.1")
namespace nsCCInterface {
enum class PLUGIN_STATE : quint8 {
NOT_INITIALIZED = 0,
INITIALIZED = 1
};
enum class RESULT_STATE : quint8 {
SUCCESS = 1,
ERROR_BACKEND = 2,
ERROR_NETWORK = 3,
ERROR_TIMEOUT = 4,
ERROR_PROCESS = 5,
ERROR_BUSY = 6,
ERROR_STATE = 7,
INFO = 8
};
}
#endif // CCINTERFACE_H

View File

@ -0,0 +1,215 @@
#include "CalculatePriceDefault.h"
#include <QDebug>
using namespace nsCalculatePriceInterface;
const std::string CalculatePriceInterfacePluginInfoString = R"(
{
"PluginName": "CalculatePriceDummy",
"Version": "1.0",
"git-describe": "",
}
)";
CalculatePriceDefault::CalculatePriceDefault(QObject *parent) :
QObject(parent),
errorCode(1),
errorDescription(""),
pluginState(PLUGIN_STATE::NOT_INITIALIZED)
{
this->pluginInfo = QString::fromUtf8(CalculatePriceInterfacePluginInfoString.c_str());
}
CalculatePriceDefault::~CalculatePriceDefault()
{
}
PLUGIN_STATE CalculatePriceDefault::initCalculatePricePlugin(QObject *healthEventReceiver, const QSettings & settings)
{
Q_UNUSED(healthEventReceiver)
qDebug() << "called CalculatePriceDummy::initCalculatePricePlugin()";
qDebug() << " pluginName from setting is: " << settings.value("PLUGINS/CalculatePricePlugin", "").toString();
this->pluginState = PLUGIN_STATE::INITIALIZED;
return this->pluginState;
}
void CalculatePriceDefault::requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType)
{
Q_UNUSED(PermitType)
emit this->requestCalculatePriceResult(RESULT_STATE::SUCCESS,
AccessInformation,
AccessInformationType,
"",
"",
"",
"",
"",
"1",
"dummyPlugin"
);
}
void CalculatePriceDefault::requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
const QString & parktime)
{
Q_UNUSED(PermitType)
Q_UNUSED(parktime)
emit this->requestCalculatePriceResult(RESULT_STATE::SUCCESS,
AccessInformation,
AccessInformationType,
"",
"",
"",
"",
"",
"1",
"dummyPlugin"
);
}
void CalculatePriceDefault::requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
nsCalculatePriceInterface::STEP step)
{
Q_UNUSED(AccessInformation)
Q_UNUSED(AccessInformationType)
Q_UNUSED(PermitType)
Q_UNUSED(step)
}
void CalculatePriceDefault::requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
int coinValue)
{
Q_UNUSED(AccessInformation)
Q_UNUSED(AccessInformationType)
Q_UNUSED(PermitType)
Q_UNUSED(coinValue)
}
void CalculatePriceDefault::requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
const QString & parktime,
const QString & cardInfo,
const QString & transactionInfo)
{
Q_UNUSED(PermitType)
Q_UNUSED(parktime)
Q_UNUSED(cardInfo)
Q_UNUSED(transactionInfo)
emit this->requestCalculatePriceResult(RESULT_STATE::SUCCESS,
AccessInformation,
AccessInformationType,
"",
"",
"",
"",
"",
"1",
"dummyPlugin"
);
}
void CalculatePriceDefault::requestProcessTransaction(const QString & AccessInformation,
const QString & AccessInformationType,
const QString &amount,
bool isOffline,
const QString & TransactionId,
const QString & ReceiptData,
const QString & PermitType, const QString &PaymentType)
{
Q_UNUSED(isOffline)
Q_UNUSED(AccessInformation)
Q_UNUSED(AccessInformationType)
Q_UNUSED(amount)
Q_UNUSED(TransactionId)
Q_UNUSED(ReceiptData)
Q_UNUSED(PermitType)
Q_UNUSED(PaymentType)
}
/************************************************************************************************
* Mandatory plugin methods
*
*/
PLUGIN_STATE CalculatePriceDefault::getState()
{
return this->pluginState;
}
quint32 CalculatePriceDefault::getLastError()
{
return this->errorCode;
}
const QString & CalculatePriceDefault::getLastErrorDescription()
{
return this->errorDescription;
}
const QString & CalculatePriceDefault::getPluginInfo()
{
return pluginInfo;
}
const QString CalculatePriceDefault::getString(nsCalculatePriceInterface::RESULT_STATE resultState)
{
QString str;
switch (resultState) {
case nsCalculatePriceInterface::RESULT_STATE::SUCCESS:
str = QString("RESULT_STATE::SUCCESS");
break;
case nsCalculatePriceInterface::RESULT_STATE::ERROR_BACKEND:
str = QString("RESULT_STATE::ERROR_BACKEND");
break;
case nsCalculatePriceInterface::RESULT_STATE::ERROR_NETWORK:
str = QString("RESULT_STATE::ERROR_NETWORK");
break;
case nsCalculatePriceInterface::RESULT_STATE::ERROR_TIMEOUT:
str = QString("RESULT_STATE::ERROR_TIMEOUT");
break;
case nsCalculatePriceInterface::RESULT_STATE::ERROR_PROCESS:
str = QString("RESULT_STATE::ERROR_PROCESS");
break;
case nsCalculatePriceInterface::RESULT_STATE::ERROR_RETRY:
str = QString("RESULT_STATE::ERROR_RETRY");
break;
case nsCalculatePriceInterface::RESULT_STATE::INFO:
str = QString("RESULT_STATE::INFO");
break;
}
return str;
}

View File

@ -0,0 +1,95 @@
#ifndef CALCULATEPRICEDUMMY_H
#define CALCULATEPRICEDUMMY_H
#include <QObject>
#include "CalculatePriceInterface.h"
using namespace nsCalculatePriceInterface;
class CalculatePriceDefault : public QObject,
public CalculatePriceInterface
{
Q_OBJECT
Q_INTERFACES(CalculatePriceInterface)
public:
CalculatePriceDefault(QObject *parent = 0);
~CalculatePriceDefault();
// interface:
PLUGIN_STATE initCalculatePricePlugin(QObject *healthEventReceiver, const QSettings & settings);
void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType);
void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
const QString & parktime);
void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
nsCalculatePriceInterface::STEP step);
void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
int coinValue);
void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
const QString & parktime,
const QString & cardInfo,
const QString & transactionInfo);
void requestProcessTransaction(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & amount,
bool isOffline,
const QString & TransactionId,
const QString & ReceiptData,
const QString & PermitType,
const QString & PaymentType);
PLUGIN_STATE getState();
quint32 getLastError();
const QString & getLastErrorDescription();
const QString & getPluginInfo();
const QString getString(nsCalculatePriceInterface::RESULT_STATE resultState);
signals:
void requestCalculatePriceResult(RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const QString & amountDueNet,
const QString & amountDueTax,
const QString & gracePeriod,
const QString & errorCode,
const QString & errorDescription);
void requestCalculatePriceResult(RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const PriceInfo & priceInfo,
const QString & errorCode,
const QString & errorDescription);
void requestProcessTransactionResult(RESULT_STATE resultState,
const QString & errorCode,
const QString & errorDescription);
private:
quint32 errorCode;
QString errorCodeString;
QString errorDescription;
QString pluginInfo;
PLUGIN_STATE pluginState;
};
#endif // CALCULATEPRICEDUMMY_H

View File

@ -0,0 +1,157 @@
#ifndef CALCULATEPRICEINTERFACE_H
#define CALCULATEPRICEINTERFACE_H
#include <QtPlugin>
#include <QSettings>
#include <QString>
#include "ATBAPPplugin.h"
namespace nsCalculatePriceInterface {
enum class PLUGIN_STATE : quint8;
enum class RESULT_STATE : quint8;
enum class STEP : quint8;
}
class PriceInfo
{
public:
int priceNet; // price net in cent
int priceTax; // price tax in cent
int priceGross; // price gross in cent
int taxRate; // tax rate per mill
};
class CalculatePriceInterface : public ATBAPPplugin
{
Q_INTERFACES(ATBAPPplugin)
public:
virtual ~CalculatePriceInterface() {}
virtual nsCalculatePriceInterface::PLUGIN_STATE initCalculatePricePlugin(QObject *healthEventReceiver,
const QSettings & settings) = 0;
// for price calculation dependent on ID (AccessInformation)
virtual void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType) = 0;
// for price calculation dependent on value (e.g. parking time)
virtual void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
const QString & parktime) = 0;
// for price/time calculation on next step up/down
virtual void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
nsCalculatePriceInterface::STEP step) = 0;
// for price/time calculation on next coin value
virtual void requestCalculatePrice(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & PermitType,
int coinValue) = 0;
// for price calculation dependent on additonal values (e.g. parking time, card info, ...)
virtual void requestCalculatePrice(const QString & AccessInformation, // primary key e.g. a license plate, credit card number
const QString & AccessInformationType, // type of AccessInformation: LICENSEPLATE, CREDITCARD, PIN, ...
const QString & PermitType, // e.g. selected product / vehicle
const QString & parktime, // parktime in minutes
const QString & cardInfo, // additonal card info (e.g. PAN, Institusnummer, Token, ...)
const QString & transactionInfo) = 0; // kind of a transcation id, could be used for identification of transaction
virtual void requestProcessTransaction(const QString & AccessInformation,
const QString & AccessInformationType,
const QString & amount,
bool isOffline,
const QString & TransactionId,
const QString & ReceiptData,
const QString & PermitType,
const QString & PaymentType) = 0;
virtual nsCalculatePriceInterface::PLUGIN_STATE getState() = 0;
virtual quint32 getLastError() = 0;
virtual const QString & getLastErrorDescription() = 0;
// return a plugin description in JSON or XML
// -> ATBAPPplugin::getPluginInfo()
// helpers e.g. for debug / log
virtual const QString getString(nsCalculatePriceInterface::RESULT_STATE resultState) = 0;
signals:
virtual void requestCalculatePriceResult(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const QString & amountDueNet,
const QString & amountDueTax,
const QString & gracePeriod,
const QString & errorCode,
const QString & errorDescription) = 0;
virtual void requestCalculatePriceResult(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & accessInformation,
const QString & accessInformationType,
const QString & amountDuePeriodStart,
const QString & amountDuePeriodEnd,
const PriceInfo & priceInfo,
const QString & errorCode,
const QString & errorDescription) = 0;
virtual void requestProcessTransactionResult(nsCalculatePriceInterface::RESULT_STATE resultState,
const QString & errorCode,
const QString & errorDescription) = 0;
// TODO:
/* APPLICATION_PROCESS_TYPE is a global ATB-Type:
* - BACKGROUND -> process can work in background without display
* - HMI -> display is needed
* - t.b.d
*
* PROCESS_ID is an identifier for e.g. debuging or log which process/module/library/plugin...
* caused the prevent
*
virtual void preventSuspend(APPLICATION_PROCESS_TYPE pt, PROCESS_ID pid) = 0;
virtual void allowSuspend(PROCESS_ID pid) = 0;
*/
};
Q_DECLARE_INTERFACE(CalculatePriceInterface,
"eu.atb.ptu.plugin.CalculatePriceInterface/4.0")
namespace nsCalculatePriceInterface {
enum class PLUGIN_STATE : quint8 {
NOT_INITIALIZED = 0,
INITIALIZED = 1
};
enum class RESULT_STATE : quint8 {
SUCCESS = 1, // got price and time from remote
ERROR_BACKEND = 2, // error from backand (e.g. backend replies with error)
ERROR_NETWORK = 3, // error from network (e.g. host not available)
ERROR_TIMEOUT = 4, // the operation timed out
ERROR_PROCESS = 5, // internal plugin error (e.g. bug in implementation)
ERROR_RETRY = 6, // retry operation
INFO = 7
};
enum class STEP : quint8 {
UP = 1,
DOWN = 2
};
}
#endif // CALCULATEPRICEINTERFACE_H

134
plugins/PluginManager.cpp Normal file
View File

@ -0,0 +1,134 @@
#include <QPluginLoader>
#include <QSettings>
#include "PluginManager.h"
#include "ATBHMIconfig.h"
#include "plugins/ATBAPPplugin.h"
#include "plugins/CC/CCInterface.h"
#include "plugins/CalculatePrice/CalculatePriceInterface.h"
PluginManager::PluginManager(ATBHMIconfig *config, QObject *parent) :
QObject(parent),
config(config)
{
this->loadPlugins();
}
void PluginManager::loadPlugins()
{
/* NOTE: setting a search path via 'QCoreApplication::addLibraryPath' does not work for
* user specific plugins...
* This seems to work only for QT core plugins which are loaded before QApplication object is
* created.
* => we set the path for our plugins manually here.
*/
// DEBUG
/* qDebug() << "--------------------------- DEBUG -----------------------------------";
* qDebug() << "QCoreApplication::applicationDirPath() = " << QCoreApplication::applicationDirPath();
* qDebug() << " ";
* qDebug() << "QCoreApplication::libraryPaths()";
* foreach (const QString &path, QCoreApplication::libraryPaths()) {
* qDebug() << " " << path;
* }
* qDebug() << "---------------------------------------------------------------------";
*/
/* NOTE: qputenv() to set LD_LIBRARY_PATH does not work either!
* We tried this to set the path were libraries used by the plugin itself could be found
* (e.g. kdsoap-library, which is used by several plugins).
*/
// load all available plugins in config group [PLUGINS]
QSettings * settings = this->config->getSettingsPtr();
if (!settings->childGroups().contains("PLUGINS")) {
qCritical() << "PluginManager: no plugins defined in config";
return;
}
settings->beginGroup("PLUGINS");
QStringList pluginStringList = settings->childKeys();
QStringListIterator PluginsIterator(pluginStringList);
QString pluginKey;
QString pluginName;
while(PluginsIterator.hasNext()) {
pluginKey = PluginsIterator.next();
pluginName = settings->value(pluginKey, "").toString();
if (pluginName == "") {
qCritical() << "PluginManager: plugin " << pluginKey << " is not defined";
}
else if (pluginKey.startsWith('#')) {
qCritical() << "PluginManager: skip comment " << pluginKey;
}
else if (QString::compare(pluginName, "notUsed", Qt::CaseInsensitive) == 0) {
qCritical() << "PluginManager: plugin " << pluginKey << " is not used";
}
else {
if (!QLibrary::isLibrary(pluginName)) pluginName.append(".so");
if (!pluginName.startsWith("lib")) pluginName.prepend("lib");
if (!pluginName.startsWith("plugins")) pluginName.prepend("plugins/");
if (!pluginName.startsWith('/')) {
pluginName.prepend('/').prepend(QApplication::applicationDirPath());
}
qCritical() << "PluginManager::loadPlugins() load plugin: "
<< pluginName;
// TODO: check, if plugin file is available, readable etc...
QPluginLoader* pluginLoader = new QPluginLoader();
pluginLoader->setFileName(pluginName);
plugins.insert(pluginKey, pluginLoader);
}
}
settings->endGroup();
}
QObject * PluginManager::getInstance(const QString & pluginname)
{
QObject * result = nullptr;
QPluginLoader* pluginLoader = plugins[pluginname];
if (pluginLoader != nullptr) {
QObject* plugin = pluginLoader->instance();
if (!pluginLoader->isLoaded()) {
qCritical() << "PluginManager::getInstance("
<< pluginname
<< ") errorString: "
<< pluginLoader->errorString();
}
else {
result = plugin;
}
}
return result;
}
const QList<QString> PluginManager::listAvailablePlugins()
{
return plugins.keys();
}
bool PluginManager::isPluginAvailable(const QString & pluginname)
{
if (plugins[pluginname] != nullptr) {
return true;
}
else {
return false;
}
}

42
plugins/PluginManager.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H
#include <QObject>
#include <QDir>
#include <QHash>
class ATBHMIconfig;
class QPluginLoader;
class PluginManager : public QObject
{
Q_OBJECT
public:
explicit PluginManager(ATBHMIconfig *config, QObject *parent = nullptr);
QObject * getInstance(const QString & pluginname);
const QList<QString> listAvailablePlugins();
bool isPluginAvailable(const QString & pluginname);
signals:
public slots:
private:
ATBHMIconfig *config;
QDir pluginsDir;
void loadPlugins();
// Hash to store all plugins
QHash<QString, QPluginLoader*> plugins;
};
#endif // PLUGINMANAGER_H

17
src/ATBAPP/ATBAPPplugin.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef ATBAPPPLUGIN_H
#define ATBAPPPLUGIN_H
/***********************************************************
* a simple class with only one method for plugin info
*/
#include <QObject>
#include <QString>
class ATBAPPplugin {
public:
virtual const QString & getPluginInfo() = 0;
};
Q_DECLARE_INTERFACE(ATBAPPplugin, "eu.atb.ptu.plugin.ATBAPPplugin/0.9")
#endif // ATBAPPPLUGIN_H

View File

@ -0,0 +1,91 @@
#include "src/ATBAPP/ATBVMCPlugin.h"
#include <QTimer>
#include <QThread>
#include <QTextCodec>
#include <QDebug>
#include <QPluginLoader>
#include <QDateTime>
#include <QFileInfo>
#include <QCoreApplication>
#include <QUuid>
#include <cstdlib>
ATBVMCPlugin::ATBVMCPlugin(QObject *parent)
: m_errorCode("")
, m_errorDescription("")
, m_pluginInfo("")
, m_serialPortName("")
, m_useDebug(false)
, m_pluginState(PLUGIN_STATE::NOT_INITIALIZED)
, m_eventReceiver(nullptr) {
this->setParent(parent);
}
ATBVMCPlugin::~ATBVMCPlugin() {
}
PLUGIN_STATE ATBVMCPlugin::initVMCPlugin(QObject *eventReceiver,
QSettings const &settings) {
Q_UNUSED(eventReceiver);
Q_UNUSED(settings);
return PLUGIN_STATE::NOT_INITIALIZED;
}
// mandantory ATBAPP plugin methods: ------------------------------------------
PLUGIN_STATE ATBVMCPlugin::getState() {
return PLUGIN_STATE::NOT_INITIALIZED;
}
QString ATBVMCPlugin::getLastError() {
return "";
}
QString ATBVMCPlugin::getLastErrorDescription() {
return "";
}
QString const &ATBVMCPlugin::getPluginInfo() {
static QString info;
return info;
}
// helpers e.g. for debug / log
QString ATBVMCPlugin::getString(RESULT_STATE /*resultState*/) {
return "";
}
void ATBVMCPlugin::onChangedProgramModeToSELL() {
}
void ATBVMCPlugin::onChangedProgramModeToSERVICE() {
}
void ATBVMCPlugin::onChangedProgramModeToIDLE() {
}
void ATBVMCPlugin::onChangedProgramModeToOOO() {
}
void ATBVMCPlugin::startPhysicalLayer() {
}
void ATBVMCPlugin::stopPhysicalLayer() {
}
void ATBVMCPlugin::reboot() {
}
void ATBVMCPlugin::reset() {
}

61
src/ATBAPP/ATBVMCPlugin.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef ATBVMCPLUGIN_H
#define ATBVMCPLUGIN_H
#include <QObject>
#include "src/ATBAPP/VMCInterface.h"
#include "src/ATBAPP/ATBAPPplugin.h"
#include "version.h"
#include "include/interfaces.h"
class ATBVMCPlugin : public VMCInterface {
Q_OBJECT
Q_INTERFACES(ATBAPPplugin)
Q_INTERFACES(UnifiedDCVMCInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA( IID "ATBVMCPlugin" )
#endif
public:
explicit ATBVMCPlugin(QObject *parent = nullptr);
~ATBVMCPlugin();
// ----------------------------------------------------------------------------
// interface:
PLUGIN_STATE initVMCPlugin(QObject *eventReceiver, QSettings const &settings);
// mandantory ATBAPP plugin methods: ------------------------------------------
PLUGIN_STATE getState() override;
QString getLastError() override;
QString getLastErrorDescription() override;
virtual const QString & getPluginInfo() override;
// helpers e.g. for debug / log
virtual QString getString(RESULT_STATE resultState) override;
public slots:
virtual void onChangedProgramModeToSELL() override;
virtual void onChangedProgramModeToSERVICE() override;
virtual void onChangedProgramModeToIDLE() override;
virtual void onChangedProgramModeToOOO() override;
virtual void startPhysicalLayer() override;
virtual void stopPhysicalLayer() override;
virtual void reboot() override;
virtual void reset() override;
private:
QString m_errorCode;
QString m_errorDescription;
QString m_pluginInfo;
QString m_serialPortName;
bool m_useDebug;
PLUGIN_STATE m_pluginState;
QObject* m_eventReceiver;
};
#endif // ATBDEVICECONTROLLERPLUGIN_H

View File

@ -0,0 +1,143 @@
#ifndef UNIFIED_DCVMC_INTERFACE_H_INCLUDED
#define UNIFIED_DCVMC_INTERFACE_H_INCLUDED
#include <QObject>
#include <QSettings>
#include <QtPlugin>
#include <QSettings>
#include <QString>
#include "ATBAPPplugin.h"
class UnifiedDCVMCInterface : public QObject, public ATBAPPplugin {
Q_OBJECT
Q_INTERFACES(ATBAPPplugin)
public:
enum class PLUGIN_STATE : quint8 {
NOT_INITIALIZED = 0,
INITIALIZED = 1
};
enum class RESULT_STATE : quint8 {
SUCCESS = 1, // operation was successfull
ERROR_BACKEND, // error from backend (e.g. backend replies with error)
ERROR_TIMEOUT, // the operation timed out
ERROR_PROCESS, // internal plugin error, should not occur (this is a bug in implementation)
ERROR_RETRY, // retry operation
INFO // informational (e.g. display a message, log something etc.)
};
enum class CASH_STATE : quint8 {
CACHE_EMPTY, // Cache still empty, default state
CACHE_INPUT, // Coins are in Cache
OVERPAYED,
/* t.b.d. */
};
enum class TICKET_VARIANT : quint8 {
PARKING_TICKET,
RECEIPT,
ERROR_RECEIPT,
START_RECEIPT, // e.g. Szeged Start
STOP_RECEIPT, // e.g. Szeged Stop
};
explicit UnifiedDCVMCInterface() = default;
virtual ~UnifiedDCVMCInterface() {}
virtual PLUGIN_STATE initPlugin(QObject *eventReceiver, QSettings const &settings) = 0;
// mandantory ATBAPP plugin methods:
virtual PLUGIN_STATE getState() = 0;
virtual QString getLastError() = 0;
virtual QString getLastErrorDescription() = 0;
virtual QString getString(RESULT_STATE resultState) = 0;
public slots:
virtual void onChangedProgramModeToSELL() = 0;
virtual void onChangedProgramModeToSERVICE() = 0;
virtual void onChangedProgramModeToIDLE() = 0;
virtual void onChangedProgramModeToOOO() = 0;
virtual void startPhysicalLayer() = 0;
virtual void stopPhysicalLayer() = 0;
virtual void reboot() = 0;
virtual void reset() = 0;
signals:
void printTicketFinished(RESULT_STATE resultState,
const QString & errorCode,
const QString & errorDescription);
void printReceiptFinished(RESULT_STATE resultState,
const QString & errorCode,
const QString & errorDescription);
/**
* emitted on e.g. a coin input
*/
void cashInputEvent(RESULT_STATE resultState,
CASH_STATE cashState,
const QString & newCashValue,
/* additional variables? */
const QString & errorCode,
const QString & errorDescription);
/**
* emitted if cashInput has been stopped, e.g. in result to task requestStopCashInput():
* -> shutter is blocked
* -> no cash input is possible
* -> coins are in cache
*/
void cashInputFinished(RESULT_STATE resultState,
const QString & newCashValue,
/* additional variables? */
const QString & errorCode,
const QString & errorDescription);
/**
* emitted e.g. if service door is opened
*/
void requestModeSERVICE();
/**
* emitted e.g. if doors are closed
*/
void requestModeIDLE();
/**
* emitted e.g. on severe errors
*/
void requestModeOOO();
/**
* emitted e.g. if service door is opened
*/
void requestAccountResponse(const QHash<QString, QVariant> & accountData);
/**
* emitted on error
* depending on errorCode:
* -> interrupt selling process
* -> machine can go to state OOO
* -> send error event to ISMAS
* -> ...
*/
void Error(
/* additional variables? */
const QString & errorCode,
const QString & errorDescription);
};
Q_DECLARE_INTERFACE(UnifiedDCVMCInterface,
"eu.atb.ptu.plugin.UnifiedDCVMCInterface/1.0")
using PLUGIN_STATE = UnifiedDCVMCInterface::PLUGIN_STATE;
using RESULT_STATE = UnifiedDCVMCInterface::RESULT_STATE;
using CASH_STATE = UnifiedDCVMCInterface::CASH_STATE;
using TICKET_VARIANT = UnifiedDCVMCInterface::TICKET_VARIANT;
#endif // UNIFIED_DCVMC_INTERFACE_H_INCLUDED

42
src/ATBAPP/VMCInterface.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef VMCINTERFACE_H
#define VMCINTERFACE_H
#include <QtPlugin>
#include <QSettings>
#include <QString>
#include "ATBAPPplugin.h"
#include "UnifiedDCVMCInterface.h"
namespace nsVMCInterface {
using PLUGIN_STATE = UnifiedDCVMCInterface::PLUGIN_STATE;
using RESULT_STATE = UnifiedDCVMCInterface::RESULT_STATE;
using CASH_STATE = UnifiedDCVMCInterface::CASH_STATE;
using TICKET_VARIANT = UnifiedDCVMCInterface::TICKET_VARIANT;
}
class VMCInterface : public UnifiedDCVMCInterface {
Q_OBJECT
Q_INTERFACES(ATBAPPplugin)
Q_INTERFACES(UnifiedDCVMCInterface)
public:
virtual PLUGIN_STATE initPlugin(QObject *eventReceiver, QSettings const &settings) override {
return initVMCPlugin(eventReceiver, settings);
}
virtual ~VMCInterface() {}
/**
* @brief initDCPlugin
* @param eventReceiver - QObject to receive ATBMachineEvents or HealthEvents
* @param settings
* @return
*/
virtual PLUGIN_STATE initVMCPlugin(QObject *eventReceiver, const QSettings & settings) = 0;
};
#endif // VMCINTERFACE_H

View File

@ -0,0 +1,244 @@
#include <QTimer>
#include "ReceiveBuffer.h"
#include "vmc.h"
#include <QDebug>
ReceiveBuffer::ReceiveBuffer(COM_interface *cinterface, QObject *parent) :
QObject(parent)
{
qRegisterMetaType<RECEIVE_ERROR>("RECEIVE_ERROR");
this->vmc = (VMC*)parent;
this->interface = cinterface;
connect(interface, SIGNAL(ReadData(QByteArray*)), this, SLOT(getData(QByteArray*)));
connect(vmc, SIGNAL(CommandProcessed()), this, SLOT(removeCommand()));
connect(this, SIGNAL(CommandAvailiable(QByteArray)), vmc, SLOT(CommandAvaliable(QByteArray)));
currentMessage.clear();
receiveIdleTimer = new QTimer(this);
receiveIdleTimer->setInterval(2000); // clear possible wrong data in receive buffer after 2s
receiveIdleTimer->setSingleShot(false);
connect(receiveIdleTimer, SIGNAL(timeout()), this, SLOT(onReceiveIdleTimerTimeout()));
}
ReceiveBuffer::~ReceiveBuffer()
{
delete(this->receiveIdleTimer);
}
int ReceiveBuffer::size()
{
return messageQueue.size();
}
void ReceiveBuffer::removeCommand()
{
if (messageQueue.size() > 0) {
messageQueue.removeFirst();
}
else {
qDebug() << "ReceiveBuffer::removeCommand(): no message to remove!";
}
}
void ReceiveBuffer::onReceiveIdleTimerTimeout()
{
this->currentMessage.clear();
this->receiveIdleTimer->stop();
}
void ReceiveBuffer::getData(QByteArray *data)
{
int CRCindex;
int COMMAND_IN_PROGRESS = 1;
// do nothing, if there is no data
if (data->size() == 0) { return; }
// DEBUG
/*
qDebug() << "ReceiveBuffer::getData(): messageQueue.size = " << messageQueue.size();
qDebug() << "ReceiveBuffer::getData(): data = " << data;
qDebug() << "ReceiveBuffer::getData(): data->size() = " << data->size();
qDebug() << "ReceiveBuffer::getData(): &currentMessage = " << &currentMessage;
qDebug() << "ReceiveBuffer::getData(): currentMessage.capacity = " << currentMessage.capacity();
qDebug() << "ReceiveBuffer::getData(): currentMessage.size() = " << currentMessage.size();
*/
this->receiveIdleTimer->start();
// for safety: prevent currentMessage to grow infinitely in size.
if (currentMessage.size() > 0xFF) {
emit ReceiveError(RECEIVE_ERROR::INVALID_COMMAND);
currentMessage.clear();
}
// we use append because data can be an interrupted command:
currentMessage.append(data->data(), data->size());
//qDebug() << "ReceiveBuffer::getData(): currentMessage = " << QString(currentMessage);
// process commands:
while (COMMAND_IN_PROGRESS) {
int startindex = currentMessage.indexOf(0x3e); // find start of command
// detect ACK/NACK response messages from vmc:
if (startindex != 0) {
int forEnd = -1;
if (startindex > 0) forEnd = startindex; // if ACK/NACK is before command ...
if (startindex == -1) forEnd = currentMessage.size(); // if ACK/NACK is the only data
for (int i = 0; i != forEnd; i++) {
switch (currentMessage.at(i)) {
case ACK: emit ReceiveResponse(ACK);
break;
case NACK: emit ReceiveResponse(NACK);
break;
}
}
}
if(startindex == -1) {
currentMessage.clear();
COMMAND_IN_PROGRESS = 0;
return;
}
else {
currentMessage.remove(0,startindex);
}
// now, we have at least a beginning message
CRCindex = checkMessageForCRC();
if (CRCindex == 0) {
// exit this methode and message part is still in currentMessage.
break;
}
if (CRCindex < 0) {
//qCriticalBAMessage(currentMessage);
emit ReceiveError(RECEIVE_ERROR::INVALID_COMMAND);
currentMessage.clear();
COMMAND_IN_PROGRESS = 0;
break;
}
//qDebug() << "ReceiveBuffer::getData(): startindex = " << startindex;
//qDebug() << "ReceiveBuffer::getData(): currentMessage = " << currentMessage;
//qDebug() << "ReceiveBuffer::getData(): CRCindex = " << CRCindex;
if (CRCindex) {
// found a complete message
if (checkCRC(currentMessage.at(CRCindex), CRCindex)) {
messageQueue << currentMessage.left(CRCindex + 1);
emit CommandAvailiable(messageQueue.first());
}
else {
emit ReceiveError(RECEIVE_ERROR::CRC);
}
if (currentMessage.size() > (CRCindex + 1)) {
currentMessage.remove(0,(CRCindex + 1));
}
else {
currentMessage.clear();
COMMAND_IN_PROGRESS = 0;
}
}
}
}
int ReceiveBuffer::checkMessageForCRC()
{
int CRCindex;
int DataLengthIndex;
// qDebug() << "ReceiveBuffer::checkMessageForCRC(): currentMessage.size = " << currentMessage.size();
// for (int i = 0; i < currentMessage.size(); i++)
// qDebug() << " currentMessage.at(" << i << ") = " << currentMessage.at(i);
if (currentMessage.size() <= 1)
return 0;
switch (currentMessage.at(1)) {
case 0x60: DataLengthIndex = 5; break;
case 0x61: DataLengthIndex = 6; break;
default: DataLengthIndex = 2; break;
}
if (currentMessage.size() <= DataLengthIndex)
return 0;
if (( (static_cast<quint8>(currentMessage.at(DataLengthIndex)) - 0x30)) <= 0 )
return -1;
CRCindex = DataLengthIndex + ( static_cast<quint8>(currentMessage.at(DataLengthIndex)) - 0x30) + 1;
if (currentMessage.size() <= CRCindex)
return 0;
else
return CRCindex;
}
bool ReceiveBuffer::checkCRC(quint8 CRC, int index)
{
quint8 cCRC = 0;
for (int i = 0; i < index; i++) {
cCRC += static_cast<quint8>(currentMessage.at(i));
//qDebug() << "ReceiveBuffer::checkCRC(): currentMessage.at(i) = " << currentMessage.at(i);
}
//qDebug() << "ReceiveBuffer::checkCRC(): cCRC = " << cCRC;
//qDebug() << "ReceiveBuffer::checkCRC(): CRC = " << CRC;
if (cCRC == CRC) return true;
else return false;
}
/**
* @brief ReceiveBuffer::qCriticalBAMessage
* @param message
*
* This is for test and debugging only.
*/
void ReceiveBuffer::qCriticalBAMessage(QByteArray message)
{
QString hexString = "received: ";
qint64 i;
for (i=0; i < message.size(); i++) {
hexString.append((QString(message.at(i))).toLatin1().toHex());
hexString.append(' ');
}
hexString.chop(1);
//qCritical() << "VMC::CommandAvaliable(): message.size(): " << message.size() << "";
qCritical() << "VMC::qCriticalBAMessage(): message: " << hexString << "";
}

View File

@ -0,0 +1,72 @@
#ifndef RECEIVEBUFFER_H
#define RECEIVEBUFFER_H
#include <QObject>
#include <QByteArray>
#include <QList>
#include "com_interface.h"
class QTimer;
class VMC;
enum class RECEIVE_ERROR : quint8;
class ReceiveBuffer : public QObject
{
Q_OBJECT
private:
VMC *vmc;
COM_interface *interface;
QList<QByteArray> messageQueue;
QByteArray currentMessage;
int checkMessageForCRC();
bool checkCRC(quint8 CRC, int index);
/* the receiveIdleTimer clears the receive buffer (currentMessag), if for
* a certain time no data was received.
* This is for improve speed for responding on vmc messages because possible
* wrong data is removed from queue.
*/
QTimer *receiveIdleTimer;
// for debug:
void qCriticalBAMessage(QByteArray message);
public:
explicit ReceiveBuffer(COM_interface *cinterface, QObject *parent = nullptr);
~ReceiveBuffer();
int size();
signals:
void CommandAvailiable(QByteArray command);
void ReceiveError(RECEIVE_ERROR error);
void ReceiveResponse(quint8 response);
private slots:
void removeCommand();
void getData(QByteArray *data);
void onReceiveIdleTimerTimeout();
};
enum class RECEIVE_ERROR : quint8 {
NO_ERROR = 0,
CRC,
NO_COMMAND,
INVALID_COMMAND
};
#endif // RECEIVEBUFFER_H

View File

@ -0,0 +1,206 @@
#include <QTimer>
#include "SendBuffer.h"
#include "vmc.h"
#include <QDebug>
#include "version.h"
SendBuffer::SendBuffer(COM_interface *cinterface, QObject *parent) :
QObject(parent)
{
qRegisterMetaType<SEND_ERROR>("SEND_ERROR");
this->vmc = (VMC*)parent;
this->interface = cinterface;
this->responseTimeoutTimer = new QTimer(this);
this->responseTimeoutTimer->setInterval(1000); // resend message to vmc after 1s without response
this->responseTimeoutTimer->setSingleShot(false);
connect(this->responseTimeoutTimer, SIGNAL(timeout()), this, SLOT(onResponseTimeoutTimerTimeout()));
responseTimerTimeoutCounter = 0;
resendCounter = 0;
}
SendBuffer::~SendBuffer()
{
delete(this->responseTimeoutTimer);
}
/****************************************************************
* public interface
*
****************************************************************/
/**
* from vmc: sendMessage / insert Message in Message-Queue
*
* interactiveFlag: (default = true)
* Interactive commands are commands resulting from user input (e.g. button clicks).
* This commands are enqueued only if responseTimeoutTimer is not active.
* This ensures, that such messages are sent in sequence and only, if an answer
* from vmc was received.
* Non-interactive commands are data messages which are sent to vmc, caused e.g. by
* an internal status change.
*
*/
int SendBuffer::SendMessage(QByteArray & ba, bool enqueue)
{
// prevent queue for growing endlessly:
// check size of queue
// if queue-size is greater than SB_MAX_SENDQUEUESIZE, remove oldest (first) element
qDebug() << "SendBuffer::SendMessage() messageQueue.size() = " << this->messageQueue.size();
if (this->messageQueue.size() > SB_MAX_SENDQUEUESIZE) {
messageQueue.removeFirst();
this->resendCounter = 0;
}
// put message in queue
if (enqueue)
this->messageQueue.enqueue(ba);
/* interactive messages are sent only, if the response timer is not active.
* this should prevent successive sending of the same message during waiting
* for an answer from vmc.
*/
if (! this->responseTimeoutTimer->isActive()) {
if(!enqueue)
this->messageQueue.enqueue(ba);
// try to send message
this->PrivateSendMessage();
}
return 0;
}
/****************************************************************
* private interface
*
*/
/****************************************************************
* handle ACK/NACK response from vmc
*
*/
void SendBuffer::onReceiveResponse(quint8 response)
{
if (this->messageQueue.size() == 0) return;
// reset counter:
this->responseTimerTimeoutCounter = 0;
//if (response == NACK) qDebug() << "onReceiveResponse() NACK";
//if (response == ACK) qDebug() << "onReceiveResponse() ACK";
qDebug() << "--- onReceiveResponse() messageQueue.size() = " << this->messageQueue.size();
/* resend command on NACK */
if (response == NACK) {
// stop timeoutTimer
this->responseTimeoutTimer->stop();
if (this->resendCounter > SB_MAX_RESEND) {
// command could not be processed on peer: remove it from message queue
this->messageQueue.removeFirst();
this->resendCounter = 0;
}
else {
// else: resend command
if (this->messageQueue.size() != 0) this->PrivateSendMessage();
}
}
/* send next command on ACK */
if (response == ACK) {
// stop timeoutTimer
this->responseTimeoutTimer->stop();
// remove old message from message-queue
this->messageQueue.removeFirst();
this->resendCounter = 0;
if (this->messageQueue.size() != 0) this->PrivateSendMessage();
}
}
/* this timeout-handler is called, if no response (ACK/NACK) was received from vmc
*/
void SendBuffer::onResponseTimeoutTimerTimeout()
{
qDebug() << "onResponseTimeoutTimerTimeout() messageQueue.size() = " << this->messageQueue.size();
if (this->messageQueue.size() == 0) {
return;
}
// wakeup vmc
emit this->sendError(SEND_ERROR::RESPONSE);
if (this->resendCounter > SB_MAX_RESEND) {
this->messageQueue.removeFirst();
this->resendCounter = 0;
this->responseTimerTimeoutCounter++;
this->responseTimeoutTimer->stop();
emit this->sendError(SEND_ERROR::RESPONSE_TIMER_TIMEOUT);
if (this->responseTimerTimeoutCounter > 10) {
// switch to self out-of-order mode ...
emit this->sendError(SEND_ERROR::MULTIPLE_RESPONSE_TIMER_TIMEOUT);
}
// try to send an possible next message in order
// to empty queue:
if (!this->messageQueue.isEmpty()) {
PrivateSendMessage();
}
}
// send next message
else {
PrivateSendMessage();
}
}
/* send first message in Message-Queue
*
* preconditon: at least one message is in queue!
*/
void SendBuffer::PrivateSendMessage()
{
// take message from queue
QByteArray ba = this->messageQueue.head();
// put bytes on serial line
for (int i = 0; i < ba.size(); i++) {
this->interface->putChar(ba.at(i));
}
// do logging here
emit this->writeLogSent(ba);
this->resendCounter++;
// start timeoutTimer
this->responseTimeoutTimer->start();
}

View File

@ -0,0 +1,59 @@
#ifndef SENDBUFFER_H
#define SENDBUFFER_H
#include <QObject>
#include <QByteArray>
#include <QQueue>
#include "com_interface.h"
class QTimer;
class VMC;
enum class SEND_ERROR : quint8;
#define SB_MAX_RESEND 3
#define SB_MAX_SENDQUEUESIZE 10
class SendBuffer : public QObject
{
Q_OBJECT
private:
VMC *vmc;
COM_interface *interface;
QQueue<QByteArray> messageQueue;
quint8 resendCounter;
/* timer for resending messages to vmc, if no valid response is resent from vmc
*/
QTimer *responseTimeoutTimer;
quint8 responseTimerTimeoutCounter;
void PrivateSendMessage();
public:
explicit SendBuffer(COM_interface *cinterface, QObject *parent = nullptr);
~SendBuffer();
int SendMessage(QByteArray & ba, bool enqueue = false);
signals:
void writeLogSent(QByteArray ba);
void sendError(SEND_ERROR error);
public slots:
void onReceiveResponse(quint8 response);
void onResponseTimeoutTimerTimeout();
};
enum class SEND_ERROR : quint8 {
NO_ERROR = 0,
RESPONSE,
RESPONSE_TIMER_TIMEOUT,
MULTIPLE_RESPONSE_TIMER_TIMEOUT
};
#endif // SENDBUFFER_H

View File

@ -0,0 +1,303 @@
#include "com_interface.h"
#include <QtDebug>
#if QT_VERSION >=0x050000
#include <QSerialPort>
#else
#include "qextserialport.h"
#endif
COM_interface::COM_interface(QObject *parent) :
QObject(parent)
{
#if QT_VERSION >=0x050000
port = new QSerialPort(this);
#else
port = new QextSerialPort(QextSerialPort::EventDriven, this);
#endif
buffer = new QByteArray();
}
COM_interface::~COM_interface()
{
delete buffer;
delete port;
}
/***************************************************************************
* *************************************************************************
*
* QT5 ( = QSerialPort) specific methodes
*
***************************************************************************
***************************************************************************/
#if QT_VERSION >=0x050000
int COM_interface::open(const QString & portname, int baudrate)
{
QSerialPort::BaudRate br = QSerialPort::Baud115200;
switch (baudrate) {
case 9600: br = QSerialPort::Baud9600;
break;
case 57600: br = QSerialPort::Baud57600;
break;
default: br = QSerialPort::Baud115200;
break;
}
qDebug() << "COM_interface::open(): baudrate = " << baudrate;
qDebug() << "COM_interface::open(): br = " << br;
port->setPortName(portname);
port->setBaudRate(br);
port->setStopBits(QSerialPort::OneStop);
port->setParity(QSerialPort::NoParity);
port->setDataBits(QSerialPort::Data8);
if (port->open(QIODevice::ReadWrite) == true) {
connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
qDebug() << "listening for data on" << port->portName();
emit connected();
return 1;
}
else {
qDebug() << "device failed to open:";
qDebug() << " device:" << portname;
qDebug() << " errorstring:" << port->errorString();
return -1;
}
}
int COM_interface::open(const QString & portname, int baudrate, int dataBits, int stopBits, int parity)
{
QSerialPort::BaudRate br = QSerialPort::Baud115200;
QSerialPort::DataBits db = QSerialPort::Data8;
QSerialPort::StopBits sb = QSerialPort::OneStop;
QSerialPort::Parity par = QSerialPort::NoParity;
switch (baudrate) {
case 9600: br = QSerialPort::Baud9600;
break;
case 57600: br = QSerialPort::Baud57600;
break;
default: br = QSerialPort::Baud115200;
break;
}
//TODO Add if needed!
switch (dataBits) {
default: db = QSerialPort::Data8;
break;
}
switch (stopBits) {
case 2: sb = QSerialPort::TwoStop;
break;
default: sb = QSerialPort::OneStop;
break;
}
switch (parity) {
default: par = QSerialPort::NoParity;
break;
}
qDebug() << "COM_interface::open(): baudrate = " << baudrate;
qDebug() << "COM_interface::open(): br = " << br;
qDebug() << "COM_interface::open(): databits = " << dataBits;
qDebug() << "COM_interface::open(): db = " << db;
qDebug() << "COM_interface::open(): stopbits = " << stopBits;
qDebug() << "COM_interface::open(): sb = " << sb;
qDebug() << "COM_interface::open(): parity = " << parity;
qDebug() << "COM_interface::open(): par = " << par;
port->setPortName(portname);
port->setBaudRate(br);
port->setStopBits(sb);
//port->setFlowControl(FLOW_OFF);
port->setParity(par);
port->setDataBits(db);
if (port->open(QIODevice::ReadWrite) == true) {
connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
qDebug() << "listening for data on" << port->portName();
emit connected();
return 1;
}
else {
qDebug() << "device failed to open:";
qDebug() << " device:" << portname;
qDebug() << " errorstring:" << port->errorString();
return -1;
}
}
/***************************************************************************
* *************************************************************************
*
* QT4 ( = QextSerialPort) specific methodes
*
***************************************************************************
***************************************************************************/
#else
int COM_interface::open(const QString & portname, int baudrate)
{
BaudRateType br = BAUD115200;
switch (baudrate) {
case 9600: br = BAUD9600;
break;
case 57600: br = BAUD57600;
break;
default: br = BAUD115200;
break;
}
qDebug() << "COM_interface::open(): baudrate = " << baudrate;
qDebug() << "COM_interface::open(): br = " << br;
port->setPortName(portname);
port->setBaudRate(br);
port->setStopBits(STOP_1);
//port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setTimeout(0);
if (port->open(QIODevice::ReadWrite) == true) {
connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
if (!(port->lineStatus() & LS_DSR))
qDebug() << "warning: device is not turned on";
qDebug() << "listening for data on" << port->portName();
emit connected();
return 1;
}
else {
qDebug() << "device failed to open:";
qDebug() << " device:" << portname;
qDebug() << " errorstring:" << port->errorString();
return -1;
}
}
int COM_interface::open(const QString & portname, int baudrate, int dataBits, int stopBits, int parity)
{
BaudRateType br = BAUD115200;
DataBitsType db = DATA_8;
StopBitsType sb = STOP_1;
ParityType par = PAR_NONE;
switch (baudrate) {
case 9600: br = BAUD9600;
break;
case 57600: br = BAUD57600;
break;
default: br = BAUD115200;
break;
}
//TODO Add if needed!
switch (dataBits) {
default: db = DATA_8;
break;
}
switch (stopBits) {
case 2: sb = STOP_2;
break;
default: sb = STOP_1;
break;
}
switch (parity) {
default: par = PAR_NONE;
break;
}
qDebug() << "COM_interface::open(): baudrate = " << baudrate;
qDebug() << "COM_interface::open(): br = " << br;
qDebug() << "COM_interface::open(): databits = " << dataBits;
qDebug() << "COM_interface::open(): db = " << db;
qDebug() << "COM_interface::open(): stopbits = " << stopBits;
qDebug() << "COM_interface::open(): sb = " << sb;
qDebug() << "COM_interface::open(): parity = " << parity;
qDebug() << "COM_interface::open(): par = " << par;
port->setPortName(portname);
port->setBaudRate(br);
port->setStopBits(sb);
//port->setFlowControl(FLOW_OFF);
port->setParity(par);
port->setDataBits(db);
port->setTimeout(0);
if (port->open(QIODevice::ReadWrite) == true) {
connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
if (!(port->lineStatus() & LS_DSR))
qDebug() << "warning: device is not turned on";
qDebug() << "listening for data on" << port->portName();
emit connected();
return 1;
}
else {
qDebug() << "device failed to open:";
qDebug() << " device:" << portname;
qDebug() << " errorstring:" << port->errorString();
return -1;
}
}
#endif
int COM_interface::close(void)
{
if (port->isOpen()) {
port->flush();
//port->reset();
port->close();
port->reset();
}
emit disconnected();
return 0;
}
void COM_interface::onReadyRead(void) {
qint64 i;
i = 0;
buffer->clear();
while (1) {
char c;
if (port->read(& c, 1) <= 0)
break;
qDebug() << "com_interface::onReadyRead(): buffer[" << i << "]: '" << c << "'";
buffer->insert(i++,c);
}
emit ReadData(buffer);
}
void COM_interface::onDsrChanged(bool state) {
// DSR-line is not used with CLR200 reader
// so we do nothing on this signal.
qDebug() << "onDsrChanged(): state is " << state;
}
void COM_interface::putChar(const char c) {
port->putChar(c);
}

View File

@ -0,0 +1,53 @@
#ifndef COM_INTERFACE_H
#define COM_INTERFACE_H
#include <QObject>
#if QT_VERSION >=0x050000
class QSerialPort;
#else
class QextSerialPort;
#endif
class COM_interface : public QObject
{
Q_OBJECT
private:
#if QT_VERSION >=0x050000
QSerialPort *port;
#else
QextSerialPort *port;
#endif
QByteArray *buffer;
public:
explicit COM_interface(QObject *parent = nullptr);
~COM_interface();
int open(const QString & portname, int baudrate);
int open(const QString & portname, int baudrate, int dataBits, int stopBits, int parity);
int close(void);
void putChar(const char c);
int isOpen(void);
signals:
void ReadData(QByteArray *buffer);
void connected(void);
void disconnected(void);
public slots:
private slots:
void onReadyRead(void);
void onDsrChanged(bool state);
};
#endif // COM_INTERFACE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,394 @@
#ifndef VMC_H
#define VMC_H
#include "com_interface.h"
#include "VMC/ReceiveBuffer.h"
#include "SendBuffer.h"
#include "support/VendingData.h"
#include <QObject>
#include <QByteArray>
#include <QStateMachine>
#include <QDebug>
#include <QTimer>
#include <QList>
#include "version.h"
#define VMC_RECEIVE_TIMEOUT 1000
#define VMC_CMD_SW_VERSION 0x10
#define VMC_CMD_STATUS_REQUEST 0x11
#define VMC_CMD_SCREEN 0x44
#define VMC_CMD_LANGUAGE 0x46
#define VMC_CMD_DISP_LICENCE_PLATE 0x48
#define VMC_CMD_DISP_PRODUCT 0x49
#define VMC_CMD_DISP_PARKTIME_END 0x50
#define VMC_CMD_DISP_PRICE 0x51
#define VMC_CMD_DATE_TIME 0x52
#define VMC_CMD_DISP_LINE1 0x53
#define VMC_CMD_DISP_LINE2 0x54
#define VMC_CMD_USER_MESSAGE 0x55
#define VMC_CMD_DISP_AMOUNT_TO_PAY 0x56
#define VMC_CMD_TEXT 0x60
#define VMC_CMD_TEXT_ENC 0x61
#define VMC_CMD_MACHINE_NR 0x62
#define VMC_CMD_SYSTEM 0x63
#define VMC_CMD_PSA_CONFIG 0x64
#define VMC_CMD_BUSY 0x66
#define VMC_CMD_MESSAGE_BOX 0x67
#define VMC_CMD_END_PRG 0x70 // kill ATBQT
#define VMC_CMD_SHUTDOWN_SYSTEM 0x71 // 'halt'
#define VMC_CMD_RESTART_PRG 0x72 // restart ATBQT
#define VMC_CMD_RESTART_SYSTEM 0x73 // reboot ptu
#define VMC_CMD_SCREEN_CFG 0x90
#define VMC_CMD_FORMATED_STRING 0xD0
#define VMC_CMD_VMC_SYSTEM 0xE0
#define VMC_CMD_SCREEN_INVALID 0x00
#define VMC_CMD_SCREEN_START 0x30
#define VMC_CMD_SCREEN_LICPLT 0x31
#define VMC_CMD_SCREEN_PRODUCT 0x32
#define VMC_CMD_SCREEN_PARKEND 0x33
#define VMC_CMD_SCREEN_PAYMETH 0x34
#define VMC_CMD_SCREEN_CREDITCARD 0x35
#define VMC_CMD_SCREEN_WAIT_FOR 0x36
#define VMC_CMD_SCREEN_GOODBYE 0x37
#define VMC_CMD_SCREEN_CASHPAY 0x38
#define VMC_CMD_SCREEN_PIN 0x39
#define VMC_CMD_SCREEN_RESIDENT 0x3A
#define VMC_CMD_SCREEN_GOODBYE2 0x3B
#define VMC_CMD_SCREEN_RECEIPT 0x3C
#define VMC_CMD_SCREEN_FREEPARK 0x3D
#define VMC_CMD_SCREEN_DEFBUTTONS 0x3E
#define VMC_CMD_SCREEN_PAYMETHODE1 0x3F
#define VMC_CMD_SCREEN_PAYMETHODE2 0x40
#define VMC_CMD_SCREEN_PAYMETHODE3 0x41
#define VMC_CMD_SCREEN_PAYMETHODE4 0x42
#define VMC_CMD_SCREEN_CARDSTATUS 0x43
#define VMC_CMD_SCREEN_PAYMETHODE5 0x44
#define VMC_CMD_SCREEN_PAYMETHODE6 0x45
#define VMC_CMD_SCREEN_PAYMETHODE7 0x46
#define VMC_CMD_SCREEN_CREDITCARDABORT 0x47
#define VMC_CMD_SCREEN_PAYMETHODE8 0x48
#define VMC_CMD_SCREEN_REMOVECARD 0x49
#define VMC_CMD_SCREEN_GOODBYE3 0x4A
#define VMC_CMD_SCREEN_GENERALABORT 0x4B
#define VMC_CMD_SCREEN_ABORT2 0x4C
#define VMC_CMD_SCREEN_ABORT3 0x4D
#define VMC_CMD_SCREEN_GOODBYE4 0x4E
#define VMC_CMD_SCREEN_GOODBYE5 0x4F
// note: SCREEN_COMMON is 0x50
#define VMC_CMD_SCREEN_FINEPAYMENT 0x51
#define VMC_CMD_SCREEN_CREDITCARD2 0x52
#define VMC_CMD_SCREEN_CREDITCARD3 0x53
#define VMC_CMD_SCREEN_RECEIPT2 0x54
#define VMC_CMD_SCREEN_CREDITCARD4 0x55
#define VMC_CMD_SCREEN_TWO_PRODUCTS1 0x56
#define VMC_CMD_SCREEN_TWO_PRODUCTS2 0x57
#define VMC_CMD_SCREEN_PARKTIME1 0x5a
#define VMC_CMD_SCREEN_PARKTIME2 0x5b
#define VMC_CMD_SCREEN_DATETIME1 0x5c
#define VMC_CMD_SCREEN_DATETIME2 0x5d
#define VMC_CMD_SCREEN_DIAG 0x60
#define VMC_CMD_SCREEN_WELCOME1 0x61
#define VMC_CMD_SCREEN_WELCOME2 0x62
#define VMC_CMD_SCREEN_WELCOME3 0x63
#define VMC_CMD_SCREEN_WELCOME4 0x64
#define VMC_CMD_SCREEN_OOO 0x65
#define VMC_CMD_SCREEN_WAIT1 0x6A
#define VMC_CMD_SCREEN_WAIT2 0x6B
#define VMC_CMD_SCREEN_WAIT3 0x6C
#define VMC_CMD_SCREEN_WAIT4 0x6D
#define VMC_CMD_SCREEN_TARIF 0x70
#define VMC_CMD_SCREEN_HELP1 0x71
#define VMC_CMD_SCREEN_HELP2 0x72
#define VMC_CMD_SCREEN_HELP3 0x73
#define VMC_CMD_SCREEN_HELP4 0x74
#define VMC_CMD_SCREEN_HELP5 0x75
#define VMC_CMD_SCREEN_ABORT4 0x80
#define VMC_CMD_SCREEN_ABORT5 0x81
#define VMC_CMD_SCREEN_BARCODE 0x82
#define VMC_CMD_SCREEN_AGEVERIFICATION 0x83
#define VMC_CMD_SCREEN_DEFBUTTONS2 0x84
#define VMC_CMD_SCREEN_DEFBUTTONS3 0x85
#define VMC_CMD_SCREEN_PRINT2 0x86
#define VMC_CMD_SCREEN_PRINT3 0x87
#define VMC_CMD_SCREEN_QRCODE_RECEIPT 0x88
#define VMC_CMD_SCREEN_LICPLT2 0x90
#define VMC_CMD_SCREEN_LICPLT3 0x91
#define VMC_CMD_SCREEN_LICPLT4 0x92
#define VMC_CMD_SCREEN_ABORT6 0x93
#define VMC_CMD_SCREEN_ABORT7 0x94
#define VMC_CMD_SCREEN_PARKEND2 0xA0
#define VMC_CMD_SCREEN_PARKEND3 0xA1
#define VMC_CMD_SCREEN_COMMON 0x50
#define VMC_CMD_SCREEN_MESSAGE_BOX 0xF1
// CARD_SERVICE_ERROR_TEXTS 0xFA
#define ACK 0x06
#define NACK 0x15
class AppControl;
class ReceiveBuffer;
class SendBuffer;
class HMI;
class ATBHMIconfig;
class VMC : public QObject
{
Q_OBJECT
private:
AppControl *main;
COM_interface *com_interface;
ReceiveBuffer *receiveBuffer;
SendBuffer *sendBuffer;
ATBHMIconfig *config;
// internal: write a ByteArray to com-port:
int SendMessage(QByteArray ba, bool enqueue = false);
quint16 parseSystemCommand(QByteArray & cmd);
quint8 parseTextCommand(QByteArray & cmd);
quint8 parseTextCommandEnc(QByteArray & cmd);
quint8 parseDataDisplayCommand(QByteArray & cmd);
quint8 parseDateCommand(QByteArray & cmd);
quint8 parseUserMessageCommand(QByteArray & cmd);
quint8 parseLanguageCommand(QByteArray & cmd);
quint8 parseBusyCommand(QByteArray & cmd);
quint8 parseScreenConfigCommand(QByteArray & cmd);
quint8 parsePSAConfigCommand(QByteArray & cmd);
quint8 parseShowMessageBoxCommand(QByteArray & cmd);
quint8 parseVMCSystemMessage(QByteArray & cmd);
quint8 parseVMCFormatedString(QByteArray & cmd);
QString & privateHandleDataCommand_Amount(quint8 data, QString & dataString);
QString & privateHandleDataCommand_AmountToPay(quint8 data, QString & dataString);
QTimer *sendDelayTimer;
QString delayedMessage;
quint8 flag_blockVMCScreen;
quint16 currentCachedScreen;
private slots:
void onDelayedMessageTimerTimeout();
void skipDiscount();
public:
explicit VMC(QObject *parent = nullptr);
VMC(AppControl *main, ATBHMIconfig *config, QObject *parent = nullptr);
~VMC();
int SendMessage(QString msg);
int SendMessageDelayed(QString msg, int delay);
int SendACK();
int SendNACK();
int sendButtonChar(QChar c);
int SendButton0(); // 0 - 3E 45 31 30 E4
int SendButton1(); // 1 - 3E 45 31 31 E5
int SendButton2(); // 2 - 3E 45 31 32 E6
int SendButton3(); // 3 - 3E 45 31 33 E7
int SendButton4(); // 4 - 3E 45 31 34 E8
int SendButton5(); // 5 - 3E 45 31 35 E9
int SendButton6(); // 6 - 3E 45 31 36 EA
int SendButton7(); // 7 - 3E 45 31 37 EB
int SendButton8(); // 8 - 3E 45 31 38 EC
int SendButton9(); // 9 - 3E 45 31 39 ED
int SendButtonNext(); // 10 - 3E 45 31 3A EE
int SendButtonBack(); // 11 - 3E 45 31 3B EF
int SendButtonCancel(); // 12 - 3E 45 31 3C F0
int SendButtonStart(); // 13 - 3E 45 31 3D F1
int SendButtonHelp(); // 14 - 3E 45 31 3E F2
int SendButtonTarif(); // 15 - 3E 45 31 3F F3
int SendButtonStart2(); // - 3E 45 31 A0 cs
int SendButtonStart3(); // - 3E 45 31 A1 cs
int SendButtonStart4(); // - 3E 45 31 A2 cs
int SendButtonArrowLeft(); // 16 - 3E 45 31 83 cs
int SendButtonArrowRight(); // 17 - 3E 45 31 84 cs -
int SendButtonArrowUp(); // 18 - 3E 45 31 85 cs -
int SendButtonArrowDown(); // 19 - 3E 45 31 86 cs -
int SendButtonCardTypeLeft(); // 20 - 3E 45 31 87 cs -
int SendButtonCardTypeRight(); // 21 - 3E 45 31 88 cs -
int SendButtonA(); // 'A' - 3E 45 31 41 F5
int SendButtonB(); // 'B' - 3E 45 31 42 F6
int SendButtonC(); // 'C' - 3E 45 31 43 F7
int SendButtonD(); // 'D' - 3E 45 31 44 F8
int SendButtonE(); // 'E' - 3E 45 31 45 F9
int SendButtonF(); // 'F' - 3E 45 31 46 FA
int SendButtonG(); // 'G' - 3E 45 31 47 FB
int SendButtonH(); // 'H' - 3E 45 31 48 FC
int SendButtonI(); // 'I' - 3E 45 31 49 FD
int SendButtonJ(); // 'J' - 3E 45 31 4A FE
int SendButtonK(); // 'K' - 3E 45 31 4B FF
int SendButtonL(); // 'L' - 3E 45 31 4C 00
int SendButtonM(); // 'M' - 3E 45 31 4D 01
int SendButtonN(); // 'N' - 3E 45 31 4E 02
int SendButtonO(); // 'O' - 3E 45 31 4F 03
int SendButtonP(); // 'P' - 3E 45 31 50 04
int SendButtonQ(); // 'Q' - 3E 45 31 51 05
int SendButtonR(); // 'R' - 3E 45 31 52 06
int SendButtonS(); // 'S' - 3E 45 31 53 07
int SendButtonT(); // 'T' - 3E 45 31 54 08
int SendButtonU(); // 'U' - 3E 45 31 55 09
int SendButtonV(); // 'V' - 3E 45 31 56 0A
int SendButtonW(); // 'W' - 3E 45 31 57 0B
int SendButtonX(); // 'X' - 3E 45 31 58 0C
int SendButtonY(); // 'Y' - 3E 45 31 59 0D
int SendButtonZ(); // 'Z' - 3E 45 31 5A 0E
int SendButtonUE(); // 'Ü' - 3E 45 31 DC - ISO 8859-1 (Latin-1): 'Ü'
int SendButtonOE(); // 'Ö' - 3E 45 31 D6 - ISO 8859-1 (Latin-1): 'Ö'
int SendButtonAE(); // 'Ä' - 3E 45 31 C4 - ISO 8859-1 (Latin-1): 'Ä'
int SendButtonDEL(); // DELL - 3E 45 31 7F 33
int SendButtonDash(); // '-' - 3E 45 31 2D E1
int SendButtonSpace(); // ' ' - 3E 45 31 20 D4
int SendButtonClose(); // - 3E 45 31 80 cs
int SendButtonYes(); // - 3E 45 31 81 cs
int SendButtonNo(); // - 3E 45 31 82 cs
int SendButtonVehicleDefintion1(); // 0x90 - 3E 45 31 90 cs
int SendButtonVehicleDefintion2(); // 0x91 - 3E 45 31 91 cs
int SendButtonVehicleDefintion3(); // 0x92 - 3E 45 31 92 cs
int SendButtonVehicleDefintion4(); // 0x93 - 3E 45 31 93 cs
int SendButtonVehicleDefintion5(); // 0x94 - 3E 45 31 94 cs
int SendButtonVehicleDefintion6(); // 0x95 - 3E 45 31 95 cs
int SendButtonVehicleDefintion7(); // 0x96 - 3E 45 31 96 cs
int SendButtonVehicleDefintion8(); // 0x97 - 3E 45 31 97 cs
int SendButtonPaymethode1(); // 0x98 - 3E 45 31 98 cs
int SendButtonPaymethode2(); // 0x99 - 3E 45 31 99 cs
int SendButtonPaymethode3(); // 0x9a - 3E 45 31 9a cs
int SendButtonPaymethode4(); // 0x9b - 3E 45 31 9b cs
int SendSystemMessage(quint8 nr); // 0xF0 - 3E F0 31 nr cs
int SendSystemMessageStart(); // 0xF0 - 3E F0 31 31 cs
int SendSystemMessageTimeout(); // 0xF0 - 3E F0 31 32 cs
int SendButtonServiceOK(QString MessageString);
// deprecated:
int SendLicPlate(QString licplate);
int SendBarcode(QString barcode);
int SendAmountDueTax(QString amount);
int SendAmountDueNet(QString amount);
int SendAmountDuePeriodStart(QString startTime);
int SendAmountDuePeriodEnd(QString endTime);
int SendCracePeriod(QString minute);
int SendGeneratedPinNumber(QString pin);
// from former "Bewonerscode": send code and id
int SendId(QString id);
int SendCode(QString code);
int SendFormatedString(QString formatString);
int SendFormatedStringError(QString errorString);
int SendLangSwitch(quint8 nr);
int SendVersion(QString VersionString); // 3E 10 14 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. CRC
int SendCurrentState();
void blockScreenSwitch(quint8 mode);
quint16 getCurrentCachedScreen();
signals:
void CommandProcessed(); // sent to ReceiveBuffer if a command is processed
void retriggerModeSell();
void setBusy();
void resetBusy();
void showMessageBox(quint8 type, quint8 text);
void sysCommand(quint16 cmd, QByteArray data);
//void PSAconfig(quint16 cust_nr, quint16 group_nr, quint16 zone_nr, quint16 machine_nr);
void setCustNr(const QString & cust_nr);
void setGroupNr(const QString & group_nr);
void setZoneNr(const QString & zone_nr);
void setMachineNr(const QString & machine_nr);
void displayData(quint8 infoFild, QString text);
void newDateTime(const QString & dateTimeString);
void setLanguage(quint8 lang);
void setDefaultLanguage(quint8 lang);
void userMessage(quint8 messagenr, quint8 action);
void writeLog(QString str);
void writeLogReceived(QByteArray ba);
void writeLogSent(QByteArray ba);
void wakeVMC();
void ccStartTransaction();
void ccConfirmTransaction();
void ccCancelTransaction();
void ccStartPreauthorisation();
void ccConfirmPreauthorisation();
void ccCancelPreauthorisation();
void ccStartReadCard();
void ccWakup();
void ccSleep();
#ifdef USE_BARCODESCANNER
void requestNewBarcode();
#endif
void VMCSystemSellingProcessStart();
void VMCSystemSellingProcessStop();
void VMCSystemTransactionSuccess();
void VMCFormatedString(FormatedStringList);
void setVendingData(QString key, QByteArray value);
public slots:
void CommandAvaliable(QByteArray message); // called when a message is in receive buffer
void onReceiveError(RECEIVE_ERROR error); // for response on wrong vmc commands
void onSendError(SEND_ERROR error); // for react on e.g. a non answering vmc
int SendLongFormatedString(QString formatString);
int SendLongFormatedStringReference(QString & formatedString);
void ccStartTransactionRequest(); // called to start/restart a CC transaction
void ccStartConfirmTransaction(); // called to start confirmation
void ccPrintReceipt(QString receipt); // called to send receipt to vmc
};
#endif // VMC_H

View File

@ -0,0 +1,76 @@
#include "VendingData.h"
#include <QDebug>
#include "ATBAPP.h"
#include "version.h"
VendingData::VendingData(QObject *parent) : QObject(parent)
{
qRegisterMetaType<FormatedStringList>("FormatedStringList");
}
QVariant VendingData::getParameter(const QString & key)
{
#if defined (ARCH_DesktopLinux)
// note: QVariant.toString() returns empty string for custom types
if (QString::compare(hash.value(key).typeName(), "APP_ACTION") == 0) {
APP_ACTION action = hash.value(key).value<APP_ACTION>();
qDebug() << "VendingData::getParameter() key = " << key << " value = " << action;
}
else {
qDebug() << "VendingData::getParameter() key = " << key << " value = " << hash.value(key).toString();
}
#endif
return hash.value(key);
}
void VendingData::setParameter(const QString & key, QVariant value)
{
#if defined (ARCH_DesktopLinux)
// note: QVariant.toString() returns empty string for custom types
if (QString::compare(value.typeName(), "APP_ACTION") == 0) {
APP_ACTION action = value.value<APP_ACTION>();
qDebug() << "VendingData::setParameter() key = " << key << " value = " << action;
}
else {
qDebug() << "VendingData::setParameter() key = " << key << " value = " << value.toString();
}
#endif
this->hash.insert(key, value);
}
void VendingData::clearParameter(const QString & key)
{
this->hash.remove(key);
}
bool VendingData::hasParameter(const QString & key)
{
return hash.contains(key);
}
void VendingData::clear()
{
this->hash.clear();
}
uint VendingData::getUintParameter(const QString & key)
{
qDebug() << "VendingData::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;
}

View File

@ -0,0 +1,37 @@
#ifndef VENDINGDATA_H
#define VENDINGDATA_H
#include <QObject>
#include <QHash>
#include <QVariant>
typedef QList<QByteArray> FormatedStringList;
class VendingData : public QObject
{
Q_OBJECT
private:
QHash<QString, QVariant> hash;
public:
explicit VendingData(QObject *parent = nullptr);
QVariant getParameter(const QString & key);
void setParameter(const QString & key, QVariant value);
void clearParameter(const QString & key);
bool hasParameter(const QString & key);
uint getUintParameter(const QString & key);
signals:
public slots:
void clear();
};
#endif // VENDINGDATA_H